简体   繁体   中英

VHDL - Clock a flip flop with a variable?

I've inherited some legacy VHDL at work and have been banging my head against the wall trying to figure out an issue. First let me say that I'm more experienced with Verilog but have been plugging away with VHDL for awhile trying to fix this issue.

So we have a product that has been working fine since 2011. However, we needed to change FPGAs, so we are in the middle of porting our code. A high level view of this code is that the FPGA stores a bootloader for the CPU in the on board flash. At power on, the CPU reads the FPGA to extract the bootloader. On our old design it worked fine. On the new design it doesn't work when cold, and it is also not 100% reliable at warm temperatures either.

I noticed that a lot of the code is done what I would consider strangely, where flip flops are clocked with signals, rather than clocks. An example:

process( N_RESET, DATA_READ, START_ADDRESS, END_ADDRESS )
begin
    if( N_RESET = '0' ) then
        ADDR_TMP    <= START_ADDRESS;

    elsif( DATA_READ'event and (DATA_READ='0') ) then
        if( ADDR_TMP <= END_ADDRESS ) then
            ADDR_TMP <= ADDR_TMP + "10";
            incremented_tmp <= incremented_tmp xor '1';

        end if;
    end if;
end process;

So the RTL that that generates ends up being a flip flop that is clocked by DATA_READ. Data read is a read enable signal coming from a CPU. The CPU is trying to read to read this register.

Is this a valid way to do things? I don't really like the idea of using a read enable as a clock myself. I wrote one in Verilog that uses a clock to detect the rising edge fo DATA_READ:

always@(posedge CLK, negedge RESETn )
begin
    if(RESETn  == 1'b0) begin        

    end else begin


                last_usr_read_n <= usr_read;
                // Next state logic, only transition on de-assertion of usr_read
                if (last_usr_read_n == 1'd0 && usr_read == 1'd1) begin
                    // check next state logic
                    envm_internal_address <= envm_internal_address + 18'h2; // incrmeent address counter
                    incremented<= incremented^ 1'b1;

                end
        endmodule 

I noticed that during execution the VHDL stops changing incremented_tmp, whereas my verilog code continues executing as expected.

The main issue we are having is that the design doesn't work when it's cold. I'm not sure why. The design had a bunch of latches in it that I've done my best to remove. All that's remaining is code like this (and there's a lot of it). My question is: Is this a valid way to clock a flip flop? Could it cause unexpected issues like we are seeing?

Thanks, Nick

The VHDL code creates a generated clock on the DATA_READ signal, not unlike the equivalent Verilog code would do. While this is certainly "valid" in the sense that it is synthesizable, if not constrained properly, this could create timing issues and marginal behavior like what you're seeing at cold and hot. The preferred solution is to replace the generated clocks with a synchronous edge-detect circuit, like what you've done in your Verilog code.

Unfortunately, I don't know a good way to automate this if you have a lot of code that needs to be cleaned up. If the code follows the same general structure for these constructs, you can try a search-and-replace. I recommend developing a solid regression test suite, if you haven't already, to verify your changes don't have any unwelcome side-effects.

Alternatively, you can try to identify and constrain all the generated clocks in the place-and-route tool, paying careful attention to hold time at the clock domain crossings. In particular if END_ADDRESS and DATA_READ are launched on the same clock edge, you'll have a race condition between the signals that will need to be resolved by adding delay. If you plan to reuse this code in the future, though, you're better off fixing it in the RTL.

The code is a mess - dump it, start again. Everything about it is a red flag. Specific problems:

  1. Check the CPU datasheet for DATA_READ - it's not usable as a clock if it's not guaranteed monotonic. It probably just had a guaranteed setup and hold relative to other signals, so it can do whatever it wants at other times, potentially clocking your code.
  2. See TJ's answer. Note also that your P&R software may not have assigned DATA_READ to a clock net if the original author did this with lots of other signals, and you've run out of clock nets in your FPGA
  3. incremented_tmp is assigned in the clock branch, but not the async reset branch. This is asking for trouble - it has to hold when N_RESET is low and there's a clock edge, so you've got latch behaviour, and issues with the timing of N_RESET relative to DATA_READ .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM