5 ms·
For me the key to making everything understandable was adding more constraints to keep myself out of trouble. Everything is a finite state machine, exclusively
by yummypaint 4y ago
For me the key to making everything understandable was adding more constraints to keep myself out of trouble. Everything is a finite state machine, exclusively non-blocking assignments, always loops use the rising edge of the clock signal only.
- JoachimS 4y agoAnother strategy to make life easier is to separate data flow (the transformation of inputs to outputs) and control flows. The control flow knows the context, and given the current state decides how the data flow transformation is performed. Think of an ALU that can perform add, sub, shift operations. The ALU implementation simply accepts operands and perform one of the supported operations to generate the output. The control flow would in this case look at an opcode and decide which of the ALU operations to perform.
- JoachimS 4y agoI would also recommend to use non-blocking assignments only for register updates, not in any description of combinational logic. It is (IMHO) much easier to read Verilog code with blocking assignments for logic since you basically can read the statements one after the other and mentally think that the RHS in a statement has been updated. IF I may point to my own code, the prince cipher core shows how I use non-blocking assignments in a very simple reg update process. The datapath is in a separate, pure combinational process. And the control path is handled by the finite state machine update logic process at the end. https://github.com/secworks/prince/blob/master/src/rtl/prince_core.v https://github.com/secworks/prince/blob/master/src/rtl/princ... (Yes, I should really move the functions to a separate include file.) The SystemVerilog always_comb and always_ff type of processes makes the distincion much clearer. But the same strategy holds for Verilog, and IMHO helps out understand the code. And often makes it less complex.