1 -- SPI bus master for System09
2 -- (http://members.optushome.com.au/jekent/system09/index.html)
3
4 -- This core implements a SPI master interface. Transfer size is 4, 8, 12 or
5 -- 16 bits. The SPI clock is 0 when idle, sampled on the rising edge of the SPI
6 -- clock. The SPI clock is derived from the bus clock input divided
7 -- by 2, 4, 8 or 16.
8
9 -- clk, reset, cs, rw, addr, data_in, data_out and irq represent the System09
10 -- bus interface.
11 -- spi_clk, spi_mosi, spi_miso and spi_cs_n are the standard SPI signals meant
12 -- to be routed off-chip.
13
14 -- The SPI core provides for four register addresses that the CPU can read or
15 -- write:
16
17 -- 0 -> DL: Data LSB
18 -- 1 -> DH: Data MSB
19 -- 2 -> CS: Command/Status
20 -- 3 -> CO: Config
21
22 -- Write bits, CS:
23 --
24 -- START CS[0]: Start transfer
25 -- END CS[1]: Deselect device after transfer (or immediately if START = '0')
26 -- IRQEN CS[2]: Generate IRQ at end of transfer
27 -- SPIAD CS[6:4]: SPI device address
28 --
29 -- Read bits, CS:
30 --
31 -- BUSY CS[0]: Currently transmitting data
32 --
33 -- Write BITS, CO:
34 --
35 -- DIVIDE CO[1:0]: SPI clock divisor, 00=clk/2, 01=clk/4, 10=clk/8, 11=clk/16
36 -- LENGTH CO[3:2]: Transfer length, 00=4 bits, 01=8 bits, 10=12 bits, 11=16 bits
37 --
38
39 library ieee;
40 use ieee.std_logic_1164.all;
41 use ieee.std_logic_unsigned.all;
42
43 entity spi_master is
44 port (
45 clk, reset, cs, rw : in std_logic;
46 addr : in std_logic_vector(1 downto 0);
47 data_in : in std_logic_vector(7 downto 0);
48 data_out : out std_logic_vector(7 downto 0);
49 irq : out std_logic;
50 spi_clk, spi_mosi : out std_logic;
51 spi_cs_n : out std_logic_vector(7 downto 0);
52 spi_miso : in std_logic);
53 end;
54
55 architecture rtl of spi_master is
56
57 -- State type of the SPI transfer state machine
58 type state_type is (s_idle, s_running, s_done);
59 signal state : state_type;
60 -- Shift register
61 signal shift_reg : std_logic_vector(15 downto 0);
62 -- Buffer to hold data to be sent
63 signal spi_data_buf : std_logic_vector(15 downto 0);
64 -- Start transmission flag
65 signal start : std_logic;
66 -- Number of bits transfered
67 signal count : std_logic_vector(3 downto 0);
68 -- Buffered SPI clock
69 signal spi_clk_buf : std_logic;
70 -- Buffered SPI clock output
71 signal spi_clk_out : std_logic;
72 -- Previous SPI clock state
73 signal prev_spi_clk : std_logic;
74 -- Number of clk cycles-1 in this SPI clock period
75 signal spi_clk_count : std_logic_vector(2 downto 0);
76 -- SPI clock divisor
77 signal spi_clk_divide : std_logic_vector(1 downto 0);
78 -- SPI transfer length
79 signal transfer_length : std_logic_vector(1 downto 0);
80 -- Flag to indicate that the SPI slave should be deselected after the current
81 -- transfer
82 signal deselect : std_logic;
83 -- Flag to indicate that an IRQ should be generated at the end of a transfer
84 signal irq_enable : std_logic;
85 -- Signal to clear IRQ
86 signal irqack : std_logic;
87 -- Internal chip select signal, will be demultiplexed through the cs_mux
88 signal spi_cs : std_logic;
89 -- Current SPI device address
90 signal spi_addr : std_logic_vector(2 downto 0);
91 begin
92
93 -- Read CPU bus into internal registers
94 cpu_write : process(clk, reset)
95 begin
96 if reset = '1' then
97 deselect <= '0';
98 irq_enable <= '0';
99 start <= '0';
100 spi_clk_divide <= "11";
101 transfer_length <= "11";
102 spi_data_buf <= (others => '0');
103 elsif falling_edge(clk) then
104 start <= '0';
105 irqack <= '0';
106 if cs = '1' and rw = '0' then
107 case addr is
108 when "00" =>
109 spi_data_buf(7 downto 0) <= data_in;
110 when "01" =>
111 spi_data_buf(15 downto 8) <= data_in;
112 when "10" =>
113 start <= data_in(0);
114 deselect <= data_in(1);
115 irq_enable <= data_in(2);
116 spi_addr <= data_in(6 downto 4);
117 irqack <= '1';
118 when "11" =>
119 spi_clk_divide <= data_in(1 downto 0);
120 transfer_length <= data_in(3 downto 2);
121 when others =>
122 null;
123 end case;
124 end if;
125 end if;
126 end process;
127
128 -- Provide data for the CPU to read
129 cpu_read : process(shift_reg, addr, state, deselect, start)
130 begin
131 data_out <= (others => '0');
132 case addr is
133 when "00" =>
134 data_out <= shift_reg(7 downto 0);
135 when "01" =>
136 data_out <= shift_reg(15 downto 8);
137 when "10" =>
138 if state = s_idle then
139 data_out(0) <= '0';
140 else
141 data_out(0) <= '1';
142 end if;
143 data_out(1) <= deselect;
144 when others =>
145 null;
146 end case;
147 end process;
148
149 spi_cs_n <= "11111110" when spi_addr = "000" and spi_cs = '1' else
150 "11111101" when spi_addr = "001" and spi_cs = '1' else
151 "11111011" when spi_addr = "010" and spi_cs = '1' else
152 "11110111" when spi_addr = "011" and spi_cs = '1' else
153 "11101111" when spi_addr = "100" and spi_cs = '1' else
154 "11011111" when spi_addr = "101" and spi_cs = '1' else
155 "10111111" when spi_addr = "110" and spi_cs = '1' else
156 "01111111" when spi_addr = "111" and spi_cs = '1' else
157 "11111111";
158
159 -- SPI transfer state machine
160 spi_proc : process(clk, reset)
161 begin
162 if reset = '1' then
163 count <= (others => '0');
164 shift_reg <= (others => '0');
165 prev_spi_clk <= '0';
166 spi_clk_out <= '0';
167 spi_cs <= '0';
168 state <= s_idle;
169 irq <= '0';
170 elsif falling_edge(clk) then
171 prev_spi_clk <= spi_clk_buf;
172 irq <= '0';
173 case state is
174 when s_idle =>
175 if start = '1' then
176 count <= (others => '0');
177 shift_reg <= spi_data_buf;
178 spi_cs <= '1';
179 state <= s_running;
180 elsif deselect = '1' then
181 spi_cs <= '0';
182 end if;
183 when s_running =>
184 if prev_spi_clk = '1' and spi_clk_buf = '0' then
185 spi_clk_out <= '0';
186 count <= count + "0001";
187 shift_reg <= shift_reg(14 downto 0) & spi_miso;
188 if ((count = "0011" and transfer_length = "00")
189 or (count = "0111" and transfer_length = "01")
190 or (count = "1011" and transfer_length = "10")
191 or (count = "1111" and transfer_length = "11")) then
192 if deselect = '1' then
193 spi_cs <= '0';
194 end if;
195 if irq_enable = '1' then
196 irq <= '1';
197 state <= s_done;
198 end if;
199 state <= s_idle;
200 end if;
201 elsif prev_spi_clk = '0' and spi_clk_buf = '1' then
202 spi_clk_out <= '1';
203 end if;
204 when s_done =>
205 if irqack = '1' then
206 state <= s_idle;
207 end if;
208 when others =>
209 null;
210 end case;
211 end if;
212 end process;
213
214 -- Generate SPI clock
215 spi_clock_gen : process(clk, reset)
216 begin
217 if reset = '1' then
218 spi_clk_count <= (others => '0');
219 spi_clk_buf <= '0';
220 elsif falling_edge(clk) then
221 if state = s_running then
222 if ((spi_clk_divide = "00")
223 or (spi_clk_divide = "01" and spi_clk_count = "001")
224 or (spi_clk_divide = "10" and spi_clk_count = "011")
225 or (spi_clk_divide = "11" and spi_clk_count = "111")) then
226 spi_clk_buf <= not spi_clk_buf;
227 spi_clk_count <= (others => '0');
228 else
229 spi_clk_count <= spi_clk_count + "001";
230 end if;
231 else
232 spi_clk_buf <= '0';
233 end if;
234 end if;
235 end process;
236
237 spi_mosi_mux : process(shift_reg, transfer_length)
238 begin
239 case transfer_length is
240 when "00" =>
241 spi_mosi <= shift_reg(3);
242 when "01" =>
243 spi_mosi <= shift_reg(7);
244 when "10" =>
245 spi_mosi <= shift_reg(11);
246 when "11" =>
247 spi_mosi <= shift_reg(15);
248 when others =>
249 null;
250 end case;
251 end process;
252
253 spi_clk <= spi_clk_out;
254
255 end rtl;