Search code examples
vhdlregister-transfer-levelasicsoc

Is it necessary to seperate combinational logic from sequential logic while coding in VHDL, while aiming for synthesis?


I am working on projects which requires synthesis of my RTL codes specifically for ASIC development. Given the case, how much important is it, to separate sequential logic from differential logic while designing my RTLs ? And if it is important, then what should be my approach while designing, as if how should I differentiate my design for sequential and combinational logic?


Solution

  • In general, I would not hesitate to mix combinational with sequential logic. I come from an IC design background and have always mixed up combinational logic with sequential. I think that you are restricting yourself too much if you don't and are not fully using the power of your logic synthesiser.

    For example, here is how I would design a simple, asynchronously-reset counter in VHDL:

      process (Clock, Reset)
      begin
        if Reset = '1' then
          Cnt <= (others => '0');
        elsif Rising_edge(Clock) then
          if Enable = '1' then
              Cnt <= Cnt + 1;
          end if;
        end if;
      end process;
    

    This style of writing a counter in VHDL is ubiquitous. I personally can see no advantage to splitting the code up into two separate processes, one sequential the other combinational. I have just taught a room full of engineers to design a counter in exactly this way.

    Here are some exceptions. I would split the combinational logic from the sequential logic if:

    i) I were designing a state machine:

    There is what I think is a really elegant way of coding a state machine, where you do split the combinational logic from the sequential:

      Registers: process (Clock, Reset)
      begin
        if Reset = '1' then
          State <= Idle;
        elsif Rising_edge(Clock) then
          State <= NextState;
        end if;
      end process Registers;
    
      Combinational: process (State, Inputs)
      begin
        NextState <= State;
        Output1 <= '0';
        Output2 <= '0';
        -- etc
        case State is
          when Idle =>
            if Inputs(1) = '1' then
              NextState <= State2;
            end if;
          when State2=>
            Output1 <= '1';
            if Inputs = "00" then
              NextState <= State3;
            end if;
          -- etc
        end case;
      end process Combinational;
    

    The advantage of coding a state machine like this is that the combinational process looks very like the state diagram. It is less error prone to write, less error prone to modify and less error prone to read.

    ii) The combinational logic were complex:

    For really big block of combinational logic, I would separate. The exact definition of "really big" is a matter of judgement.

    iii) The combinational logic were on the Q output of a flip-flop:

    Any signal driven in a sequential process infers a flip-flop. Therefore, if you wish to implement combinational logic that drives an output of an entity* then this combinational logic must be in a separate process.

    *often not a good idea - be careful.