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

Subversion Repositories open8_urisc

[/] [open8_urisc/] [trunk/] [VHDL/] [o8_spi_16b_tx.vhd] - Blame information for rev 290

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

Line No. Rev Author Line
1 268 jshamlet
-- Copyright (c) 2020 Jeremy Seth Henry
2
-- All rights reserved.
3
--
4
-- Redistribution and use in source and binary forms, with or without
5
-- modification, are permitted provided that the following conditions are met:
6
--     * Redistributions of source code must retain the above copyright
7
--       notice, this list of conditions and the following disclaimer.
8
--     * Redistributions in binary form must reproduce the above copyright
9
--       notice, this list of conditions and the following disclaimer in the
10
--       documentation and/or other materials provided with the distribution,
11
--       where applicable (as part of a user interface, debugging port, etc.)
12
--
13
-- THIS SOFTWARE IS PROVIDED BY JEREMY SETH HENRY ``AS IS'' AND ANY
14
-- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15
-- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16
-- DISCLAIMED. IN NO EVENT SHALL JEREMY SETH HENRY BE LIABLE FOR ANY
17
-- DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18
-- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19
-- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20
-- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21
-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22
-- THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23
--
24
-- VHDL units : o8_spi_16b_tx
25
-- Description: Transmits (only) a 16-bit word using a synchronous interface
26
--              Clock_Polarity sets the clock state at idle
27
--              Clock_Phase sets the clock edge data is shifted on
28
--              Half_Period_Clks sets the number of CPU clocks used to generate
29
--               a half-period tick that runs the transmit state machine.
30
--              (Note that 2x this value is the full SPI period in CPU clocks)
31
--
32
-- Register Map:
33
-- Offset  Bitfield Description                        Read/Write
34
--   0x0   AAAAAAAA Pending Word (7:0)                 (R/W)
35
--   0x1   AAAAAAAA Pending Word (11:8)                (R/W)
36
--   0x2   A------- Busy Flag / TX on Write            (R/W)
37
--
38
-- Revision History
39
-- Author          Date     Change
40
------------------ -------- ---------------------------------------------------
41
-- Seth Henry      09/16/20 Initial version
42
 
43
library ieee;
44
use ieee.std_logic_1164.all;
45
use ieee.std_logic_unsigned.all;
46
use ieee.std_logic_arith.all;
47
use ieee.std_logic_misc.all;
48
 
49
library work;
50
  use work.open8_pkg.all;
51
 
52
entity o8_spi_16b_tx is
53
generic(
54
  Clock_Polarity             : std_logic;
55
  Clock_Phase                : std_logic;
56
  Half_Period_Clks           : integer range 1 to integer'high;
57
  Address                    : ADDRESS_TYPE
58
);
59
port(
60
  Open8_Bus                  : in  OPEN8_BUS_TYPE;
61
  Write_Qual                 : in  std_logic;
62
  Rd_Data                    : out DATA_TYPE;
63
  -- SPI
64
  DOUT                       : out std_logic;
65
  SCLK                       : out std_logic;
66
  SYNC                       : out std_logic
67
);
68
end entity;
69
 
70
architecture behave of o8_spi_16b_tx is
71
 
72
  alias Clock                is Open8_Bus.Clock;
73
  alias Reset                is Open8_Bus.Reset;
74
  alias uSec_Tick            is Open8_Bus.uSec_Tick;
75
 
76
  constant Clk_Div_i         : integer := Half_Period_Clks - 1;
77
  constant Clk_Div_Bits      : integer := ceil_log2(Clk_Div_i);
78
  constant CLK_DIV_VAL       : std_logic_vector(Clk_Div_Bits - 1 downto 0) :=
79
                                conv_std_logic_vector(Clk_Div_i,Clk_Div_Bits);
80
  signal HT_Cntr             : std_logic_vector(Clk_Div_Bits - 1 downto 0);
81
  signal HT_Tick             : std_logic := '0';
82
 
83
  constant User_Addr         : std_logic_vector(15 downto 2) := Address(15 downto 2);
84
  alias  Comp_Addr           is Open8_Bus.Address(15 downto 2);
85
  signal Addr_Match          : std_logic;
86
  alias  Reg_Sel_d           is Open8_Bus.Address(1 downto 0);
87
  signal Reg_Sel_q           : std_logic_vector(1 downto 0);
88
  signal Wr_En_d             : std_logic := '0';
89
  signal Wr_En_q             : std_logic := '0';
90
  alias  Wr_Data_d           is Open8_Bus.Wr_Data;
91
  signal Wr_Data_q           : DATA_TYPE := x"00";
92
  signal Rd_En_d             : std_logic := '0';
93
  signal Rd_En_q             : std_logic := '0';
94
 
95
  signal spi_xmit            : std_logic := '0';
96
 
97
  type SPI_STATES is ( IDLE, ALIGN, SYNC_START, CLK_SETUP, CLK_HOLD, CLK_END, SYNC_END );
98
  signal spi_state           : SPI_STATES;
99
 
100
  signal spi_buffer          : std_logic_vector(15 downto 0) := x"0000";
101
  alias  spi_buffer_lb       is spi_buffer(7 downto 0);
102
  alias  spi_buffer_ub       is spi_buffer(15 downto 8);
103
  signal bit_cntr            : std_logic_vector(3 downto 0) := x"0";
104
  signal spi_busy            : std_logic := '0';
