Axi4LiteRegisterFileSuite.scala 8.44 KB
Newer Older
1
package chisel.axiutils.registers
Jens Korinth's avatar
Jens Korinth committed
2
3
4
5
6
import  chisel.axiutils.{Axi4LiteProgrammableMaster, MasterAction}
import  chisel3._
import  chisel3.util._
import  chisel3.iotesters.{ChiselFlatSpec, Driver, PeekPokeTester}
import  chisel.axi._
7
8
9
10
11
12
13
14
15
16
17
18

/**
 * Harness for Axi4LiteRegisterFile:
 * Creates a register file using the specified register map, connects an Axi4LiteProgrammableMaster
 * to the register file and programs it with the specified actions.
 * Read data is queued in a FIFO and can be accessed from the outside.
 * When all actions are processed, the `finished` flag is driven high.
 * @param size number of registers
 * @param distance byte distance of registers
 * @param regs register map for register file
 * @param actions master actions to perform
 **/
Jens Korinth's avatar
Jens Korinth committed
19
20
21
22
23
24
25
26
27
class RegFileTest(val size: Int, val off: Int, regs: Map[Int, ControlRegister], actions: Seq[MasterAction])
                 (implicit axi: Axi4Lite.Configuration) extends Module {
  val io = IO(new Bundle {
    val out = Decoupled(UInt(axi.dataWidth))
    val finished = Output(Bool())
    val rresp = Output(UInt(2.W))
    val wresp = Output(UInt(2.W))
  })
  val cfg = new Axi4LiteRegisterFileConfiguration(regs = regs)
28
29
30
  val saxi = Module(new Axi4LiteRegisterFile(cfg))
  val m = Module(new Axi4LiteProgrammableMaster(actions))
  m.io.maxi <> saxi.io.saxi
Jens Korinth's avatar
Jens Korinth committed
31
32
33
34
35
  io.out    <> m.io.out
  io.finished       := m.io.finished
  m.io.w_resp.ready := true.B
  io.rresp          := m.io.maxi.readData.bits.resp
  io.wresp          := m.io.maxi.writeResp.bits
36
37
38
39
40
41
42
}

/**
 * ReadTester checks attempts to read from all registers.
 * @param m configured RegFileTest module
 * @param isTrace turns on debug output (default: true)
 **/
Jens Korinth's avatar
Jens Korinth committed
43
class ReadTester(m: RegFileTest) extends PeekPokeTester(m) {
44
45
46
47
48
49
50
51
52
53
54
  reset(10)
  poke(m.io.out.ready, true)
  var steps = m.size * 10 // no more than 10 clock cycles per read
  for (i <- 1 until m.size + 1 if steps > 0) {
    // wait til output queue is ready
    while (steps > 0 && peek(m.io.out.ready) == 0 || peek(m.io.out.valid) == 0) {
      steps -= 1
      step(1)
    }
    val v = peek(m.io.out.bits)
    val e = BigInt("%02x".format(i) * 4, 16)
Jens Korinth's avatar
Jens Korinth committed
55
    val resp = peek(m.io.rresp)
56
57
58
59
60
61
62
63
64
65
66
67
    expect (resp == 0, "read #%d: resp is 0x%x (%d), should be 0 (OKAY)".format(i, resp, resp))
    expect(v == e, "at action #%d, expected: 0x%x (%d) but found %x (%d)".format(i, e, e, v, v))
    step(1)
  }
  expect(peek(m.io.finished) != 0, "finished signal should be true at end of test")
}

/**
 * WriteTester checks attempts to write to all registers.
 * @param m configured RegFileTest module
 * @param isTrace turns on debug output (default: true)
 **/
