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

Subversion Repositories spi_master_slave

[/] [spi_master_slave/] [trunk/] [syn/] [spi_master_atlys_top.vhd] - Blame information for rev 12

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

Line No. Rev Author Line
1 5 jdoin
----------------------------------------------------------------------------------
2 12 jdoin
-- Author:          Jonny Doin, jdoin@opencores.org, jonnydoin@gmail.com
3 5 jdoin
-- 
4
-- Create Date:     01:21:32 06/30/2011 
5
-- Design Name: 
6
-- Module Name:     spi_master_atlys_top
7
-- Project Name:    spi_master_slave
8
-- Target Devices:  Spartan-6 LX45
9
-- Tool versions:   ISE 13.1
10
-- Description: 
11 10 jdoin
--          This is a verification project for the Digilent Atlys board, to test the SPI_MASTER, SPI_SLAVE and GRP_DEBOUNCE cores.
12 5 jdoin
--          It uses the board's 100MHz clock input, and clocks all sequential logic at this clock.
13
--
14 10 jdoin
--          See the "spi_master_atlys.ucf" file for pin assignments.
15 5 jdoin
--          The test circuit uses the VHDCI connector on the Atlys to implement a 16-pin debug port to be used
16
--          with a Tektronix MSO2014. The 16 debug pins are brought to 2 8x2 headers that form a umbilical
17
--          digital pod port.
18
--
19
------------------------------ REVISION HISTORY -----------------------------------------------------------------------
20
--
21
-- 2011/07/02   v0.01.0010  [JD]    implemented a wire-through from switches to LEDs, just to test the toolchain. It worked!
22
-- 2011/07/03   v0.01.0020  [JD]    added clock input, and a simple LED blinker for each LED. 
23
-- 2011/07/03   v0.01.0030  [JD]    added clear input, and instantiated a SPI_MASTER from my OpenCores project. 
24
-- 2011/07/04   v0.01.0040  [JD]    changed all clocks to clock enables, and use the 100MHz board gclk_i to clock all registers.
25
--                                  this change made the design go up to 288MHz, after synthesis.
26
-- 2011/07/07   v0.03.0050  [JD]    implemented a 16pin umbilical port for the MSO2014 in the Atlys VmodBB board, and moved all
27
--                                  external monitoring pins to the VHDCI ports.
28
-- 2011/07/10   v1.10.0075  [JD]    verified spi_master_slave at 50MHz, 25MHz, 16.666MHz, 12.5MHz, 10MHz, 8.333MHz, 7.1428MHz, 
29
--                                  6.25MHz, 1MHz and 500kHz 
30 12 jdoin
-- 2011/07/29   v1.12.0105  [JD]    spi_master.vhd and spi_slave_vhd changed to fix CPHA='1' bug.
31 5 jdoin
--
32
--
33
----------------------------------------------------------------------------------
34
library ieee;
35
use ieee.std_logic_1164.all;
36 11 jdoin
use ieee.std_logic_arith.all;
37 5 jdoin
 
38
entity spi_master_atlys_top is
39
    Port (
40 12 jdoin
        gclk_i : in std_logic := 'X';                           -- board clock input 100MHz
41
        --- SPI interface ---           
42
        spi_ssel_o : out std_logic;                             -- spi port SSEL
43
        spi_sck_o : out std_logic;                              -- spi port SCK
44
        spi_mosi_o : out std_logic;                             -- spi port MOSI
45
        spi_miso_o : out std_logic;                             -- spi port MISO
46
        --- input slide switches ---            
47
        sw_i : in std_logic_vector (7 downto 0);                -- 8 input slide switches
48
        --- input buttons ---           
49
        btn_i : in std_logic_vector (5 downto 0);               -- 6 input push buttons
50
        --- output LEDs ----            
51
        led_o : out std_logic_vector (7 downto 0);              -- output leds
52 5 jdoin
        --- debug outputs ---
53 12 jdoin
        dbg_o : out std_logic_vector (11 downto 0)              -- 12 generic debug pins
54 5 jdoin
    );
55
end spi_master_atlys_top;
56
 
