----------------------------------------------------------------------
-- Simulation models of ADC/DAC

use ieee.numeric_std.all;
use work.spi_bus_pkg.all;
entity adc is
    port (
        spi : bus spi_slave_r(slave);
        vin : in real;
    );
end entity adc;

architecture Behavioral of adc is
    signal intl_miso : std_logic_vector := 'Z';
begin
    FAKEIT: process
        variable data : unsigned(15 downto 0);
        variable bitn : integer range data'high downto -1;
    begin
        intl_miso <= 'Z';
        wait until falling_edge(spi.ssel);
        data := TO_UNSIGNED(vin / 5.0 * 65536, data'length);
        bitn := data'high;
        loop
            if bitn = -1 then
                intl_miso <= 'U';
            else
                intl_miso <= data(bitn);
                bitn := bitn - 1;
            end if;
            wait until rising_edge(spi.sclk) or rising_edge(spi.ssel);
            exit when spi.ssel'event;
        end loop;
    end process FAKEIT;
    
    spi.miso <= intl_miso after 10 ns;
end architecture Behavioral;

use ieee.numeric_std.all;
use work.spi_bus_pkg.all;
entity dac is
    port (
        spi : bus spi_slave_r(slave);
        vout : out real := 0.0;
    );
end entity dac;

architecture Behavioral of dac is
begin
    FAKEIT: process
        variable data : unsigned(15 downto 0);
        variable bitn : integer range data'high downto -1;
    begin
        spi.miso <= 'Z';
        wait until falling_edge(spi.ssel);
        data := (others => '0');
        loop
            wait until rising_edge(spi.sclk) or rising_edge(spi.ssel);
            exit when spi.ssel'event;
            data := data(14 downto 0) & spi.mosi;
        end loop;
        vout <= REAL(TO_INTEGER(data)) * 5.0 / 65536.0 after 10 ns;
    end process FAKEIT;
end architecture Behavioral;

----------------------------------------------------------------------
-- And the complete testbench

use work.spi_bus_pkg.all;
entity Testbench
end entity Testbench;

architecture TB of Testbench is

    signal clk : std_logic;
    signal rst : std_logic;
    -- Notice that SPI is just a normal signal here; the top level has no
    -- interest in the whole interfaces concept.  Size is defined by the FPGA,
    -- which gets it from the spi_communicator.
    signal spi : spi_master_r;
    signal daclnk : spi_slave_r;
    ...

begin
    DUT: entity work.FPGA
        port map (
            clk => clk,
            rst => rst,
            spi => spi
        );

    ADCS: for i in 0 to 2 generate
        signal lnk : spi_slave_r;
    begin
        -- Translate the master bus to a slave bus.
        RIPPER: entity spi_slave_link
            generic map (
                CHIP_SELECT => i
            ) port map (
                mst => spi,
                slv => lnk
            );
            
        -- And hook the ADC to that slave bus.
        ADC: entity work.adc
            port map (
                spi => lnk,
                vin => analog_voltage(i)
            );
    end generate ADCs;

    DACRIPPER: entity spi_slave_link
        generic map (
            CHIP_SELECT => 3
        ) port map (
            mst => spi,
            slv => daclnk
        );
            
    DAC: entity work.dac
        port map (
            spi => daclnk,
            vout => driven_voltage
        );

    -- And a resistive pullup for the tri-state MISO line.
    spi.miso <= 'H';

end architecture TB;