Jens Korinth's avatar
Jens Korinth committed
68
class WriteTester(m: RegFileTest) extends PeekPokeTester(m) {
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
  reset(10)
  poke(m.io.out.ready, true)
  println("running for a total of %d steps max ...".format(m.size * 20))
  var steps = m.size * 20 // no more than 10 clock cycles per read+write
  for (i <- 1 until m.size + 1 if steps > 0) {
    while (steps > 0 && (peek(m.io.out.ready) == 0 || peek(m.io.out.valid) == 0)) {
      steps -= 1
      step(1)
    }
    val v = peek(m.io.out.bits)
    val e = BigInt("%02x".format(i) * 4, 16)
    expect(v == e, "at output #%d, expected: 0x%x (%d), found %x (%d)".format(i, e, e, v, v))
    step(1)
  }
  expect(peek(m.io.finished) != 0, "finished signal should be true at end of test")
}

/**
 * InvalidReadTester checks invalid read attempts for proper return code.
 * @param m configured RegFileTest module
 * @param reads number of invalid reads to perform
 * @param isTrace turns on debug output (default: true)
 **/
Jens Korinth's avatar
Jens Korinth committed
92
class InvalidReadTester(m: RegFileTest, reads: Int) extends PeekPokeTester(m) {
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
  reset(10)
  println("performing %d invalid reads ...")
  var steps = reads * 10
  for (i <- 1 until reads + 1 if steps > 0) {
    while (steps > 0 && (peek(m.m.io.maxi.readData.valid) == 0 || peek(m.m.io.maxi.readData.ready) == 0)) {
      steps -= 1
      step(1)
    }
    val resp = peek(m.m.io.maxi.readData.bits.resp)
    expect (resp == 2, "read #%d: resp is 0x%x (%d), should be 2 (SLVERR)".format(i, resp, resp))
    step(1)
  }
  expect(peek(m.io.finished) != 0, "finished signal should be true at end of test")
}

/**
 * InvalidWriteTester checks invalid write attempts for proper return code.
 * @param m configured RegFileTest module
 * @param writes number of invalid writes to perform
 * @param isTrace turns on debug output (default: true)
 **/
Jens Korinth's avatar
Jens Korinth committed
114
class InvalidWriteTester(m: RegFileTest, writes: Int) extends PeekPokeTester(m) {
115
  reset(10)
Jens Korinth's avatar
Jens Korinth committed
116
  println("performing %d invalid writes ...".format(writes))
117
118
119
120
121
122
  var steps = writes * 10
  for (i <- 1 until writes + 1 if steps > 0) {
    while (steps > 0 && peek(m.m.io.w_resp.valid) == 0) {
      steps -= 1
      step(1)
    }
Jens Korinth's avatar
Jens Korinth committed
123
    val resp = peek(m.io.wresp)
124
125
126
127
128
129
130
    expect(resp == 2, "write #%d: resp is 0x%x (%d), should be 2 (SLVERR)".format(i, resp, resp))
    step(1)
  }
  expect(peek(m.io.finished) != 0, "finished signal should be true at end of test")
}

/** Unit test suite for Axi4LiteRegisterFile module. **/
Jens Korinth's avatar
Jens Korinth committed
131
class Axi4LiteRegisterFileSuite extends ChiselFlatSpec {
132
  // basic Chisel arguments
Jens Korinth's avatar
Jens Korinth committed
133
  val chiselArgs = Array("--fint-write-vcd")
134
  // implicit AXI configuration
Jens Korinth's avatar
Jens Korinth committed
135
  implicit val axi = Axi4Lite.Configuration(dataWidth = Axi4Lite.Width32, addrWidth = AddrWidth(32))
136
137
138

  /** Attempts to read from all registers. **/
  private def readTest(size: Int, off: Int) =  {
Jens Korinth's avatar
Jens Korinth committed
139
    val args = chiselArgs ++ Array("--target-dir", "test/Axi4RegisterFileSuite/read/size_%d_off_%d".format(size, off))
140
141
142
    // fill constant registers with pattern
    val regs = (for (i <- 1 until size + 1) yield
      off * i -> new ConstantRegister(value = BigInt("%02x".format(i) * 4, 16))
Jens Korinth's avatar
Jens Korinth committed
143
    ).toMap
144
145
146
    // read each of the registers in sequence
    val actions = for (i <- 1 until size + 1) yield MasterAction(true, off * i, None)
    // run test
Jens Korinth's avatar
Jens Korinth committed
147
148
    Driver.execute(args, () => new RegFileTest(size, off, regs, actions))
      { m => new ReadTester(m) }
149
150
151
152
  }

