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;