diff options
| author | Tristan Gingold <tgingold@free.fr> | 2022-08-14 21:55:05 +0200 | 
|---|---|---|
| committer | Tristan Gingold <tgingold@free.fr> | 2022-08-14 21:55:05 +0200 | 
| commit | 6d4fad2cb725799d2c7834cd0918e4036905f24e (patch) | |
| tree | 88aece00404d1d744ea3c2382639d8c5c2e201ca | |
| parent | 153fbf23a362bc56275a009670e3de65e82b7987 (diff) | |
| download | ghdl-6d4fad2cb725799d2c7834cd0918e4036905f24e.tar.gz ghdl-6d4fad2cb725799d2c7834cd0918e4036905f24e.tar.bz2 ghdl-6d4fad2cb725799d2c7834cd0918e4036905f24e.zip  | |
testsuite/synth: add a test for #2177
| -rw-r--r-- | testsuite/synth/issue2177/clock_functions_pack.vhd | 178 | ||||
| -rwxr-xr-x | testsuite/synth/issue2177/testsuite.sh | 8 | ||||
| -rw-r--r-- | testsuite/synth/issue2177/vlm5030_gl.vhd | 2309 | ||||
| -rw-r--r-- | testsuite/synth/issue2177/vlm5030_pack.vhd | 70 | ||||
| -rw-r--r-- | testsuite/synth/issue2177/vlm5030_subcircuits.vhd | 203 | 
5 files changed, 2768 insertions, 0 deletions
diff --git a/testsuite/synth/issue2177/clock_functions_pack.vhd b/testsuite/synth/issue2177/clock_functions_pack.vhd new file mode 100644 index 000000000..76ba013f6 --- /dev/null +++ b/testsuite/synth/issue2177/clock_functions_pack.vhd @@ -0,0 +1,178 @@ +---------------------------------------------------------------------- +--               Typedefs and functions for clocks +--                      www.fpgaarcade.com +--                     All rights reserved. +-- +--                     admin@fpgaarcade.com +-- +-- This Source Code Form is subject to the terms of the Mozilla Public +-- License, v. 2.0. If a copy of the MPL was not distributed with this +-- file, You can obtain one at https://mozilla.org/MPL/2.0/. +---------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; + +package clock_functions_pack is + +  ----------------------------------------------------------------------------- +  -- Transparent handling of clock enables +  -- +  -- Basic type def +  type r_clk is record +    base : std_logic; +    val  : std_logic; +    rise : std_logic; +    fall : std_logic; +  end record; +  constant z_clk : r_clk := ( +    base => '0', +    val  => '0', +    rise => '0', +    fall => '0'); + +  -- Overloaded functions for synchronous process template +  function rising_edge(signal clk : r_clk) return boolean; +  function falling_edge(signal clk : r_clk) return boolean; + +  -- Overloaded functions for boolean arithmetic on clocks +  function  "not" (clk : r_clk) return r_clk; +  -- +  function  "and" (clk1, clk2 : r_clk) return r_clk; +  function  "and" (clk1 : r_clk; op2 : std_logic) return r_clk; +  function  "and" (op1 : std_logic; clk2 : r_clk) return std_logic; +  -- +  function "nand" (clk1, clk2 : r_clk) return r_clk; +  function "nand" (clk1 : r_clk; op2 : std_logic) return r_clk; +  function "nand" (op1 : std_logic; clk2 : r_clk) return std_logic; +  -- +  function   "or" (clk1, clk2 : r_clk) return r_clk; +  function   "or" (clk1 : r_clk; op2 : std_logic) return r_clk; +  function   "or" (op1 : std_logic; clk2 : r_clk) return std_logic; +  -- +  function  "nor" (clk1, clk2 : r_clk) return r_clk; +  function  "nor" (clk1 : r_clk; op2 : std_logic) return r_clk; +  function  "nor" (op1 : std_logic; clk2 : r_clk) return std_logic; +  -- +  function    "=" (clk1 : r_clk; op2 : std_logic) return boolean; + +end; + +package body clock_functions_pack is + +  function rising_edge(signal clk : r_clk) return boolean is +  begin +    return rising_edge(clk.base) and clk.rise = '1'; +  end; + +  function falling_edge(signal clk : r_clk) return boolean is +  begin +    return rising_edge(clk.base) and clk.fall = '1'; +  end; + +  function  "not" (clk : r_clk) return r_clk is +  begin +    return (base => clk.base, +            val  => not clk.val, +            rise => clk.fall, +            fall => clk.rise); +  end; + +  function  "and" (clk1, clk2 : r_clk) return r_clk is +  begin +    return (base => clk1.base, +            val  => clk1.val and clk2.val, +            rise => (clk1.rise and clk2.val and not clk2.fall) or +                    (clk2.rise and clk1.val and not clk1.fall), +            fall => (clk1.fall and clk2.val) or +                    (clk2.fall and clk1.val)); +  end; + +  function  "and" (clk1 : r_clk; op2 : std_logic) return r_clk is +  begin +    return (base => clk1.base, +            val  => clk1.val and op2, +            rise => clk1.rise and op2, +            fall => clk1.fall and op2); +  end; + +  function  "and" (op1 : std_logic; clk2 : r_clk) return std_logic is +  begin +    return op1 and clk2.val; +  end; + +  function "nand" (clk1, clk2 : r_clk) return r_clk is +  begin +    return (base => clk1.base, +            val  => clk1.val nand clk2.val, +            rise => (clk1.fall and clk2.val) or +                    (clk2.fall and clk1.val), +            fall => (clk1.rise and clk2.val and not clk2.fall) or +                    (clk2.rise and clk1.val and not clk1.fall)); +  end; + +  function "nand" (clk1 : r_clk; op2 : std_logic) return r_clk is +  begin +    return (base => clk1.base, +            val  => clk1.val nand op2, +            rise => clk1.fall and op2, +            fall => clk1.rise and op2); +  end; + +  function "nand" (op1 : std_logic; clk2 : r_clk) return std_logic is +  begin +    return op1 nand clk2.val; +  end; + +  function   "or" (clk1, clk2 : r_clk) return r_clk is +  begin +    return (base => clk1.base, +            val  => clk1.val or clk2.val, +            rise => (clk1.rise and not clk2.val) or +                    (clk2.rise and not clk1.val), +            fall => (clk1.fall and not clk2.val and not clk2.rise) or +                    (clk2.fall and not clk1.val and not clk1.rise)); +  end; + +  function   "or" (clk1 : r_clk; op2 : std_logic) return r_clk is +  begin +    return (base => clk1.base, +            val  => clk1.val or op2, +            rise => clk1.rise and not op2, +            fall => clk1.fall and not op2); +  end; + +  function   "or" (op1 : std_logic; clk2 : r_clk) return std_logic is +  begin +    return op1 or clk2.val; +  end; + +  function  "nor" (clk1, clk2 : r_clk) return r_clk is +  begin +    return (base => clk1.base, +            val  => clk1.val nor clk2.val, +            rise => (clk1.fall and not clk2.val and not clk2.rise) or +                    (clk2.fall and not clk1.val and not clk1.rise), +            fall => (clk1.rise and not clk2.val) or +                    (clk2.rise and not clk1.val)); +  end; + +  function  "nor" (clk1 : r_clk; op2 : std_logic) return r_clk is +  begin +    return (base => clk1.base, +            val  => clk1.val nor op2, +            rise => clk1.fall and not op2, +            fall => clk1.rise and not op2); +  end; + +  function  "nor" (op1 : std_logic; clk2 : r_clk) return std_logic is +  begin +    return op1 nor clk2.val; +  end; + +  function    "=" (clk1 : r_clk; op2 : std_logic) return boolean is +  begin +    return clk1.val = op2; +  end; + +end; diff --git a/testsuite/synth/issue2177/testsuite.sh b/testsuite/synth/issue2177/testsuite.sh new file mode 100755 index 000000000..496e00805 --- /dev/null +++ b/testsuite/synth/issue2177/testsuite.sh @@ -0,0 +1,8 @@ +#! /bin/sh + +. ../../testenv.sh + + +synth --out=verilog vlm5030_pack.vhd clock_functions_pack.vhd vlm5030_subcircuits.vhd vlm5030_gl.vhd -e > syn_vlm5030.v + +echo "Test successful" diff --git a/testsuite/synth/issue2177/vlm5030_gl.vhd b/testsuite/synth/issue2177/vlm5030_gl.vhd new file mode 100644 index 000000000..bf11a9458 --- /dev/null +++ b/testsuite/synth/issue2177/vlm5030_gl.vhd @@ -0,0 +1,2309 @@ +---------------------------------------------------------------------- +--                           VLM5030 +--                      www.fpgaarcade.com +--                     All rights reserved. +-- +--                     admin@fpgaarcade.com +-- +-- This Source Code Form is subject to the terms of the Mozilla Public +-- License, v. 2.0. If a copy of the MPL was not distributed with this +-- file, You can obtain one at https://mozilla.org/MPL/2.0/. +---------------------------------------------------------------------- +-- +-- Copyright (c) 2021, Arnim Laeuger  arnim.laeuger@gmx.net +-- All rights reserved. +-- +------------------------------------------------------------------------------- +-- +-- Sanyo VLM5030 speech synthesizer +-- +-- Gate-level recreation extracted from the die image at +--   https://siliconpr0n.org/archive/doku.php?id=ogoun:vlm5030 +-- +--   https://www.fpgaarcade.com/tag/vlm5030/ +-- +------------------------------------------------------------------------------- +-- +--                 +-------,_,-------+ +--        GND   -- |  1           40 | <-    RST +--        TST1  -> |  2           39 | ->    TST4 +--        OSC2  ck |  3     _     38 | <-    TST3 +--        OSC1  ck |  4    (_)    37 | ->    TST2 +--        D0    -> |  5           36 | ->    DAO +--        D1    -> |  6           35 | <-    VREF +--        D2    -> |  7           34 | ->    MTE +--        D3    -> |  8     V     33 | ->    /ME +--        D4    -> |  9     L     32 | <-    VCU +--        D5    -> | 10     M     31 | <-    START +--        D6    -> | 11     5     30 | ->    BSY +--        D7    -> | 12     0     29 | --    Vdd +--        A0    <- | 13     3     28 | ->    A15 +--        A1    <- | 14     0     27 | ->    A14 +--        A2    <- | 15           26 | ->    A13 +--        A3    <- | 16     _     25 | ->    A12 +--        A4    <- | 17    (_)    24 | ->    A11 +--        A5    <- | 18           23 | ->    A10 +--        A6    <- | 19           22 | ->    A9 +--        A7    <- | 20           21 | ->    A8 +--                 +-----------------+ +-- +-- Clocking +-- ======== +-- +-- This model requires overclocking of OSC1/OSC2 by 2x or higher. +-- Violating this requirement results in undefined behaviour. +-- +-- i_clk is supplied with a free-running clock at >= 2x OSC frequency. +-- +-- i_oscen acts as clock enable for i_clk to define the 3.58 MHz clock +-- at OSC1/OSC2 of a real chip. +-- +-- +-- Test pins +-- ========= +-- +-- i_tst1 must be tied to '0' for mission mode operation. +-- Other unused test pins can be left unconnected: +-- * i_vref +-- * o_tst2 +-- * i_tst3 +-- * o_tst4 +-- +-- +-- Audio output +-- ============ +-- +-- The VLM5030 internally generates 12 bit signed PCM audio with ~8136 Hz +-- sample rate. +-- +-- During /ME=1 this PCM data is available at A[13:12], A[9:0]. +-- Note that A[9] has to be inverted externally if A[9:0] is to be used as a +-- standard signed vector. +-- +-- Typical applications use audio from the DAO pin. It is fed by a combination +-- of a 5 bit parallel DAC (tapping A[9:5]) and overlaid with a PWM signal +-- (controlled by A[4:2]). Bits A[1:0] are not used for DAO generation +-- +-- DAO characteristics +-- ------------------- +-- +-- DAO is an overlay of the 8136 Hz PCM data with high frequency PWM. +-- The PWM overlay periodically increases the DAO output voltage to the next +-- higher value with a duty cycle controlled by A[4:2]. +-- +--   ^   new PCM value                                 new PCM value +--   |   .                PWM overlay                              . +--   |   .+---+      +---+      +---+      +---+      +---+      +-+ +--   |   ++   +------+   +------+   +------+   +------+   +------+ + +--   |   |                                                         | +--   |   |                                                         +-- +--   |---+ +--   +------------------------------------------------------------------> +-- +-- When fed through an external low-pass filter, this PWM overlay augments +-- the discreete PCM DAC voltages with fractional levels. +-- +-- PWM period approx. 24.581 us, 40.682 kHz +--   PWM |  high  |  low +--  -----+--------+-------- +--    7  | 20.112 |  4.470 +--    6  | 17.318 |  7.263 +--    5  | 13.966 | 10.615 +--    4  | 11.173 | 13.408 +--    3  |  7.821 | 16.760 +--    2  |  4.670 | 19.553 +--    1  |  1.676 | 22.905 +--    0  |  0.000 | 24.581 +-- +-- Direct PCM output +-- ----------------- +-- +-- This model outputs signed 10 bit audio at o_audio in addition to DAO. +-- o_audio is equivalent to A[9:0] during /ME=1 with corrected sign bit. +-- + + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + + +entity vlm5030_gl is + +  port ( +    i_clk   : in  std_logic; +    i_oscen : in  std_logic; +    i_rst   : in  std_logic; +    i_start : in  std_logic; +    i_vcu   : in  std_logic; +    i_vref  : in  std_logic := '1'; +    i_tst1  : in  std_logic; +    o_tst2  : out std_logic; +    i_tst3  : in  std_logic := '1'; +    o_tst4  : out std_logic; +    i_d     : in  std_logic_vector( 7 downto 0); +    o_a     : out std_logic_vector(15 downto 0); +    o_me_l  : out std_logic; +    o_mte   : out std_logic; +    o_bsy   : out std_logic; + +    -- o_dao: unsigned audio, sample rate ~8136Hz, PWM ~40.682 kHz +    o_dao    : out std_logic_vector( 5 downto 0); + +    -- o_audio: signed audio, sample rate ~8136Hz +    o_audio  : out std_logic_vector(9 downto 0) +  ); + +end; + +use work.clock_functions_pack.all; +use work.vlm5030_pack.all; + +architecture gl of vlm5030_gl is + +  signal osc   : r_clk; +  signal clk2  : r_clk := z_clk; +  signal nclk2 : r_clk; + +  signal rst   : std_logic; + + +  signal dq       : std_logic_vector(7 downto 0); +  signal maskdq53 : std_logic; + +  signal starttst    : std_logic; +  signal tststopclk2, tstend2ID, tstend2IE, +         tstenID2A, tstenIE2A, tstenctrl2A, +         tstenIE2DAC : std_logic; + +  signal clk2divq          : std_logic_vector(10 downto 0) := (others => '0'); +  signal c2d0, c2d1, -- c2d2, +         c2d3, c2d4, c2d5, +         c2d6, c2d7, c2d8, +         c2d9, c2d10       : r_clk; +  signal c2d5fin           : r_clk; +  signal c2d7fin, nc2d7fin : r_clk; +  signal c2d9fin, nc2d9fin : r_clk; +  signal clk2gd5           : r_clk; +  signal nc2d1, nc2d6, +         nc2d8, nc2d10     : r_clk; +  signal c2d3gated         : r_clk; + + +  signal fsromevalout : std_logic; +  signal fsromdo      : std_logic_vector(13 downto 0); +  signal fsromnorhigh, +         fsromnorlow  : std_logic; +  -- +  signal clk2ctrl    : r_clk; +  signal ncen1, cen3 : std_logic; +  signal eaoen       : std_logic; +  signal xromdo7nq   : std_logic := '0'; +  signal xromdo7q    : std_logic; +  signal xromdo      : std_logic_vector(36 downto 0); +  signal yromdo      : std_logic_vector( 4 downto 0); +  signal c2d3gate    : std_logic; + + +  signal cntdn0 : std_logic; + + +  signal dinalq : std_logic_vector(7 downto 0) := (others => '0'); +  signal aq     : std_logic_vector(o_a'range); + + +  signal startrise  : std_logic; +  signal clkcntdn   : r_clk; +  signal ncntdnload : std_logic; +  signal ncntdn     : std_logic; + +  signal eavcu      : std_logic; +  signal ealatchh   : std_logic; +  signal neaload    : std_logic; +  signal eainc      : std_logic; +  signal clrdinal   : std_logic; +  signal clkdin     : std_logic; +  signal nvcufinal  : std_logic; +  signal vcufinal12 : std_logic; +  signal nbsy       : std_logic; +  signal me         : std_logic; +  signal rflatchwen : std_logic; +  signal asshift2   : std_logic; +  signal updtpitch  : std_logic; +  signal enrf2ID    : std_logic; +  signal clkksa     : r_clk; +  signal ensum2ID   : std_logic; + + +  signal clk2ena, clk2enb : r_clk; + +  signal rstdel : std_logic; + + +  signal ksa  : std_logic_vector(4 downto 0); +  signal nkdo : std_logic_vector(9 downto 0); + + +  signal rfdo        : std_logic_vector(nkdo'range); +  signal rfdo97zero  : std_logic; + + +  signal nID : std_logic_vector(9 downto 0); + +  signal assum : std_logic_vector(nID'range); + +  signal nIE : std_logic_vector(11 downto 0); + +  signal idlat       : std_logic_vector(7 downto 0); +  signal idlatall1   : std_logic; +  signal enIDlinv2ID : std_logic; +  signal enIDl2IE    : std_logic; +  signal enIDlinv2IE : std_logic; + + +  signal pitchoverflow : std_logic; +  signal enpitchlat    : r_clk; + + +  signal enmem02ID : std_logic; +  signal nmem0do, +         mem0do    : std_logic_vector(nID'range); +  signal enmem12IE : std_logic; +  signal mem1do2IE : std_logic_vector(nIE'range); +  signal enmem22IE : std_logic; +  signal mem2do2IE : std_logic_vector(nIE'range); + +  signal ieregdrv, +         ieregdrv4IE  : std_logic_vector(nIE'range); +  signal ieregload    : r_clk; + +  signal enieregfa2IE : std_logic; + +  signal c2d10xr9  : r_clk; +  signal enIE2A    : std_logic; +  signal ieaddrreg : std_logic_vector(nIE'range); + +  signal pitchmod : std_logic; + +  signal random : std_logic; + +  signal pwmsr : std_logic; + +begin + +  -- MSB K-slice address bit +  -- logic exists that generates it but output is not used (patched wiring) +  ksa(4) <= '0'; + +  -- main clock, corresponds to oscillator output +  osc  <= (base => i_clk, +           val  => i_clk, +           rise => i_oscen, +           fall => '0'); + +  clk2ena <= clk2 or (cen3 nor tstenctrl2A) or ncen1; +  clk2enb <= clk2 or (cen3 nor tstenctrl2A) or ncen1 or (fsromdo(6) nor tstenctrl2A); + + + +  ----------------------------------------------------------------------------- +  -- RST / POR generation +  -- +  rstdel_block : block +    signal porcnt : unsigned(7 downto 0) := (others => '1'); +    signal npor   : std_logic := '0'; +    signal del    : std_logic_vector(1 downto 0) := (others => '0'); +  begin +    por_p : process (osc) +    begin +      if rising_edge(osc) then +        if porcnt > 0 then +          porcnt <= porcnt - 1; +        end if; +        if porcnt = 0 then              -- TODO: measure POR hold time +          npor <= '1'; +        end if; +      end if; +    end process; + +    o_tst4 <= not npor; + +    rst <= '1' when npor = '0' and i_tst3 = '1' else i_rst; + +    rstdel_p : process (clk2) +    begin +      if rising_edge(clk2) then +        del <= del(0) & rst; +      end if; +    end process; +    -- +    rstdel <= del(1); +  end block; + + + +  ----------------------------------------------------------------------------- +  -- DQ registers +  -- +  dq_block : block +    signal rstq   : std_logic := '0'; +    signal rstclk : r_clk; +    signal ldq    : std_logic_vector(dq'range); +    signal maskdq53m, maskdq53s : std_logic := '0'; + +  begin +    rstclk_p : process (osc.base) +    begin +      if rising_edge(osc.base) then +        rstq <= rst; +      end if; +    end process; +    -- +    rstclk <= (base => osc.base, +               val  => rstq, +               rise => not rstq and     rst, +               fall =>     rstq and not rst); + +    dq_p : process (rstclk) +    begin +      if falling_edge(rstclk) then +        ldq <= i_d; +      end if; +    end process; + +    maskqm_p : process(startrise, enpitchlat) +    begin +      if startrise = '1' then +        maskdq53m <= '1'; +      elsif rising_edge(enpitchlat) then +        maskdq53m <= rfdo97zero; +      end if; +    end process; +    maskqs_p : process(startrise, enpitchlat) +    begin +      if startrise = '1' then +        maskdq53s <= '1'; +      elsif falling_edge(enpitchlat) then +        maskdq53s <= maskdq53m; +      end if; +    end process; +    maskdq53 <= maskdq53s; + +    dqmask_p : process(maskdq53, ldq) +    begin +      dq <= ldq; +      if maskdq53 = '1' then +        dq(5 downto 3) <= (others => '0'); +      end if; +    end process; + +  end block; + + + +  ----------------------------------------------------------------------------- +  -- TST logic +  -- +  -- +  -- TST1 VREF VCU START    Function +  --  0    X    X    X      Mission mode +  --  1    0    1    1      Clock stopped +  --  1    1    1    0      D to ID +  --  1    1    0    0      D to IE +  --  1    1    1    1      ID to A +  --  1    1    0    1      IE to A +  --  1    0    0    1      CTRL to A +  --  1    0    X    0      IE to DAC, forces D to IE +  --                        VCU controls pwmsel +  -- +  tst_block : block +    signal ntst1, nstart, nvcu : std_logic; +    signal ntst1vref : std_logic; +  begin +    ntst1  <= not i_tst1; +    nstart <= not i_start; +    nvcu   <= not i_vcu; + +    starttst <= nstart nor i_tst1; + +    ntst1vref <= i_tst1 nand i_vref; + +    tststopclk2 <= not( ntst1 or i_vref or  nvcu or  nstart ); +    tstend2ID   <= not( ntst1vref       or  nvcu or i_start ); +    tstend2IE   <= not( ntst1vref       or i_vcu or i_start ) or tstenIE2DAC; +    tstenID2A   <= not( ntst1vref       or  nvcu or  nstart ); +    tstenIE2A   <= not( ntst1vref       or i_vcu or  nstart ); +    tstenctrl2A <= not( ntst1 or i_vref or i_vcu or  nstart ); +    tstenIE2DAC <= not( ntst1 or i_vref          or i_start ); +  end block; + + + +  ----------------------------------------------------------------------------- +  -- CLK2 generation +  -- +  clk2_block : block +  begin + +    clk2.base <= osc.base; + +    process (osc) +    begin +      if rising_edge(osc) then +        if tststopclk2 = '1' then +          clk2.val  <= '0'; + +        else +          clk2.val <= not clk2.val; +        end if; +      end if; +    end process; + +    clk2.rise <= '0' when tststopclk2 = '1' else +                 osc.rise when clk2 = '0' else +                 '0'; +    clk2.fall <= '0' when tststopclk2 = '1' else +                 osc.rise when clk2 = '1' else +                 '0'; + +    nclk2 <= not clk2; + +  end block; + + + +  ----------------------------------------------------------------------------- +  -- CLK2 divider +  -- +  clk2div_block : block +    signal c2qnor   : std_logic; +    signal feedback : std_logic; + +    -- edge detection for val that will change to preval on the rising refclk edge +    function rising_edge_detect(refclk : r_clk; val, preval : std_logic) return r_clk is +    begin +      return (base => refclk.base, +              val  => val, +              rise => refclk.rise and not val and     preval, +              fall => refclk.rise and     val and not preval); +    end; + +  begin +    -- the 10 bit shift register chain for CLK2DIV +    process (clk2) +    begin +      if rising_edge(clk2) then +        clk2divq <= clk2divq(9 downto 0) & feedback; +      end if; +    end process; + +    c2qnor <= norf(clk2divq(9 downto 0)); + +    -- feedback signal for the CLK2DIV shifter +    feedback <= '0' when rstdel = '1' else c2qnor; + +    c2d0  <= rising_edge_detect(refclk => clk2, val => clk2divq( 0), preval => feedback); +    c2d1  <= rising_edge_detect(refclk => clk2, val => clk2divq( 1), preval => clk2divq(0)); +    -- c2d2  <= rising_edge_detect(refclk => clk2, val => clk2divq( 2), preval => clk2divq(1)); +    c2d3  <= rising_edge_detect(refclk => clk2, val => clk2divq( 3), preval => clk2divq(2)); +    c2d4  <= rising_edge_detect(refclk => clk2, val => clk2divq( 4), preval => clk2divq(3)); +    c2d5  <= rising_edge_detect(refclk => clk2, val => clk2divq( 5), preval => clk2divq(4)); +    c2d6  <= rising_edge_detect(refclk => clk2, val => clk2divq( 6), preval => clk2divq(5)); +    c2d7  <= rising_edge_detect(refclk => clk2, val => clk2divq( 7), preval => clk2divq(6)); +    c2d8  <= rising_edge_detect(refclk => clk2, val => clk2divq( 8), preval => clk2divq(7)); +    c2d9  <= rising_edge_detect(refclk => clk2, val => clk2divq( 9), preval => clk2divq(8)); +    c2d10 <= rising_edge_detect(refclk => clk2, val => clk2divq(10), preval => clk2divq(9)); + + +    -- SR-latches +    c2d5fin_b : entity work.vlm5030_srlatchclk +      port map ( +        i_clk => osc, +        i_res => c2d0, +        i_set => c2d5, +        o_q   => c2d5fin +      ); +    c2d7fin_b : entity work.vlm5030_srlatchclk +      port map ( +        i_clk => osc, +        i_res => c2d0, +        i_set => c2d7, +        o_q   => c2d7fin +      ); +    nc2d7fin <= not c2d7fin; + +    c2d9fin_b : entity work.vlm5030_srlatchclk +      port map ( +        i_clk => osc, +        i_res => c2d0, +        i_set => c2d9, +        o_q   => c2d9fin +      ); +    nc2d9fin <= not c2d9fin; + +    clk2gd5   <= c2d0 nor (c2d5 and nclk2); +    nc2d1     <= not c2d1; +    c2d3gated <= (not c2d3) nor c2d3gate; +    nc2d6     <= not c2d6; +    nc2d8     <= not c2d8; +    nc2d10    <= not c2d10; +  end block; + + + +  ----------------------------------------------------------------------------- +  -- FSROM +  -- +  fsrom_block : block +    signal fsroma : std_logic_vector(5 downto 0); +  begin + +    agen_block : block +    begin +      process (clk2ena) +      begin +        if rising_edge(clk2ena) then +          if (fsromnorlow nand nvcufinal) = '0' then +            -- shift chain +            fsroma <= fsroma(4 downto 0) & (fsroma(0) xor fsroma(5)); +          else +            -- reset chain +            fsroma <= (3 => not rstdel, +                       others => '0'); +          end if; + +        end if; +      end process; + +      fsromevalout <= not(   (fsromdo( 9) and (xromdo(0) or xromdo(4))) +                          or (fsromdo(10) and (xromdo(1) or xromdo(4))) +                          or (fsromdo(11) and (xromdo(6) or xromdo(3) or xromdo(0))) +                          or (fsromdo(12) and (xromdo(5) or xromdo(2))) +                          or (fsromdo(13) and  xromdo(5)) +                          or (fsromdo( 8) and (xromdo(7) or xromdo(1))) ); +    end block; + +    rom_block : block +      alias  a   : std_logic_vector(fsroma'range) is fsroma; +      signal na  : std_logic_vector(a'range); +      signal ndq : std_logic_vector(5 downto 3); + +      -- NOTE: vectors for norf must be range 0 to N! +      signal wl : std_logic_vector(0 to 17); + +    begin +      na  <= not a; +      ndq <= not dq(5 downto 3); + +      ------------------------------------------------------------------------- +      -- FSROM data out +      -- +      -- The sequence of the word lines must match the ROM bitmaps below +      wl <= a(5)&na(5) & na(4)&a(4) & a(3)&na(3) & na(2)&a(2) & a(1)&na(1) & na(0)&a(0) & dq(3)&ndq(3) & ndq(4)&dq(4) & dq(5)&ndq(5); + +      --              wl(0)           wl(17) +      --              a(5)            ndq(5) +      --                |                | +      fsromdo <= (--    |                | +        00 => norf(wl, "100110011001000000"), +        01 => norf(wl, "011010010110001010"), +        02 => norf(wl, "101001010101010110"), +        03 => norf(wl, "011001011001100100"), +        04 => norf(wl, "011010010101001001"), +        05 => norf(wl, "011010011001010101"), +        06 => norf(wl, "010110011001000000"), +        -- +        07 => norf(wl, "101010011001000000"), +        08 => norf(wl, "011001100110000000"), +        09 => norf(wl, "101001100110000000"), +        10 => norf(wl, "100101100110000000"), +        11 => norf(wl, "100110100110000000"), +        12 => norf(wl, "100110010110000000"), +        13 => norf(wl, "100110011010000000"), +        others => '1'); +      -- +      ------------------------------------------------------------------------- + +      fsromnorhigh <= norf(fsromdo(13 downto 8)); +      fsromnorlow  <= norf(fsromdo( 5 downto 0)); +    end block; + +  end block; + + + +  ----------------------------------------------------------------------------- +  -- Sequencer ROM +  -- +  seqrom_block : block +    signal gseqroma : std_logic_vector(4 downto 0); +  begin + +    agen_block : block +      signal ncen3 : std_logic; +      -- signal nclk2ctrlcen3 : std_logic; +      -- signal nclk2ctrlncen3 : std_logic; +      signal seqroma : std_logic_vector(4 downto 0) := "11110"; + +    begin +      ncen1    <= tstenctrl2A nor c2d10; + +      clk2ctrl <= clk2 or ncen1; + +      ncen3 <= rstdel nor xromdo(7); +      cen3  <= not ncen3; + +      -- nclk2ctrlcen3  <=  cen3 nor clk2ctrl; +      -- nclk2ctrlncen3 <= ncen3 nor clk2ctrl; + + +      process (clk2ctrl) +      begin +        if rising_edge(clk2ctrl) then +          seqroma(0) <= rstdel nor not (cen3 or xromdo(36) or not (seqroma(4) xor not seqroma(1))); + +          if cen3 = '0' then +            seqroma(1) <= not seqroma(0); +            seqroma(2) <= seqroma(1); +            seqroma(3) <= seqroma(2); +            seqroma(4) <= seqroma(3); +          end if; +          if ncen3 = '0' then +            seqroma(4 downto 1) <= (others => '1'); +          end if; + +          xromdo7nq <= xromdo(7);       -- unclear circuit extraction +        end if; + +      end process; + +      xromdo7q <= not xromdo7nq; + +      gseqroma <= seqroma(4 downto 1) & not seqroma(0); + +      eaoen    <= i_tst1 nor xromdo7nq; + +    end block; + +    rom_block : block +      alias   a0 : std_logic is gseqroma(0); +      alias   a1 : std_logic is gseqroma(1); +      alias   a2 : std_logic is gseqroma(2); +      alias   a3 : std_logic is gseqroma(3); +      alias   a4 : std_logic is gseqroma(4); +      alias  xa5 : std_logic is nc2d9fin.val; +      alias  xa6 : std_logic is c2d9fin.val; +      signal  na : std_logic_vector(gseqroma'range); +      alias  na0 : std_logic is na(0); +      alias  na1 : std_logic is na(1); +      alias  na2 : std_logic is na(2); +      alias  na3 : std_logic is na(3); +      alias  na4 : std_logic is na(4); + +      signal ny : std_logic_vector(yromdo'range); + +      -- NOTE: vectors for norf must be range 0 to N! +      signal xwl : std_logic_vector(0 to 11); +      signal ywl : std_logic_vector(0 to 35); + +    begin +      na <= not gseqroma; + +      ------------------------------------------------------------------------- +      -- XROM data out +      -- +      -- The sequence of the word lines must match the ROM bitmaps below +      xwl <= na0 & a0 & a1 & na1 & na2 & a2 & a3 & na3 & na4 & a4 & xa5 & xa6; + +      --              xwl(0)     xwl(11) +      --                na0        xa6 +      --                 |          | +      xromdo <= (--      |          | +        00 => norf(xwl, "100110100100"), +        01 => norf(xwl, "010110010100"), +        02 => norf(xwl, "011010011000"), +        03 => norf(xwl, "011001011000"), +        04 => norf(xwl, "011001101000"), +        05 => norf(xwl, "011001100100"), +        06 => norf(xwl, "101001100100"), +        07 => norf(xwl, "100101100100"), +        -- +        08 => norf(xwl, "100110100100"), +        09 => norf(xwl, "011010100100"), +        10 => norf(xwl, "101001101000"), +        11 => norf(xwl, "011001010100"), +        12 => norf(xwl, "011001101010"), +        13 => norf(xwl, "011010011010"), +        14 => norf(xwl, "100110100110"), +        -- +        15 => norf(xwl, "101001000110"), +        16 => norf(xwl, "011001100101"), +        17 => norf(xwl, "011001011001"), +        18 => norf(xwl, "010110010101"), +        19 => norf(xwl, "010001010100"), +        20 => norf(xwl, "010101000000"), +        21 => norf(xwl, "011001100010"), +        -- +        22 => norf(xwl, "000110000110"), +        23 => norf(xwl, "011001001001"), +        24 => norf(xwl, "010110011000"), +        25 => norf(xwl, "101000101000"), +        26 => norf(xwl, "010101011000"), +        27 => norf(xwl, "011000011010"), +        28 => norf(xwl, "100101101001"), +        -- +        29 => norf(xwl, "000110000100"), +        30 => norf(xwl, "011010011000"), +        31 => norf(xwl, "001010101000"), +        32 => norf(xwl, "010101010000"), +        33 => norf(xwl, "100101101010"), +        34 => norf(xwl, "101001010100"), +        35 => norf(xwl, "101010011000"), +        36 => norf(xwl, "100110011000"), +        others => '1'); +      -- +      ------------------------------------------------------------------------- + + +      ------------------------------------------------------------------------- +      -- YROM data out +      -- +      x_to_ywl : for idx in ywl'range generate +        ywl(idx) <= xromdo(idx); +      end generate; + +      -- The sequence of the word lines must match the ROM bitmap below: +      -- Leftmost word line is x0, rightmost word line is x35 +      -- +      --               ywl(0)                            ywl(35) +      --                 x0                                x35 +      --                 |                                  | +      ny <= (--          |                                  | +        04 => norf(ywl, "000000000100000000011000110000010001"), +        03 => norf(ywl, "000000000000111111111000100010000000"), +        02 => norf(ywl, "000000001001000000000111011010000000"), +        01 => norf(ywl, "000000000000000000000000000111111000"), +        00 => norf(ywl, "000000000000000000000000100000000111"), +        others => '1'); + +      c2d3gate <= norf(xromdo(7 downto 0)); + +      yromdo <= not ny; +      -- +      ------------------------------------------------------------------------- + +    end block; + +  end block; + + + +  ----------------------------------------------------------------------------- +  -- COUNT DOWN +  -- +  cntdown_block : block +    signal cntq : unsigned(7 downto 3) := (others => '0'); +  begin +    process (clkcntdn) +    begin +      if rising_edge(clkcntdn) then +        if ncntdnload = '0' then +          cntq(7 downto 4) <= unsigned(dinalq(7 downto 4)); +          cntq(3)          <= '1'; + +        else +          if ncntdn = '0' then +            cntq <= cntq - 1; +          end if; + +        end if; +      end if; +    end process; + +    cntdn0 <= '1' when cntq = 0 else '0'; + +  end block; + + + +  ----------------------------------------------------------------------------- +  -- DIN ALIGNMENT +  -- +  din_block : block +    signal dinlat  : std_logic_vector(i_d'range) := (others => '0'); +    signal ndincom : std_logic; + +    signal latchhq, latchh : std_logic_vector(15 downto 8); + +  begin +    process (osc.base) +    begin +      if rising_edge(osc.base) then +        if clkdin = '0' then +          dinlat <= i_d; +        end if; +      end if; +    end process; + +    ndincom <= norf(dinlat and xromdo(7 downto 0)); + +    process (clrdinal, c2d3gated) +    begin +      if clrdinal = '1' then +        dinalq <= (others => '0'); +      elsif rising_edge(c2d3gated) then +        dinalq <= not ndincom & dinalq(7 downto 1); +      end if; +    end process; + +    process (osc.base) +    begin +      if rising_edge(osc.base) then +        if ealatchh = '1' then +          latchhq <= dinalq; +        end if; +      end if; +    end process; + +    latchh(8) <= dinalq(0) when eavcu = '1' else +                 latchhq(8); +    latchh(15 downto 9) <= (others => '0') when eavcu = '1' else +                           latchhq(15 downto 9); + +    process (clk2ena) +    begin +      if rising_edge(clk2ena) then +        if neaload = '0' then +          -- parallel load +          aq( 0)          <= eavcu nor (not dinalq(0)); +          aq( 7 downto 1) <= dinalq(7 downto 1); +          aq(15 downto 8) <= latchh; +        else +          if eainc = '1' then +            -- toggle/ripple +            aq <= std_logic_vector(unsigned(aq) + 1); +          end if; +        end if; +      end if; +    end process; + +  end block; + + + +  ----------------------------------------------------------------------------- +  -- Random data source +  -- +  random_block : block +    signal lfsr     : std_logic_vector(9 downto 0) := (others => '0'); +    signal all0     : std_logic; +    signal feedback : std_logic; +  begin + +    all0 <= norf(lfsr(lfsr'high-1 downto 0)); + +    feedback <= (lfsr(9) xor lfsr(2)) nor all0; + +    process (clk2ena) +    begin +      if rising_edge(clk2ena) then +        lfsr <= lfsr(8 downto 0) & (rstdel nor feedback); +      end if; +    end process; + +    random <= lfsr(9); + +  end block; + + + +  ----------------------------------------------------------------------------- +  -- START control logic +  -- +  start_block : block +    alias  vcu  : std_logic is i_vcu; +    signal nvcu : std_logic; + +    signal startq        : std_logic_vector(2 downto 0); +    alias  startq0       : std_logic is startq(0); +    alias  startq1       : std_logic is startq(1); +    alias  startq2       : std_logic is startq(2); +    signal startriseq    : std_logic; +    signal startriseqvcu : std_logic; + +    signal ffsset         : std_logic; +    signal ffsloop        : std_logic; +    signal ffs1q, ffs2q, +           ffs3q, ffs4q   : std_logic := '1'; +    signal ffs1nq, ffs2nq, +           ffs3nq, ffs4nq : std_logic; +    signal ffs5q          : std_logic := '0'; +    signal ffs5nq         : std_logic; +    signal vcumode        : std_logic; +    alias  nvcumode       : std_logic is ffs1q; + +    signal vcufinal    : std_logic; +    signal vcufinal1q, +           vcufinal2q  : std_logic; +    signal nvcufinal12 : std_logic; + +    signal xromdo7nqdel : std_logic; + +    signal msff1q, msff2q, +           pmsff3q  : std_logic := '0'; +    signal msff1nq, msff2nq, +           pmsff3nq : std_logic; +    signal msffset  : std_logic; + +    signal n001x, n002x, n003x, n004x, n005x, n006x, +           n007x, n008x, n009x, n014x, n015x, +           n016x, n017x : std_logic; +    signal n012x : r_clk; + +    signal busy1q, +           busy2q   : std_logic; +    signal setbusy1 : std_logic; + +  begin +    nvcu    <= not vcu; +    vcumode <= not nvcumode; + +    vcufinal <= not nvcufinal; + +    process (rstdel, clk2ena) +    begin +      if rstdel = '1' then +        startq     <= (others => '0'); +        startriseq <= '1'; + +      elsif rising_edge(clk2ena) then +        startq     <= startq(1 downto 0) & starttst; +        startriseq <= startrise nand vcu; + +      end if; +    end process; + +    startrise <= (not startq1) nor startq2; +    startriseqvcu <= not startriseq; + + +    ffsset <= rstdel or n005x; +    process (ffsset, clk2ena) +    begin +      if ffsset = '1' then +        ffs1q <= '1'; +        ffs1q <= '1'; +        ffs4q <= '1'; +        ffs5q <= '0'; +      elsif rising_edge(clk2ena) then +        ffs1q <= (ffs1nq  and ffsloop)   nor (nvcu    and startrise);  -- async set +        ffs2q <= (ffs2nq  and ffsloop)   nor ( vcu    and startrise);  -- async set +        ffs4q <= (ffs4q   nor startrise) nor (startq1  nor ffs3nq);    -- async set +        ffs5q <= ffs5nq  nand ffsloop;  -- async clr + +      end if; +    end process; +    process (clk2ena) +    begin +      if rising_edge(clk2ena) then +        ffs3q <= ffs1nq;               -- no async set/clr +      end if; +    end process; +    ffs1nq <= not ffs1q; +    ffs2nq <= not ffs2q; +    ffs3nq <= not ffs3q; +    ffs4nq <= not ffs4q; +    ffs5nq <= not ffs5q; +    -- +    ffsloop <= ffs1q or (not ffs3q) or (not fsromdo(6)); + + +    process (vcufinal, clk2enb) +    begin +      if vcufinal = '1' then +        vcufinal1q <= '1'; +        vcufinal2q <= '1'; + +      elsif rising_edge(clk2enb) then +        vcufinal1q <= not vcufinal1q; + +        if vcufinal1q = '1' then +          vcufinal2q <= not vcufinal2q; +        end if; +      end if; + +    end process; + +    vcufinal12  <= (not vcufinal1q) nor (not vcufinal2q); +    nvcufinal12 <= not vcufinal12; +    nvcufinal   <= rstdel nor (nvcumode nor (not ffs4q)); + +    eavcu <= ffs2nq xor (ffs3q nor nvcumode); + +    neaload <= (nvcumode or (ffs3q and (ffs2nq or (not fsromdo(6)) or nvcufinal12))); + +    xromdo7nqdel_b : entity work.vlm5030_delay_inv +      generic map ( +        -- delay by ~558ns = 2 clocks +        g_numclks => 2 +      ) +      port map ( +        i_clk => osc, +        i_in  => xromdo7q, +        o_out => xromdo7nqdel +      ); + +    clkdin   <= (xromdo7nq and xromdo7nqdel and (vcumode or startriseqvcu)) nor ffs4nq; + +    ealatchh <= startriseqvcu or (fsromdo(7) and ffs3q and vcufinal12); + + +    msffset <= rstdel or startrise; +    -- +    process (msffset, c2d0) +    begin +      if msffset = '1' then +        msff1q <= '1'; +      elsif rising_edge(c2d0) then +        msff1q <= n008x nor (pmsff3nq and xromdo(7)); +      end if; +    end process; +    msff1nq <= not msff1q; +    -- +    process (msffset, c2d6) +    begin +      if msffset = '1' then +        msff2q <= '1'; +      elsif rising_edge(c2d6) then +        msff2q <= msff2nq nor (xromdo(1) and n007x and pmsff3nq); +      end if; +    end process; +    msff2nq <= not msff2q; +    -- +    process (c2d6) +    begin +      if rising_edge(c2d6) then +        pmsff3q <= (n007x and xromdo(0)) nor (pmsff3nq and msff1q); +      end if; +    end process; +    pmsff3nq <= not pmsff3q; + + +    n001x <= not( (not fsromdo(7)) or nvcufinal12 or ffs2nq or ffs3nq ); +    n002x <= not( dq(0) or vcufinal2q or vcufinal1q ); +    n003x <= not( n002x or dq(1) or n004x ); +    n004x <= vcufinal1q nor (not dq(0)); +    n005x <= not( msff2q or n006x or nc2d6 ); +    n006x <= n009x nand cntdn0; +    n007x <= not( n003x or ffs5nq or (fsromdo(13) nand dinalq(7)) ); +    n008x <= not( msff1q or rstdel or (not n006x) ); +    n009x <= not( nvcufinal12 or (not fsromdo(6)) or (not xromdo(7)) ); +    n012x <= not( nc2d10 or n003x or fsromevalout or ffs5nq ); +    n014x <= n001x nor not( n003x or ffs5nq or fsromnorhigh ); +    n015x <= not( dq(1) or n004x or (not ( vcufinal2q or (not vcufinal1q) or dq(0)) ) ); +    n016x <= (not fsromdo(6)) nor (not( dq(1) or n017x or (dq(0) and vcufinal1q) )); +    n017x <= not( dq(0) or (not vcufinal12) or (not vcufinal1q) ); + +    ncntdn <= not( msff1nq and n009x and (not cntdn0) ); + +    ncntdnload <= xromdo(5) nand pmsff3nq; +    clkcntdn <= (c2d0 and msff1nq) or (c2d6 and (xromdo(5) and pmsff3nq)); + +    clrdinal <= msff1nq or n012x; + +    eainc <= n014x nor msff1nq; + + +    setbusy1 <= startq1 nor startriseqvcu; +    process (setbusy1, clk2ctrl) +    begin +      if setbusy1 = '1' then +        busy1q <= '1'; +      elsif rising_edge(clk2ctrl) then +        busy1q <= startriseqvcu nor (not busy1q); +      end if; +    end process; + +    process (ffsset, clk2ctrl) +    begin +      if ffsset = '1' then +        busy2q <= '1'; +      elsif rising_edge(clk2ctrl) then +        busy2q <= vcumode nor (not busy2q); +      end if; +    end process; + +    nbsy <= (not busy1q) nor (not busy2q); + +    me <= not( ffs4q or i_start or xromdo7nq ); + +    rflatchwen <= not( fsromevalout or n003x or nc2d6 ); + +    asshift2 <= not( vcufinal2q or dq(1) or dq(0) ); + +    updtpitch <= not( n015x or (not fsromdo(6)) or (not xromdo(11)) ); + +    enrf2ID <= (not( n016x and (tstend2ID nor ffs5nq) )) nor nc2d8; + +    clkksa <= n012x; + +    ensum2ID <= not( ffs5nq or tstend2ID or ((n016x nor nc2d8) nor c2d4) ); + +  end block; + + + +  ----------------------------------------------------------------------------- +  -- K-Factor ROM +  -- +  krom_block : block +    signal ka : std_logic_vector(4 downto 0); +  begin + +    agen_block : block +      signal nfsrdo6 : std_logic; +      signal ksaq    : std_logic_vector(3 downto 0); +    begin + +      ka  <= dinalq(7 downto 3); + +      process (fsromdo(6), clkksa) +        variable toggle : std_logic_vector(ksaq'high+1 downto 0); +      begin +        if fsromdo(6) = '1' then +          ksaq <= "1011"; + +        elsif rising_edge(clkksa) then +          toggle(0) := '1'; +          for idx in 0 to ksaq'high loop +            if toggle(idx) = '1' then +              ksaq(idx) <= not ksaq(idx); +            end if; + +            toggle(idx+1) := ksaq(idx) nor (not toggle(idx)); +          end loop; + +        end if; +      end process; + +      nfsrdo6 <= not fsromdo(6); + +      ksa(3 downto 0) <= ( +        0 => ((not ksaq(0)) and nfsrdo6) nor (nfsrdo6 nor yromdo(3)), +        1 => ((not ksaq(1)) and nfsrdo6) nor (nfsrdo6 nor yromdo(2)), +        2 => ((not ksaq(2)) and nfsrdo6) nor (nfsrdo6 nor yromdo(1)), +        3 => ((not ksaq(3)) and nfsrdo6) nor (fsromdo(6) and (yromdo(0) xor (xromdo(10) nor xromdo(11)))) +        ); + +    end block; + +    rom_block : block +      signal kslice0, kslice1, kslice2, kslice3, kslice4, kslice5 : std_logic_vector(9 downto 0); + +      -- NOTE: vectors for norf must be range 0 to N! +      signal wl       : std_logic_vector(0 to 31); +      signal wl_slice : std_logic_vector(0 to  5); + +      alias   kaodd : std_logic is dinalq(2); +      signal nkaodd : std_logic; +      alias   ksa0  : std_logic is ksa(0); +      signal nksa0  : std_logic; +      signal range_s0s1s2, range_s3s4 : std_logic; + +      signal kout : std_logic_vector(nkdo'range); +    begin + +      process (ka) +      begin +        wl <= (others => '0'); +        wl(to_integer(unsigned(ka))) <= '1'; +      end process; + +      --------------------------------------------------------------------------- +      -- KROM data out +      -- +      -- The sequence of the word lines must match the ROM bitmaps below + +      --              wl(0)                          wl(31) +      --                |                              | +      kslice0 <= (--    |                              | +        00 => orf(wl, "11110111110000101101000111000101"), +        01 => orf(wl, "00000001001010110101010111101111"), +        02 => orf(wl, "00110111010011001110111111000001"), +        03 => orf(wl, "10110010011100000001101111010010"), +        04 => orf(wl, "10011011100000000001011111001011"), +        05 => orf(wl, "11011100000000000100111111000110"), +        06 => orf(wl, "11100000000000000110101010010100"), +        07 => orf(wl, "00000000000000001000110011100111"), +        08 => orf(wl, "00000000000000001111000011111000"), +        09 => orf(wl, "11111111111111110000000011111111"), +        others => '0'); + +      kslice1 <= ( +        00 => orf(wl, "00000100101110101100000110000011"), +        01 => orf(wl, "01011010100100111100111110001111"), +        02 => orf(wl, "11110001110111001101001110110111"), +        03 => orf(wl, "10001010111000000000011110011100"), +        04 => orf(wl, "01010011000000001110111110001000"), +        05 => orf(wl, "10011100000000001010000001111010"), +        06 => orf(wl, "11100000000000001100101010101100"), +        07 => orf(wl, "00000000000000000000110011001111"), +        08 => orf(wl, "00000000000000001111000011110000"), +        09 => orf(wl, "11111111111111110000000011111111"), +        others => '0'); + +      kslice2 <= ( +        00 => orf(wl, "11101010111101111111011110101011"), +        01 => orf(wl, "10111111010110001000010100101010"), +        02 => orf(wl, "11000100101011001110000001000100"), +        03 => orf(wl, "11111101000100101101101110100000"), +        04 => orf(wl, "10101001111101001110100000110101"), +        05 => orf(wl, "10011011010110001111001010010011"), +        06 => orf(wl, "11010010011000001111110011011010"), +        07 => orf(wl, "11100011100000001111111100011100"), +        08 => orf(wl, "11111100000000001111111111100000"), +        09 => orf(wl, "11111111111111111000000000000000"), +        others => '0'); + +      kslice3 <= ( +        00 => orf(wl, "10100100000001100111000110101010"), +        01 => orf(wl, "11001001010100100000001010010010"), +        02 => orf(wl, "11110001100110110101011001111100"), +        03 => orf(wl, "11111110000111000110010010101010"), +        04 => orf(wl, "11111111111000000111100011001100"), +        05 => orf(wl, "11111111111111111000000011110000"), +        06 => orf(wl, "11111111111111111111111100000000"), +        others => '0'); + +      kslice4 <= ( +        03 => orf(wl, "10101010100000000000000000000000"), +        04 => orf(wl, "11001100110101010111111111111111"), +        05 => orf(wl, "10001111000110011010101010000000"), +        06 => orf(wl, "11110000000111100011001100101010"), +        07 => orf(wl, "10000000000111111100001111001100"), +        08 => orf(wl, "11111111111000000000001111110000"), +        09 => orf(wl, "11111111111111111111110000000000"), +        others => '0'); + +      kslice5 <= ( +        06 => not ka(1), +        07 => not ka(2), +        08 => not ka(3), +        09 => not ka(4), +        others => '0'); +      -- +      --------------------------------------------------------------------------- + +      ------------------------------------------------------------------------- +      -- Output mux +      -- +      range_s0s1s2 <= norf(ksa(3 downto 1)); +      range_s3s4   <= ksa(2) nor (ksa(3) nand ksa(1)); +      nkaodd       <= not kaodd; +      nksa0        <= not ksa0; + +      -- NOTE: Each bitline forms a distributed complex gate: (enable) AND (OR'ed wl-transistors) +      --       Bitlines from each slice are then NORed together to the data lines. +      -- +      --       1. Wordlines are OR'ed on each bitline by the transistors +      --       2. The enable lines gate the effect of the bitline: +      --          - enabled: can pull data line to 0 if result of OR is 1 +      --          - not enabled: data line remains 1 +      --       3. Bitline result is visible as a NOR on the data line if enabled +      -- +      --       This model pre-calculates the bitlines above using OR and NORs +      --       their results (enabled by the slice wls) onto the data lines. +      -- +      --       --> kout represents the data lines + +      wl_slice <= (range_s0s1s2 and nksa0 and nkaodd) &  -- enable kslice0 +                  (range_s0s1s2 and nksa0 and  kaodd) &  -- enable kslice1 +                  (range_s0s1s2 and  ksa0           ) &  -- enable kslice2 +                  (range_s3s4   and nksa0           ) &  -- enable kslice3 +                  (range_s3s4   and  ksa0           ) &  -- enable kslice4 +                  (range_s0s1s2 nor range_s3s4      ) ;  -- enable kslice5 +      kout_gen : for idx in kout'range generate +        kout(idx) <= norf(wl_slice, +                          kslice0(idx) & +                          kslice1(idx) & +                          kslice2(idx) & +                          kslice3(idx) & +                          kslice4(idx) & +                          kslice5(idx)); +      end generate; +      -- data lines are subsequently inverted by the INVBUFs +      nkdo <= not kout; + +    end block; +  end block; + + + +  ----------------------------------------------------------------------------- +  -- Register file +  -- +  -- Memory map +  -- +  --             9 8 7 6 5 4 3 2 1 0 +  -- ksa[3..0] +---------------------+ +  --        11 |      Pitch   |XXXXXX| +  --           +---------------------+ +  --        10 |XXXXXX|    Energy    | +  --           +---------------------+ +  --         9 |  K10 |XXXXXXXXXXXXXX| +  --           +---------------------+ +  --         8 |  K9  |XXXXXXXXXXXXXX| +  --           +---------------------+ +  --         7 |  K8  |XXXXXXXXXXXXXX| +  --           +---------------------+ +  --         6 |  K7  |XXXXXXXXXXXXXX| +  --           +---------------------+ +  --         5 |  K6  |XXXXXXXXXXXXXX| +  --           +---------------------+ +  --         4 |  K5  |XXXXXXXXXXXXXX| +  --           +---------------------+ +  --         3 |   K4   |XXXXXXXXXXXX| +  --           +---------------------+ +  --         2 |   K3   |XXXXXXXXXXXX| +  --           +---------------------+ +  --         1 |          K2         | +  --           +---------------------+ +  --         0 |          K1         | +  --           +---------------------+ +  -- +  -- +  regfile_block : block +    signal rf0, rf1 : std_logic_vector(9 downto 0) := (others => '0'); +    signal rf2, rf3 : std_logic_vector(9 downto 6) := (others => '0'); +    signal rf4, rf5, +           rf6, rf7, +           rf8, rf9 : std_logic_vector(9 downto 7) := (others => '0'); +    signal rf10     : std_logic_vector(6 downto 0) := (others => '0'); +    signal rf11     : std_logic_vector(9 downto 3) := (others => '0'); +    signal a        : natural; +    signal al       : std_logic_vector(0 to 11); +    signal nrfdo    : std_logic_vector(rfdo'range); + +  begin +    a <= to_integer(unsigned(ksa)); + +    process (osc.base) +    begin +      if rising_edge(osc.base) then +        if rflatchwen = '1' then +          case a is +            when  0 => rf0  <= nkdo; +            when  1 => rf1  <= nkdo; +            when  2 => rf2  <= nkdo( rf2'range); +            when  3 => rf3  <= nkdo( rf3'range); +            when  4 => rf4  <= nkdo( rf4'range); +            when  5 => rf5  <= nkdo( rf5'range); +            when  6 => rf6  <= nkdo( rf6'range); +            when  7 => rf7  <= nkdo( rf7'range); +            when  8 => rf8  <= nkdo( rf8'range); +            when  9 => rf9  <= nkdo( rf9'range); +            when 10 => rf10 <= nkdo(rf10'range); +            when 11 => rf11 <= nkdo(rf11'range); +            when others => null; +          end case; +        end if; +      end if; +    end process; + +    process (a) +    begin +      al <= (others => '0'); +      if a <= al'high then +        al(a) <= '1'; +      end if; +    end process; + +    -- unimplemented bits read as '0' +    -- they're coded with '1' here because the norif function inverts the vec operand +    nrfdo(0) <= norif(al, rf0(0) & rf1(0) &  '1'   &  '1'   &  '1'   &  '1'   &  '1'   &  '1'   &  '1'   &  '1'   & rf10(0) &   '1'   ); +    nrfdo(1) <= norif(al, rf0(1) & rf1(1) &  '1'   &  '1'   &  '1'   &  '1'   &  '1'   &  '1'   &  '1'   &  '1'   & rf10(1) &   '1'   ); +    nrfdo(2) <= norif(al, rf0(2) & rf1(2) &  '1'   &  '1'   &  '1'   &  '1'   &  '1'   &  '1'   &  '1'   &  '1'   & rf10(2) &   '1'   ); +    nrfdo(3) <= norif(al, rf0(3) & rf1(3) &  '1'   &  '1'   &  '1'   &  '1'   &  '1'   &  '1'   &  '1'   &  '1'   & rf10(3) & rf11(3) ); +    nrfdo(4) <= norif(al, rf0(4) & rf1(4) &  '1'   &  '1'   &  '1'   &  '1'   &  '1'   &  '1'   &  '1'   &  '1'   & rf10(4) & rf11(4) ); +    nrfdo(5) <= norif(al, rf0(5) & rf1(5) &  '1'   &  '1'   &  '1'   &  '1'   &  '1'   &  '1'   &  '1'   &  '1'   & rf10(5) & rf11(5) ); +    nrfdo(6) <= norif(al, rf0(6) & rf1(6) & rf2(6) & rf3(6) &  '1'   &  '1'   &  '1'   &  '1'   &  '1'   &  '1'   & rf10(6) & rf11(6) ); +    nrfdo(7) <= norif(al, rf0(7) & rf1(7) & rf2(7) & rf3(7) & rf4(7) & rf5(7) & rf6(7) & rf7(7) & rf8(7) & rf9(7) &   '1'   & rf11(7) ); +    nrfdo(8) <= norif(al, rf0(8) & rf1(8) & rf2(8) & rf3(8) & rf4(8) & rf5(8) & rf6(8) & rf7(8) & rf8(8) & rf9(8) &   '1'   & rf11(8) ); +    nrfdo(9) <= norif(al, rf0(9) & rf1(9) & rf2(9) & rf3(9) & rf4(9) & rf5(9) & rf6(9) & rf7(9) & rf8(9) & rf9(9) &   '1'   & rf11(9) ); +    -- register file ouputs are subsequently inverted by the INVBUFs +    rfdo <= not nrfdo; + +    rfdo97zero <= norf(rfdo(9 downto 7)); + +  end block; + + + +  ----------------------------------------------------------------------------- +  -- ADDSHIFT +  -- +  addshift_block : block +    signal nIDlat, port_nID, +           port_rf  : std_logic_vector(nID'range); +    signal sumlat   : std_logic_vector(nID'high+2 downto 0); +    signal cin, sum : std_logic_vector(nID'high+1 downto 0); +    signal idpos    : std_logic; +  begin + +    idpos <= not( (dq(6) and updtpitch) nor c2d5fin); + +    cin(0) <= not idpos; + +    -- +    -- Generate adder/shifter slices +    -- +    addshift_slice : for idx in nID'high downto 0 generate + +      -- nID bus latch cell +      process (osc.base) +      begin +        if rising_edge(osc.base) then +          if c2d1 = '1' then +            nIDlat(idx) <= nID(idx); +          end if; +        end if; +      end process; + +      -- adder port: nID bus +      port_nID(idx) <= not nIDlat(idx) when idpos = '1' else nIDlat(idx); +      -- adder port: registerfile or shift +      port_rf(idx)  <= rfdo(idx)     when c2d5fin = '0'  else +                       sumlat(idx+1) when asshift2 = '0'     else +                       sumlat(idx+2); +      -- xor3 cell +      sum(idx)   <= port_nID(idx) xor port_rf(idx) xor cin(idx); +      -- carry cell +      cin(idx+1) <= (port_nID(idx) and port_rf(idx)) or ((port_nID(idx) or port_rf(idx)) and cin(idx)); + +      -- sum latch cell +      -- note: sumlat[0] is omitted on the die +      process (osc.base) +      begin +        if rising_edge(osc.base) then +          if c2d4 = '1' then +            sumlat(idx) <= sum(idx); +          end if; +        end if; +      end process; +    end generate; + +    -- extra cells +    sum(nID'high+1) <= cin(nID'high+1) xor port_nID(nID'high) xor port_rf(nID'high); +    process (osc.base) +    begin +      if rising_edge(osc.base) then +        if c2d4 = '1' then +          sumlat(nID'high+1) <= sum(nID'high+1); +        end if; +      end if; +    end process; +    sumlat(nID'high+2) <= sumlat(nID'high+1); + +    assum <= sum(nID'range); + +  end block; + + + +  ----------------------------------------------------------------------------- +  -- Pitch incrementer +  -- +  pitchinc_block : block +    signal pitchlat, +          pitchreg : std_logic_vector(9 downto 3) := (others => '0'); +    signal toggle  : std_logic_vector(pitchreg'high+1 downto pitchreg'low); +  begin + +    enpitchlat <= not (c2d4 nand updtpitch); + +    process (osc.base) +    begin +      if rising_edge(osc.base) then +        if enpitchlat = '1' then +          pitchlat <= nID(pitchlat'range); +        end if; +      end if; +    end process; + +    process (rstdel, clk2ena) +    begin +      if rstdel = '1' then +        pitchreg <= (others => '0'); + +      elsif rising_edge(clk2ena) then +        if pitchoverflow = '1' then +          -- load +          pitchreg <= pitchlat; +        else +          -- toggle reg +          for idx in pitchreg'range loop +            if toggle(idx) = '1' then +              pitchreg(idx) <= not pitchreg(idx); +            end if; +          end loop; +        end if; + +      end if; +    end process; + +    toggle(3) <= '1'; +    gen_toggle: for idx in 4 to toggle'high generate +      toggle(idx) <= (not pitchreg(idx-1)) nor (not toggle(idx-1)); +    end generate; + +    pitchoverflow <= toggle(toggle'high); + +  end block; + + +  pitchmod <= not( (not(dq(6) xor dq(7))) or tstend2ID or nc2d1 ); + + + +  ----------------------------------------------------------------------------- +  -- nID bus +  -- +  nID_block : block +    signal wl : std_logic_vector(0 to 5); +  begin + +    wl     <=          tstend2ID & enrf2ID & ensum2ID & updtpitch & enIDlinv2ID  & enmem02ID  ; +    --               |           |         |          |           |              |            | +    nID(0) <= norf(wl,  i_d(0)   & rfdo(0) & assum(0) &    '0'    & not idlat(0) & nmem0do(0) ); +    nID(1) <= norf(wl,  i_d(1)   & rfdo(1) & assum(1) &    '0'    & not idlat(1) & nmem0do(1) ); +    nID(2) <= norf(wl,  i_d(2)   & rfdo(2) & assum(2) &    '0'    & not idlat(2) & nmem0do(2) ); +    nID(3) <= norf(wl,  i_d(3)   & rfdo(3) & assum(3) &    '0'    & not idlat(3) & nmem0do(3) ); +    nID(4) <= norf(wl,  i_d(4)   & rfdo(4) & assum(4) &    '0'    & not idlat(4) & nmem0do(4) ); +    nID(5) <= norf(wl,  i_d(5)   & rfdo(5) & assum(5) &    '0'    & not idlat(5) & nmem0do(5) ); +    nID(6) <= norf(wl,  i_d(6)   & rfdo(6) & assum(6) & pitchmod  & not idlat(6) & nmem0do(6) ); +    nID(7) <= norf(wl,  i_d(7)   & rfdo(7) & assum(7) &    '0'    & not idlat(7) & nmem0do(7) ); +    nID(8) <= norf(wl,  i_d(0)   & rfdo(8) & assum(8) &    '0'    &     '0'      & nmem0do(8) ); +    nID(9) <= norf(wl,  i_d(1)   & rfdo(9) & assum(9) &    '0'    &     '0'      & nmem0do(9) ); + +  end block; + + + +  ----------------------------------------------------------------------------- +  -- ID Latch +  -- +  idlat_block : block +    signal idlaten : std_logic; +    signal n       : std_logic; +  begin + +    idlaten     <= not( (not fsromdo(6)) or (not xromdo(10)) or nc2d8 ); +    enIDlinv2ID <= not( (not xromdo(10)) or tstend2ID or nc2d1 ); + +    n           <= xromdo7q or tstend2IE or c2d7fin; +    enIDlinv2IE <= (not( (maskdq53 and random) or ((not maskdq53) and pitchoverflow) )) nor n; +    enIDl2IE    <= not( n or random or idlatall1 or (not maskdq53) ); + +    process (osc.base) +    begin +      if rising_edge(osc.base) then +        if idlaten = '1' then +          idlat <= nID(7 downto 0); +        end if; +      end if; +    end process; + +    idlatall1 <= norf(not idlat); + +  end block; + + + +  ----------------------------------------------------------------------------- +  -- Memories +  -- +  mem_block : block +    signal swapa : unsigned(3 downto 0); +    signal a     : natural; + +    signal clkmem0, clkmem1, clkmem2 : std_logic; + +    type t_mem0 is array(0 to 9) of std_logic_vector(nID'range); +    signal mem0 : t_mem0 := (others => (others => '0')); +    type t_mem1 is array(0 to 9) of std_logic_vector(nIE'range); +    signal mem1 : t_mem1 := (others => (others => '0')); +    type t_mem2 is array(0 to 8) of std_logic_vector(nIE'range); +    signal mem2 : t_mem2 := (others => (others => '0')); +  begin + +    yswap_gen : for idx in 3 downto 0 generate +      swapa(idx) <= yromdo(3-idx); +    end generate; +    a <= to_integer(swapa); + +    -- +    -- MEM0 +    -- +    clkmem0   <= not( xromdo(7) or (not fsromdo(6)) or (xromdo7q and yromdo(4)) or nc2d8 ); +    enmem02ID <= not( tstend2ID or (xromdo7q and yromdo(4)) or nc2d1 ); + +    mem0_p : process (osc.base) +    begin +      if rising_edge(osc.base) then +        if clkmem0 = '1' then +          if a <= t_mem0'high then +            mem0(a) <= nID; +          end if; +        end if; +      end if; +    end process; + +    -- the latches provide inverted Q on output, enabled by a +    nmem0do <= not mem0(a) when a <= t_mem0'high else (others => '1'); +    mem0do  <= not nmem0do; + + +    -- +    -- MEM1 +    -- +    clkmem1   <= yromdo(4) nor nc2d10; +    enmem12IE <= not( yromdo(4) or tstend2IE or c2d7fin ); + +    mem1_p : process (osc.base) +    begin +      if rising_edge(osc.base) then +        if clkmem1 = '1' then +          if a <= t_mem1'high then +            mem1(a) <= nIE; +          end if; +        end if; +      end if; +    end process; + +    -- the latches provide inverted Q on output, enabled by a +    mem1do2IE <= not mem1(a) when a <= t_mem1'high else (others => '1'); + + +    -- +    -- MEM2 +    -- +    clkmem2   <= yromdo(4) and c2d10; +    enmem22IE <= not( tstend2IE or (not xromdo(7)) or nc2d10 ); + +    mem2_p : process (osc.base) +    begin +      if rising_edge(osc.base) then +        if clkmem2 = '1' then +          if a <= t_mem2'high then +            mem2(a) <= nIE; +          end if; +        end if; +      end if; +    end process; + +    -- the latches provide inverted Q on output, enabled by a +    mem2do2IE <= not mem2(a) when a <= t_mem2'high else (others => '1'); + + +  end block; + + +  ----------------------------------------------------------------------------- +  -- Arithmetic block +  -- +  arithmetic_block : block +    signal memxdo       : std_logic_vector(nIE'range); +    signal wl           : std_logic_vector(0 to 1); +    constant num_slices : natural := nIE'high+2;  -- 13 slices + +    type r_row is record +      line1   : std_logic; +      line2   : std_logic; +      line3   : std_logic; +      line4in : std_logic_vector(num_slices-1+1 downto 0); +      lxor    : std_logic_vector(num_slices-1 downto 0); +      sum     : std_logic_vector(num_slices-1 downto 0); +      carry   : std_logic_vector(num_slices-1 downto 0); +      rowcarry1, rowcarry2 : std_logic; +    end record; +    signal row0, row1, row2, row3, row4 : r_row; + +    -- map the slice index to the memxdo index +    function map_slice_memxdo_f (slice : natural) return natural is +    begin +      if slice <= 9 then +        -- slices 0 to 9 are supplied by memxdo(9) downto (0) +        return 9-slice; +      elsif slice = 10 then +        -- slice 10 is supplied by memxdo(11) +        return 11; +      elsif slice = 11 then +        -- slice 11 is supplied by memxdo(10) +        return 10; +      else +        -- invalid slice +        return 100; +      end if; +    end; +    -- +    function line1_f(odd_prev : std_logic; +                     even     : std_logic) return std_logic is +    begin +      return not (odd_prev xor (not even)); +    end; +    -- +    function line2_f(odd_prev : std_logic; +                     even     : std_logic; +                     odd      : std_logic) return std_logic is +    begin +      return ( +                    (not odd_prev) +                and (not even) +                and      odd +              ) or ( +                         odd_prev +                and      even +                and (not odd) +              ); +    end; +    -- +    function xor_f (line4_upper : std_logic; +                    line1       : std_logic; +                    line2       : std_logic; +                    line3       : std_logic; +                    line4_lower : std_logic) return std_logic is +    begin +      return line3 xor not((line4_upper and line2) or (line4_lower and line1)); +    end; +    -- +    function sum_f (porta : std_logic; +                    portb : std_logic; +                    carry : std_logic) return std_logic is +    begin +      return porta xor portb xor carry; +    end; +    -- +    function carry_f (porta : std_logic; +                      portb : std_logic; +                      carry : std_logic) return std_logic is +    begin +      return ( +                carry and (porta or portb) +              ) or ( +                porta and portb +              ); +    end; +    -- +    function map_slice_ie_f (slice : natural) return natural is +    begin +      return map_slice_memxdo_f(slice); +    end; + +    signal oeq, oenq : std_logic; +    signal memlatmuxq : std_logic_vector(nIE'range); +    type r_memlatmux is record +      sum   : std_logic_vector(nIE'range); +      carry : std_logic_vector(nIE'range); +    end record; +    signal memlatmux : r_memlatmux; + +    type r_iereg is record +      q     : std_logic_vector(nIE'range); +      portb : std_logic_vector(nIE'range); +      cout  : std_logic_vector(nIE'high+1 downto 0); +      sum   : std_logic_vector(nIE'range); +    end record; +    signal iereg : r_iereg; + +  begin + +    wl <= yromdo(4) & not yromdo(4); +    memxdo_gen : for idx in memxdo'range generate +      memxdo(idx) <= norf(wl, mem1do2IE(idx) & mem2do2IE(idx)); +    end generate; + + +    -- +    -- Row 0 +    -- +    row0.line1 <= line1_f(odd_prev => '1', +                          even     => mem0do(0)); +    row0.line2 <= (not mem0do(0)) nor mem0do(1);  -- line2_f with odd_prev='1' +    row0.line3 <= mem0do(1); +    row0.line4in(0) <= row0.line4in(1);  -- metal short between upper and lower line4 +    -- preset with 0 to replicate unimplemented left half of MUXI +    row0.line4in(13) <= '0'; +    -- +    row0_gen_low : for slice in 0 to 11 generate +      row0.line4in(slice+1) <= not memxdo(map_slice_memxdo_f(slice)); +      row0.lxor(slice)  <= xor_f(line4_upper => row0.line4in(slice+1), +                                 line1 => row0.line1, +                                 line2 => row0.line2, +                                 line3 => row0.line3, +                                 line4_lower => row0.line4in(slice)); +      row0.sum(slice)   <= sum_f(porta => row0.lxor(slice), +                                 portb => '0', +                                 carry => '0'); +      row0.carry(slice) <= '0'; +    end generate; + +    -- rowcarry is built based on slice 11 +    row0.rowcarry1 <= not( (row0.line1 and row0.line4in(12)) or (row0.line3 or (not row0.sum(11))) ); +    row0.rowcarry2 <= row0.rowcarry1; + +    -- +    -- Row 1 +    -- +    row1.line1 <= line1_f(odd_prev => mem0do(1), +                          even     => mem0do(2)); +    row1.line2 <= line2_f(odd_prev => mem0do(1), +                          even     => mem0do(2), +                          odd      => mem0do(3)); +    row1.line3 <= mem0do(3); +    row1.line4in <= (others => '0'); +    -- slices 0 and 1 +    row1_gen_0_1 : for slice in 0 to 1 generate +      row1.lxor(slice)  <= xor_f(line4_upper => row0.line4in(slice+1), +                                 line1 => row1.line1, +                                 line2 => row1.line2, +                                 line3 => row1.line3, +                                 line4_lower => row0.line4in(slice)); +      row1.sum(slice)   <= not row1.lxor(slice); +      row1.carry(slice) <= '0' when slice = 0 else +                            row1.lxor(slice); +    end generate; +    -- slice 2 has special carry calculation +    row1.lxor(2)  <= xor_f(line4_upper => row0.line4in(2+1), +                           line1 => row1.line1, +                           line2 => row1.line2, +                           line3 => row1.line3, +                           line4_lower => row0.line4in(2)); +    row1.sum(2)   <= sum_f(porta => row1.lxor(2), +                           portb => row0.sum(2-2), +                           carry => '0');  -- just XOR lxor with sum-2 +    row1.carry(2) <= (not row1.lxor(2)) nand row0.sum(2-2);  -- special operator in slice 2 +    -- slices 3 to 12 +    row1_gen_upper : for slice in 3 to num_slices-1 generate +      row1.lxor(slice) <= xor_f(line4_upper => row0.line4in(slice+1), -- slice 12 expects 0 +                                line1 => row1.line1, +                                line2 => row1.line2, +                                line3 => row1.line3, +                                line4_lower => row0.line4in(slice)); +      row1.sum(slice)   <= sum_f(porta => row1.lxor(slice), +                                 portb => row0.sum(slice-2), +                                 carry => '0');  -- just XOR lxor with sum-2 +      row1.carry(slice) <= carry_f(porta => row1.lxor(slice), +                                   portb => row0.sum(slice-2), +                                   carry => '0');  -- just AND lxor with sum-2 +    end generate; + +    -- rowcarry chain +    row1.rowcarry1 <= carry_f(porta => not row1.line3, +                              portb => row1.sum(12), +                              carry => row0.rowcarry2); +    row1.rowcarry2 <= carry_f(porta => row1.carry(12), +                              portb => row1.sum(11), +                              carry => row1.rowcarry1); +                                  + +    -- +    -- Row 2 +    -- +    row2.line1 <= line1_f(odd_prev => mem0do(3), +                          even     => mem0do(4)); +    row2.line2 <= line2_f(odd_prev => mem0do(3), +                          even     => mem0do(4), +                          odd      => mem0do(5)); +    row2.line3 <= mem0do(5); +    row2.line4in <= (others => '0'); +    -- slices 0 and 1 +    row2_gen_0_1 : for slice in 0 to 1 generate +      row2.lxor(slice)  <= xor_f(line4_upper => row0.line4in(slice+1), +                                 line1 => row2.line1, +                                 line2 => row2.line2, +                                 line3 => row2.line3, +                                 line4_lower => row0.line4in(slice)); +      row2.sum(slice)   <= not row2.lxor(slice); +      row2.carry(slice) <= '0' when slice = 0 else +                            row2.lxor(slice); +    end generate; +    -- slices 2 to 12 +    row2_gen_upper : for slice in 2 to num_slices-1 generate +      row2.lxor(slice) <= xor_f(line4_upper => row0.line4in(slice+1), -- slice 12 expects 0 +                                line1 => row2.line1, +                                line2 => row2.line2, +                                line3 => row2.line3, +                                line4_lower => row0.line4in(slice)); +      row2.sum(slice)   <= sum_f(porta => row2.lxor(slice), +                                 portb => row1.sum(slice-2), +                                 carry => row1.carry(slice-1)); +      row2.carry(slice) <= carry_f(porta => row2.lxor(slice), +                                   portb => row1.sum(slice-2), +                                   carry => row1.carry(slice-1)); +    end generate; + +    -- rowcarry chain +    row2.rowcarry1 <= carry_f(porta => not row2.line3, +                              portb => row2.sum(12), +                              carry => row1.rowcarry2); +    row2.rowcarry2 <= carry_f(porta => row2.carry(12), +                              portb => row2.sum(11), +                              carry => row2.rowcarry1); + +    -- +    -- Row 3 +    -- +    row3.line1 <= line1_f(odd_prev => mem0do(5), +                          even     => mem0do(6)); +    row3.line2 <= line2_f(odd_prev => mem0do(5), +                          even     => mem0do(6), +                          odd      => mem0do(7)); +    row3.line3 <= mem0do(7); +    row3.line4in <= (others => '0'); +    -- slices 0 and 1 +    row3_gen_0_1 : for slice in 0 to 1 generate +      row3.lxor(slice)  <= xor_f(line4_upper => row0.line4in(slice+1), +                                 line1 => row3.line1, +                                 line2 => row3.line2, +                                 line3 => row3.line3, +                                 line4_lower => row0.line4in(slice)); +      row3.sum(slice)   <= not row3.lxor(slice); +      row3.carry(slice) <= '0' when slice = 0 else +                            row3.lxor(slice); +    end generate; +    -- slices 2 to 12 +    row3_gen_upper : for slice in 2 to num_slices-1 generate +      row3.lxor(slice) <= xor_f(line4_upper => row0.line4in(slice+1), -- slice 12 expects 0 +                                line1 => row3.line1, +                                line2 => row3.line2, +                                line3 => row3.line3, +                                line4_lower => row0.line4in(slice)); +      row3.sum(slice)   <= sum_f(porta => row3.lxor(slice), +                                 portb => row2.sum(slice-2), +                                 carry => row2.carry(slice-1)); +      row3.carry(slice) <= carry_f(porta => row3.lxor(slice), +                                   portb => row2.sum(slice-2), +                                   carry => row2.carry(slice-1)); +    end generate; + +    -- rowcarry chain +    row3.rowcarry1 <= carry_f(porta => not row3.line3, +                              portb => row3.sum(12), +                              carry => row2.rowcarry2); +    row3.rowcarry2 <= carry_f(porta => row3.carry(12), +                              portb => row3.sum(11), +                              carry => row3.rowcarry1); + +    -- +    -- Row 4 +    -- +    row4.line1 <= line1_f(odd_prev => mem0do(7), +                          even     => mem0do(8)); +    row4.line2 <= line2_f(odd_prev => mem0do(7), +                          even     => mem0do(8), +                          odd      => mem0do(9)); +    row4.line3 <= mem0do(9); +    row4.line4in <= (others => '0'); +    -- slices 0 and 1 +    row4_gen_0_1 : for slice in 0 to 1 generate +      row4.lxor(slice)  <= xor_f(line4_upper => row0.line4in(slice+1), +                                 line1 => row4.line1, +                                 line2 => row4.line2, +                                 line3 => row4.line3, +                                 line4_lower => row0.line4in(slice)); +      row4.sum(slice)   <= not row4.lxor(slice); +      row4.carry(slice) <= '0' when slice = 0 else +                            row4.lxor(slice); +    end generate; +    -- slices 2 to 12 +    row4_gen_upper : for slice in 2 to num_slices-1 generate +      row4.lxor(slice) <= xor_f(line4_upper => row0.line4in(slice+1), -- slice 12 expects 0 +                                line1 => row4.line1, +                                line2 => row4.line2, +                                line3 => row4.line3, +                                line4_lower => row0.line4in(slice)); +      row4.sum(slice)   <= sum_f(porta => row4.lxor(slice), +                                 portb => row3.sum(slice-2), +                                 carry => row3.carry(slice-1)); +      row4.carry(slice) <= carry_f(porta => row4.lxor(slice), +                                   portb => row3.sum(slice-2), +                                   carry => row3.carry(slice-1)); +    end generate; + +    -- rowcarry chain +    row4.rowcarry1 <= carry_f(porta => not row4.line3, +                              portb => row4.sum(12), +                              carry => row3.rowcarry2); +    row4.rowcarry2 <= row4.rowcarry1; + + +    -- +    -- MEMLATMUX +    -- +    memlatmux_p : process (c2d7fin) +    begin +      if rising_edge(c2d7fin) then +        memlatmuxq <= not ieregdrv; +      end if; +    end process; +    -- +    gen_memlatmux : for slice in 0 to memlatmuxq'high generate +      memlatmux.sum(slice) <=     row4.carry(slice+1) when c2d7fin = '0' else +                                  memlatmuxq(slice)   when yromdo(4) = '0'   else  -- OEQ  /c2d7fin nor  yromdo(4) = '1' +                              not memlatmuxq(slice);                               -- OEnQ /c2d7fin nor /yromdo(4) = '1' +      memlatmux.carry(slice) <= row4.sum(slice); +    end generate; + + +    -- +    -- IEREG level +    -- + +    -- represents MUX on output of ROWCARRY chain +    iereg.cout(iereg.cout'high) <= not yromdo(4) when c2d7fin = '1' else +                                   row4.rowcarry2; +    iereg_gen : for slice in 0 to nIE'high generate + +      -- IEREG +      iereg_p : process (ieregload) +      begin +        if falling_edge(ieregload) then +          iereg.q(slice) <= nIE(map_slice_ie_f(slice)); +        end if; +      end process; + +      iereg.portb(slice) <= not iereg.q(slice) when c2d7fin = '1' else +                            memlatmux.carry(slice); +      iereg.cout(slice)  <= carry_f(porta => memlatmux.sum(slice), +                                    portb => iereg.portb(slice), +                                    carry => iereg.cout(slice+1)); +      iereg.sum(slice)   <= sum_f(porta => memlatmux.sum(slice), +                                  portb => iereg.portb(slice), +                                  carry => iereg.cout(slice+1)); +    end generate; + +    ieregdrv <= iereg.sum       when   ( ((not iereg.cout(0)) xor (not iereg.cout(1))) nand  c2d7fin ) = '1' else +                (others => '1') when not(      iereg.cout(1)   or (not iereg.cout(0))    or nc2d7fin ) = '1' else +                (others => '0') when not( (not iereg.cout(1))  or      iereg.cout(0)     or nc2d7fin ) = '1' else +                (others => 'X');        -- invalid +    iregdrv_gen : for slice in 0 to nIE'high generate +      ieregdrv4IE(slice) <= ieregdrv(map_slice_ie_f(slice)); +    end generate; + +    ieregload <= ( (c2d10 and yromdo(4)) or (  c2d6 and (xromdo7q nand yromdo(4) ) ) ); +    enieregfa2IE <= not( tstend2IE or xromdo(7) or nc2d10 ); + + +    -- +    -- nIE distribution to ABUS and DAC +    -- +    c2d10xr9 <= c2d10 and xromdo(9); +    enIE2A <= i_tst1 nor xromdo7q; + +    ieaddr_p : process (c2d10xr9) +    begin +      if falling_edge(c2d10xr9) then +        ieaddrreg <= not nIE; +      end if; +    end process; + +  end block; + + +  ----------------------------------------------------------------------------- +  -- nIE bus +  -- +  nIE_block : block +    signal wl : std_logic_vector(0 to 5); +  begin + +    wl      <=          enIDlinv2IE  & enIDl2IE &   enmem12IE   &   enmem22IE   &  enieregfa2IE   & tstend2IE; +    --                |              |          |               |               |                 |          | +    nIE( 0) <= norf(wl,     '0'      &   '1'    & mem1do2IE( 0) & mem2do2IE( 0) & ieregdrv4IE( 0) &  i_d(0)  ); +    nIE( 1) <= norf(wl, not idlat(0) & idlat(0) & mem1do2IE( 1) & mem2do2IE( 1) & ieregdrv4IE( 1) &  i_d(1)  ); +    nIE( 2) <= norf(wl, not idlat(1) & idlat(1) & mem1do2IE( 2) & mem2do2IE( 2) & ieregdrv4IE( 2) &  i_d(2)  ); +    nIE( 3) <= norf(wl, not idlat(2) & idlat(2) & mem1do2IE( 3) & mem2do2IE( 3) & ieregdrv4IE( 3) &  i_d(3)  ); +    nIE( 4) <= norf(wl, not idlat(3) & idlat(3) & mem1do2IE( 4) & mem2do2IE( 4) & ieregdrv4IE( 4) &  i_d(4)  ); +    nIE( 5) <= norf(wl, not idlat(4) & idlat(4) & mem1do2IE( 5) & mem2do2IE( 5) & ieregdrv4IE( 5) &  i_d(5)  ); +    nIE( 6) <= norf(wl, not idlat(5) & idlat(5) & mem1do2IE( 6) & mem2do2IE( 6) & ieregdrv4IE( 6) &  i_d(6)  ); +    nIE( 7) <= norf(wl, not idlat(6) & idlat(6) & mem1do2IE( 7) & mem2do2IE( 7) & ieregdrv4IE( 7) &  i_d(7)  ); +    nIE( 8) <= norf(wl, not idlat(7) & idlat(7) & mem1do2IE( 8) & mem2do2IE( 8) & ieregdrv4IE( 8) &  i_d(0)  ); +    nIE( 9) <= norf(wl,     '0'      &   '1'    & mem1do2IE( 9) & mem2do2IE( 9) & ieregdrv4IE( 9) &  i_d(1)  ); +    nIE(10) <= norf(wl,     '0'      &   '1'    & mem1do2IE(10) & mem2do2IE(10) & ieregdrv4IE(10) &  i_d(2)  ); +    nIE(11) <= norf(wl,     '0'      &   '1'    & mem1do2IE(11) & mem2do2IE(11) & ieregdrv4IE(11) &  i_d(3)  ); + +  end block; + + + +  ----------------------------------------------------------------------------- +  -- DAC block +  -- +  dac_block : block +    signal pwmsel : std_logic; +  begin + +    pwm_block : block +      signal pwm0, pwm1, pwm2 : std_logic; + +      signal nc2d10xr9del : std_logic; +      --signal nclk2gd5hi, +      --      nclk2gd5lo    : std_logic; + +      signal pwmreg1toggle, +             pwmreg2toggle    : std_logic; +      signal pwmreg0, pwmreg1, +             pwmreg2          : std_logic; + +      signal pwmcomm, +             pwmcommdel, +             pwmcommand : std_logic; +      signal pwmcomp    : std_logic; + +    begin + +      pwm2 <= ieaddrreg(4) when tstenIE2DAC = '0' else nIE(4); +      pwm1 <= ieaddrreg(3) when tstenIE2DAC = '0' else nIE(3); +      pwm0 <= ieaddrreg(2) when tstenIE2DAC = '0' else nIE(2); + +      nc2d10xr9del_b : entity work.vlm5030_delay_inv +        generic map ( +          -- delay by ~1.1us = 4 osc clocks +          g_numclks => 4 +        ) +        port map ( +          i_clk => osc, +          i_in  => c2d10xr9.val, +          o_out => nc2d10xr9del +        ); +      -- nclk2gd5hi <= nc2d10xr9del       nor clk2gd5; +      -- nclk2gd5lo <= (not nc2d10xr9del) nor clk2gd5; + +      pwmreg1toggle <= pwmreg0; +      pwmreg2toggle <= (not pwmreg1) nor (not pwmreg0); + +      process (clk2gd5) +      begin +        if rising_edge(clk2gd5) then +          if nc2d10xr9del = '0' then +            -- clear +            pwmreg0 <= '0'; +            pwmreg1 <= '0'; +            pwmreg2 <= '0'; + +          else +            pwmreg0 <= not pwmreg0; +            if pwmreg1toggle = '1' then +              pwmreg1 <= not pwmreg1; +            end if; +            if pwmreg2toggle = '1' then +              pwmreg2 <= not pwmreg2; +            end if; +          end if; +        end if; + +      end process; + +      pwmcomm <= norf(pwmreg0 & pwmreg1 & pwmreg2); +      pwmcommdel_b : entity work.vlm5030_delay +        generic map ( +          -- delay by ~1.1us = 4 osc clocks +          g_numclks => 4 +        ) +        port map ( +          i_clk => osc, +          i_in  => pwmcomm, +          o_out => pwmcommdel +        ); +      pwmcommand <= pwmcomm and pwmcommdel; + +      pwmcomp <= norif(pwm2 & pwm1 & pwm0, pwmreg2 & pwmreg1 & pwmreg0); + +      pwmsr_b : entity work.vlm5030_srlatch +        port map ( +          i_clk => osc.base, +          i_res => pwmcomp, +          i_set => pwmcommand, +          o_q   => pwmsr +        ); +      pwmsel <= not i_vcu when tstenIE2DAC = '1' else +                not pwmsr; + +    end block; + +    dacrom_block : block +      signal ndac   : std_logic_vector(4 downto 0); +      signal dacval, dacpwm : signed(o_dao'high+1 downto 0); +    begin + +      ndac <= ieaddrreg(9) & not ieaddrreg(8 downto 5) when tstenIE2DAC = '0' else +              nIE(9) & not nIE(8 downto 5); + +      -- The R-ladder between GND and VREF has 34 segments. +      -- * the lowest setting (-16 & pwmsel=1) generates 33 over 1 +      -- * the highest setting (15 & pwmsel=0) generates 1 over 33 +      -- TODO: check absolute resistance value of segments + +      -- dacval is range 1 to 32 +      dacval <= RESIZE(signed(not ndac), dacval'length) + 16+1; +      -- dacpwm is range 1 to 33 +      dacpwm <= dacval when pwmsel = '1' else dacval + 1; + +      o_dao <= std_logic_vector(dacpwm(o_dao'range)); +      -- TST2 not modelled +      o_tst2 <= '0'; + +    end block; + +  end block; + + + +  ----------------------------------------------------------------------------- +  -- Address bus block +  -- +  abus_block : block +    signal wl : std_logic_vector(0 to 5); +  begin + +    wl      <=              eaoen  &     enIE2A       & tstenID2A  &  tstenIE2A  & tstenctrl2A & tstenIE2DAC; +    --                    |        |                  |            |             |             |            | +    o_a( 0) <= not norf(wl, aq( 0) &   ieaddrreg(0)   & not nID(0) & not nIE( 0) &    '0'      &     '0'    ); +    o_a( 1) <= not norf(wl, aq( 1) &   ieaddrreg(1)   & not nID(1) & not nIE( 1) &    '0'      &     '0'    ); +    o_a( 2) <= not norf(wl, aq( 2) &   ieaddrreg(2)   & not nID(2) & not nIE( 2) &    '0'      &     '0'    ); +    o_a( 3) <= not norf(wl, aq( 3) &   ieaddrreg(3)   & not nID(3) & not nIE( 3) &    '0'      &     '0'    ); +    o_a( 4) <= not norf(wl, aq( 4) &   ieaddrreg(4)   & not nID(4) & not nIE( 4) &    '0'      &     '0'    ); +    o_a( 5) <= not norf(wl, aq( 5) &   ieaddrreg(5)   & not nID(5) & not nIE( 5) &    '0'      &     '0'    ); +    o_a( 6) <= not norf(wl, aq( 6) &   ieaddrreg(6)   & not nID(6) & not nIE( 6) &    '0'      &     '0'    ); +    o_a( 7) <= not norf(wl, aq( 7) &   ieaddrreg(7)   & not nID(7) & not nIE( 7) &    '0'      &     '0'    ); +    o_a( 8) <= not norf(wl, aq( 8) &   ieaddrreg(8)   & not nID(8) & not nIE( 8) &    '0'      &     '0'    ); +    o_a( 9) <= not norf(wl, aq( 9) & not ieaddrreg(9) & not nID(9) & not nIE( 9) &    '0'      &     '0'    ); +    o_a(10) <= not norf(wl, aq(10) &   pitchoverflow  &     '0'    &     '0'     &  c2d0.val   &    pwmsr   ); +    o_a(11) <= not norf(wl, aq(11) &      random      &     '0'    &     '0'     &  xromdo7nq  &     '0'    ); +    o_a(12) <= not norf(wl, aq(12) &   ieaddrreg(10)  &     '0'    & not nIE(10) & fsromdo(13) &     '0'    ); +    o_a(13) <= not norf(wl, aq(13) &   ieaddrreg(11)  &     '0'    & not nIE(11) & vcufinal12  &     '0'    ); +    o_a(14) <= not norf(wl, aq(14) &        '0'       &     '0'    &     '0'     &   cntdn0    &     '0'    ); +    o_a(15) <= not norf(wl, aq(15) &        '0'       &     '0'    &     '0'     &     '0'     &     '0'    ); + +  end block; + + +  o_audio <= ieaddrreg(9 downto 0) when tstenIE2DAC = '0' else +             not nIE(9 downto 0); + +  o_bsy <= not nbsy; + +  o_me_l <= not me; + +  mte_delay_b : entity work.vlm5030_delay +    generic map ( +      -- delay for ~6us ==> 21 osc clocks +      g_numclks => 21 +    ) +    port map ( +      i_clk => osc, +      i_in  => xromdo(35), +      o_out => o_mte +    ); + +end; diff --git a/testsuite/synth/issue2177/vlm5030_pack.vhd b/testsuite/synth/issue2177/vlm5030_pack.vhd new file mode 100644 index 000000000..a048b67c1 --- /dev/null +++ b/testsuite/synth/issue2177/vlm5030_pack.vhd @@ -0,0 +1,70 @@ +---------------------------------------------------------------------- +--                           VLM5030 +--                      www.fpgaarcade.com +--                     All rights reserved. +-- +--                     admin@fpgaarcade.com +-- +-- This Source Code Form is subject to the terms of the Mozilla Public +-- License, v. 2.0. If a copy of the MPL was not distributed with this +-- file, You can obtain one at https://mozilla.org/MPL/2.0/. +---------------------------------------------------------------------- +-- +-- Copyright (c) 2021, Arnim Laeuger  arnim.laeuger@gmx.net +-- All rights reserved. +-- + + +library ieee; +use ieee.std_logic_1164.all; + +package vlm5030_pack is + +  ----------------------------------------------------------------------------- +  -- Verctorized NOR and OR functions +  ----------------------------------------------------------------------------- +  function  norf(i : std_logic_vector) return std_logic; +  function  norf(wl, vec : std_logic_vector) return std_logic; +  function norif(wl, vec : std_logic_vector) return std_logic; +  function   orf(wl, vec : std_logic_vector) return std_logic; + +end; + +package body vlm5030_pack is + +  function norf(i : std_logic_vector) return std_logic is +    variable lorf : std_logic; +  begin +    lorf := '0'; +    for idx in i'range loop +      lorf := lorf or i(idx); +    end loop; +    return not lorf; +  end; + +  function norf(wl, vec : std_logic_vector) return std_logic is +    variable lorf : std_logic; +  begin +    lorf := '0'; +    for idx in wl'range loop +      lorf := lorf or (wl(idx) and vec(idx)); +    end loop; +    return not lorf; +  end; + +  function norif(wl, vec : std_logic_vector) return std_logic is +    variable lorf : std_logic; +  begin +    lorf := '0'; +    for idx in wl'range loop +      lorf := lorf or (wl(idx) and not vec(idx)); +    end loop; +    return not lorf; +  end; + +  function orf(wl, vec : std_logic_vector) return std_logic is +  begin +    return not norf(wl, vec); +  end; + +end; diff --git a/testsuite/synth/issue2177/vlm5030_subcircuits.vhd b/testsuite/synth/issue2177/vlm5030_subcircuits.vhd new file mode 100644 index 000000000..5e3da1a93 --- /dev/null +++ b/testsuite/synth/issue2177/vlm5030_subcircuits.vhd @@ -0,0 +1,203 @@ +---------------------------------------------------------------------- +--                           VLM5030 +--                      www.fpgaarcade.com +--                     All rights reserved. +-- +--                     admin@fpgaarcade.com +-- +-- This Source Code Form is subject to the terms of the Mozilla Public +-- License, v. 2.0. If a copy of the MPL was not distributed with this +-- file, You can obtain one at https://mozilla.org/MPL/2.0/. +---------------------------------------------------------------------- +-- +-- Copyright (c) 2021, Arnim Laeuger  arnim.laeuger@gmx.net +-- All rights reserved. +-- + + +------------------------------------------------------------------------------- +-- SR-latch, synchronous to common clock +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; + +entity vlm5030_srlatch is + +  port ( +    i_clk : in  std_logic; +    i_res : in  std_logic; +    i_set : in  std_logic; +    o_q   : out std_logic +  ); + +end; + +architecture rtl of vlm5030_srlatch is +  signal q : std_logic := '0'; +begin + +  process (i_clk) +  begin +    if rising_edge(i_clk) then +      if i_res = '1' then +        q <= '0'; +      elsif i_set = '1' then +        q <= '1'; +      end if; +    end if; +  end process; + +  o_q <= q; + +end; + + +------------------------------------------------------------------------------- +-- SR-latch, synchronous to common clock, r_clk version +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; + +use work.clock_functions_pack.all; + +entity vlm5030_srlatchclk is + +  port ( +    i_clk : in  r_clk; +    i_res : in  r_clk; +    i_set : in  r_clk; +    o_q   : out r_clk +  ); + +end; + +architecture rtl of vlm5030_srlatchclk is +  signal q : std_logic := '0'; +begin + +  process (i_clk) +  begin +    if rising_edge(i_clk) then +      if i_res.val = '1' then +        q <= '0'; +      elsif i_set.val = '1' then +        q <= '1'; +      end if; +    end if; +  end process; + +  o_q <= (base => i_clk.base, +          val  => q, +          rise => not q and i_set.val, +          fall =>     q and i_res.val); + +end; + + +------------------------------------------------------------------------------- +-- vlm5030_delay +-- +-- Delay input signal by the specified number of clocks. +-- +-- NOTE: This is inertial delay. +-- +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; +use work.clock_functions_pack.all; + +entity vlm5030_delay is + +  generic ( +    g_numclks : integer := 3 +  ); +  port ( +    i_clk : in  r_clk; +    i_in  : in  std_logic; +    o_out : out std_logic +  ); + +end; + +architecture rtl of vlm5030_delay is +begin + +  delay_p : process (i_clk) +    variable cnt : natural := 0; +    variable inq : std_logic := '0'; +  begin +    if rising_edge(i_clk) then +      if i_in /= inq then +        cnt := g_numclks-2; +        inq := i_in; +      else +        if cnt > 0 then +          cnt := cnt - 1; +        else +          o_out <= i_in; +        end if; +      end if; +    end if; +  end process; + +end; + + +------------------------------------------------------------------------------- +-- vlm5030_delay_inv +-- +-- Invert input signal and delay falling edge of input. +-- The input's rising edge is not delayed. +-- +-- NOTE: This is inertial delay. +-- +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; +use work.clock_functions_pack.all; + +entity vlm5030_delay_inv is + +  generic ( +    g_numclks : integer := 3 +  ); +  port ( +    i_clk : in  r_clk; +    i_in  : in  std_logic; +    o_out : out std_logic +  ); + +end; + +architecture rtl of vlm5030_delay_inv is +  signal outq : std_logic; +begin + +  delay_p : process (i_clk) +    variable cnt : natural := 0; +    variable inq : std_logic := '0'; +  begin +    if rising_edge(i_clk) then +      if i_in /= inq then +        cnt := g_numclks-2; +        inq := i_in; +        if i_in = '1' then +          outq <= '1'; +        end if; +      else +        if cnt > 0 then +          cnt := cnt - 1; +        else +          outq <= i_in; +        end if; +      end if; +    end if; +  end process; + +  o_out <= '0' when i_in = '1' else not outq; + +end;  | 