  /** Attempts to write to all registers. **/
  private def writeTest(size: Int, off: Int) =  {
Jens Korinth's avatar
Jens Korinth committed
153
    val args = chiselArgs ++ Array("--target-dir", "test/Axi4RegisterFileSuite/write/size_%d_off_%d".format(size, off))
154
155
156
    // fill constant registers with pattern
    val regs = (for (i <- 1 until size + 1) yield
      off * i -> new Register(width = axi.dataWidth)
Jens Korinth's avatar
Jens Korinth committed
157
    ).toMap
158
159
160
161
162
163
164
165
    // read each of the registers in sequence
    val actions = (for (i <- 1 until size + 1) yield Seq(
      // first write the register
      MasterAction(false, off * i, Some(BigInt("%02x".format(i) * (axi.dataWidth/8), 16))),
      // then read the new value
      MasterAction(true, off * i, None)
    )) reduce (_++_)
    // run test
Jens Korinth's avatar
Jens Korinth committed
166
167
    Driver.execute(args, () => new RegFileTest(size, off, regs, actions))
      { m => new WriteTester(m) }
168
169
170
171
  }

  /** Attempts to perform invalid reads and checks return code. **/
  private def invalidReads(reads: Int) = {
Jens Korinth's avatar
Jens Korinth committed
172
    val args = chiselArgs ++ Array("--target-dir", "test/Axi4RegisterFileSuite/invalidReads/%d".format(reads))
173
174
175
176
177
    // only zero is valid register
    val regs = Map( 0 -> new ConstantRegister(value = 0) )
    // read from increasing addresses (all above 0 are invalid)
    val actions = for (i <- 1 until reads + 1) yield MasterAction(true, i * (axi.dataWidth / 8), None)
    // run test
Jens Korinth's avatar
Jens Korinth committed
178
179
    Driver.execute(args, () => new RegFileTest(1, 4, regs, actions))
      { m => new InvalidReadTester(m, reads) }
180
181
182
183
  }

  /** Attempts to perform invalid writes and checks return code. **/
  private def invalidWrites(writes: Int) = {
Jens Korinth's avatar
Jens Korinth committed
184
    val args = chiselArgs ++ Array("--target-dir", "test/Axi4RegisterFileSuite/invalidWrites/%d".format(writes))
185
186
187
188
189
    // only zero is valid register
    val regs = Map( 0 -> new ConstantRegister(value = 0) )
    // write from increasing addresses (all above 0 are invalid)
    val actions = for (i <- 1 until writes + 1) yield MasterAction(false, i * (axi.dataWidth / 8), Some(42))
    // run test
Jens Korinth's avatar
Jens Korinth committed
190
191
    Driver.execute(args, () => new RegFileTest(1, 4, regs, actions))
      { m => new InvalidWriteTester(m, writes) }
192
193
194
  }

  /* READ TESTS */
Jens Korinth's avatar
Jens Korinth committed
195
196
197
198
  "read_255_4" should "be ok" in { readTest(255, 4) }
  "read_16_16" should "be ok" in { readTest(16, 16) }
  "read_4_4" should "be ok" in   { readTest(4, 4) }
  "read_7_13" should "be ok" in  { readTest(7, 13) }
199
200

  /* WRITE TESTS */
Jens Korinth's avatar
Jens Korinth committed
201
202
203
204
  "write_255_4" should "be ok" in { writeTest(255,   4) }
  "write_16_16" should "be ok" in { writeTest( 16,  16) }
  "write_4_4" should "be ok" in   { writeTest(  4,   4) }
  "write_7_13" should "be ok" in  { writeTest(  7,  13) }
205
206

  /* INVALID R/W TESTS */
Jens Korinth's avatar
Jens Korinth committed
207
208
  "invalidReads_16" should "be ok" in  { invalidReads(16) }
  "invalidWrites_16" should "be ok" in { invalidWrites(16) }
209
}