57
architecture behavioral of spi_master_atlys_top is
58
 
59
    --=============================================================================================
60
    -- Constants
61
    --=============================================================================================
62
    -- clock divider count values from gclk_i (100MHz board clock)
63
    -- these constants shall not be zero
64 10 jdoin
    constant FSM_CE_DIV         : integer := 1;     -- fsm operates at 100MHz
65 5 jdoin
    constant SPI_2X_CLK_DIV     : integer := 1;     -- 50MHz SPI clock
66 10 jdoin
    constant SAMP_CE_DIV        : integer := 1;     -- board signals sampled at 100MHz
67 5 jdoin
    -- spi port generics
68 11 jdoin
    constant N      : integer   := 8;               -- 8 bits
69 12 jdoin
    constant CPOL   : std_logic := '1';
70
    constant CPHA   : std_logic := '1';
71 5 jdoin
 
72
    -- button definitions
73
    constant btRESET    : integer := 0;             -- these are constants to use as btn_i(x)
74
    constant btUP       : integer := 1;
75
    constant btLEFT     : integer := 2;
76
    constant btDOWN     : integer := 3;
77
    constant btRIGHT    : integer := 4;
78
    constant btCENTER   : integer := 5;
79
 
80
    --=============================================================================================
81
    -- Type definitions
82
    --=============================================================================================
83
    type fsm_state_type is (st_reset, st_wait_spi_idle, st_wait_new_switch,
84 12 jdoin
                            st_send_spi_data, st_wait_spi_ack );
85 5 jdoin
 
86
    --=============================================================================================
87
    -- Signals for state machine control
88
    --=============================================================================================
89 10 jdoin
    signal state_reg        : fsm_state_type := st_reset;
90
    signal state_next       : fsm_state_type := st_reset;
91 5 jdoin
 
92
    --=============================================================================================
93
    -- Signals for internal operation
94
    --=============================================================================================
95 10 jdoin
    --- clock enable signals ---
96
    signal samp_ce          : std_logic := '1';         -- clock enable for sample inputs
97
    signal fsm_ce           : std_logic := '1';         -- clock enable for fsm logic
98
    --- switch debouncer signals ---
99
    signal sw_data          : std_logic_vector (7 downto 0) := (others => '0'); -- debounced switch data
100
    signal sw_reg           : std_logic_vector (7 downto 0) := (others => '0'); -- registered switch data 
101
    signal sw_next          : std_logic_vector (7 downto 0) := (others => '0'); -- combinatorial switch data
102
    signal new_switch       : std_logic := '0';                                 -- detector for new switch data
103
    --- pushbutton debouncer signals ---
104
    signal btn_data         : std_logic_vector (5 downto 0) := (others => '0'); -- debounced state of pushbuttons
105
    signal btn_reg          : std_logic_vector (5 downto 0) := (others => '0'); -- registered button data 
106
    signal btn_next         : std_logic_vector (5 downto 0) := (others => '0'); -- combinatorial button data
107
    signal new_button       : std_logic := '0';                                 -- detector for new button data
108
    --- spi port signals ---
109
    -- spi bus wires
110
    signal spi_ssel         : std_logic;
111
    signal spi_sck          : std_logic;
112
    signal spi_mosi         : std_logic;
113
    signal spi_miso         : std_logic;
114
    -- spi master port control signals
115
    signal spi_rst_reg      : std_logic := '1';
116
    signal spi_rst_next     : std_logic := '1';
117
    signal spi_ssel_reg     : std_logic;
118
    signal spi_wren_reg_m   : std_logic := '0';
119
    signal spi_wren_next_m  : std_logic := '0';
120
    -- spi master port flow control flags
121
    signal spi_di_req_m     : std_logic;
122
    signal spi_do_valid_m   : std_logic;
123
    -- spi master port parallel data bus
124
    signal spi_di_reg_m     : std_logic_vector (N-1 downto 0) := (others => '0');
125
    signal spi_di_next_m    : std_logic_vector (N-1 downto 0) := (others => '0');
126
    signal spi_do_m         : std_logic_vector (N-1 downto 0);
