Search code examples
chisel

Poking individual bits using peekpoketester


I have an IO bundle as shown below

val io = IO(new Bundle{
  val test = Input(UInt(32.W))
})

Now from the testbench I want to give inputs to the test pin. I know that we can use peekpoketesters to give an input like this

poke(dut.io.test, 40.U)

But is there a way I can use peekpoketester to set the individual bits of the test input pin? For example something like this

poke(dut.io.test(31,23) , 6.U)

Solution

  • The short answer is no, poking to specific bits of an input is not directly supported, but using the fact that you can peek top level inputs here is a very simplistic workaround. You can run and test this on scastie here. You could generalize this to operate on inputs more directly as in your example. This code uses an extremely quick, dirty, and naive bit manipulation method, but I like working with binary text strings when I'm in a hurry. One more note, this is using the more modern chiseltest (vs old iotesters), but a similar method could be used in iotesters

    import chisel3._
    import chiseltest._
    import chiseltest.experimental.ChiselTestShell
    
    class PassThrough extends Module {
      val io = IO(new Bundle {
        val in = Input(UInt(32.W))
        val out = Output(UInt(32.W))
      })
    
      io.out := io.in
    }
    
    /** use strings to construct bit mask to clear target range and then or in newbits */
    def setBits(
        target: BigInt,
        topBit: Int,
        lowBit: Int,
        newBits: BigInt
    ): BigInt = {
      val clearMask = BigInt(
        "1" * (target.bitLength.max(
          newBits.bitLength
        ) - topBit) + "0" * (topBit - lowBit + 1) + "1" * lowBit,
        radix = 2
      )
      (target & clearMask) | (newBits << lowBit)
    }
    
    // crude verification of setBits
    println(setBits(BigInt(31), 2, 1, 2).toString(2))
    
    chiseltest.RawTester.test(new PassThrough) { c =>
      c.io.in.poke(40.U)
      c.clock.step()
      c.io.out.expect(40.U)
    
      val lastIn = c.io.in.peek().litValue()
      val newVal = setBits(lastIn, 31, 23, 6)
    
      val bitAddr = (0 to 31).map { x => x % 10 }.reverse.mkString("")
      
      println(s"          = $bitAddr")
      println(f"lastIn    = ${lastIn.toString(2)}%32s")
      println(f"newVal    = ${newVal.toString(2)}%32s")
      c.io.in.poke(newVal.U)
      c.clock.step()
      c.io.out.expect(newVal.U)
    }