Electronic – VHDL using flow control vs minimization

flow controlvhdl

I am currently designing a mips microcontroller for a class. I am now working on the control unit for the microprocessor and I am wondering if I should use minimization vs using flow control (if, case).

Is minimization (ex : using karnaugh) really good performance wise when using vhdl or should I just keep it easy to expand, modify with flow control?

Best Answer

Are you referring to simulation or synthesis performance?

Simulation computational complexity is controlled by subprograms being dynamically elaborated plus simulation overhead, all expressions use operators (subprograms) or basic operations (also functions).

You'll also find the more abstract (control flow) a design model can be described the faster it will simulate.

The amount of work to minimize so is related to the number of concurrent control bits being evaluated times the number of elaborated assignments.

The entire idea of synthesis is to avoid having to do minimization and mapping yourself. Come up with a couple of equivalent test cases and time them - the resulting logic will be the same.

As far as expressing code in minimized terms try this:

library ieee;
use ieee.std_logic_1164.all;

entity s381 is
    port (
        signal  A,B:    in  std_logic_vector (3 downto 0);
        signal  S:      in  std_logic_vector (2 downto 0);
        signal  CIN:    in  std_logic;
        signal  SUM:    out std_logic_vector (3 downto 0);
        signal  P:      out std_logic;
        signal  G:      out std_logic;
        signal  ZERO:   out std_logic
    ) ;
end entity;

architecture behave of s381 is

    signal SEL:     std_logic_vector (4 downto 0);
    signal CY_EN:   std_logic;
    signal C:       std_logic_vector (3 downto 0);
    signal E:       std_logic_vector (3 downto 0);
    signal LC:      std_logic_vector (3 downto 0);
    signal F:       std_logic_vector (3 downto 0);

begin
    SEL(0)  <= not S(0) nand not S(1);
    SEL(1)  <= not S(1) nand not S(2);  
    SEL(2)  <= not S(0) nand S(1);
    SEL(3)  <= not (S(0) and S(1) and not S(2));
    SEL(4)  <= (not S(0) and S(2)) nor (not S(1) and S(2));
    CY_EN   <= (not S(0) nand not S(1)) and not S(2);
    C(0) <= not (
                (not A(0) and not B(0) and SEL(2) and SEL(1)) or
                (  SEL(0) and SEL(2) and SEL(3) and not B(0) and A(0)) or
                (  SEL(1) and SEL(3) and   B(0) and not A(0)) 
            );
    E(0) <= not (
                (not A(0) and not B(0) and SEL(0) and SEL(3) and SEL(4)) or
                (  SEL(1) and SEL(2) and not B(0) and A(0)) or
                (  SEL(1) and SEL(2) and B(0) and not A(0)) or
                (  SEL(0) and SEL(3) and B(0) and A(0))
            );
    LC(0) <= CIN nand CY_EN;

    C(1) <= not (
                (not A(1) and not B(1) and SEL(2) and SEL(1)) or
                (  SEL(0) and SEL(2) and SEL(3) and not B(1) and A(1)) or
                (  SEL(1) and SEL(3) and   B(1) and not A(1)) 
            );
    E(1) <= not (
                (not A(1) and not B(1) and SEL(0) and SEL(3) and SEL(4)) or
                (  SEL(1) and SEL(2) and not B(1) and A(1)) or
                (  SEL(1) and SEL(2) and B(1) and not A(1)) or
                (  SEL(0) and SEL(3) and B(1) and A(1))
            );
    LC(1) <= not ((CIN and C(0) and CY_EN) or (C(0) and E(0) and CY_EN));

    C(2) <= not (
                (not A(2) and not B(2) and SEL(2) and SEL(1)) or
                (  SEL(0) and SEL(2) and SEL(3) and not B(2) and A(2)) or
                (  SEL(1) and SEL(3) and   B(2) and not A(2)) 
            );
    E(2) <= not (
            (not A(2) and not B(2) and SEL(0) and SEL(3) and SEL(4)) or
                (  SEL(1) and SEL(2) and not B(2) and A(2)) or
                (  SEL(1) and SEL(2) and B(2) and not A(2)) or
                (  SEL(0) and SEL(3) and B(2) and A(2))
            );
    LC(2) <= not (
                (CIN and C(0) and C(1) and CY_EN) or
                (C(0) and C(1) and E(0) and CY_EN) or
                (C(1) and E(1) and CY_EN)
            );
    C(3) <= not (
                (not A(3) and not B(3) and SEL(2) and SEL(1)) or
                (  SEL(0) and SEL(2) and SEL(3) and not B(3) and A(3)) or
                (  SEL(1) and SEL(3) and   B(3) and not A(3)) 
            );
    E(3) <= not (
                (not A(3) and not B(3) and SEL(0) and SEL(3) and SEL(4)) or
                (  SEL(1) and SEL(2) and not B(3) and A(3)) or
                (  SEL(1) and SEL(2) and B(3) and not A(3)) or
                (  SEL(0) and SEL(3) and B(3) and A(3))
            );
    LC(3) <= not (
                (CIN and C(0) and C(1) and C(2) and CY_EN) or
                (C(0) and C(1) and C(2) and E(0) and CY_EN) or
                (C(1) and C(2) and E(1) and CY_EN) or
                (C(2) and E(2) and CY_EN)
                );
    F <= LC xor E;
    P <= C(0) and C(1) and C(2) and C(3);
    G <= (
             (C(0) and C(1) and C(2) and C(3) and E(0)) or
             (C(1) and C(2) and C(3) and E(1)) or
             (C(2) and C(3) and E(2)) or
             (C(3) and E(3))
         );
    SUM <= F;
    ZERO <= not (F(3) or F(2) or F(1) or F(0));