127
    -- spi master port debug flags
128
    signal spi_rx_bit_m     : std_logic;
129
    signal spi_wr_ack_m     : std_logic;
130 12 jdoin
    signal state_dbg_m      : std_logic_vector (5 downto 0);
131 10 jdoin
    -- spi slave port control signals
132
    signal spi_wren_reg_s   : std_logic := '1';
133 12 jdoin
    signal spi_wren_next_s  : std_logic := '1';
134 10 jdoin
    -- spi slave port flow control flags
135
    signal spi_di_req_s     : std_logic;
136
    signal spi_do_valid_s   : std_logic;
137
    -- spi slave port parallel data bus
138 12 jdoin
    signal spi_di_reg_s     : std_logic_vector (N-1 downto 0) := (others => '0');
139 10 jdoin
    signal spi_di_next_s    : std_logic_vector (N-1 downto 0) := (others => '0');
140
    signal spi_do_s         : std_logic_vector (N-1 downto 0);
141
    -- spi slave port debug flags
142
    signal spi_rx_bit_s     : std_logic;
143
    signal spi_wr_ack_s     : std_logic;
144 12 jdoin
    signal state_dbg_s      : std_logic_vector (5 downto 0);
145 5 jdoin
    -- other signals
146 10 jdoin
    signal clear            : std_logic := '0';
147
    -- debug output signals
148
    signal leds_reg         : std_logic_vector (7 downto 0) := (others => '0');
149 12 jdoin
    signal dbg              : std_logic_vector (11 downto 0) := (others => '0');
150 5 jdoin
begin
151
 
152
    --=============================================================================================
153 10 jdoin
    -- COMPONENT INSTANTIATIONS FOR THE CORES UNDER TEST
154 5 jdoin
    --=============================================================================================
155 10 jdoin
    -- spi master port: 
156
    --      receives parallel data from the slide switches, transmits to slave port.
157
    --      receives serial data from slave port, sends to 8bit parallel debug port.
158
    Inst_spi_master_port: entity work.spi_master(rtl)
159 11 jdoin
        generic map (N => N, CPOL => CPOL, CPHA => CPHA, PREFETCH => 3, SPI_2X_CLK_DIV => SPI_2X_CLK_DIV)
160 5 jdoin
        port map(
161 10 jdoin
            sclk_i => gclk_i,                   -- system clock is used for serial and parallel ports
162
            pclk_i => gclk_i,
163 5 jdoin
            rst_i => spi_rst_reg,
164
            spi_ssel_o => spi_ssel,
165
            spi_sck_o => spi_sck,
166
            spi_mosi_o => spi_mosi,
167 10 jdoin
            spi_miso_i => spi_miso,
168
            di_req_o => spi_di_req_m,
169
            di_i => spi_di_reg_m,
170 12 jdoin
            wren_i => spi_wren_reg_m,
171 10 jdoin
            do_valid_o => spi_do_valid_m,
172
            do_o => spi_do_m,
173 12 jdoin
            ------------ debug pins ------------
174
--            rx_bit_reg_o => spi_rx_bit_m,
175
--            state_dbg_o => state_dbg_m,       -- monitor internal master state register
176
--            sck_ena_o => sck_ena_m,           -- monitor internal sck_ena register
177 11 jdoin
--            wren_o => spi_wren_o,
178 12 jdoin
            wr_ack_o => spi_wr_ack_m            -- monitor wren ack from inside spi port
179 5 jdoin
        );
180
 
181 12 jdoin
--    state_dbg_o(3 downto 0) <= state_dbg_m(3 downto 0); -- connect master state debug port
182
--    sck_ena_o <= sck_ena_m;                             -- sck_ena debug port
183
--    spi_rx_bit_m_o  <= spi_rx_bit_m;                    -- connect rx_bit monitor for master port
184 10 jdoin
 
185
    -- spi slave port
186
    --      receives parallel data from the pushbuttons, transmits to master port.
187
    --      receives serial data from master port, sends to the 8 LEDs.
188
    Inst_spi_slave_port: entity work.spi_slave(rtl)
