Home > Back-end >  Chisel persist value in module until new write
Chisel persist value in module until new write

Time:12-03

I have created a basic module that is meant to represent a unit of memory in Chisel3:

class MemristorCellBundle() extends Bundle {
    val writeBus = Input(UInt(1.W))
    val dataBus = Input(UInt(8.W))
    val cellBus = Output(UInt(8.W))
}

class MemCell() extends Module {
    val io = IO(new MemCellBundle())

    val write = Wire(UInt())
    write := io.voltageBus

    val internalValue = Reg(UInt())
    // More than 50% of total voltage in (255).
    when(write === 1.U) {
        internalValue := io.dataBus
        io.cellBus := io.dataBus
    } .otherwise {
        io.cellBus := internalValue
    }
}

What I want is for it to output the internalValue when the write bus is logic LOW, and change this value with logic HIGH. My understanding of Chisel is that the register can persist this internalValue between clock cycles, so that this basically acts as a single unit of memory.

I'm doing it in this way as part of a larger project. However when writing a unit test I am finding that the 'read-after-write' scenario fails.

class MemCellTest extends FlatSpec with ChiselScalatestTester with Matchers {
    behavior of "MemCell"
    it should "read and write" in {
        test(new MemCell()) { c =>
            c.io.dataBus.poke(5.U)
            c.io.write.poke(0.U)
            c.io.cellBus.expect(0.U)
            // Write
            c.io.dataBus.poke(5.U)
            c.io.write.poke(1.U)
            c.io.cellBus.expect(5.U)
            // Verify read-after-write
            c.io.dataBus.poke(12.U)
            c.io.write.poke(0.U)
            c.io.cellBus.expect(5.U)
        }
    }
}

The first two expectations work just as I would expect. However, when I try to read after writing, the cellBus returns to 0 instead of persisting the 5 that I had written previously.

test MemCell Success: 0 tests passed in 1 cycles in 0.035654 seconds 28.05 Hz
[info] MemCellTest:
[info] MemCell
[info] - should read and write *** FAILED ***
[info]   io_cellBus=0 (0x0) did not equal expected=5 (0x5) (lines in MyTest.scala: 10) (MyTest.scala:21)

Clearly the register is not keeping this value, and so internalValue reverts to 0. But why does this happen, and how would I be able to create a value that can persist?

CodePudding user response:

Drakinite's comment is correct. You need to make sure to step the clock in order to see the register latch the value. I tweaked your test to include a couple of steps and it works as expected:

  c.io.dataBus.poke(5.U)
  c.io.writeBus.poke(0.U)
  c.io.cellBus.expect(0.U)
  c.clock.step() // Added step
  // Write passthrough (same cycle)
  c.io.dataBus.poke(5.U)
  c.io.writeBus.poke(1.U)
  c.io.cellBus.expect(5.U)
  c.clock.step() // Added step
  // Verify read-after-write
  c.io.dataBus.poke(12.U)
  c.io.writeBus.poke(0.U)
  c.io.cellBus.expect(5.U)

Here's an executable example showing that this works (using chisel3 v3.4.4 and chiseltest v0.3.4): https://scastie.scala-lang.org/5E1rOEsYSzSUrLXZCvoyNA

  • Related