fabianschuiki / llhd

Low Level Hardware Description — A foundation for building hardware design tools.
http://www.llhd.io
Apache License 2.0
392 stars 30 forks source link

Add logic type #55

Open fabianschuiki opened 4 years ago

fabianschuiki commented 4 years ago

Add the logic type lN, e.g. l32 or l9001 which represents a IEEE 1164 value, i.e. UX01ZWLH-. Decide whether to allow for arithmetic to occur on logic types, or if a conversion function should be provided that maps lN to iN. There will also need to be instructions that check for unknown/high impedance states in logic values. Also think about whether we need a "strong logic" type slN, which is restricted to the strong values of IEEE 1164, i.e. X01Z.

Todo

azarmadr commented 4 years ago

that is how we start right?

fabianschuiki commented 3 years ago

Yes that would be a great start. The LogicType should be pretty straightforward. Then the next step would probably be to define a new ConstLogic instruction %result = const l42 "10HLWZXU-" to construct a constant logic value. From there, we probably want to add logic variants of the basic bitwise instructions and, or, and xor, with corresponding implementations on LogicValue. Then maybe inss and exts, and shifts.

The tricky part after that is how we implement operations like add or mux. SystemVerilog and VHDL define these operations on the logic type, but it's generally a "if any bit is not 0/L or 1/H, the result is X" deal. So one nice approach would be to define a cast from lN to iN which produces an additional i1 indicating whether any of the bits were unknown. The addition would then be done on the iN value, and a potential X result would be multiplexed back in at the end. This keeps the "type surface area" of arithmetic operations small, makes X detection/propagation explicit and allows a synthesizer to just strip out the X injection logic, and allows for transformation passes to reason about X propagation (e.g. by allowing consecutive arithmetic operations to be short-circuited together on iN).

Another angle to consider is wheter we want a strong logic type slN, in accordance with IEEE-1164, which is basically the subset "U01X". This would allow types in a design to be "strengthened" by annotating which circuits ever have weak/high impedance drives (lN), or which ones always produce a defined value (slN). The expectation would be that almost everything in a digital design uses slN, and only a few signals -- the ones where tri-state buffers participate -- would require the full lN range. Could be a useful touch to make this distinction.

programmerjake commented 3 years ago

nmigen is planning on only supporting the strong logic values without X. U is needed to handle uninitialized sram, but, other than that, they are trying to support only 0 and 1.

fabianschuiki commented 3 years ago

I guess that makes a lot of sense in the case of nmigen, given that they seem to focus on generating RTL for synchronous digital hardware. In order to support the full range of SystemVerilog and VHDL, LLHD will need something like the slN and lN types to really accurately simulate designs coming from these languages.

azarmadr commented 3 years ago

i was thinking of creating basic logic type with 0 1 x values and then implement strong weak drives on them along with unitialized don't care

fabianschuiki commented 3 years ago

That sounds like a good start. In the end we should arrive at an implementation of IEEE 1164 (which has now been merged into the VHDL standard). I think I would start with the basic logic type (where we don't need to decide the value range yet), then add a ConstLogic instruction (where we need to implement the UX01ZWLH- range), then implement basic and/or/xor (since they are the easiest starting points). The real challenge will be designing the mechanism to handle drive conflicts (probably a variation of the con instruction).

We can do this in many small pull requests, if you like 😃 !

azarmadr commented 3 years ago

i am doing some experiments first

azarmadr commented 3 years ago
pub enum Logic {
    U, X, W, Any, Sd(bool), Wd(bool),
}

single length logic enum like this is fine?

fabianschuiki commented 3 years ago

Looks like a good start. How do the variants relate to UX01ZWLH-? Is something like the following correct?

U = Logic::U
X = Logic::X
0 = Logic::Sd(false)
1 = Logic::Sd(true)
Z = missing?
W = Logic::W
L = Logic::Wd(false)
H = Logic::Wd(true)
- = Logic::Any

How do we represent the Z state?

azarmadr commented 3 years ago

yesterday i realized i forgot high impedence 👍.

pub enum Logic {
    U,        // Uninitialized
    X,        // Forcing Unkown
    Sd(bool), // Forcing logic '1' or '0'
    Z,        // High Impedence
    W,        // Weak Unkown
    Wd(bool), // Weak logic '1' or '0'
    Any,      // '-' Don't Care logic
}
fabianschuiki commented 3 years ago

Looks good :+1:!

azarmadr commented 3 years ago

i prepared the above enum with prilimnary operations https://github.com/azarmadr/logic-vec/blob/master/src/logic.rs

fabianschuiki commented 3 years ago

Cool this is very nice!