VHDLでSPIスレーブを実装します。SPIで受信して、値を保持するってだけ。ghdlではちゃんと動いていたんだけど、QuartusのModelSimで試したらちゃんとデータを受信できていなかったので、修正。やっぱり、コアクロックを入力するようにして、クロック同期で動作するようにする。
my_spi_slave.vhd
library ieee; use ieee.std_logic_1164.all; --library altera; --use altera.altera_syn_attributes.all; entity my_spi_slave is port ( cs : in std_logic; sck : in std_logic; mosi : in std_logic; miso : out std_logic; a0 : out std_logic_vector(31 downto 0); a1 : out std_logic_vector(31 downto 0); b0 : out std_logic_vector(31 downto 0); b1 : out std_logic_vector(31 downto 0); i_clk : in std_logic ); end my_spi_slave; architecture ppl_type of my_spi_slave is signal miso_pos : integer range 0 to 63:=0; signal mosi_pos : integer range 0 to 63:=0; signal tx_buf : std_logic_vector(63 downto 0):=X"0000000000000000"; signal rx_buf : std_logic_vector(63 downto 0):=X"0000000000000000"; signal cmd : std_logic_vector(7 downto 0):=X"00"; signal a0_buf : std_logic_vector(31 downto 0):=X"00000000"; signal a1_buf : std_logic_vector(31 downto 0):=X"00000000"; signal b0_buf : std_logic_vector(31 downto 0):=X"00000000"; signal b1_buf : std_logic_vector(31 downto 0):=X"00000000"; signal cs_wire : std_logic:='1'; signal sck_wire : std_logic:='0'; signal mosi_wire : std_logic:='0'; signal miso_wire : std_logic:='0'; signal cs_pres : std_logic:='1'; signal cs_prev : std_logic:='1'; signal cs_rising : std_logic:='0'; signal cs_falling : std_logic:='0'; signal sck_pres : std_logic:='0'; signal sck_prev : std_logic:='0'; signal sck_rising : std_logic:='0'; signal sck_falling : std_logic:='0'; begin a0<=a0_buf; a1<=a1_buf; b0<=b0_buf; b1<=b1_buf; sck_wire<=sck; miso<=miso_wire; cs_wire<=cs; mosi_wire<=mosi; cs_pres<=cs_wire; cs_rising<='1' when (cs_prev='0' and cs_pres='1') else '0'; cs_falling<='1' when (cs_prev='1' and cs_pres='0') else '0'; sck_pres<=sck_wire; sck_rising<='1' when (sck_prev='0' and sck_pres='1') else '0'; sck_falling<='1' when (sck_prev='1' and sck_pres='0') else '0'; process(i_clk)begin if i_clk'event and i_clk='1' then cs_prev<=cs_wire; sck_prev<=sck_wire; end if; end process; process(i_clk)begin if i_clk'event and i_clk='1' then if cs_falling='1' then mosi_pos<=0; miso_pos<=0; tx_buf<=X"0000000000000000"; rx_buf<=X"0000000000000000"; cmd<=X"00"; miso_wire<=tx_buf(63); end if; if cs_rising='1' then case cmd is when "10000000"=> a0_buf<=rx_buf(31 downto 0); when "10000001"=> a1_buf<=rx_buf(31 downto 0); when "10000010"=> b0_buf<=rx_buf(31 downto 0); when "10000011"=> b1_buf<=rx_buf(31 downto 0); when others=> null; end case; end if; if sck_rising='1' and cs_wire='0' then if mosi_pos=7 then cmd<=(rx_buf(6 downto 0) & mosi_wire); end if; rx_buf<=(rx_buf(62 downto 0) & mosi_wire); tx_buf<=(tx_buf(62 downto 0) & '0'); mosi_pos<=mosi_pos+1; end if; if sck_falling='1' and cs_wire='0' then if mosi_pos=8 then case cmd is when "00000000"=> tx_buf(63 downto 32)<=a0_buf; when "00000001"=> tx_buf(63 downto 32)<=a1_buf; when "00000010"=> tx_buf(63 downto 32)<=b0_buf; when "00000011"=> tx_buf(63 downto 32)<=b1_buf; when others=> null; end case; case cmd is when "00000000"=> miso_wire<=a0_buf(31); when "00000001"=> miso_wire<=a1_buf(31); when "00000010"=> miso_wire<=b0_buf(31); when "00000011"=> miso_wire<=b1_buf(31); when others=> null; end case; else miso_wire<=tx_buf(63); end if; miso_pos<=miso_pos+1; end if; end if; end process; end;
これで、とりあえず、Analysis&Synthesisをすると、ErrorもWarningもでない。で、Tools-->Run Simulation Tool-->RTL SimulationでModelSimを起動。、、、ていうかこのあたりの操作は、SPIハードをFPGAで(2)、SPIハードをFPGAで(3)参照で。
そして、テストベンチ。
tb.vhd
library ieee; use ieee.std_logic_1164.all; -- use ieee.std_logic_unsigned.all; entity my_spi_slave_tb is end my_spi_slave_tb; architecture sim of my_spi_slave_tb is component my_spi_slave is port ( cs : in std_logic; sck : in std_logic; mosi : in std_logic; miso : out std_logic; a0 : out std_logic_vector(31 downto 0); a1 : out std_logic_vector(31 downto 0); b0 : out std_logic_vector(31 downto 0); b1 : out std_logic_vector(31 downto 0); i_clk : in std_logic ); end component; signal clksys : std_logic:='0'; constant STEPSYS : TIME := 6.25 ns; signal cs_tb : std_logic:='1'; signal sck_tb : std_logic:='0'; signal mosi_tb : std_logic:='0'; signal miso_tb : std_logic:='0'; signal a0_tb : std_logic_vector(31 downto 0):=X"3F800000"; signal a1_tb : std_logic_vector(31 downto 0):=X"BF7814CD"; signal b0_tb : std_logic_vector(31 downto 0):=X"3C7D6652"; signal b1_tb : std_logic_vector(31 downto 0):=X"3C7D6652"; signal spitxbuf : std_logic_vector(39 downto 0):=X"0000000000"; signal spirxbuf : std_logic_vector(39 downto 0):=X"0000000000"; signal a0 : std_logic_vector(31 downto 0); signal a1 : std_logic_vector(31 downto 0); signal b0 : std_logic_vector(31 downto 0); signal b1 : std_logic_vector(31 downto 0); begin my_spi_slave_inst : component my_spi_slave port map( cs=>cs_tb, sck=>sck_tb, mosi=>mosi_tb, miso=>miso_tb, a0=>a0, a1=>a1, b0=>b0, b1=>b1, i_clk=>clksys ); process begin cs_tb<='1'; spitxbuf<=X"80"&a0_tb; wait for 100 us; cs_tb<='0'; sck_tb<='0'; mosi_tb<=spitxbuf(39); for i in 0 to 39 loop wait for 1 us; sck_tb<='1'; spirxbuf(0)<=miso_tb; spitxbuf(39 downto 0)<=spitxbuf(38 downto 0)&'0'; wait for 1 us; sck_tb<='0'; mosi_tb<=spitxbuf(39); spirxbuf(39 downto 0)<=spirxbuf(38 downto 0)&'0'; end loop; wait for 1 us; cs_tb<='1'; spitxbuf<=X"81"&a1_tb; wait for 3 us; cs_tb<='0'; sck_tb<='0'; mosi_tb<=spitxbuf(39); for i in 0 to 39 loop wait for 1 us; sck_tb<='1'; spirxbuf(0)<=miso_tb; spitxbuf(39 downto 0)<=spitxbuf(38 downto 0)&'0'; wait for 1 us; sck_tb<='0'; mosi_tb<=spitxbuf(39); spirxbuf(39 downto 0)<=spirxbuf(38 downto 0)&'0'; end loop; wait for 1 us; cs_tb<='1'; spitxbuf<=X"82"&b0_tb; wait for 3 us; cs_tb<='0'; sck_tb<='0'; mosi_tb<=spitxbuf(39); for i in 0 to 39 loop wait for 1 us; sck_tb<='1'; spirxbuf(0)<=miso_tb; spitxbuf(39 downto 0)<=spitxbuf(38 downto 0)&'0'; wait for 1 us; sck_tb<='0'; mosi_tb<=spitxbuf(39); spirxbuf(39 downto 0)<=spirxbuf(38 downto 0)&'0'; end loop; wait for 1 us; cs_tb<='1'; spitxbuf<=X"83"&b1_tb; wait for 3 us; cs_tb<='0'; sck_tb<='0'; mosi_tb<=spitxbuf(39); for i in 0 to 39 loop wait for 1 us; sck_tb<='1'; spirxbuf(0)<=miso_tb; spitxbuf(39 downto 0)<=spitxbuf(38 downto 0)&'0'; wait for 1 us; sck_tb<='0'; mosi_tb<=spitxbuf(39); spirxbuf(39 downto 0)<=spirxbuf(38 downto 0)&'0'; end loop; wait for 1 us; cs_tb<='1'; wait for 100 us; assert false report "Finish" severity failure; end process; clksys <= not(clksys) after STEPSYS/2; end;
doファイル。
my_spi_slave_run_msim_rtl_vhdl.do
transcript on if {[file exists rtl_work]} { vdel -lib rtl_work -all } vlib rtl_work vmap work rtl_work vcom -93 -work work {C:/Users/hoge/Documents/Quartus/work_Prime18.1/my_spi_slave_101/my_spi_slave.vhd} vcom -93 -work work {C:/Users/hoge/Documents/Quartus/work_Prime18.1/my_spi_slave_101/simulation/modelsim/tb.vhd} vsim -L altera_mf_ver -c work.my_spi_slave_tb add wave -hex sim:/my_spi_slave_tb/clksys add wave -position end sim:/my_spi_slave_tb/cs_tb add wave -position end sim:/my_spi_slave_tb/sck_tb add wave -position end sim:/my_spi_slave_tb/mosi_tb add wave -position end sim:/my_spi_slave_tb/miso_tb add wave -radix hexadecimal -position end sim:/my_spi_slave_tb/a0 add wave -radix hexadecimal -position end sim:/my_spi_slave_tb/a1 add wave -radix hexadecimal -position end sim:/my_spi_slave_tb/b0 add wave -radix hexadecimal -position end sim:/my_spi_slave_tb/b1 add wave -radix hexadecimal -position end sim:/my_spi_slave_tb/my_spi_slave_inst/cmd log -r * run -all
で、Transcryptウィンドウで、
do my_spi_slave_run_msim_rtl_vhdl.do
ってすると、
ってことで、うまくいったっぽい。
デバイスメーカーのツールはいろいろやれることが多くてむしろ邪魔くさいってことも多いけど、慣れればこれはこれで使いやすいんだろうなー、、、
ところで、QuartusPrimeの最新版(現時点で22.1.1)でNios開発するならWSLのUbuntu 18.04 LTSが要件ってやつ、何とかならんのかね、、、WSLには複数のディストリビューションは入れれんから、とんでもなく狭い範囲に拘束されるわけで。なので今でもうちはQuartusPrime18.1.0。
コメントをお書きください