1
\$\begingroup\$

I have a register that I want to update using two different mechanisms

  1. Shifting left, triggered by signal a
  2. Updating the whole value, triggered by signal b

This was my solution to a SPI solution where the slave can receive data, do some calculations on it and send it out.

What are the complications I have to watch for in the following code?

byte data;
always_ff@(posedge a or negedge b) begin
    if(!b) begin
        data <= compute(data);
    end
    else begin
        data <= {data[6:0], in}
    end
end

As b is usually the reset signal, I'm worried this would cause a timing issue in the reset path. Is there a better way of doing this if I want data to be registered?

\$\endgroup\$
1

2 Answers 2

2
\$\begingroup\$

In general resetting Flip-Flops to "non-constant" values is not a standard digital design pattern. I'm not saying that it can't be done, but it is disadvantageous.

It depends a little on what target technology you want to implement this. I guess you want to implement this on an FPGA.

In general the approach is, to implement these initializations using synchronous logic:

always_ff@(posedge a) begin
    if(!b)
        data <= compute(data);
    else
        data <= {data[6:0], in}
end

This is not the same thing, but is is highly advantageous from a timing perspective. The Flip-Flop is now fully synchronous and only changes on a clock edge of a. Logic paths in the asynchronous reset paths of FFs can generate hard to solve timing problems. Essentially this description adds a mux to the input of the FFs controlled by b and muxes the parallel "reset value" to the input if desired.

Most Flip Flops don't allow specifying a "reset value". They simply have an input for a reset to low and a preset to high. Let's see what an ASIC Synthesis makes of your code. I slightly modified it to be a full module:

module test(a, b, data, rst_data, in);
output reg [7:0] data;
input a;
input b;
input [7:0] rst_data;
input in;


always_ff @(posedge a or negedge b) begin
    if(!b) begin
        data <= rst_data;
    end
    else begin
        data <= {data[6:0], in};
    end
end
endmodule

This leads to the following result (I only show the paths for the Flip Flop for bit 6 of your byte):

Synthesized schematic of the module

As you can see, signal a is connected as clock to the FFs. The output of the previous data register is connected to the data input, implementing your shift register. The reset logic, however, is implemented by logically combining the reset value with the reset signal, generating the appropriate asynchronous set (SD) and reset (RD) signals.

One problem is the glitches coming from the reset logic (these NAND gates). Due to the reset and preset being a async input, these glitches can propagate to the FF output, which is not a very nice design and can actually be a showstopper.

For an FPGA implementation, it can happen that your FPGA is not able to map this logic very well onto its logic elements because they cannot be freely wired like an ASIC, and the logic elements are usually intended for synchronous logic and at most one asynchronous reset (which in an FPGA is often not even done, since the FF design is booted with its reset values from the configuration).

Have you already tried synthesizing your code for your FPGA?

Last but not least: IMHO, you should never try to solve something simple and standard like an SPI interface with something like this. Use synchronous logic. Far easier to verify and implement. No weird timing paths, (for an Asic: no problems during scan insertion) etc.

\$\endgroup\$
2
\$\begingroup\$

Aside from the excellent advice in the other answer, here are some other considerations regarding this line of code:

byte data;

Things to keep in mind is that the byte data type is:

  • Signed
  • 2-state

There are no timing implications, but there may be pre- and post-synthesis simulation mismatches, depending on the synthesis tool.

Typically, you would declare the signal as:

logic [7:0] data;

logic is 4-state, meaning that the Verilog unknown x value is supported. If your input in signal contains x or z, they will be converted to 0 with your byte declaration (which only supports 0 and 1 values). It is often useful to see x in simulation as it can help when finding bugs in your design code.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.