{josuah.net} | {panoramix-labs.fr}
 (DIR)  • {josuah.net}
 (DIR)  • {panoramix-labs.fr}
       
        {git} | {cv} | {links} | {quotes} | {ascii} | {tgtimes} | {gopher} | {mail}
 (DIR)  • {git}
 (BIN)  • {cv}
 (DIR)  • {links}
 (DIR)  • {quotes}
 (DIR)  • {ascii}
 (HTM)  • {tgtimes}
 (DIR)  • {gopher}
       
       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
       Sequential signals may hide combinational ones
       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
        Verilog is a hardware language with a syntax similar to C, but very different
        semantics: signals, circuits, and registers for storing the state.
       
       Registers and sequential logic
       ──────────────────────────────
        ┊                  ┌─────┐
        ┊ some circuit  >──┤D   Q├──>  some circuit
        ┊                  │     │     updated one clock edge later
        ┊                ┌─>     │
        ┊                │ └─────┘
        ┊              clock
       
        They use the `<=` assignment operator to build-up sequential logic. Like
        software variables, they can hold values across multiple clock cycles. An
        assignment to a register (on `D`) gets read (on `Q`) on the next clock cycle.
       
        ┊ reg r;
        ┊ always_ff @(posedge clk) begin
        ┊   r <= 1;             └── This is the clock connected to all registers
        ┊ end    └── This is the input signal D fed into the register
        ┊ 
        ┊ wire w = r;
        ┊          └── This is the output signal Q read from the register
       
       Wires, signals, and combinational logic
       ───────────────────────────────────────
        ┊ some circuit  >───────────────>  some circuit
        ┊                 the_wire_name
       
        Most verilog expressions gets converted to a circuit of gates implementing it.
        The `=` assignment used in various contexts permit to attach an end of a wire
        to a name, a label. The `always_comb` block can only have `=`, no `<=`, and
        implement combinational logic.
       
        ┊ input i;
        ┊ wire [7:0] w;
        ┊ always_comb begin
        ┊   w = i ^ 8'b10101010;
        ┊ end
       
       How combinational logic appear
       ──────────────────────────────
        But what if complex expressions are assigned to a register instead of a wire?
        The signal coming into the register may be represented as an expression itself,
        and expressions are combinational logic. The flip-flop-only `always_ff`
        contains, in fact, a mix of combinational and sequential logic.
       
        The restriction in `always_ff` is that adding extra combinational logic is
        forbidden (no `=` operator) but combinational logic feeding registers can still
        occur. It helps with preventing `<=` being typoed into `=`.
       
        ┊ input i;
        ┊ reg [7:0] r;
        ┊ always_ff @(posedge clk) begin
        ┊   r <= i ^ 8'b10101010;
        ┊ end
       
        This is not a problem per-se, just a remark.
       
       The LowRISC approach
       ────────────────────
 (HTM)  The above permits us to explain the approach {LowRISC} is taking. The team
 (HTM)  described it in their {style guide for SystemVerilog}:
       
        It is done by coupling a `always_ff` that applies the changes to registers,
        with `always_comb` that build-up the next values. Each register is having:
       
        • a `_d` wire that is fed into the register, driving the next value of the
          register;
       
        • a `_q` register, representing the output value of the register, which is
          delayed by one clock.
       
        On each clock, this happens alone in a block: `something_q <= something_d`; and
        the rest is purely combinational.
       
        In other words, the sequential operation have been isolated, by giving the
        input signal a name (`something_d` here).
       
        ┊ wire something_d;
        ┊ reg [7:0] something_q;
        ┊ always_ff @(posedge clk) begin
        ┊   // apply the changes to the registers
        ┊   something_q <= something_d;
        ┊ end
        ┊ 
        ┊ always_comb begin
        ┊   // by default, the value stays the same as the register previous value
        ┊   // this was happening under the hood in the previous examples, it is now
        ┊   // explicit
        ┊   something_d = someting_q;
        ┊ 
        ┊   // for giving something_q another value, something_d can be changed with
        ┊   // in the combinational logic
        ┊   if (i > 3) begin
        ┊     something_d = something_d + 1;
        ┊   end
        ┊ end
       
       Extra convention
       ────────────────
        In addition to LowRISC guideline, I also use this convention: When declaring
        signals with `logic`, the `_d` wire comes first, followed by `_q` and `_q2`
        etc. That way, there is one line per signal, including its past state. This
        help with reading code faster:
       
        ┊ logic ack_d, ack_q, ack_q2;
        ┊ logic state_d, state_q;
        ┊ logic counter_q;
       
       In practice?
       ────────────
        Inconvenients:
       
        • More verbose outside the combinational block;
       
        • Extra signals to declare (the `_d` ones):
       
        Advantages:
       
        • Everything is explicit around the registers;
       
        • In expressions using these signals, change `_q` into `_d` to save one clock
          cycle;
       
        • Consistent naming using the `Q`/`D` signal naming of registers.
       
        It is also frequent to have a reset signal that puts all registers to a default
        value. The LowRISC approach makes it convenient to integrate it within the
        `always_ff` block, introducing a little bit of combinational logic, without
        much effect.
       
        ┊ always_ff @(posedge clk) begin
        ┊   if (rst) begin
        ┊     something0_q <= 0;
        ┊     something1_q <= 0;
        ┊     something2_q <= 0;
        ┊     something3_q <= 0;
        ┊   end else begin
        ┊     something0_q <= something0_d;
        ┊     something1_q <= something1_d;
        ┊     something2_q <= something2_d;
        ┊     something3_q <= something3_d;
        ┊   end
        ┊ end
       
        In a real world example, I would have been using `logic` instead of `wire` and
        `reg`, the `_q` and `_d` helping with making the distinction. I would also
        likely use `rst_ni` instead of `rst` and `clk_i` instead of `clk`.
       
        Also sometimes the whole design is so trivial that a separate `always_comb`
        would be an overkill.
       
       Links
       ─────
 (HTM)  {https://lowrisc.org/}
       
 (HTM)  {https://github.com/lowRISC/style-guides/blob/master/VerilogCodingStyle.md}