Add a spi_filepath generic for better ModelSim/Quartus integration.
[bos2k9.git] / bos2k9_t.vhd
1 -----------------------------------------------------------------------
2 -- Copyright (c) 2009 Malte S. Stretz <http://msquadrat.de> 
3 --
4 -- Testing the top level entity.
5 --
6 -- SPI input data is read from the text file `bos2k9_t.dat` (or the
7 -- filename specified by the generic `spi_filename`). Each line 
8 -- consists of two bytes, std_logic style and separated by a single 
9 -- space: The first byte is the data expected from the SPI master (ie. 
10 -- the SD host), the second the reply to be sent. All following 
11 -- characters on the line are ignored and can be used as a comment.
12 --
13 -- Of course lines are only read when data is read, not while the 
14 -- system is idle.
15 --
16 -- If the data sent by the SD host doesn't equal the expected data,
17 -- an assertion is raised. Each input and output data is printed on 
18 -- stdout.
19 --
20 -- This test should be run about 1500 us to reach the first simulated
21 -- read.  A full 512 Byte block needs about 15 ms.
22 -----------------------------------------------------------------------
23
24 use work.bos2k9_globals.all;
25
26 library fhw_tools;
27 use fhw_tools.types.all;
28
29 library ieee;
30 use ieee.std_logic_1164.all;
31 use ieee.numeric_std.all;
32
33 use std.textio.all;
34 use work.txt_util.all;
35
36 -----------------------------------------------------------------------
37
38 entity bos2k9_t is
39   generic(
40     clock_interval : time   := clock_interval_c;
41     spi_filepath   : string := ".";
42     spi_filename   : string := "bos2k9_t.dat");
43 end bos2k9_t;
44
45 -----------------------------------------------------------------------
46
47 architecture test of bos2k9_t is
48
49   component bos2k9 is
50     port(
51       CLOCK_50 : in std_logic;
52     
53       KEY  : in  std_logic_vector(3 downto 0);
54       SW   : in  std_logic_vector(17 downto 0);
55       LEDR : out std_logic_vector(17 downto 0);
56       LEDG : out std_logic_vector(8 downto 0);
57     
58       SD_DAT  : in  std_logic;
59       SD_CMD  : out std_logic;
60       SD_DAT3 : out std_logic;
61       SD_CLK  : out std_logic);
62   end component;
63   
64   -- These are the low eight bytes sent as the read address;
65   -- if this constant is changed, the data file has to be
66   -- modified as well.
67   constant addr_sw_c : std_logic_byte_t := "01101010";
68
69   file   spi_file : text open read_mode is spi_filepath & "/" & spi_filename;
70   signal test_s   : integer;
71   
72   signal clock_s  : std_logic;
73   signal reset_s  : std_logic;
74   
75   signal KEY_i_s      : std_logic_vector(3 downto 0);
76   signal SW_i_s       : std_logic_vector(17 downto 0);
77   signal LEDR_o_s     : std_logic_vector(17 downto 0);
78   signal LEDG_o_s     : std_logic_vector(8 downto 0);
79   signal SD_DAT_i_s   : std_logic;
80   signal SD_CMD_o_s   : std_logic;
81   signal SD_DAT3_o_s  : std_logic;
82   signal SD_CLK_o_s   : std_logic;
83   
84   signal init_s  : std_logic;
85   signal ready_s : std_logic;
86   signal start_s : std_logic;
87   signal error_s : std_logic;
88   signal txd_s   : std_logic_byte_t;
89   signal rxd_s   : std_logic_byte_t;
90   signal spi_s   : spi_bus_t;
91   
92   signal init_btn_s : std_logic;
93   signal addr_sw_s : std_logic_byte_t;
94   signal byte_sw_s : std_logic_byte_t;
95   signal byte_dw_s : std_logic_byte_t;
96 begin
97   dut : bos2k9 port map(clock_s,
98     KEY_i_s,
99     SW_i_s,
100     LEDR_o_s,
101     LEDG_o_s,
102     SD_DAT_i_s,
103     SD_CMD_o_s,
104     SD_DAT3_o_s,
105     SD_CLK_o_s);
106   SD_DAT_i_s <= spi_s.miso;
107   spi_s.mosi <= SD_CMD_o_s;
108   spi_s.sck  <= SD_CLK_o_s;
109   spi_s.cs   <= SD_DAT3_o_s;
110   
111   -- Make sure to change these lines if the board pin assignments 
112   -- are modified.
113   byte_dw_s           <= LEDR_o_s(7 downto 0);
114   SW_i_s(7 downto 0)  <= addr_sw_s;
115   SW_i_s(15 downto 8) <= byte_sw_s;
116   SW_i_s(16)          <= '0';
117   SW_i_s(17)          <= not reset_s;
118   KEY_i_s(0)          <= not init_btn_s;
119   KEY_i_s(1)          <= not start_s;
120   KEY_i_s(3 downto 2) <= (others => '1');
121   error_s <= LEDG_o_s(0);
122   ready_s <= LEDG_o_s(1);
123   addr_sw_s <= addr_sw_c;
124   byte_sw_s <= (others => '0');
125   
126   -- Send the init and the start signal.
127   stimulus : process
128   begin
129     init_s  <= '0';
130     start_s <= '0';
131     wait until falling_edge(reset_s);
132     
133     init_s <= '1';
134     wait until rising_edge(clock_s);
135     init_s <= '0';
136     
137     wait until rising_edge(ready_s);
138     start_s <= '1';
139     wait until rising_edge(clock_s);
140     start_s <= '0';
141     
142     wait;
143   end process;
144   
145   -- Validate input and output against the data in the data file.
146   -- Uses helper routines from txt_util.
147   slave : process
148     procedure read_skip_header is
149       variable line_v  : line;
150     begin
151       readline(spi_file, line_v);
152     end read_skip_header;
153     procedure read_txd_and_rxd is
154       variable line_v  : line;
155       variable input_v : string(1 to 17);
156       variable byte_v  : std_logic_byte_t;
157     begin
158       readline(spi_file, line_v);
159       read(line_v, input_v);
160       print(input_v);
161       txd_s <= to_std_logic_vector(input_v(1 to 8));
162       rxd_s <= to_std_logic_vector(input_v(10 to 17));
163       wait until rising_edge(clock_s);
164     end read_txd_and_rxd;
165     variable index_v : integer;
166     variable txd_v   : std_logic_byte_t;
167   begin
168     read_skip_header;
169     rxd_s <= (others => 'Z');
170     txd_v := (others => 'U');
171     test_s <= 0;
172     spi_s.miso <= 'Z';
173     wait until falling_edge(clock_s);
174     
175     while true loop
176       test_s <= test_s + 1;
177       index_v := 7;
178       read_txd_and_rxd;
179       while true loop
180         -- Latch on odd edges, shift on even
181         spi_s.miso <= rxd_s(index_v);
182         wait until rising_edge(spi_s.sck);
183         txd_v(0) := spi_s.mosi;
184         wait until falling_edge(spi_s.sck);
185         index_v  := index_v - 1;
186         if index_v = -1 then
187           exit;
188         end if;
189         txd_v    := txd_v(6 downto 0) & 'U';
190       end loop;
191       test_s <= test_s + 1;
192       assert txd_v = txd_s report "unexpected spi data. got: " & str(txd_v) & " expected: " & str(txd_s);
193     end loop;
194   end process;
195   
196   -- Simulate slow fingers on the init button.
197   button: process
198   begin
199     init_btn_s <= '0';
200     wait until rising_edge(init_s);
201     init_btn_s <= '1';
202     wait until rising_edge(clock_s);
203     wait until rising_edge(clock_s);
204     wait until rising_edge(clock_s);
205     wait until rising_edge(clock_s);
206     wait until rising_edge(clock_s);
207     wait until rising_edge(clock_s);
208   end process;
209   
210   reset : process
211   begin
212     reset_s <= '1';
213     wait until rising_edge(clock_s);
214     wait until rising_edge(clock_s);
215     reset_s <= '0';
216     wait;
217   end process;
218   
219   clock : process
220   begin
221     clock_s <= '0';
222     wait for clock_interval / 2;
223     clock_s <= '1';
224     wait for clock_interval / 2;
225   end process;
226   
227 end test;