fault
fault copied to clipboard
Where should we type check?
Imagine a circuit with input I
of type Bits(4)
. If we have a fault.Tester
for this circuit, and we issue for example a poke(circuit.I, 100)
, what should happen? I see 3 options:
- In
Tester.poke(port, value)
do a type check thatvalue
is compatible with the type ofport
. Right now we do some type checking (e.g. ifport
is typeBits
only a bit-vector or int is allowed forvalue
), but this doesn't check if the value fits in the bit-width. We could also do this in thePoke
class constructor -- but this is the same idea. - Pass this on to the target. It's possible that some targets can handle this trivially, some maybe not. For example, verilator is all
int
based, so we can always dotop->I = value
. On the other hand, another simulator may have a bit-vector interface, alatop.I = BitVector(value, n)
, in which case this may not always work. - Enforce that the targets always generate valid code for any such pokes (and they should fail downstream).
The issue is more complex for expect()
than poke()
because if a bit-vector gets truncated it may return a false-positive equality. For example
BitVector(3, 4) == BitVector(BitVector(35, 8), 4)
though
BitVector(3, 4) != BitVector(35, 8)
My hunch is that we should issue a warning in the top-level poke
and expect
functions and try to enforce that the targets maintain as much structure as possible (i.e. do not truncate/zext).
One way to approach this would be consider that the interface to the fault Tester
object is a magma circuit, so perhaps poke
, expect
should match the magma type system. How this is enforced (fault frontend versus target) would be an implementation detail, but I would vote that poke
and expect
exhibit the same semantics as wiring constant values in magma
. So, we do promotion when possible, but truncation is an error (the user needs to do this themselves).
One question is whether we can factor the code in a way such that we can use the exact same rules as magma (perhaps this requires magma to abstract it's type checking code for integers into routines which we can call in fault).
I think this might be better to do at the frontend, because the targets may have different semantics/ For example, verilator and ncsim might follow different type checking/promotion/conversion rules for integers than magma. I think our goal was to have a test bench work on all targets, so it should be specified in one frontend, and mapped to the semantics of the target. So my vote is to use magma's typing rules for the frontend.
Good idea, I'm on board for that. So just to be clear, the most-user facing functions (e.g. Tester.poke/expect
) should have promotion logic (e.g. python int
to magma.uint
), and the interface to the targets will be such that they all receive magma values (via the action objects).