OpenCores
URL https://opencores.org/ocsvn/System09/System09/trunk

Subversion Repositories System09

[/] [System09/] [trunk/] [rtl/] [VHDL/] [spi-master.vhd] - Blame information for rev 66

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.