189 11 jdoin
        generic map (N => N, CPOL => CPOL, CPHA => CPHA, PREFETCH => 3)
190 10 jdoin
        port map(
191
            clk_i => gclk_i,
192
            spi_ssel_i => spi_ssel,             -- generated by the spi master
193
            spi_sck_i => spi_sck,               -- generated by the spi master
194
            spi_mosi_i => spi_mosi,
195
            spi_miso_o => spi_miso,
196
            di_req_o => spi_di_req_s,
197
            di_i => spi_di_reg_s,
198
            wren_i => spi_wren_reg_s,
199
            do_valid_o => spi_do_valid_s,
200 12 jdoin
            do_o => spi_do_s,
201
            ------------ debug pins ------------
202
            state_dbg_o => state_dbg_s,        -- monitor internal state register
203
            rx_bit_next_o => spi_rx_bit_s,
204
            wr_ack_o => dbg(5),
205
            do_transfer_o => dbg(4)
206 10 jdoin
        );
207
 
208 12 jdoin
    -- connect debug port pins to slave instance interface signals
209
    dbg(7) <= spi_rx_bit_s;
210
    dbg(6) <= spi_wren_reg_s;
211
    dbg(3) <= spi_do_valid_s;
212
    dbg(2) <= spi_di_req_s;
213
    dbg(1) <= '0';
214
    dbg(0) <= '0';
215
 
216
    dbg(11 downto 8) <= state_dbg_s(3 downto 0);-- connect state register
217
 
218 11 jdoin
    spi_di_reg_s(7) <= btn_data(btLEFT);        -- get the slave transmit data from pushbuttons
219
    spi_di_reg_s(6) <= btn_data(btCENTER);
220
    spi_di_reg_s(5 downto 1) <= B"10101";
221
    spi_di_reg_s(0) <= btn_data(btRIGHT);
222
    spi_wren_reg_s <= '1';                      -- fix wren to '1', for continuous load of transmit data
223 10 jdoin
 
224 5 jdoin
    -- debounce for the input switches, with new data strobe output
225
    Inst_sw_debouncer: entity work.grp_debouncer(rtl)
226 12 jdoin
        generic map (N => 8, CNT_VAL => 20000)  -- debounce 8 inputs with 200 us settling time
227 5 jdoin
        port map(
228 10 jdoin
            clk_i => gclk_i,                    -- system clock
229 5 jdoin
            data_i => sw_i,                     -- noisy input data
230 10 jdoin
            data_o => sw_data                   -- registered stable output data
231 12 jdoin
        );
232 5 jdoin
 
233
    -- debounce for the input pushbuttons, with new data strobe output
234
    Inst_btn_debouncer: entity work.grp_debouncer(rtl)
235 12 jdoin
        generic map (N => 6, CNT_VAL => 20000)  -- debounce 6 inputs with 200 us settling time
236 5 jdoin
        port map(
237 10 jdoin
            clk_i => gclk_i,                    -- system clock
238 5 jdoin
            data_i => btn_i,                    -- noisy input data
239 10 jdoin
            data_o => btn_data                  -- registered stable output data
240 12 jdoin
        );
241 5 jdoin
 
242
    --=============================================================================================
243
    --  CONSTANTS CONSTRAINTS CHECKING
244
    --=============================================================================================
245
    -- clock dividers shall not be zero
246 11 jdoin
    assert FSM_CE_DIV > 0
247
    report "Constant 'FSM_CE_DIV' should not be zero"
248 5 jdoin
    severity FAILURE;
249
    -- minimum prefetch lookahead check
250 11 jdoin
    assert SPI_2X_CLK_DIV > 0
251
    report "Constant 'SPI_2X_CLK_DIV' should not be zero"
252 5 jdoin
    severity FAILURE;
253
    -- maximum prefetch lookahead check
254 11 jdoin
    assert SAMP_CE_DIV > 0
255
    report "Constant 'SAMP_CE_DIV' should not be zero"
256 5 jdoin
    severity FAILURE;
257
 
258
    --=============================================================================================
259
    --  CLOCK GENERATION
260
    --=============================================================================================
