The idea progresses while I gather the necessary ingredients for the new version of the library. At this moment I consider getting rid of all the C and VHPI code because VHDL already contains all the required features, I think.
Let's start with the fundamental feature, that evaluates the gate's function. It must be short, simple, efficient, fast. We work with SLV8 (std_logic_vector(7 downto 0)) as the boolean function table.
subtype FunctTableType is std_logic_vector( 7 downto 0);
The input signal A has the least significant effect on the index, so we have the linear relationship :
C | B | A | Index |
---|---|---|---|
0 | 0 | 0 | 0 |
0 | 0 | 1 | 1 |
0 | 1 | 0 | 2 |
0 | 1 | 1 | 3 |
1 | 0 | 0 | 4 |
1 | 0 | 1 | 5 |
1 | 1 | 0 | 6 |
1 | 1 | 1 | 7 |
OR3 is coded as "11111110" and AND3 as "10000000".
From there, it's very easy to look it up :
function TableLookup( A : std_logic ; B : std_logic ; C : std_logic ; Table : FunctTableType) return std_logic is variable index : integer := 0; begin if A = '1' then index := 1; end if; if B = '1' then index := index + 2; end if; if C = '1' then index := index + 4; end if; return Table(index); end function;
There. No C code required.
Then the body of the gate's entity applies this function to the corresponding table.
entity AND3 is port( A, B, C : in std_logic; Y : out std_logic); end AND3; architecture rtl of AND3 is constant Table : FuncTableType := "10000000"; begin Y <= TableLookup(A, B, C, Table) after gate_delay; end rtl;
Nothing complex, here, either, though I have moved the constant for a separated declaration, instead of a mere inline mention. That's where the hinge of the system resides.
First, we must initialise the function table.
Initially I wanted it to be initialised in the gate file itself. It would make the system self-contained, reducing confusion and complexity. Then I realised that the initialisation (and table creation) would be computed, again and again, for every gate in the DUT. It's not an issue for the example INC8 unit but imagine a huge processor... So it's best to create all the tables once and for all, before everything. And since I don't want to do it by hand, some code is required (even though it will take more dev time, huh huh huh).
I want to reduce the duplication of code as much as possible and at that moment, it is VERY tempting to create only one entity/architecture, with a function table provided as a generic but this would break the compatibility with the historical ACTEL files. As a consequence, the collection of gate files will continue to exist...
However the constants can be precomputed in the package.
Library ieee; use ieee.std_logic_1164.all; package proasic3 is subtype FunctTableType is std_logic_vector( 7 downto 0); type A3PTileName is ( AND2, AND2A, AND3, AND3A, AND3B, AND3C, AO1, AO12, AO13, AO14, AO15, AO16, AO17, AO18, AO1A, AO1B, AO1C, AO1D, AO1E, AOI1, AOI1A, AOI1B, AOI1C, AOI1D, AOI5, AX1, AX1A, AX1B, AX1C, AX1D, AX1E, AXO1, AXO2, AXO3, AXO5, AXO6, AXO7, AXOI1, AXOI2, AXOI3, AXOI4, AXOI5, AXOI7, CLKINT, DFN1, DFN1C0, DFN1C1, DFN1E0, DFN1E0C0, DFN1E0C1, DFN1E0P0, DFN1E0P1, DFN1E1, DFN1E1C0, DFN1E1C1, DFN1E1P0, DFN1E1P1, DFN1P0, DFN1P1, INV, MAJ3, MX2, MX2A, MX2B, MX2C, NAND2, NAND3A, NAND3B, NAND3, NOR2A, NOR2, NOR2B, NOR3, NOR3A, NOR3B, NOR3C, OA1A, OA1B, OA1C, OAI1, OR2, OR2A, OR2B, OR3, OR3A, OR3B, OR3C, XA1, XA1A, XA1B, XA1C, XNOR2, XNOR3, XO1, XO1A, XOR2, XOR3, ZOR3, ZOR3I); function Create_Table(f : A3PTileName) return FunctTableType; function TableLookup( A, B, C : std_logic; Table : FunctTableType) return std_logic; constant A3P_AND3 : FunctTableType := Create_Table(AND3); ... component AND3 port(A, B, C : in std_logic; Y : out std_logic); end component; ... end proasic3; package body ygrec8_def is function TableLookup( A, B, C : std_logic ; Table : FunctTableType) return std_logic is variable index : integer := 0; begin if A = '1' then index := 1; end if; if B = '1' then index := index + 2; end if; if C = '1' then index := index + 4; end if; return Table(index); end function; end ygrec8_def;
I must admit that at this point, I have tested nothing so I'm wildly speculating, but you might see where I'm going.
All the constants are created by a single function that contains all the boolean code in a large case().
function Create_Table(f : A3PTileName) return FunctTableType is variable i : integer := 0; variable A, B, C, Y : std_logic; variable t : FunctTableType; begin C := '0'; loop_C: loop B := '0'; loop_B: loop A := '0'; loop_A: loop -- nested loop's body: Y := .... -- huge case() here t[i] := Y; i := i+1; exit loop_A when A = '1'; A := '1'; end loop loop_A; exit loop_B when B = '1'; B := '1'; end loop loop_B; exit loop_C when C = '1'; C := '1'; end loop loop_C; return t; end Create_Table;
Then we simply have to copy-paste the previously tested and grep'ed code.
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.