end architecture;

It can't be maintained without resorting to other documentation showing what operations S defines and why there are particular intermediary terms.

From the LRM, IEEE Std 1076-2008, 1.2 Purpose:

The VHDL language was defined for use in the design and documentation of electronics systems.

How much documentation is inherent in the above VHDL code?

Compare the above minimized description to a control flow expression (VHDL code for an 74-series ALU (the 74LS381 chip))

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

--  s2  s1  s0  operation
--------------------------
--  L   L   L   clear
--  L   L   H   B minus A
--  L   H   L   A minus B
--  L   H   H   A plus B
--  H   L   L   A xor B
--  H   L   H   A + B
--  H   H   L   AB
--  H   H   H   PRESET  

entity IC74381 is
port(   a: in std_logic_vector (3 downto 0);
        b: in std_logic_vector (3 downto 0);
        s: in std_logic_vector (2 downto 0);
        f: out std_logic_vector (3 downto 0)
);
end IC74381;

architecture arch of IC74381 is
signal BminusA,AminusB,AplusB,AxorB,AandB,AB: std_logic_vector(3 downto 0);
signal au,bv0,bv1,bv2,bv3: unsigned(3 downto 0);
signal p0,p1,p2,p3,prod: unsigned(7 downto 0);

begin

BminusA <=  std_logic_vector(signed(b)-signed(a));
AminusB <=  std_logic_vector(signed(a)-signed(b));
AplusB  <=  std_logic_vector(signed(a)+signed(b));
AxorB   <= a xor b;
AandB   <= a and b;

au  <=unsigned(a);
bv0 <=(others=>b(0));
bv1 <=(others=>b(1));
bv2 <=(others=>b(2));
bv3 <=(others=>b(3));
p0  <="0000" & (bv0 and au);
p1  <="000"&(bv1 and au) & "0";
p2  <="00" & (bv2 and au) & "00";
p3  <="0" & (bv3 and au) & "000";
prod<=((p0+p1)+(p2+p3));
AB<=std_logic_vector(prod(3 downto 0));

f   <=  "0000"      when s="000" else
        BminusA     when s="001" else
        AminusB     when s="010" else
        AplusB      when s="011" else
        AxorB       when s="100" else
        AandB       when s="101" else
        AB          when s="110" else
        "1111"; 
end arch;

(And I'd personally have replaced BminusA, etc. with the expressions on the right hand side of their assignments in the assignment to f. Finding an equivalent was fortuitous, around 20 years separate their authorship.)

Without validating both I'd expect they both can produced the same complexity logic following synthesis. The amount of grunt work synthesis tools perform isn't the controlling factor in EDA today. In addition to design and documentation verification is increasingly more important (also from the LRM, same paragraph):

It is revised to incorporate capabilities that improve the languageā€™s usefulness for its intended purpose as well as extend it to address design verification methodologies that have developed in industry.

Now ask yourself from which of the two above forms can the person stuck doing verification more easily determine what the expected result should be?

You might notice there are two errors in the second example. The distinction being there is almost sufficient information to fix it from the design description. What's missing is a more complete description of the 8 operations:

-- eight function ALU

--      S(0)    S(1)    S(2)
--      0       0       0       CLEAR
--      1       0       0       B MINUS A
--      0       1       0       A MINUS B
--      1       1       0       A PLUS B
--      0       0       1       A XOR B
--      1       0       1       A OR B
--      0       1       1       A AND B
--      1       1       1       PRESET

A hardware description is about more than just the logic.

The minimized expression version was done in a time when synthesizing arithmetic functions cost more in licensing costs. CPU performance and memory sizes made the distinction in time (expressed in the value added) increasingly less significant.

We tended to document better for ASIC targets than is generally done for FPGAs, you could look it up in the design specification, plus their were data books of datasheets with schematics.