diff --git a/lib/spi/sim/tb_spi.fdo b/lib/spi/sim/tb_spi.fdo new file mode 100644 index 0000000..49c59c0 --- /dev/null +++ b/lib/spi/sim/tb_spi.fdo @@ -0,0 +1,18 @@ +## NOTE: Do not edit this file. +## Autogenerated by ProjNav (creatfdo.tcl) on Thu Jul 06 20:49:07 Westeuropäische Sommerzeit 2006 +## +if {[file exists work]} {vdel -lib work -all} + +vlib work +vcom -explicit -93 "../../misc/utils_pkg.vhd" +vcom -explicit -93 "../src/spi_types.vhd" +vcom -explicit -93 "../src/spi_tx.vhd" +vcom -explicit -93 "../src/spi_rx.vhd" +vcom -explicit -93 "../src/tb_spi.vhd" +vsim -t 1ps -lib work tb_spi +view wave +do {tb_spi.wdo} +view structure +view signals + +run 20 us diff --git a/lib/spi/sim/tb_spi.wdo b/lib/spi/sim/tb_spi.wdo new file mode 100644 index 0000000..0cee556 --- /dev/null +++ b/lib/spi/sim/tb_spi.wdo @@ -0,0 +1,51 @@ +onerror {resume} +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 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 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 +add wave -noupdate -format Logic /tb_spi/tx_clk +add wave -noupdate -divider TX +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 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 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 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/cmd_reg +add wave -noupdate -format Literal /tb_spi/inst_spi_tx/state +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 +TreeUpdate [SetDefaultTree] +WaveRestoreCursors {{Cursor 1} {5674147 ps} 0} +configure wave -namecolwidth 197 +configure wave -valuecolwidth 131 +configure wave -justifyvalue left +configure wave -signalnamewidth 1 +configure wave -snapdistance 10 +configure wave -datasetprefix 0 +configure wave -rowmargin 4 +configure wave -childrowmargin 2 +configure wave -gridoffset 0 +configure wave -gridperiod 1 +configure wave -griddelta 40 +configure wave -timeline 0 +update +WaveRestoreZoom {0 ps} {21 us} diff --git a/lib/spi/src/spi_rx.vhd b/lib/spi/src/spi_rx.vhd new file mode 100644 index 0000000..48c2a1e --- /dev/null +++ b/lib/spi/src/spi_rx.vhd @@ -0,0 +1,118 @@ +LIBRARY IEEE; +USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.NUMERIC_STD.ALL; +use std.textio.all; -- Imports the standard textio package. + +use work.utils_pkg.all; -- Imports the standard textio package. + +ENTITY sipo IS + Generic + ( + data_width_in : natural := 8; + data_width_out : natural := 32; + msb_first : boolean := false + ); + Port + ( + rst : in STD_LOGIC; + clk : in STD_LOGIC; + din_en : in STD_LOGIC; + din_vld : in STD_LOGIC; + din : in unsigned(data_width_in-1 downto 0); + shift_en : out STD_LOGIC; + dout_vld : out STD_LOGIC; + dout : out unsigned(data_width_out-1 downto 0); + dout_be : out unsigned(data_width_out/data_width_in-1 downto 0) + + ); +END sipo; + +ARCHITECTURE behavior OF sipo IS + + constant num_shifts : natural := data_width_out/data_width_in; + signal pre_fin : STD_LOGIC; + signal shift_cnt_pipe : unsigned(num_shifts-1 downto 0); + signal shift_pipe : unsigned(data_width_out-1 downto 0); + signal out_en : STD_LOGIC; + signal out_vld : STD_LOGIC; + signal din_vld_r : STD_LOGIC; + signal abort : STD_LOGIC; + +-------------------------------------------------------------------------- +begin + + pre_fin <= shift_cnt_pipe(shift_cnt_pipe'left) when msb_first else shift_cnt_pipe(0); + shift_en <= out_en; + dout_vld <= out_vld; + +-------------------------------------------------------------------------- +process(clk) +begin + if rising_edge(clk) then + if rst = '1' or pre_fin = '1' then + abort <= '0'; + elsif din_vld_r = '1' and din_en = '0' then + abort <= '1'; + end if; + end if; +end process; + +process(clk) +begin + if rising_edge(clk) then + din_vld_r <= din_vld and din_en; + if rst = '1' then + out_en <= '0'; + elsif out_en = '0' then + out_en <= pre_fin and din_en; + elsif out_vld = '1' then + out_en <= din_en; + end if; + end if; +end process; + +process(clk) +begin + if rising_edge(clk) then + out_vld <= pre_fin; + if pre_fin = '1' then + dout <= shift_pipe; + dout_be <= shift_cnt_pipe; + end if; + end if; +end process; + +process(clk) +begin + if rising_edge(clk) then + if rst = '1' or pre_fin = '1' then + if (msb_first) then + shift_cnt_pipe <= (shift_cnt_pipe'left downto 1 => '0') & (din_en and din_vld); + else + shift_cnt_pipe <= (din_en and din_vld) & (shift_cnt_pipe'left downto 1 => '0'); + end if; + elsif din_vld = '1' or abort = '1' then + if (msb_first) then + shift_cnt_pipe <= shift_cnt_pipe(shift_cnt_pipe'left-1 downto 0) & din_en; + else + shift_cnt_pipe <= din_en & shift_cnt_pipe(shift_cnt_pipe'left downto 1); + end if; + end if; + end if; +end process; + +process(clk) +begin + if rising_edge(clk) then + if din_vld = '1' or abort = '1' then + if (msb_first) then + shift_pipe <= shift_pipe(shift_pipe'left-data_width_in downto 0) & din; + else + shift_pipe <= din & shift_pipe(shift_pipe'left downto data_width_in); + end if; + end if; + end if; +end process; + +-------------------------------------------------------------------------- +end behavior; diff --git a/lib/spi/src/spi_tx.vhd b/lib/spi/src/spi_tx.vhd new file mode 100644 index 0000000..31ba68f --- /dev/null +++ b/lib/spi/src/spi_tx.vhd @@ -0,0 +1,148 @@ +LIBRARY IEEE; +USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.NUMERIC_STD.ALL; +use std.textio.all; -- Imports the standard textio package. + +use work.utils_pkg.all; +use work.spi_types.all; + +ENTITY spi_tx IS + Generic + ( + word_width : natural := 32 + ); + Port + ( + rst : in STD_LOGIC; + clk : in STD_LOGIC; + cmd_vld : in STD_LOGIC; + cmd_ack : out STD_LOGIC; + cmd : in cmd_t; + din_vld : in STD_LOGIC; + din_re : 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 + + ); +END spi_tx; + +ARCHITECTURE behavior OF spi_tx IS + + type state_t is (idle, prepare, shift, finish); + + signal xfer_count : unsigned(NextExpBaseTwo(XFER_SIZE_MAX)-1 downto 0); + signal data_count : unsigned(NextExpBaseTwo(XFER_SIZE_MAX)-1 downto 0); + signal word_count : unsigned(NextExpBaseTwo(XFER_SIZE_MAX)-1 downto 0); + signal cmd_reg : cmd_t; + signal state : state_t; + signal state_next : state_t; + signal cmd_reg_we : std_logic; + signal xfer_count_en : std_logic; + signal data_count_en : std_logic; + signal xfer_count_busy : std_logic; + signal data_count_busy : std_logic; + signal clk_en : std_logic; + +-------------------------------------------------------------------------- +begin + + clk_out <= clk and clk_en; + +-------------------------------------------------------------------------- +proc_state_next: +process(clk) +begin + if rising_edge(clk) then + if rst = '1' then + state <= idle; + else + state <= state_next; + end if; + end if; +end process; + +proc_fsm: +process(state, cmd_vld, xfer_count_busy) +begin + state_next <= state; + cmd_reg_we <= '0'; + cmd_ack <= '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 + cmd_reg_we <= '1'; + state_next <= prepare; + end if; + + when prepare => + xfer_count_en <= '1'; + data_count_en <= '1'; + state_next <= shift; + + when shift => + clk_en <= '1'; + xfer_count_en <= '1'; + data_count_en <= '1'; + if xfer_count_busy = '0' then + state_next <= finish; + end if; + + when finish => + state_next <= idle; + + when others => + state_next <= idle; + + end case; +end process; + +process(clk) +begin + if rising_edge(clk) then + if xfer_count_en = '0' then + xfer_count <= cmd.xfer_size; + xfer_count_busy <= '0'; + elsif shift_en = '1' then + if xfer_count /= to_unsigned(0, xfer_count'length) then + xfer_count_busy <= '1'; + xfer_count <= xfer_count - 1; + else + xfer_count_busy <= '0'; + end if; + end if; + end if; +end process; + +process(clk) +begin + if rising_edge(clk) then + din_re <= '0'; + if data_count_en = '0' then + word_count <= to_unsigned(0, word_count'length); + data_count <= cmd.data_size; + data_count_busy <= '0'; + elsif shift_en = '1' then + 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 + data_count_busy <= '1'; + data_count <= data_count - 1; + else + data_count_busy <= '0'; + 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 new file mode 100644 index 0000000..656f3f0 --- /dev/null +++ b/lib/spi/src/spi_types.vhd @@ -0,0 +1,38 @@ +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.NUMERIC_STD.ALL; + +use work.utils_pkg.all; -- Imports the standard textio package. + +package spi_types is + + -- Constants + constant XFER_SIZE_MAX : natural := 256; + + -- Types + 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); + polarity : std_logic; + msb_first : std_logic; + end record; + + -- Functions + function to_cmd (xfer_size, data_size : natural) return cmd_t; + +end spi_types; + +package body spi_types is + + 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; + +end spi_types; diff --git a/lib/spi/src/tb_spi.vhd b/lib/spi/src/tb_spi.vhd new file mode 100644 index 0000000..1133ffe --- /dev/null +++ b/lib/spi/src/tb_spi.vhd @@ -0,0 +1,100 @@ +------------------------------------------------------------------------- +-- Project: JCPU, a portable 8-bit RISC CPU written in VHDL +-- This file: testbench for system test using Xilinx ML-402 + +-- Copyright (C) 2007 J. Ahrensfeld + +-- This library is free software; you can redistribute it and/or +-- modify it under the terms of the GNU Lesser General Public +-- License as published by the Free Software Foundation; either +-- version 2.1 of the License, or (at your option) any later version. + +-- This library is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +-- Lesser General Public License for more details. + +-- You should have received a copy of the GNU Lesser General Public +-- License along with this library; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +-- For questions and ideas, please contact the author at jens@jayfield.org + +----------------------------------------------------------------------- + +LIBRARY ieee; +use IEEE.STD_LOGIC_1164.ALL; +USE ieee.numeric_std.ALL; + +use work.spi_types.all; + +ENTITY tb_spi IS +END tb_spi; + +ARCHITECTURE behavior OF tb_spi IS + + constant CLK_PERIOD : time := 10 ns; + + signal CLK : std_logic := '1'; + signal RST : std_logic := '1'; + + signal tx_cmd_vld : STD_LOGIC := '0'; + signal tx_cmd_ack : STD_LOGIC; + signal tx_cmd : cmd_t; + signal tx_din_vld : STD_LOGIC := '0'; + signal tx_din_re : 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; + +BEGIN + +inst_spi_tx : entity work.spi_tx + GENERIC MAP + ( + word_width => 32 + ) + PORT MAP + ( + rst => RST, + clk => CLK, + cmd_vld => tx_cmd_vld, + cmd_ack => tx_cmd_ack, + cmd => tx_cmd, + din_vld => tx_din_vld, + din_re => tx_din_re, + din => tx_din, + shift_en => tx_shift_en, + data_out => tx_mosi, + clk_out => tx_clk + + ); + +CLK_GEN: process + begin + wait for CLK_PERIOD/2; + CLK <= not CLK; + end process; + + +-- Master +STIMULUS: process + + + begin + + wait for 600*CLK_PERIOD; + RST <= '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'; + tx_cmd_vld <= '0'; + + wait; + + end process; + +END;