261
    -- The clock generation block derives 3 internal clocks, divided down from the 100MHz input clock 
262
    --      core clock, 
263
    --      spi 2x base clock,
264
    --      fsm clock,
265
    -----------------------------------------------------------------------------------------------
266
    -- generate the sampling clock enable from the 100MHz board input clock 
267
    samp_ce_gen_proc: process (gclk_i) is
268
        variable clk_cnt : integer range SAMP_CE_DIV-1 downto 0 := 0;
269
    begin
270
        if gclk_i'event and gclk_i = '1' then
271
            if clk_cnt = SAMP_CE_DIV-1 then
272
                samp_ce <= '1';
273
                clk_cnt := 0;
274
            else
275
                samp_ce <= '0';
276
                clk_cnt := clk_cnt + 1;
277
            end if;
278
        end if;
279
    end process samp_ce_gen_proc;
280
    -- generate the fsm clock enable from the 100MHz board input clock 
281
    fsm_ce_gen_proc: process (gclk_i) is
282
        variable clk_cnt : integer range FSM_CE_DIV-1 downto 0 := 0;
283
    begin
284
        if gclk_i'event and gclk_i = '1' then
285
            if clk_cnt = FSM_CE_DIV-1 then
286
                fsm_ce <= '1';
287
                clk_cnt := 0;
288
            else
289
                fsm_ce <= '0';
290
                clk_cnt := clk_cnt + 1;
291
            end if;
292
        end if;
293
    end process fsm_ce_gen_proc;
294
 
295
    --=============================================================================================
296
    -- INPUTS LOGIC
297
    --=============================================================================================
298
    -- registered inputs
299 10 jdoin
    samp_inputs_proc: process (gclk_i) is
300 5 jdoin
    begin
301 10 jdoin
        if gclk_i'event and gclk_i = '1' then
302 5 jdoin
            if samp_ce = '1' then
303 10 jdoin
                clear <= btn_data(btUP);        -- clear is button UP
304
                leds_reg <= spi_do_s;           -- update LEDs with spi_slave received data
305 5 jdoin
            end if;
306
        end if;
307
    end process samp_inputs_proc;
308
 
309
    --=============================================================================================
310 10 jdoin
    --  REGISTER TRANSFER PROCESSES
311 5 jdoin
    --=============================================================================================
312
    -- fsm state and data registers: synchronous to the spi base reference clock
313 10 jdoin
    fsm_reg_proc : process (gclk_i) is
314 5 jdoin
    begin
315
        -- FFD registers clocked on rising edge and cleared on sync 'clear'
316 10 jdoin
        if gclk_i'event and gclk_i = '1' then
317 5 jdoin
            if clear = '1' then                 -- sync reset
318
                state_reg <= st_reset;          -- only provide local reset for the state register
319
            else
320
                if fsm_ce = '1' then
321
                    state_reg <= state_next;    -- state register
322
                end if;
323
            end if;
324
        end if;
325
        -- FFD registers clocked on rising edge, with no reset
326 10 jdoin
        if gclk_i'event and gclk_i = '1' then
327 5 jdoin
            if fsm_ce = '1' then
328 10 jdoin
                spi_wren_reg_m <= spi_wren_next_m;
329
                spi_di_reg_m <= spi_di_next_m;
330 5 jdoin
                spi_rst_reg <= spi_rst_next;
331
                spi_ssel_reg <= spi_ssel;
332
                sw_reg <= sw_next;
333
                btn_reg <= btn_next;
334
            end if;
335
        end if;
336
    end process fsm_reg_proc;
337
 
338
    --=============================================================================================
339 10 jdoin
    --  COMBINATORIAL NEXT-STATE LOGIC PROCESSES
340 5 jdoin
    --=============================================================================================
341
    -- edge detector for new switch data
342 10 jdoin
    new_switch_proc: new_switch <= '1' when sw_data /= sw_reg else '0';     -- '1' for difference
343 5 jdoin
    -- edge detector for new button data
344 10 jdoin
    new_button_proc: new_button <= '1' when btn_data /= btn_reg else '0';   -- '1' for difference