105
 
106
begin
107
 
108
  Addr_Match                 <= '1' when Comp_Addr = User_Addr else '0';
109
  Wr_En_d                    <= Addr_Match and Open8_Bus.Wr_En;
110
  Rd_En_d                    <= Addr_Match and Open8_Bus.Rd_En;
111
 
112
  io_reg: process( Clock, Reset )
113
  begin
114
    if( Reset = Reset_Level )then
115
      Reg_Sel_q              <= "00";
116
      Wr_En_q                <= '0';
117
      Wr_Data_q              <= x"00";
118
      Rd_En_q                <= '0';
119
      Rd_Data                <= OPEN8_NULLBUS;
120
 
121
      spi_buffer             <= (others => '0');
122
      spi_xmit               <= '0';
123
 
124
    elsif( rising_edge( Clock ) )then
125
      Reg_Sel_q              <= Reg_Sel_d;
126
 
127
      Wr_En_q                <= Wr_En_d;
128
      Wr_Data_q              <= Wr_Data_d;
129
 
130
      spi_xmit               <= '0';
131
      if( Wr_En_q = '1' and Write_Qual = '1' )then
132
        case( Reg_Sel_q )is
133
          when "00" =>
134
            spi_buffer_lb    <= Wr_Data_q;
135
          when "01" =>
136
            spi_buffer_ub    <= Wr_Data_q;
137
          when "10" | "11" =>
138
            spi_xmit         <= '1';
139
          when others =>
140
            null;
141
        end case;
142
      end if;
143
 
144
      Rd_En_q                <= Rd_En_d;
145
      Rd_Data                <= OPEN8_NULLBUS;
146
      if( Rd_En_q = '1' )then
147
        case( Reg_Sel_q )is
148
          when "00" =>
149
            Rd_Data          <= spi_buffer_lb;
150
          when "01" =>
151
            Rd_Data          <= spi_buffer_ub;
152
          when "10" | "11" =>
153
            Rd_Data          <= spi_busy & "0000000";
154
          when others =>
155
            null;
156
        end case;
157
      end if;
158
    end if;
159
  end process;
160
 
161
  ADC_IO_FSM: process( Clock, Reset )
162
  begin
163
    if( Reset = Reset_Level )then
164
      spi_state              <= IDLE;
165
      bit_cntr               <= (others => '0');
166
      spi_busy               <= '0';
167
 
168
      HT_Cntr                <= (others => '0');
169
      HT_Tick                <= '0';
170
 
171
      DOUT                   <= '0';
172
      SCLK                   <= '0';
173
      SYNC                   <= '1';
174
    elsif( rising_edge(Clock) )then
175
 
176
      HT_Cntr                <= HT_Cntr - 1;
177
      HT_Tick                <= '0';
178
      if( HT_Cntr = 0 )then
179
        HT_Cntr              <= CLK_DIV_VAL;
180
        HT_Tick              <= '1';
181
      end if;
182
 
183
      case( spi_state )is
184
        when IDLE =>
185
          DOUT               <= '0';
186
          SCLK               <= Clock_Polarity;
187
          SYNC               <= '1';
188
          bit_cntr           <= x"F";
189
          spi_busy           <= '0';
190
          if( spi_xmit = '1' )then
191
            spi_busy         <= '1';
192
            spi_state        <= ALIGN;
193
          end if;
194
 
195
        when ALIGN =>
196
          if( HT_Tick = '1' )then
197
            spi_state        <= CLK_SETUP;
198
            if( Clock_Phase = '1' )then
199
              spi_state      <= SYNC_START;
200
            end if;
201
          end if;
202
 
203
        when SYNC_START =>
204
          SYNC               <= '0';
205
          if( HT_Tick = '1' )then
206
            spi_state        <= CLK_SETUP;
207
          end if;
208
 
209
        when CLK_SETUP =>
210
          SCLK               <= Clock_Polarity xor Clock_Phase;
211
          DOUT               <= spi_buffer(conv_integer(bit_cntr));
212
          SYNC               <= '0';
213
          if( HT_Tick = '1' )then
214
            spi_state        <= CLK_HOLD;
215
          end if;
216
 
217
        when CLK_HOLD =>
218
          SCLK               <= (not Clock_Polarity) xor Clock_Phase;
219
          DOUT               <= spi_buffer(conv_integer(bit_cntr));
220
          if( HT_Tick = '1' )then
221
            bit_cntr         <= bit_cntr - 1;
222
            spi_state        <= CLK_SETUP;
223
            if( bit_cntr = 0 )then
224
              spi_state      <= CLK_END;
225
            end if;
226
          end if;
227
 
228
        when CLK_END =>
229
          SCLK               <= Clock_Polarity;
230
          if( Clock_Phase = '1' )then
231
            SYNC             <= '1';
232
          end if;
233
          if( HT_Tick = '1' )then
234
            spi_state        <= SYNC_END;
235
            if( Clock_Phase = '1' )then
236
              spi_state      <= IDLE;
237
            end if;
238
          end if;
239
 
240
        when SYNC_END =>
241
          SYNC               <= '1';
242
          if( HT_Tick = '1' )then
243
            spi_state        <= IDLE;
244
          end if;
245
 
246
        when others =>
247
          null;
248
      end case;
249
 
250
    end if;
251
  end process;
252
 
253
end architecture;

powered by: WebSVN 2.1.0

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