Finally some inline documentation.
[bos2k9.git] / bos2k9.vhd
1 -----------------------------------------------------------------------
2 -- Copyright (c) 2009 Malte S. Stretz <http://msquadrat.de> 
3 --
4 -- The project top level entity.
5 --
6 -- It implements a simple test setup which can read data from an SD 
7 -- card.  Blocks are read in 512 Byte blocks, so both block addresses
8 -- and byte addresses (relative to the block start) can be specified.
9 -- The system starts up doing nothing, an init button has to be pressed
10 -- to initialize the card and afterwards the selected block can be read
11 -- to an internal buffer.
12 --
13 -- This is designed around the DE2 evaluation board.  To simplify
14 -- development, the ports of the entity are named after the file
15 -- `DE2_Pin_Table.pdf`, which is part of the DE2 documentation.
16 -- The PDF file was converted to a TCL file and is included in this
17 -- project as `de2_pins.tcl` and can be copied to the `bos2k9.qsf`
18 -- project file.  This has the side effect that Quartus will complain
19 -- that some of these pins are stuck to GND or not used; these 
20 -- warnings can be ignored.
21 --
22 -- The following pins are used:
23 --  * `CLOCK_50` is the 50 MHz system clock.
24 --  * `KEY` are the four push button which are low-active.
25 --  * `SW` are the eighteen on-off switches.
26 --  * `LEDR` are the eighteen red LEDs above the switches.
27 --  * `LEDG` are the nine green LEDs; the low eight are located above
28 --    the push buttons, the ninth is above the row of red LEDs.
29 --  * `SD_DAT` is the SPI MISO.
30 --  * `SD_CMD` is the SPI MOSI.
31 --  * `SD_DAT3` is the SPI CS.
32 --  * `SD_CLK` is the SPI SCK.
33 --  * `UART_RXD` is the serial input.
34 --  * `UART_TXD` is the serial output.
35 --
36 -- LEDG(0) should be always on and represents a powered system. The 
37 -- `reset` is wired to `SW(17)`, so the switch should be off when these
38 -- system is started.  Once `reset` is off (ie. the switch on), the card
39 -- is initialized as soon as it is inserted.  Whe n this is successful,
40 -- LEDG(2) is led, the system is ready to read a block; if an error 
41 -- occurs, LEDG(1) is switched on instead.
42 --
43 -- The low eight bits of the block address can be specified by the
44 -- first eight `SW`es, ie. SW(0) to SW(7).  Only the first 256 blocks 
45 -- of 4096 possible ones (on 2 GiB SD cards; SDHC is not supported) can 
46 -- be read.  `KEY(1)` starts the reading of the selected block.
47 --
48 -- The used `button` entity ensures that even with really slow fingers,
49 -- the button press is only signaled once.  As the buttons on the DE2
50 -- board tend to break, this cannot be ensured but a longer press 
51 -- doesn't break anything.
52 --
53 -- The whole block is output via `UART_TXD`.
54 --
55 -- For debugging purposes, the SPI bus is also wired to the LEDs 
56 -- LEDG(7) to LEDG(4). 
57 -----------------------------------------------------------------------
58
59 library ieee;
60 use ieee.std_logic_1164.all;
61 use ieee.numeric_std.all;
62
63 library fhw_sd;
64 use fhw_sd.sd_host;
65
66 library fhw_tools;
67 use fhw_tools.all;
68 use fhw_tools.types.all;
69
70 use work.bos2k9_globals.all;
71
72 -----------------------------------------------------------------------
73
74 entity bos2k9 is
75   port(
76     CLOCK_50 : in std_logic;
77     
78     KEY  : in  std_logic_vector(3 downto 0);
79     SW   : in  std_logic_vector(17 downto 0);
80     LEDR : out std_logic_vector(17 downto 0);
81     LEDG : out std_logic_vector(8 downto 0);
82     
83     UART_RXD : in  std_logic;
84     UART_TXD : out std_logic;
85     
86     SD_DAT  : in  std_logic;
87     SD_CMD  : out std_logic;
88     SD_DAT3 : out std_logic;
89     SD_CLK  : out std_logic);
90 end bos2k9;
91
92 -----------------------------------------------------------------------
93
94 architecture board of bos2k9 is
95
96   component sd_host is
97     generic(
98       clock_interval : time     := clock_interval_c;
99       clock_divider  : positive := sd_clock_div_c);
100     port(
101       clk : in  std_logic;
102       rst : in  std_logic;
103
104       init  : in  std_logic;
105       ready : out std_logic;
106       error : out std_logic;
107       
108       address : in  std_logic_block_address_t;
109       start   : in  std_logic;
110       rxd     : out std_logic_byte_t;
111       shd     : out std_logic;
112       
113       miso  : in  std_logic;
114       mosi  : out std_logic;
115       sck   : out std_logic;
116       cs    : out std_logic);
117   end component;
118   
119   component bos2k9_counter is
120     generic(
121       cnt  : positive);
122     port(
123       clk  : in  std_logic;
124       rst  : in  std_logic;
125       en   : in  std_logic;
126       clr  : in  std_logic;
127       done : out std_logic);
128   end component;
129   
130   component bos2k9_pump is
131     generic(
132       clock_divider  : positive  := ser_clock_div_c;
133       parity_enabled : std_logic := ser_parity_enabled_c;
134       parity_type    : std_logic := ser_even_parity_c);
135     port(
136       clock : in  std_logic;
137       reset : in  std_logic;
138     
139       txn : in  std_logic;
140       txd : in  std_logic_byte_t;
141       txb : out std_logic;
142       tx  : out std_logic);
143   end component;
144   
145   component button
146     port(
147       clk : in std_logic;
148       rst : in std_logic;
149       
150       input  : in  std_ulogic;
151       output : out std_ulogic);
152   end component;
153
154   signal clock_s : std_logic;
155   signal reset_s : std_logic;
156   
157   signal ready_led_s : std_logic;
158   signal error_led_s : std_logic;
159   signal busy_led_s  : std_logic;
160   
161   signal read_btn_s : std_logic;
162   
163   signal byte_led_s  : std_logic_vector(7 downto 0);
164   signal byte_sw1_s  : std_logic_vector(7 downto 0);
165   
166   signal spi_s : spi_bus_t;
167   signal ser_s : ser_bus_t;
168   
169 begin
170   clock_s <= CLOCK_50;
171   reset_s <= not SW(17);
172
173   read_button : button port map(clock_s, reset_s,
174     input  => KEY(1),
175     output => read_btn_s);
176   
177   spi_s.miso <= SD_DAT;
178   SD_CMD     <= spi_s.mosi;
179   SD_CLK     <= spi_s.sck;
180   SD_DAT3    <= spi_s.cs;
181   
182   UART_TXD <= ser_s.tx;
183   ser_s.rx <= UART_RXD;
184   
185   LEDG <= (
186     7 => spi_s.miso,
187     6 => spi_s.mosi,
188     5 => spi_s.sck,
189     4 => spi_s.cs,
190     2 => busy_led_s,
191     1 => ready_led_s,
192     0 => error_led_s,
193     others => '0');
194   LEDR <= (
195    17 => not reset_s,
196     7 => byte_led_s(7),
197     6 => byte_led_s(6),
198     5 => byte_led_s(5),
199     4 => byte_led_s(4),
200     3 => byte_led_s(3),
201     2 => byte_led_s(2),
202     1 => byte_led_s(1),
203     0 => byte_led_s(0),
204     others => '0');
205   byte_sw1_s <= SW(7 downto 0);
206   
207   guts : block
208     -- SD interface.
209     signal sd_init_s    : std_logic;
210     signal sd_ready_s   : std_logic;
211     signal sd_error_s   : std_logic;
212     signal sd_address_s : std_logic_block_address_t;
213     signal sd_start_s   : std_logic;
214     signal sd_data_s    : std_logic_byte_t;
215     signal sd_latch_s   : std_logic;
216     signal sd_shift_s   : std_logic;
217     
218     signal pumping_s    : std_logic;
219   begin
220
221     -- Map the board outputs.
222     ready_led_s <= sd_ready_s;
223     error_led_s <= sd_error_s;
224     busy_led_s  <= pumping_s;
225     byte_led_s  <= (others => '0');
226     
227     -- We can address the first 256 blocks only.
228     sd_address_s(std_logic_block_address_t'high downto std_logic_byte_t'high + 1) <= (others => '0');
229     sd_address_s(std_logic_byte_t'range) <= byte_sw1_s;
230     
231     -- Make sure we can't accidently start another read action while 
232     -- something else is still going on.
233     sd_start_s <= read_btn_s and sd_ready_s and not pumping_s;
234     
235     -- Magic wiring between the `sd_host` and the timeout/poll counter:
236     -- The counter will trigger the `init` port each `init_ticks_c` 
237     -- but once the `sd_host` is initialized, the `ready` line will 
238     -- keep the counter via the `clr` line at zero.
239     sd_io : sd_host port map(
240       clk => clock_s,
241       rst => reset_s,
242     
243       init    => sd_init_s, 
244       ready   => sd_ready_s,
245       error   => sd_error_s,
246       address => sd_address_s,
247       start   => sd_start_s,
248       rxd     => sd_data_s,
249       shd     => sd_latch_s,
250     
251       miso  => spi_s.miso,
252       mosi  => spi_s.mosi,
253       sck   => spi_s.sck,
254       cs    => spi_s.cs);
255     sd_to : bos2k9_counter generic map(
256       cnt  => init_ticks_c) port map(
257       clk  => clock_s,
258       rst  => reset_s,
259       en   => '1',
260       clr  => sd_ready_s,
261       done => sd_init_s);
262     
263     pump : bos2k9_pump port map(
264       clock => clock_s,
265       reset => reset_s,
266       
267       txd   => sd_data_s,
268       txn   => sd_latch_s,
269       txb   => pumping_s,
270       tx    => ser_s.tx);
271   end block;
272 end board;