ucb-bar / chiseltest

The batteries-included testing and formal verification library for Chisel-based RTL designs.
Other
221 stars 74 forks source link

Add peek/poke/expect for memories #182

Open nrother opened 4 years ago

nrother commented 4 years ago

As requested in #145 a much needed feature (for me at least) would be peek/poke/expect support on memories.

This is currently fully supported in Treadle, but not exposed in the tester API.

I made a prototype implementation of a TestableMem and it seems to work well: https://gist.github.com/nrother/37693bb7df287f3ad9e528381c28855d

Maybe you could include test support for memories based on my prototype? If I'll find some time I'll try to convert it to a proper PR, but currently my understanding of the internals of Chisel and Treadle is quite limited. The code currently assumes that a Bundle always gets split into multiple memories, using an underscore as the separator. Maybe there is an API to query the memory name for a Bundle element?

ducky64 commented 4 years ago

Cool!

So giving it a bit of though, there's more than one option for a memory access API:

In theory, the first API could allow sub-"row" pokes by taking in a partial bundle literals, and you can access the Bundle literal sub-field from a poke. Note that partial Bundle literal pokes, in general, are currently disallowed. In either case, sub-"row" pokes will require support in the simulator, or a shim read-modify-write operation in the interface layer.

Skimming through your PR, I think most of it looks reasonable, though integrating it into mainline code means that you can get direct access to the internals and avoid some of the boilerplate, though you'll also need to expand some internal interfaces to memory operations. But two things I'd probably change:

nrother commented 4 years ago

Some thoughts on this:

Note that partial Bundle literal pokes, in general, are currently disallowed.

Do you have any information on this? pokePartial looks like it is fully supported...

I'll see if I can find some time to convert this sketch into an actual PR...

ducky64 commented 4 years ago

About partial Bundle literal pokes: mainly an API design consideration, instead of a can-we-do-it issue (which we can, as demonstrated with pokePartial). The idea is that the common API is "strict", and if you want to do something a bit more loose, you need to explicitly say so by using a different, looser API.

That's an interesting observation on the Lo?Firrtl bundle memory transform - I'll ask at the next chisel-dev meeting about what we can rely on with regards to that behavior, and also what interfaces are common in simulators for memory access.

For bulk operations: I guess that makes sense. Main question would be what should happen when not all elements are passed in. I generally prefer a more explicit API, so maybe something like mem.pokeAll(...) and mem.pokeSome(...) (but with better naming)?

ducky64 commented 4 years ago

We discussed this at the dev meeting today:

For memory APIs (mem.pokeElement(i, value), mem(i).pokeElement(value)): also makes sense to have a similar philosophy: get something working so it can be useful. Given that, it probably makes sense to use the former mem-specific API. Also, while the latter is cleaner, very little code will probably actually need to access memory elements like wires, and it will be difficult to implement.

nrother commented 4 years ago

Just to confirm: The gist currently assumes the observed behavior that bundle-mems are split to multiple "basic-type" mems, with the names split by _.

The "done is better than perfect" approach sounds good for me!

ducky64 commented 4 years ago

Yes, I think you're correct. I'm not completely sure on naming guarantees, but in general it's probably best to use a "feedback" API (eg, a rename map from FIRRTL - instead of a hard-coded naming structure and assuming it will hold) where possible.

nrother commented 2 years ago

Digging this up, after #358 has landed.

Is there any possibility to implement this easily now? I tried to update my code above to use the correct type SimulatorContext (Since ThreadleContext is now private) but it is missing the expectMemory function.

Before I resort to even more reflection-hacking I just wanted to ask if it became possible to implement this cleanly now :slightly_smiling_face:

ekiwi commented 2 years ago

The only way to access the expectMemory functionality for now is through the old PeekPokeTester compatibility API (in chiseltest.iotesters). My minimum requirement for exposing functionality in the mainstream API is that it needs to work for Treadle and for Verilator. People should be able to seamlessly switch between the two backends.

So if someone from the community implements peekMemory and pokeMemory support for Verilator, I would be happy to expose it. The way to go about implementing support for Verilator is to add some peekMemory/pokeMemory tests to this suite of tests: https://github.com/ucb-bar/chiseltest/blob/master/src/test/scala/chiseltest/simulator/MemoryCompliance.scala These tests should pass for treadle (check by running the TreadleMemoryCompliance tests), but will fail for Verilator (check by running the VerilatorMemoryCompliance tests). Then you can start adding the required changes to the Verilator backend. You will probably have to touch at least https://github.com/ucb-bar/chiseltest/blob/master/src/main/scala/chiseltest/simulator/VerilatorSimulator.scala and the files in https://github.com/ucb-bar/chiseltest/tree/master/src/main/scala/chiseltest/simulator/jna.

nrother commented 2 years ago

Hm, ok. I personally would love to see peek/pokeMem support in the API, even if it would only work on one backend. Verilator support would be awesome, of course. Maybe I can have a look into it (thanks for the pointers!)

For now, I updaded the Gist liked above to work with Chiseltest 0.5.0

nrother commented 2 years ago

I just had a quick look into the Verilator API and found no evidence on how to peek/poke memories... For me this looks like being totally unsupported in Verilator :/

ekiwi commented 2 years ago

I just had a quick look into the Verilator API and found no evidence on how to peek/poke memories... For me this looks like being totally unsupported in Verilator :/

It can be done, but is fairly tricky to achieve (cocotb afaik allows poking/peeking memory with Verilator). However, I think I would be OK adding some memory peek/poke methods that will throw an exception unless you are using treadle. If anyone wants to open a PR with a minimal number of methods.