Search code examples
verilogcombinationssequential

Implementing between sequential and combinational logic in HDL


I'm getting started HDL in especially Verilog area.

I found that there are two kind of way to implement 'sequential logic' and 'combinational logic' and would like to implement a fractional operation but can't have a decision between combinational logic and sequential logic.

I know that sequential logic has a memory and it usually used for critical timing path but not combinational logic like a wire.

Let me go to my example.

reg [ 9:0] x; 

always@(clk)
#5    x = ~x;

wire [39:0] x_ext = {x,30b'0};
wire [39:0] x_fract;
assign x_fract = (x>>29) - (x>>27) + (x>>24) + (x>>21) - (x>>19) - (x>>15) + (x>>10) + (x>>9) - (x>>5) + (x>>2) - (x>>1) ;

like above code, I can implement easy combinatioanl logic but I confused that do I need to that implement to sequential logic?


Solution

  • There are at least 2 reasons for using sequential logic: 1) logic related and 2) hardware related.

    The first just depends on the needs of your design and can be used to implement memories, synchronize between different parts of logic, or break combinational cycles. In your small example there is no logical need for such an action.

    The second is due to the electrical delays in modern hardware. You can imagine a logical graph. Electrical signals go different paths and have different delays over the paths. As a result, the correct electrical answer will be settled after the longest path gets settled. In the meanwhile the output signals will just jiggle, consuming power. So, you need to know how long it takes to settle down. Till then you'd like to keep the old values in the outputs and only update them when the result is ready. In order to preserve power and make logic work smoothly you need to break your design into smaller combination pieces and synchronize their execution with some clock.

    Since you are using a lot of addition/subtraction in your design, your logic could be too big for real hardware to execute as a single chunk. Synthesis flow tools will tell you about it.

    There is a way in which you can split the example.

    reg x_part1[39:0], x_part2[39:0], ...;
    always @(posedge clk) x_part1 <= (x>>29) - (x>>27);
    always @(posedge clk) x_part2 <= (x>>24) + (x>>21);
    ...
    always @(posedge clk) x_comb <=  x_part1 + x_part2 + ...;
    assign x_fract = x_comb;
    

    In the above code, if 'x' changes, the corresponding results will appear with one clock cycle delay.

    You might need split it even further down or use a different pattern. Or it might just work as is. In any case, it is a good idea to flop the output as in always @(posedge clk) x_comb <= ..; assign x_fract = x_comb;