VHDLでフィルタを作ってみます。これまでやってきたことを組み合わせて、こんな感じで実装するのを目指します。
実はこいつら(中身の部品)はほぼこれまでに作ってきたものをそのまま持ってきています。
my_1iir_elementはVHDLで1次IIRフィルタ(1)で作ったものですが、i_resetってのを追加しています。i_resetのrising edgeでy(n-1), x(n-1)を強制的にそれぞれ0.0, 0にします。
clk_genはi_en='1'になった瞬間o_resetにパルスを出力し、その後32クロックごとにo_startにパルスを出します。
clk_gen.vhd(今回作成)
library ieee; use ieee.std_logic_1164.all; -- use ieee.std_logic_unsigned.all; entity clk_gen is port ( i_en : in std_logic; o_start : out std_logic; o_reset : out std_logic; i_clk : in std_logic ); end clk_gen; architecture ppl_type of clk_gen is type t_state is (STATE_IDLE,STATE_RESET,STATE_RUN); signal state : t_state := STATE_IDLE; signal state_num : integer range 0 to 7 := 0; signal i_en_pres : std_logic:='0'; signal i_en_prev : std_logic:='0'; signal i_en_rising : std_logic:='0'; signal i_en_falling : std_logic:='0'; constant clk_count_max : integer range 0 to 63:=31; signal clk_counter : integer range 0 to 63:=0; signal outp_reset : std_logic:='0'; signal outp_start : std_logic:='0'; begin i_en_pres<=i_en; i_en_rising<='1' when (i_en_prev='0' and i_en_pres='1') else '0'; i_en_falling<='1' when (i_en_prev='1' and i_en_pres='0') else '0'; o_reset<=outp_reset; o_start<=outp_start; process(i_clk,i_en_rising,state)begin if i_clk'event and i_clk='1' then i_en_prev<=i_en; if i_en_falling='1' then state<=STATE_IDLE; state_num<=0; outp_reset<='0'; outp_start<='0'; end if; if i_en_rising='1' and state=STATE_IDLE then outp_reset<='1'; state<=STATE_RESET; state_num<=1; end if; if state=STATE_RESET then outp_reset<='0'; clk_counter<=0; state<=STATE_RUN; state_num<=2; end if; if state=STATE_RUN then if clk_counter=clk_count_max then clk_counter<=0; outp_start<='1'; else clk_counter<=clk_counter+1; outp_start<='0'; end if; end if; end if; end process; end;
my_1iir_element.vhd(前回から修正あり)
library ieee; use ieee.std_logic_1164.all; -- use ieee.std_logic_unsigned.all; entity my_1iir_element is port ( i_1bit : in std_logic; o_32bit : out std_logic_vector(31 downto 0); i_start : in std_logic; i_reset : in std_logic; o_complete : out std_logic; i_a0 : in std_logic_vector(31 downto 0); i_a1 : in std_logic_vector(31 downto 0); i_b0 : in std_logic_vector(31 downto 0); i_b1 : in std_logic_vector(31 downto 0); i_clk : in std_logic ); end my_1iir_element; architecture ppl_type of my_1iir_element is signal xn : std_logic:='0'; signal xnm1 : std_logic:='0'; signal yn : std_logic_vector(31 downto 0):=X"00000000"; signal ynm1 : std_logic_vector(31 downto 0):=X"00000000"; constant fzero : std_logic_vector(31 downto 0):=X"00000000"; constant fone : std_logic_vector(31 downto 0):=X"3F800000"; signal b_index : std_logic_vector(31 downto 0):=X"00000000"; signal a_index : std_logic_vector(31 downto 0):=X"00000000"; signal i_start_prev : std_logic:='0'; signal i_start_pres : std_logic:='0'; signal i_start_rising : std_logic:='0'; signal i_reset_prev : std_logic:='0'; signal i_reset_pres : std_logic:='0'; signal i_reset_rising : std_logic:='0'; signal indicator_complete : std_logic:='0'; type t_state is (STATE_IDLE,STATE_SET1, STATE_WAIT1,STATE_SET2, STATE_WAIT2, STATE_WAIT3, STATE_DONE); signal state : t_state := STATE_IDLE; signal state_num : integer range 0 to 15 := 0; constant fpu_add : std_logic_vector(2 downto 0):="000"; constant fpu_sub : std_logic_vector(2 downto 0):="001"; constant fpu_mul : std_logic_vector(2 downto 0):="010"; constant fpu_rmode : std_logic_vector(1 downto 0):="00"; signal outp_32bit : std_logic_vector(31 downto 0):=X"00000000"; component fpu port ( clk_i : in std_logic; opa_i : in std_logic_vector(31 downto 0); opb_i : in std_logic_vector(31 downto 0); fpu_op_i : in std_logic_vector(2 downto 0); rmode_i : in std_logic_vector(1 downto 0); output_o : out std_logic_vector(31 downto 0); ine_o : out std_logic; overflow_o : out std_logic; underflow_o : out std_logic; div_zero_o : out std_logic; inf_o : out std_logic; zero_o : out std_logic; qnan_o : out std_logic; snan_o : out std_logic; start_i : in std_logic; ready_o : out std_logic ); end component; signal opa_i_1 : std_logic_vector(31 downto 0):=X"00000000"; signal opb_i_1 : std_logic_vector(31 downto 0):=X"00000000"; signal fpu_op_i_1 : std_logic_vector(2 downto 0):="000"; signal output_o_1 : std_logic_vector(31 downto 0); signal start_i_1 : std_logic:='0'; signal ready_o_1 : std_logic ; signal ine_o_1, overflow_o_1, underflow_o_1, div_zero_o_1, inf_o_1, zero_o_1, qnan_o_1, snan_o_1: std_logic; signal comp_1: std_logic:='0'; signal opa_i_2 : std_logic_vector(31 downto 0):=X"00000000"; signal opb_i_2 : std_logic_vector(31 downto 0):=X"00000000"; signal fpu_op_i_2 : std_logic_vector(2 downto 0):="000"; signal output_o_2 : std_logic_vector(31 downto 0); signal start_i_2 : std_logic:='0'; signal ready_o_2 : std_logic ; signal ine_o_2, overflow_o_2, underflow_o_2, div_zero_o_2, inf_o_2, zero_o_2, qnan_o_2, snan_o_2: std_logic; signal comp_2: std_logic:='0'; begin -- instantiate fpu i_fpu_1: fpu port map ( clk_i => i_clk, opa_i => opa_i_1, opb_i => opb_i_1, fpu_op_i => fpu_op_i_1, rmode_i => fpu_rmode, output_o => output_o_1, ine_o => ine_o_1, overflow_o => overflow_o_1, underflow_o => underflow_o_1, div_zero_o => div_zero_o_1, inf_o => inf_o_1, zero_o => zero_o_1, qnan_o => qnan_o_1, snan_o => snan_o_1, start_i => start_i_1, ready_o => ready_o_1 ); i_fpu_2: fpu port map ( clk_i => i_clk, opa_i => opa_i_2, opb_i => opb_i_2, fpu_op_i => fpu_op_i_2, rmode_i => fpu_rmode, output_o => output_o_2, ine_o => ine_o_2, overflow_o => overflow_o_2, underflow_o => underflow_o_2, div_zero_o => div_zero_o_2, inf_o => inf_o_2, zero_o => zero_o_2, qnan_o => qnan_o_2, snan_o => snan_o_2, start_i => start_i_2, ready_o => ready_o_2 ); i_start_pres<=i_start; i_start_rising<='1' when (i_start_prev='0' and i_start_pres='1') else '0'; o_complete<=indicator_complete; i_reset_pres<=i_reset; i_reset_rising<='1' when (i_reset_prev='0' and i_reset_pres='1') else '0'; o_32bit<=outp_32bit; process (i_clk,i_start_rising,state) begin if i_clk'event and i_clk='1' then i_start_prev<=i_start; i_reset_prev<=i_reset; if i_reset_rising='1' then state<=STATE_IDLE; xnm1<='0'; ynm1<=fzero; end if; if i_start_rising='1' and state=STATE_IDLE then -- b_0+b_1 opa_i_1<=i_b0; opb_i_1<=i_b1; fpu_op_i_1<=fpu_add; start_i_1<='1'; comp_1<='0'; -- a_1*y_{n-1} opa_i_2<=i_a1; opb_i_2<=ynm1; fpu_op_i_2<=fpu_mul; start_i_2<='1'; comp_2<='0'; xn<=i_1bit; state<=STATE_SET1; state_num<=1; end if; if state=STATE_SET1 then start_i_1<='0'; start_i_2<='0'; state<=STATE_WAIT1; state_num<=2; end if; if state=STATE_WAIT1 then if ready_o_1='1' then comp_1<='1'; b_index<=output_o_1; end if; if ready_o_2='1' then comp_2<='1'; a_index<=output_o_2; end if; if comp_1='1' and comp_2='1' then if xnm1='0' and xn='0' then opa_i_1<=fzero; elsif xnm1='0' and xn='1' then opa_i_1<=i_b0; elsif xnm1='1' and xn='0' then opa_i_1<=i_b1; elsif xnm1='1' and xn='1' then opa_i_1<=b_index; end if; opb_i_1<=a_index; fpu_op_i_1<=fpu_sub; start_i_1<='1'; comp_1<='0'; state<=STATE_SET2; state_num<=3; end if; end if; if state=STATE_SET2 then start_i_1<='0'; state<=STATE_WAIT2; state_num<=4; end if; if state=STATE_WAIT2 then if ready_o_1='1' then comp_1<='1'; yn<=output_o_1; outp_32bit<=output_o_1; state<=STATE_DONE; state_num<=5; indicator_complete<='1'; end if; end if; if state=STATE_DONE then indicator_complete<='0'; xnm1<=xn; ynm1<=yn; state<=STATE_IDLE; state_num<=0; end if; end if; end process; end;
my_1iir_top.vhd(配線しただけ)
library ieee; use ieee.std_logic_1164.all; -- use ieee.std_logic_unsigned.all; entity my_1iir_top is port ( i_1bit : in std_logic; i_en : in std_logic; cs : in std_logic; sck : in std_logic; mosi : in std_logic; miso : out std_logic; o_ui32 : out std_logic_vector(31 downto 0); i_clk : in std_logic ); end my_1iir_top; architecture ppl_type of my_1iir_top is component clk_gen port( i_en : in std_logic; o_start : out std_logic; o_reset : out std_logic; i_clk : in std_logic );end component; 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) );end component; component my_1iir_element is port ( i_1bit : in std_logic; o_32bit : out std_logic_vector(31 downto 0); i_start : in std_logic; i_reset : in std_logic; o_complete : out std_logic; i_a0 : in std_logic_vector(31 downto 0); i_a1 : in std_logic_vector(31 downto 0); i_b0 : in std_logic_vector(31 downto 0); i_b1 : in std_logic_vector(31 downto 0); i_clk : in std_logic );end component; component Float2UI32 is port ( i_src : in std_logic_vector(31 downto 0); o_ui32 : out std_logic_vector(31 downto 0) );end component; signal internal_wire_start : std_logic:='0'; signal internal_wire_reset : std_logic:='0'; signal internal_wire_complete : std_logic:='0'; signal internal_wires_a0 : std_logic_vector(31 downto 0):=X"00000000"; signal internal_wires_a1 : std_logic_vector(31 downto 0):=X"00000000"; signal internal_wires_b0 : std_logic_vector(31 downto 0):=X"00000000"; signal internal_wires_b1 : std_logic_vector(31 downto 0):=X"00000000"; signal internal_wires_float32 : std_logic_vector(31 downto 0):=X"00000000"; begin clk_gen_inst: clk_gen port map( i_en=>i_en, o_start=>internal_wire_start, o_reset=>internal_wire_reset, i_clk=>i_clk ); my_spi_slave_inst: my_spi_slave port map( cs=>cs, sck=>sck, mosi=>mosi, miso=>miso, a0=>internal_wires_a0, a1=>internal_wires_a1, b0=>internal_wires_b0, b1=>internal_wires_b1 ); my_1iir_element_inst: my_1iir_element port map( i_1bit=>i_1bit, o_32bit=>internal_wires_float32, i_start=>internal_wire_start, i_reset=>internal_wire_reset, o_complete=>internal_wire_complete, i_a0=>internal_wires_a0, i_a1=>internal_wires_a1, i_b0=>internal_wires_b0, i_b1=>internal_wires_b1, i_clk=>i_clk ); Float2UI32_inst: Float2UI32 port map( i_src=>internal_wires_float32, o_ui32=>o_ui32 ); end;
my_1iir_tb.vhd(SPIで係数を送って、その後波形を出力)
library ieee; use ieee.std_logic_1164.all; -- use ieee.std_logic_unsigned.all; entity my_1iir_tb is end my_1iir_tb; architecture sim of my_1iir_tb is component my_1iir_top is port ( i_1bit : in std_logic; i_en : in std_logic; cs : in std_logic; sck : in std_logic; mosi : in std_logic; miso : out std_logic; o_ui32 : 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 i_1bit_tb : std_logic:='0'; signal o_32bit_tb : std_logic_vector(31 downto 0); signal i_en_tb : std_logic:='0'; 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 clk_counter_bb : integer range 0 to 65535:=0; signal spitxbuf : std_logic_vector(39 downto 0):=X"0000000000"; signal spirxbuf : std_logic_vector(39 downto 0):=X"0000000000"; begin my_1iir_inst : component my_1iir_top port map( i_1bit=>i_1bit_tb, i_en=>i_en_tb, cs=>cs_tb, sck=>sck_tb, mosi=>mosi_tb, miso=>miso_tb, o_ui32=>o_32bit_tb, i_clk=>clksys ); process begin cs_tb<='1'; spitxbuf<=X"80"&a0_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"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 3 us; i_en_tb<='1'; wait for 500 us; assert false report "Finish" severity failure; end process; clksys <= not(clksys) after STEPSYS/2; process(clksys)begin if clksys'event and clksys='1' then if i_en_tb='1' then clk_counter_bb<=clk_counter_bb+1; if clk_counter_bb=8000 then clk_counter_bb<=0; i_1bit_tb<=not(i_1bit_tb); end if; end if; end if; end process; end;
Makefile(基本的に今までと同じ。ソースが多くなったので分割。)
VHDLC=/usr/bin/ghdl SRC_FPU=fpu_v19/fpupack.vhd fpu_v19/pre_norm_addsub.vhd fpu_v19/addsub_28.vhd fpu_v19/post_norm_addsub.vhd fpu_v19/pre_norm_mul.vhd fpu_v19/mul_24.vhd fpu_v19/serial_mul.vhd fpu_v19/post_norm_mul.vhd fpu_v19/pre_norm_div.vhd fpu_v19/serial_div.vhd fpu_v19/post_norm_div.vhd fpu_v19/pre_norm_sqrt.vhd fpu_v19/sqrt.vhd fpu_v19/post_norm_sqrt.vhd fpu_v19/comppack.vhd fpu_v19/fpu.vhd SRC=clk_gen.vhd float2uint.vhd my_1iir_element.vhd my_1iir_top.vhd my_spi_slave.vhd TBSRC=my_1iir_tb.vhd VCD=my_1iir.vcd FST=my_1iir.fst SIMRTL=my_1iir_tb all : @make comp @make tb @make tb_e @make vcd comp : $(VHDLC) -a --ieee=synopsys -fexplicit $(SRC) $(SRC_FPU) tb : $(VHDLC) -a --ieee=synopsys -fexplicit $(TBSRC) tb_e : $(VHDLC) -e --ieee=synopsys -fexplicit $(SIMRTL) vcd : $(VHDLC) -r --ieee=synopsys -fexplicit $(SIMRTL) --vcd=$(VCD)
ということで、あっさりできました。まぁ部品はできていたわけなので。一方、テストベンチはどうしようか悩んだ。普通にデバイスを書くように書くのか、テストベンチっぽく書く(センシティビティなしのprocess)のか、、、結果、なんとなくミックスになっていて、違和感もありますが、素人なのでしょせんこんなもんです。
SPIの部分。テストベンチからの通信が内部の配線に反映されています。
32ビット浮動小数点の16ビット符号なし整数(レジスタとしては32ビット幅にしている)への変換部分。
0.015466*65536=1013.579776
なので、あってます。
全体。それらしい波形が出ています。
とはいえ、シミュレーション中に
../../src/synopsys/std_logic_arith.vhdl:255:20:@339271875ps:(assertion warning): There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es).
ってwarningが1クロックごとに出てきてた。どこかにやってはいけない計算があるんだと思うけど、このメッセージじゃどこでこれが起こっているのかわからんな。QuartusとかDiamondとかならどこか教えてくれるかも。
ここまできたので、この後は実デバイスへの実装を検討します。休みが終わるのでやれるかどうかわからんけど。ていうか、半年くらい休みたい。
コメントをお書きください