345 5 jdoin
    -- fsm state and combinatorial logic
346
    -- the sequencer will wait for a new switch combination, and send the switch data to the spi port
347 10 jdoin
    fsm_combi_proc: process (   state_reg, spi_wren_reg_m, spi_di_reg_m, spi_di_req_m, spi_wr_ack_m, -- spi_di_reg_s, 
348
                                spi_wren_reg_s, spi_ssel_reg, spi_rst_reg, sw_data,
349
                                sw_reg, new_switch, btn_data, btn_reg, new_button) is
350 5 jdoin
    begin
351
        spi_rst_next <= spi_rst_reg;
352 10 jdoin
        spi_di_next_m <= spi_di_reg_m;
353
        spi_wren_next_m <= spi_wren_reg_m;
354 5 jdoin
        sw_next <= sw_reg;
355
        btn_next <= btn_reg;
356
        state_next <= state_reg;
357
        case state_reg is
358
            when st_reset =>
359
                spi_rst_next <= '1';                        -- place spi interface on reset
360 10 jdoin
                spi_di_next_m <= (others => '0');           -- clear spi data port
361
                spi_di_next_s <= (others => '0');           -- clear spi data port
362
                spi_wren_next_m <= '0';                     -- deassert write enable
363
                spi_wren_next_s <= '0';                     -- deassert write enable
364 5 jdoin
                state_next <= st_wait_spi_idle;
365
 
366
            when st_wait_spi_idle =>
367 12 jdoin
                spi_wren_next_m <= '0';                     -- remove write strobe on next clock
368 5 jdoin
                if spi_ssel_reg = '1' then
369
                    spi_rst_next <= '0';                    -- remove reset when interface is idle
370
                    state_next <= st_wait_new_switch;
371
                end if;
372
 
373
            when st_wait_new_switch =>
374
                if new_switch = '1' then                    -- wait for new stable switch data
375
                    sw_next <= sw_data;                     -- load new switch data (end the mismatch condition)
376
                    state_next <= st_send_spi_data;
377
                elsif new_button = '1' then
378
                    btn_next <= btn_data;                   -- load new button data (end the mismatch condition)
379 10 jdoin
                    if btn_data /= B"000001" then
380 5 jdoin
                        state_next <= st_send_spi_data;
381
                    end if;
382
                end if;
383
 
384
            when st_send_spi_data =>
385 10 jdoin
                spi_di_next_m <= sw_reg;                    -- load switch register to the spi port
386
                spi_wren_next_m <= '1';                     -- write data on next clock
387 5 jdoin
                state_next <= st_wait_spi_ack;
388
 
389
            when st_wait_spi_ack =>                         -- the actual write happens on this state
390 10 jdoin
                spi_di_next_m <= sw_reg;                    -- load switch register to the spi port
391 12 jdoin
                spi_wren_next_m <= '0';                     -- remove write strobe on next clock
392
                state_next <= st_wait_spi_idle;
393 5 jdoin
 
394
            when others =>
395
                state_next <= st_reset;                     -- state st_reset is safe state
396
        end case;
397
    end process fsm_combi_proc;
398
 
399
    --=============================================================================================
400
    --  OUTPUT LOGIC PROCESSES
401
    --=============================================================================================
402
    -- connect the spi output wires
403 10 jdoin
    spi_ssel_o_proc:        spi_ssel_o      <= spi_ssel;
404
    spi_sck_o_proc:         spi_sck_o       <= spi_sck;
405
    spi_mosi_o_proc:        spi_mosi_o      <= spi_mosi;
406
    spi_miso_o_proc:        spi_miso_o      <= spi_miso;
407 12 jdoin
    -- connect leds_reg signal to LED outputs
408
    led_o_proc:             led_o           <= leds_reg;
409 5 jdoin
 
410
    --=============================================================================================
411
    --  DEBUG LOGIC PROCESSES
412
    --=============================================================================================
413
    -- connect the debug vector outputs
414 10 jdoin
    dbg_o_proc:             dbg_o <= dbg;
415
 
416 5 jdoin
end behavioral;
417
 

powered by: WebSVN 2.1.0

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