AXIのWriteを作った
AXI-GPIOは、クロックやストローブがなくアドレスもないので、複数のレジスタに書き込めるようにしたり、ハンドシェイクをするにはGPIOのどこかのbitを使うということになるのですが、そんなことするくらいなら、AXI-GPIOではなくAXI Slaveそのものを使ったほうがよいと気が付きました。
そこで、ZYNQ用にAXI Slaveの受け側を作ってみることにしました。
まず、AXIのWriteを受け取れるようにしようと思います。
AWREADY(アドレス受信可)とWREADY(データ受信可)を'1'に固定し、データを受け取ったらBVALIDを'1'にします。
ソフトでは
volatile unsigned long *tmp = (volatile unsigned long *)(XPAR_AXI_EXT_SLAVE_CONN_0_S_AXI_RNG00_BASEADDR);
*tmp = count++;
と、ポインタでメモリアクセスします。
すると、
こんな感じで、AWVALID(アドレス出力有効)とWVALID(データ出力有効)が同時に出ていました。
AWVALIDとWVALIDが必ず同時にでるかどうか確証が得られません。場合によっては、AWVALIDが出てから数クロックしてからWVALIDが出るということがあるかもしれません。
そのため、アドレスをデコードしてから、そのあとでWVALIDを受け取るようにしたいのですが、同時に出てしまうとそうもいきません。そこで、WREADYを制御することにしました。
次に作った波形がこれ。
AWVALIDが出てアドレスを受け取ったら、WREADYを上げるようにしました。
これでアドレス→データという順序で確実に受け取れます。
さて、ソフトでlong long型のポインタでアクセスしてみると、
volatile unsigned long long *tmpll = (volatile unsigned long long*)(XPAR_AXI_EXT_SLAVE_CONN_0_S_AXI_RNG00_BASEADDR);
*tmpll = count++;
このようにバースト転送が発行されました。しかし、書き込みアドレスAWADDRは先頭のアドレスを指したままで自動的には更新されていないようです。
そこで、アドレスはZYNQが出してくるAWADDRをそのまま使うのではなく、いったん自分の信号としてキャプチャしてから、使うようにしました。
最終的な波形はこちら。まず、シングルライトの場合。3サイクルで処理しています。
次にバーストライトの場合。4サイクルでアクセスしています。
また、アドレスも自動的にインクリメントするようにしました。これで、シングル転送でもバースト転送でも受信できます。それに処理中はAWVALIDを下げておくようにしているので、他のトランザクションが同時にきても排他的にアクセスできるでしょう。
最終的に出来上がったコードをこちらに記載しておきます。
process(plclk) begin if(plclk'event and plclk = '1') then
if(axis_reset = '0') then -- リセットで、アドレスはレディ、データは非レディに設定
axis_WREADY_i <= '0';
axis_AWREADY_i <= '1';
else
if(axis_AWVALID_o = '1') then -- アドレスが来たらキャプチャ
axis_addr <= axis_AWADDR_o;
axis_BID_i <= axis_AWID_o; -- BIDにはAWIDをコピー
elsif(axis_WREADY_i = '1') and (axis_WVALID_o = '1') then
axis_addr <= axis_addr + 4; -- データを受け取ったらアドレスを4増やす
end if; if(axis_AWVALID_o = '1') then -- アドレスを受け取ったら
axis_WREADY_i <= '1'; -- データを受け取りレディ
axis_AWREADY_i <= '0'; -- アドレスはもう受け取らない
elsif(axis_WREADY_i = '1') and (axis_WVALID_o = '1') and (axis_WLAST_o = '1') then -- 最後のデータを受け取ったら
axis_WREADY_i <= '0'; -- データはもう受け取らない
elsif(axis_BVALID_i = '1') and (axis_BREADY_o = '1') then -- レスポンスを返したら
axis_AWREADY_i <= '1'; -- アドレスを再び受け取る
end if; -- 最後のデータを受け取ったら
if(axis_WREADY_i = '1') and (axis_WVALID_o = '1') and (axis_WLAST_o = '1') then
axis_BVALID_i <= '1'; -- レスポンスを返す
axis_BRESP_i <= "00"; -- 正常終了の意味?
elsif(axis_BREADY_o = '1') then -- レスポンスを受け取ってくれた
axis_BVALID_i <= '0'; -- レスポンスを下げる
end if; if(axis_WREADY_i = '1') and (axis_WVALID_o = '1') then -- データを受け取った
case axis_addr(7 downto 0) is
when x"00" => -- addr xxxxxx00
if(axis_WSTRB_o(0) = '1') then
led_op <= axis_WDATA_o(7 downto 0);
end if;
when x"04" => -- addr xxxxxx04
reg_04 <= axis_WDATA_o(7 downto 0);
when others =>
end case;
end if;
end if;
end if;
end process;
cpu_i : cpu
port map (
processing_system7_0_MIO => MIO,
processing_system7_0_PS_SRSTB_pin => PS_SRSTB_pin,
processing_system7_0_PS_CLK_pin => PS_CLK_pin,
processing_system7_0_PS_PORB_pin => PS_PORB_pin,
processing_system7_0_DDR_Clk => DDR_Clk,
processing_system7_0_DDR_Clk_n => DDR_Clk_n,
processing_system7_0_DDR_CKE => DDR_CKE,
processing_system7_0_DDR_CS_n => DDR_CS_n,
processing_system7_0_DDR_RAS_n => DDR_RAS_n,
processing_system7_0_DDR_CAS_n => DDR_CAS_n,
processing_system7_0_DDR_WEB_pin => DDR_WEB,
processing_system7_0_DDR_BankAddr => DDR_BankAddr,
processing_system7_0_DDR_Addr => DDR_Addr,
processing_system7_0_DDR_ODT => DDR_ODT,
processing_system7_0_DDR_DRSTB => DDR_DRSTB,
processing_system7_0_DDR_DQ => DDR_DQ,
processing_system7_0_DDR_DM => DDR_DM,
processing_system7_0_DDR_DQS => DDR_DQS,
processing_system7_0_DDR_DQS_n => DDR_DQS_n,
processing_system7_0_DDR_VRN => DDR_VRN,
processing_system7_0_DDR_VRP => DDR_VRP,
processing_system7_0_FCLK_CLK0_pin => plclk,
processing_system7_0_M_AXI_GP1_ARESETN_pin => axis_reset,
axi_gpout_GPIO_IO_O_pin => gpout,
axi_gpin_GPIO_IO_I_pin => gpin,
axi_ext_slave_conn_0_M_AXI_AWID_pin => axis_AWID_o,
axi_ext_slave_conn_0_M_AXI_AWADDR_pin => axis_AWADDR_o,
axi_ext_slave_conn_0_M_AXI_AWLEN_pin => axis_AWLEN_o,
axi_ext_slave_conn_0_M_AXI_AWSIZE_pin => axis_AWSIZE_o,
axi_ext_slave_conn_0_M_AXI_AWBURST_pin => axis_AWBURST_o,
axi_ext_slave_conn_0_M_AXI_AWVALID_pin => axis_AWVALID_o,
axi_ext_slave_conn_0_M_AXI_AWREADY_pin => axis_AWREADY_i,
axi_ext_slave_conn_0_M_AXI_WDATA_pin => axis_WDATA_o,
axi_ext_slave_conn_0_M_AXI_WSTRB_pin => axis_WSTRB_o,
axi_ext_slave_conn_0_M_AXI_WLAST_pin => axis_WLAST_o,
axi_ext_slave_conn_0_M_AXI_WVALID_pin => axis_WVALID_o,
axi_ext_slave_conn_0_M_AXI_WREADY_pin => axis_WREADY_i,
axi_ext_slave_conn_0_M_AXI_BID_pin => axis_BID_i,
axi_ext_slave_conn_0_M_AXI_BRESP_pin => axis_BRESP_i,
axi_ext_slave_conn_0_M_AXI_BVALID_pin => axis_BVALID_i,
axi_ext_slave_conn_0_M_AXI_BREADY_pin => axis_BREADY_o,
axi_ext_slave_conn_0_M_AXI_ARID_pin => axis_ARID_o,
axi_ext_slave_conn_0_M_AXI_ARADDR_pin => axis_ARADDR_o,
axi_ext_slave_conn_0_M_AXI_ARLEN_pin => axis_ARLEN_o,
axi_ext_slave_conn_0_M_AXI_ARSIZE_pin => axis_ARSIZE_o,
axi_ext_slave_conn_0_M_AXI_ARBURST_pin => axis_ARBURST_o,
axi_ext_slave_conn_0_M_AXI_ARVALID_pin => axis_ARVALID_o,
axi_ext_slave_conn_0_M_AXI_ARREADY_pin => axis_ARREADY_i,
axi_ext_slave_conn_0_M_AXI_RID_pin => axis_RID_i,
axi_ext_slave_conn_0_M_AXI_RDATA_pin => axis_RDATA_i,
axi_ext_slave_conn_0_M_AXI_RRESP_pin => axis_RRESP_i,
axi_ext_slave_conn_0_M_AXI_RLAST_pin => axis_RLAST_i,
axi_ext_slave_conn_0_M_AXI_RVALID_pin => axis_RVALID_i,
axi_ext_slave_conn_0_M_AXI_RREADY_pin => axis_RREADY_o
);
宣言部はこんな感じです
component cpu is
port (
processing_system7_0_MIO : inout std_logic_vector(53 downto 0);
processing_system7_0_PS_SRSTB_pin : in std_logic;
processing_system7_0_PS_CLK_pin : in std_logic;
processing_system7_0_PS_PORB_pin : in std_logic;
processing_system7_0_DDR_Clk : inout std_logic;
processing_system7_0_DDR_Clk_n : inout std_logic;
processing_system7_0_DDR_CKE : inout std_logic;
processing_system7_0_DDR_CS_n : inout std_logic;
processing_system7_0_DDR_RAS_n : inout std_logic;
processing_system7_0_DDR_CAS_n : inout std_logic;
processing_system7_0_DDR_WEB_pin : out std_logic;
processing_system7_0_DDR_BankAddr : inout std_logic_vector(2 downto 0);
processing_system7_0_DDR_Addr : inout std_logic_vector(14 downto 0);
processing_system7_0_DDR_ODT : inout std_logic;
processing_system7_0_DDR_DRSTB : inout std_logic;
processing_system7_0_DDR_DQ : inout std_logic_vector(31 downto 0);
processing_system7_0_DDR_DM : inout std_logic_vector(3 downto 0);
processing_system7_0_DDR_DQS : inout std_logic_vector(3 downto 0);
processing_system7_0_DDR_DQS_n : inout std_logic_vector(3 downto 0);
processing_system7_0_DDR_VRN : inout std_logic;
processing_system7_0_DDR_VRP : inout std_logic;
processing_system7_0_FCLK_CLK0_pin : out std_logic;
processing_system7_0_M_AXI_GP1_ARESETN_pin : out std_logic;
axi_gpout_GPIO_IO_O_pin : out std_logic_vector(31 downto 0);
axi_gpin_GPIO_IO_I_pin : in std_logic_vector(31 downto 0);
axi_ext_slave_conn_0_M_AXI_AWID_pin : out std_logic_vector(11 downto 0);
axi_ext_slave_conn_0_M_AXI_AWADDR_pin : out std_logic_vector(31 downto 0);
axi_ext_slave_conn_0_M_AXI_AWLEN_pin : out std_logic_vector(7 downto 0);
axi_ext_slave_conn_0_M_AXI_AWSIZE_pin : out std_logic_vector(2 downto 0);
axi_ext_slave_conn_0_M_AXI_AWBURST_pin : out std_logic_vector(1 downto 0);
axi_ext_slave_conn_0_M_AXI_AWVALID_pin : out std_logic;
axi_ext_slave_conn_0_M_AXI_AWREADY_pin : in std_logic;
axi_ext_slave_conn_0_M_AXI_WDATA_pin : out std_logic_vector(31 downto 0);
axi_ext_slave_conn_0_M_AXI_WSTRB_pin : out std_logic_vector(3 downto 0);
axi_ext_slave_conn_0_M_AXI_WLAST_pin : out std_logic;
axi_ext_slave_conn_0_M_AXI_WVALID_pin : out std_logic;
axi_ext_slave_conn_0_M_AXI_WREADY_pin : in std_logic;
axi_ext_slave_conn_0_M_AXI_BID_pin : in std_logic_vector(11 downto 0);
axi_ext_slave_conn_0_M_AXI_BRESP_pin : in std_logic_vector(1 downto 0);
axi_ext_slave_conn_0_M_AXI_BVALID_pin : in std_logic;
axi_ext_slave_conn_0_M_AXI_BREADY_pin : out std_logic;
axi_ext_slave_conn_0_M_AXI_ARID_pin : out std_logic_vector(11 downto 0);
axi_ext_slave_conn_0_M_AXI_ARADDR_pin : out std_logic_vector(31 downto 0);
axi_ext_slave_conn_0_M_AXI_ARLEN_pin : out std_logic_vector(7 downto 0);
axi_ext_slave_conn_0_M_AXI_ARSIZE_pin : out std_logic_vector(2 downto 0);
axi_ext_slave_conn_0_M_AXI_ARBURST_pin : out std_logic_vector(1 downto 0);
axi_ext_slave_conn_0_M_AXI_ARVALID_pin : out std_logic;
axi_ext_slave_conn_0_M_AXI_ARREADY_pin : in std_logic;
axi_ext_slave_conn_0_M_AXI_RID_pin : in std_logic_vector(11 downto 0);
axi_ext_slave_conn_0_M_AXI_RDATA_pin : in std_logic_vector(31 downto 0);
axi_ext_slave_conn_0_M_AXI_RRESP_pin : in std_logic_vector(1 downto 0);
axi_ext_slave_conn_0_M_AXI_RLAST_pin : in std_logic;
axi_ext_slave_conn_0_M_AXI_RVALID_pin : in std_logic;
axi_ext_slave_conn_0_M_AXI_RREADY_pin : out std_logic
);
end component; attribute BOX_TYPE : STRING;
attribute BOX_TYPE of cpu : component is "user_black_box"; signal axis_AWID_o : std_logic_vector(11 downto 0);
signal axis_AWADDR_o : std_logic_vector(31 downto 0);
signal axis_AWLEN_o : std_logic_vector(7 downto 0);
signal axis_AWSIZE_o : std_logic_vector(2 downto 0);
signal axis_AWBURST_o : std_logic_vector(1 downto 0);
signal axis_AWVALID_o : std_logic;
signal axis_AWREADY_i : std_logic;
signal axis_WDATA_o : std_logic_vector(31 downto 0);
signal axis_WSTRB_o : std_logic_vector(3 downto 0);
signal axis_WLAST_o : std_logic;
signal axis_WVALID_o : std_logic;
signal axis_WREADY_i : std_logic;
signal axis_BID_i : std_logic_vector(11 downto 0);
signal axis_BRESP_i : std_logic_vector(1 downto 0);
signal axis_BVALID_i : std_logic;
signal axis_BREADY_o : std_logic;
signal axis_ARID_o : std_logic_vector(11 downto 0);
signal axis_ARADDR_o : std_logic_vector(31 downto 0);
signal axis_ARLEN_o : std_logic_vector(7 downto 0);
signal axis_ARSIZE_o : std_logic_vector(2 downto 0);
signal axis_ARBURST_o : std_logic_vector(1 downto 0);
signal axis_ARVALID_o : std_logic;
signal axis_ARREADY_i : std_logic;
signal axis_RID_i : std_logic_vector(11 downto 0);
signal axis_RDATA_i : std_logic_vector(31 downto 0);
signal axis_RRESP_i : std_logic_vector(1 downto 0);
signal axis_RLAST_i : std_logic;
signal axis_RVALID_i : std_logic;
signal axis_RREADY_o : std_logic;
signal plclk : std_logic;
signal axis_addr : std_logic_vector(31 downto 0);
signal axis_reset : std_logic;
最近のコメント