Search code examples
vhdlfpga

VHDL: having multiple clock enables in one process


Hello I am new to VHDL and I want to ask if it is ok to have a process like this where I have multiple clocks in one process C256Hz and C4Hz are clock enables driven from the 50MHz clock

process (Reset, C50Mhz, Go, start_flag, C256Hz, C4Hz)
  begin
  if reset = '1' then
     start_flag <= '0';
  elsif rising_edge (C50Mhz) then
     if C4Hz = '1' then
        if count4 = "11" and single_run_flag = '0' then
           start_flag <= '0';
        end if;
     end if;
   if C256Hz = '1' then
      if Go = '1' and start_flag = '0' then
          start_flag <= '1';
      end if;
   end if;
  end if;
  end process;   `

Solution

  • It is okay, but whether synthesis will generate a good result depends on the fabric.

    The sensitivity list should have just reset and C50MHz, because these are the only events that actually change signals. When C4Hz toggles, then rising_edge(C50MHz) is false, because these are not synchronized, and nothing would happen if the process were to run then.

    The separate enable can be assumed to be available everywhere -- clock fanout is so high that everyone implements separate clock distribution networks, and the enable on the registers is required then. So this is safe to use.

    The asynchronous reset might not be available on all fabrics, but usually is. Some devices will support asynchronous load (i.e. you can decide the value to be taken on reset), others only reset (i.e. you can set the register to zero only, and initializing to one would generate an inverted table, a register with reset-to-zero, and an inverter in the next LE.

    So in general, this is fairly safe, this can be synthesized as

    -- intermediates
    do_clear_start_flag := C4Hz = '1' and count4 = "11" and single_run_flag = '0';
    do_set_start_flag := C256Hz = '1' and Go = '1' and start_flag = '0';
    
    -- to register
    enable_start_flag := do_clear_start_flag or do_set_start_flag;
    new_start_flag := do_set_start_flag;
    

    The check for the old value of start_flag in do_set_start_flag cannot be optimized out even if setting start_flag has no effect if it has been set before, because it might just be reset in the current clock cycle.

    If the block beginning with if C256Hz = '1' were an elsif instead, the second intermediate would read

    do_set_start_flag := C256Hz = '1' and Go = '1' and do_clear_start_flag = '0'