If you remember the log What if we generated the files for each gate ? you know I discarded the idea of generating the gates with a script.
Well, after a few days of sitting on this setback, I decided that there were enough "low hanging fruits", and the advantages are good enough, to justify writing some code to generate those gates. The trick is to keep the system simple and small enough that it doesn't create more problems than it solves.
The first change is to create 4 types of combinatorial gates, depending on the number of inputs. The sequential gates (latches, flip-flops) will be ignored for now.
4 types means there are dealing with 4 sizes of lookup tables : 1, 2, 4 and 8 entries. Ideally we would use only one size (8 entries) and an extra size parameter (stored somewhere) gives the range, or something... but since VHDL arrays already has 'range-related attributes, we can infer the actual type. The perturbation logic would be something like :
index = Random() mod Table'Length; table(index) <= table(index) xor '1';
The lookup table array is std_logic_vector because it helps with something else : coverage. If one element of the table is set to 'X' then the value will (ideally) propagate to the output, showing that this entry is sensitive to a given test vector. The universal gate must be modified:
if (a='X') or (b='X') or (c='X') then return 'X'; end if;
We can go even further because each input gets compared sequentially to create the index :
variable i : integer := 0; ... if a = '1' then index := 1; else if a /= '0' then return a; end if; end if;
Then the same code is copy-pasted-modified for b and c, depending on the number of inputs (and names) of the gates.
Sounds like a plan...
Now that we can deal with a flexible size of lookup table, we can define the corresponding type :
subtype LookupType1 is std_logic_vector( 0 downto 0); subtype LookupType2 is std_logic_vector( 1 downto 0); subtype LookupType4 is std_logic_vector( 3 downto 0); subtype LookupType8 is std_logic_vector( 7 downto 0);
Then we can sort the gates according to their inputs :
- no input : GND VCC (CLKBUFF is an exception with the implicit input from a pin)
- 1 input : INV CLKINT (CLKINT wouldn't be used in a portable design anyway)
- 2 inputs : AND2 AND2A NAND2 NOR2 NOR2A NOR2B OR2 OR2A OR2B NOR2 XNOR2 XOR2 (some functions would be redundant)
- 3 inputs : 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 XO6 AXO7 AXOI1 AXOI2 AXOI3 AXOI4 AXOI5 AXOI7 MAJ3 NAND3 NAND3A NAND3B NOR3 NOR3A NOR3B NOR3C OA1 OA1A OA1B OA1C OAI1 OR3 OR3A OR3B OR3C XA1 XA1A XA1B XA1C XO1 XO1A XOR3 XNOR3 ZOR3 ZOR3I
- 3 inputs with modified input signal names : MX2 MX2A MX2B MX2C