diff --git a/lib/spi/sim/tb_spi.fdo b/lib/spi/sim/tb_spi.fdo index 49c59c0..096886a 100644 --- a/lib/spi/sim/tb_spi.fdo +++ b/lib/spi/sim/tb_spi.fdo @@ -5,6 +5,13 @@ if {[file exists work]} {vdel -lib work -all} vlib work vcom -explicit -93 "../../misc/utils_pkg.vhd" +vcom -explicit -93 "../../FIFO/src/fifo_ctrl_pkg.vhd" +vcom -explicit -93 "../../rams/dpram_1w1r2c_ra_sim.vhd" +vcom -explicit -93 "../../FIFO/src/gray_counter.vhd" +vcom -explicit -93 "../../FIFO/src/fifo_async_ctrl.vhd" +vcom -explicit -93 "../../FIFO/src/fifo_async.vhd" +vcom -explicit -93 "../../FIFO/src/fifo_sync_ctrl.vhd" +vcom -explicit -93 "../../FIFO/src/fifo_sync.vhd" vcom -explicit -93 "../src/spi_types.vhd" vcom -explicit -93 "../src/spi_tx.vhd" vcom -explicit -93 "../src/spi_rx.vhd" diff --git a/lib/spi/sim/tb_spi.wdo b/lib/spi/sim/tb_spi.wdo index 0cee556..2c74d36 100644 --- a/lib/spi/sim/tb_spi.wdo +++ b/lib/spi/sim/tb_spi.wdo @@ -3,10 +3,10 @@ quietly WaveActivateNextPane {} 0 add wave -noupdate -format Logic /tb_spi/clk add wave -noupdate -format Logic /tb_spi/rst add wave -noupdate -format Logic /tb_spi/tx_cmd_vld -add wave -noupdate -format Logic /tb_spi/tx_cmd_ack +add wave -noupdate -format Logic /tb_spi/tx_cmd_rdy add wave -noupdate -format Literal -radix hexadecimal /tb_spi/tx_cmd add wave -noupdate -format Logic /tb_spi/tx_din_vld -add wave -noupdate -format Logic /tb_spi/tx_din_re +add wave -noupdate -format Logic /tb_spi/tx_din_rdy add wave -noupdate -format Literal -radix hexadecimal /tb_spi/tx_din add wave -noupdate -format Logic /tb_spi/tx_shift_en add wave -noupdate -format Logic /tb_spi/tx_mosi @@ -16,25 +16,36 @@ add wave -noupdate -format Literal /tb_spi/inst_spi_tx/word_width add wave -noupdate -format Logic /tb_spi/inst_spi_tx/rst add wave -noupdate -format Logic /tb_spi/inst_spi_tx/clk add wave -noupdate -format Logic /tb_spi/inst_spi_tx/cmd_vld -add wave -noupdate -format Logic /tb_spi/inst_spi_tx/cmd_ack +add wave -noupdate -format Logic /tb_spi/inst_spi_tx/cmd_rdy add wave -noupdate -format Literal -radix hexadecimal /tb_spi/inst_spi_tx/cmd add wave -noupdate -format Logic /tb_spi/inst_spi_tx/din_vld -add wave -noupdate -format Logic /tb_spi/inst_spi_tx/din_re +add wave -noupdate -format Logic /tb_spi/inst_spi_tx/din_rdy add wave -noupdate -format Literal -radix hexadecimal /tb_spi/inst_spi_tx/din add wave -noupdate -format Logic /tb_spi/inst_spi_tx/shift_en add wave -noupdate -format Logic /tb_spi/inst_spi_tx/data_out +add wave -noupdate -format Literal -radix hexadecimal /tb_spi/inst_spi_tx/shift_reg add wave -noupdate -format Logic /tb_spi/inst_spi_tx/clk_out add wave -noupdate -format Literal -radix hexadecimal /tb_spi/inst_spi_tx/xfer_count add wave -noupdate -format Literal -radix hexadecimal /tb_spi/inst_spi_tx/data_count +add wave -noupdate -format Literal -radix hexadecimal /tb_spi/inst_spi_tx/word_count add wave -noupdate -format Literal -radix hexadecimal /tb_spi/inst_spi_tx/cmd_reg add wave -noupdate -format Literal /tb_spi/inst_spi_tx/state +add wave -noupdate -format Logic /tb_spi/inst_spi_tx/data_load_en +add wave -noupdate -format Literal /tb_spi/inst_spi_tx/shift_cnt_pipe add wave -noupdate -format Logic /tb_spi/inst_spi_tx/cmd_reg_we add wave -noupdate -format Logic /tb_spi/inst_spi_tx/xfer_count_en add wave -noupdate -format Logic /tb_spi/inst_spi_tx/data_count_en add wave -noupdate -format Logic /tb_spi/inst_spi_tx/xfer_count_busy add wave -noupdate -format Logic /tb_spi/inst_spi_tx/data_count_busy +add wave -noupdate -format Logic /tb_spi/inst_spi_tx/spi_clk +add wave -noupdate -format Literal -radix hexadecimal /tb_spi/inst_spi_tx/cat_fifo_din +add wave -noupdate -format Literal -radix hexadecimal /tb_spi/inst_spi_tx/cat_fifo_dout +add wave -noupdate -format Logic /tb_spi/inst_spi_tx/cat_fifo_re +add wave -noupdate -format Logic /tb_spi/inst_spi_tx/cat_fifo_we +add wave -noupdate -format Logic /tb_spi/inst_spi_tx/cat_fifo_full +add wave -noupdate -format Logic /tb_spi/inst_spi_tx/cat_fifo_empty TreeUpdate [SetDefaultTree] -WaveRestoreCursors {{Cursor 1} {5674147 ps} 0} +WaveRestoreCursors {{Cursor 1} {6254805 ps} 0} configure wave -namecolwidth 197 configure wave -valuecolwidth 131 configure wave -justifyvalue left @@ -48,4 +59,4 @@ configure wave -gridperiod 1 configure wave -griddelta 40 configure wave -timeline 0 update -WaveRestoreZoom {0 ps} {21 us} +WaveRestoreZoom {5843806 ps} {8445242 ps} diff --git a/lib/spi/src/spi_tx.vhd b/lib/spi/src/spi_tx.vhd index 31ba68f..11c3951 100644 --- a/lib/spi/src/spi_tx.vhd +++ b/lib/spi/src/spi_tx.vhd @@ -9,21 +9,25 @@ use work.spi_types.all; ENTITY spi_tx IS Generic ( - word_width : natural := 32 + word_width : natural := 32; + CAT_FIFO_DEPTH : natural := 2; + DATA_FIFO_DEPTH : natural := 16 ); Port ( rst : in STD_LOGIC; clk : in STD_LOGIC; cmd_vld : in STD_LOGIC; - cmd_ack : out STD_LOGIC; + cmd_rdy : out STD_LOGIC; cmd : in cmd_t; din_vld : in STD_LOGIC; - din_re : out STD_LOGIC; + din_rdy : out STD_LOGIC; din : in unsigned(word_width-1 downto 0); shift_en : in STD_LOGIC; data_out : out STD_LOGIC; - clk_out : out STD_LOGIC + clk_out : out STD_LOGIC; + ctrl : in ctrl_t; + status : out status_t ); END spi_tx; @@ -43,18 +47,113 @@ ARCHITECTURE behavior OF spi_tx IS signal data_count_en : std_logic; signal xfer_count_busy : std_logic; signal data_count_busy : std_logic; + signal spi_clk : std_logic := '0'; + signal spi_clk_out : std_logic := '0'; signal clk_en : std_logic; + + signal cat_fifo_din : unsigned(to_unsigned(cmd)'length-1 downto 0); + signal cat_fifo_dout : unsigned(to_unsigned(cmd)'length-1 downto 0); + signal cat_fifo_re : std_logic; + signal cat_fifo_we : std_logic; + signal cat_fifo_full : std_logic; + signal cat_fifo_empty : std_logic; + + signal write_fifo_din : unsigned(word_width-1 downto 0); + signal write_fifo_dout : unsigned(word_width-1 downto 0); + signal write_fifo_re : std_logic; + signal write_fifo_we : std_logic; + signal write_fifo_full : std_logic; + signal write_fifo_empty : std_logic; + + signal shift_reg : unsigned(word_width-1 downto 0); + signal shift_cnt_pipe : unsigned(word_width-1 downto 0); + signal data_load_en : std_logic; -------------------------------------------------------------------------- begin - clk_out <= clk and clk_en; + clk_out <= spi_clk_out; + cat_fifo_din <= to_unsigned(cmd); + write_fifo_din <= din; + cmd_rdy <= not cat_fifo_full; + din_rdy <= not write_fifo_full; + cat_fifo_we <= cmd_vld; + cmd_reg <= to_cmd(cat_fifo_dout); + data_out <= shift_reg(shift_reg'left) when ctrl.msb_first = '1' else shift_reg(shift_reg'right); + data_load_en <= not data_count_en or shift_cnt_pipe(shift_cnt_pipe'left-1); -------------------------------------------------------------------------- -proc_state_next: + -- Instantiate synchronous FIFO + inst_cat_fifo: entity work.fifo_async + GENERIC MAP + ( + addr_width => NextExpBaseTwo(CAT_FIFO_DEPTH), + data_width => cmd_size + ) + PORT MAP + ( + rst => rst, + clk_w => clk, + clk_r => spi_clk, + we => cat_fifo_we, + re => cat_fifo_re, + fifo_full => cat_fifo_full, + fifo_empty => cat_fifo_empty, + fifo_afull => open, + fifo_aempty => open, + data_w => cat_fifo_din, + data_r => cat_fifo_dout + ); + + -- Instantiate synchronous FIFO + inst_write_fifo: entity work.fifo_async + GENERIC MAP + ( + addr_width => NextExpBaseTwo(DATA_FIFO_DEPTH), + data_width => word_width + ) + PORT MAP + ( + rst => rst, + clk_w => clk, + clk_r => spi_clk, + we => din_vld, + re => write_fifo_re, + fifo_full => write_fifo_full, + fifo_empty => write_fifo_empty, + fifo_afull => open, + fifo_aempty => open, + data_w => write_fifo_din, + data_r => write_fifo_dout + ); + +-------------------------------------------------------------------------- +proc_spi_clk_gen: process(clk) begin if rising_edge(clk) then + spi_clk <= not spi_clk; + end if; +end process; + +proc_spi_clk_out_gen: +process(clk) +begin + if rising_edge(clk) then + if rst = '1' then + spi_clk_out <= '0'; + elsif clk_en = '0' then + spi_clk_out <= ctrl.polarity; + else + spi_clk_out <= not spi_clk_out; + end if; + end if; +end process; + +proc_state_next: +process(spi_clk) +begin + if rising_edge(spi_clk) then if rst = '1' then state <= idle; else @@ -64,24 +163,26 @@ begin end process; proc_fsm: -process(state, cmd_vld, xfer_count_busy) +process(state, cat_fifo_empty, xfer_count_busy) begin state_next <= state; cmd_reg_we <= '0'; - cmd_ack <= '0'; + cat_fifo_re <= '0'; xfer_count_en <= '0'; data_count_en <= '0'; clk_en <= '0'; case state is when idle => - cmd_ack <= cmd_vld; - if cmd_vld = '1' then + if cat_fifo_empty = '0' then cmd_reg_we <= '1'; state_next <= prepare; end if; when prepare => + cat_fifo_re <= '1'; + write_fifo_re <= '1'; + clk_en <= '1'; xfer_count_en <= '1'; data_count_en <= '1'; state_next <= shift; @@ -103,11 +204,11 @@ begin end case; end process; -process(clk) +process(spi_clk) begin - if rising_edge(clk) then + if rising_edge(spi_clk) then if xfer_count_en = '0' then - xfer_count <= cmd.xfer_size; + xfer_count <= cmd_reg.xfer_size; xfer_count_busy <= '0'; elsif shift_en = '1' then if xfer_count /= to_unsigned(0, xfer_count'length) then @@ -120,22 +221,22 @@ begin end if; end process; -process(clk) +process(spi_clk) begin - if rising_edge(clk) then - din_re <= '0'; + if rising_edge(spi_clk) then if data_count_en = '0' then word_count <= to_unsigned(0, word_count'length); - data_count <= cmd.data_size; + data_count <= cmd_reg.data_size; data_count_busy <= '0'; + shift_cnt_pipe <= (others => '0'); elsif shift_en = '1' then + shift_cnt_pipe <= shift_cnt_pipe(shift_cnt_pipe'left-1 downto 0) & '1'; if word_count /= to_unsigned(0, word_count'length) then word_count <= word_count - 1; else - din_re <= '1'; word_count <= to_unsigned(word_width, word_count'length); end if; - if data_count /= to_unsigned(1, data_count'length) then + if data_count /= to_unsigned(0, data_count'length) then data_count_busy <= '1'; data_count <= data_count - 1; else @@ -145,4 +246,19 @@ begin end if; end process; +process(spi_clk) +begin + if rising_edge(spi_clk) then + if shift_en = '1' then + if data_load_en = '0' then + shift_reg <= write_fifo_dout; + elsif (ctrl.msb_first = '1') then + shift_reg <= shift_reg(shift_reg'left-1 downto 0) & '0'; + else + shift_reg <= '0' & shift_reg(shift_reg'left downto 1); + end if; + end if; + end if; +end process; + end behavior; diff --git a/lib/spi/src/spi_types.vhd b/lib/spi/src/spi_types.vhd index 656f3f0..436a201 100644 --- a/lib/spi/src/spi_types.vhd +++ b/lib/spi/src/spi_types.vhd @@ -13,26 +13,56 @@ package spi_types is type cmd_t is record xfer_size : unsigned(NextExpBaseTwo(XFER_SIZE_MAX)-1 downto 0); data_size : unsigned(NextExpBaseTwo(XFER_SIZE_MAX)-1 downto 0); + end record; + + type ctrl_t is record polarity : std_logic; msb_first : std_logic; end record; + + type status_t is record + dummy : std_logic; + end record; -- Functions + function cmd_size return positive; function to_cmd (xfer_size, data_size : natural) return cmd_t; - + function to_unsigned (cmd : cmd_t) return unsigned; + function to_cmd (cmd : unsigned) return cmd_t; + end spi_types; package body spi_types is + function cmd_size return positive is + variable res : cmd_t; + begin + return res.xfer_size'length + res.data_size'length + 1 + 1; + end cmd_size; + function to_cmd(xfer_size, data_size : natural) return cmd_t is variable res : cmd_t; begin - res.polarity := '1'; - res.msb_first := '1'; res.xfer_size := to_unsigned(xfer_size, res.xfer_size'length); res.data_size := to_unsigned(data_size, res.data_size'length); - return res; end to_cmd; + function to_unsigned(cmd : cmd_t) return unsigned is + variable res : unsigned(cmd.xfer_size'length + cmd.data_size'length + 1 + 1 -1 downto 0) := (others => '0'); + begin + res(res'left downto res'left - cmd.xfer_size'length+1) := cmd.xfer_size; + res(res'left - cmd.xfer_size'length downto res'left - cmd.xfer_size'length - cmd.data_size'length +1) := cmd.data_size; + return res; + end to_unsigned; + + function to_cmd (cmd : unsigned) return cmd_t is + variable res : cmd_t; + begin + res.xfer_size := cmd(cmd'left downto cmd'left - res.xfer_size'length+1); + res.data_size := cmd(cmd'left - res.xfer_size'length downto cmd'left - res.xfer_size'length - res.data_size'length +1); + + return res; + end to_cmd; + end spi_types; diff --git a/lib/spi/src/tb_spi.vhd b/lib/spi/src/tb_spi.vhd index 1133ffe..949b9d8 100644 --- a/lib/spi/src/tb_spi.vhd +++ b/lib/spi/src/tb_spi.vhd @@ -39,17 +39,22 @@ ARCHITECTURE behavior OF tb_spi IS signal RST : std_logic := '1'; signal tx_cmd_vld : STD_LOGIC := '0'; - signal tx_cmd_ack : STD_LOGIC; + signal tx_cmd_rdy : STD_LOGIC; signal tx_cmd : cmd_t; signal tx_din_vld : STD_LOGIC := '0'; - signal tx_din_re : STD_LOGIC; + signal tx_din_rdy : STD_LOGIC; signal tx_din : unsigned(31 downto 0) := (others => '0'); signal tx_shift_en : STD_LOGIC := '1'; signal tx_mosi : STD_LOGIC; signal tx_clk : STD_LOGIC; + signal ctrl : ctrl_t; + signal status : status_t; BEGIN + ctrl.polarity <= '0'; + ctrl.msb_first <= '1'; + inst_spi_tx : entity work.spi_tx GENERIC MAP ( @@ -60,14 +65,16 @@ inst_spi_tx : entity work.spi_tx rst => RST, clk => CLK, cmd_vld => tx_cmd_vld, - cmd_ack => tx_cmd_ack, + cmd_rdy => tx_cmd_rdy, cmd => tx_cmd, din_vld => tx_din_vld, - din_re => tx_din_re, + din_rdy => tx_din_rdy, din => tx_din, shift_en => tx_shift_en, data_out => tx_mosi, - clk_out => tx_clk + clk_out => tx_clk, + ctrl => ctrl, + status => status ); @@ -86,11 +93,20 @@ STIMULUS: process wait for 600*CLK_PERIOD; RST <= '0'; + wait for 6*CLK_PERIOD; + wait until rising_edge(CLK); + tx_din <= X"C355AAC1"; + tx_din_vld <= '1'; + wait until rising_edge(CLK) and tx_din_rdy = '1'; + tx_din <= X"03AAFF05"; + wait until rising_edge(CLK) and tx_din_rdy = '1'; + tx_din_vld <= '0'; + wait until rising_edge(CLK); tx_cmd <= to_cmd(64, 48); tx_cmd_vld <= '1'; - wait until rising_edge(CLK) and tx_cmd_ack = '1'; + wait until rising_edge(CLK) and tx_cmd_rdy = '1'; tx_cmd_vld <= '0'; wait;