#include <stdint.h>
#include <stdbool.h>
void Laplacian_filer(uint8_t x0y0, uint8_t x1y0, uint8_t x2y0, uint8_t x0y1, uint8_t x1y1, uint8_t x2y1, uint8_t x0y2, uint8_t x1y2, uint8_t x2y2, uint8_t * out_sig)
{
int32_t temp;
temp = -x0y0 -x1y0 -x2y0 -x0y1 +8*x1y1 -x2y1 -x0y2 -x1y2 -x2y2;
if (temp <0)
*out_sig = 0;
else if (temp>255)
*out_sig = 255;
else
*out_sig = temp;
}
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--USE ieee.numeric_std.ALL;
ENTITY Laplacian_filter_tb IS
END Laplacian_filter_tb;
ARCHITECTURE behavior OF Laplacian_filter_tb IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT Laplacian_filter_U_Laplacian_filer
PORT(
CLOCK : IN std_logic;
DONE : OUT std_logic;
RESET : IN std_logic;
RESET_DONE : OUT std_logic;
START : IN std_logic;
out_sig : OUT std_logic_vector(7 downto 0);
x0y0 : IN std_logic_vector(7 downto 0);
x0y1 : IN std_logic_vector(7 downto 0);
x0y2 : IN std_logic_vector(7 downto 0);
x1y0 : IN std_logic_vector(7 downto 0);
x1y1 : IN std_logic_vector(7 downto 0);
x1y2 : IN std_logic_vector(7 downto 0);
x2y0 : IN std_logic_vector(7 downto 0);
x2y1 : IN std_logic_vector(7 downto 0);
x2y2 : IN std_logic_vector(7 downto 0)
);
END COMPONENT;
--Inputs
signal CLOCK : std_logic := '0';
signal RESET : std_logic := '0';
signal START : std_logic := '0';
signal x0y0 : std_logic_vector(7 downto 0) := (others => '0');
signal x0y1 : std_logic_vector(7 downto 0) := (others => '0');
signal x0y2 : std_logic_vector(7 downto 0) := (others => '0');
signal x1y0 : std_logic_vector(7 downto 0) := (others => '0');
signal x1y1 : std_logic_vector(7 downto 0) := (others => '0');
signal x1y2 : std_logic_vector(7 downto 0) := (others => '0');
signal x2y0 : std_logic_vector(7 downto 0) := (others => '0');
signal x2y1 : std_logic_vector(7 downto 0) := (others => '0');
signal x2y2 : std_logic_vector(7 downto 0) := (others => '0');
--Outputs
signal DONE : std_logic;
signal RESET_DONE : std_logic;
signal out_sig : std_logic_vector(7 downto 0);
-- Clock period definitions
constant CLOCK_period : time := 10 ns;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: Laplacian_filter_U_Laplacian_filer PORT MAP (
CLOCK => CLOCK,
DONE => DONE,
RESET => RESET,
RESET_DONE => RESET_DONE,
START => START,
out_sig => out_sig,
x0y0 => x0y0,
x0y1 => x0y1,
x0y2 => x0y2,
x1y0 => x1y0,
x1y1 => x1y1,
x1y2 => x1y2,
x2y0 => x2y0,
x2y1 => x2y1,
x2y2 => x2y2
);
-- Clock process definitions
CLOCK_process :process
begin
CLOCK <= '0';
wait for CLOCK_period/2;
CLOCK <= '1';
wait for CLOCK_period/2;
end process;
-- Stimulus process
stim_proc: process
begin
RESET <= '1';
START <= '0';
x0y0 <= CONV_STD_LOGIC_VECTOR(0, 8);
x1y0 <= CONV_STD_LOGIC_VECTOR(10, 8);
x2y0 <= CONV_STD_LOGIC_VECTOR(20, 8);
x0y1 <= CONV_STD_LOGIC_VECTOR(30, 8);
x1y1 <= CONV_STD_LOGIC_VECTOR(40, 8);
x2y1 <= CONV_STD_LOGIC_VECTOR(50, 8);
x0y2 <= CONV_STD_LOGIC_VECTOR(60, 8);
x1y2 <= CONV_STD_LOGIC_VECTOR(70, 8);
x2y2 <= CONV_STD_LOGIC_VECTOR(80, 8);
-- hold reset state for 100 ns.
wait for 100 ns;
wait for CLOCK_period*10;
-- insert stimulus here
RESET <= '0';
wait for CLOCK_period;
for i in 1 to 10 loop
START <= '1';
wait for CLOCK_period;
START <= '0';
wait for CLOCK_period*5;
x0y0 <= x0y0;
x1y0 <= x1y0;
x2y0 <= x2y0;
x0y1 <= x0y1;
x1y1 <= x1y1 + i;
x2y1 <= x2y1;
x0y2 <= x0y2;
x1y2 <= x1y2;
x2y2 <= x2y2;
end loop;
wait;
end process;
END;
CHC Performance Test, file main.c, compiled on Apr 28 2012
Running Tests:
--------------
- SW plot (pixels)
- HW plot (pixels)
- SW lines
- HW lines
- SW circles
- HW circles
Results
-------
SW plot = 5529600 cycles
HW plot = 5344977 cycles
Performance gain = 3%
SW line = 43425358 cycles
HW line = 2493835 cycles
Performance gain = 1641%
SW circle = 513557 cycles
HW circle = 63216 cycles
Performance gain = 712%
library IEEE;
use IEEE.STD_LOGIC_1164.all;
package array_test_pack is
type define_nn_array is array (16 downto 1) of std_logic_vector(7 downto 0);
type define_sig_out_array is array (3 downto 0) of std_logic_vector(7 downto 0);
end package array_test_pack;
-- array_test_top.vhd
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
library work;
use work.array_test_pack.all;
entity array_test_top is
port(
clk : in std_logic;
reset : in std_logic;
sig_out0 : out std_logic_vector(7 downto 0);
sig_out1 : out std_logic_vector(7 downto 0);
sig_out2 : out std_logic_vector(7 downto 0);
sig_out3 : out std_logic_vector(7 downto 0)
);
end array_test_top;
architecture Behavioral of array_test_top is
signal nn_array : define_nn_array;
signal sig_node : define_sig_out_array;
component array_test
port (
nn_array : in define_nn_array;
sig_out : out define_sig_out_array
);
end component;
begin
process(clk) begin
if clk'event and clk='1' then
if reset='1' then
for i in 1 to 16 loop
nn_array(i) <= CONV_STD_LOGIC_VECTOR(i,8);
end loop;
else
for i in 1 to 16 loop
nn_array(i) <= nn_array(i) + 1;
end loop;
end if;
end if;
end process;
array_test_inst : array_test port map(
nn_array => nn_array,
sig_out => sig_node
);
sig_out0 <= sig_node(0);
sig_out1 <= sig_node(1);
sig_out2 <= sig_node(2);
sig_out3 <= sig_node(3);
end Behavioral;
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
library work;
use work.array_test_pack.all;
entity array_test is
port (
nn_array : in define_nn_array;
sig_out : out define_sig_out_array
);
end array_test;
architecture Behavioral of array_test is
begin
sig_out(0) <= nn_array(1) + nn_array(2) + nn_array(3) + nn_array(4);
sig_out(1) <= nn_array(5) + nn_array(6) + nn_array(7) + nn_array(8);
sig_out(2) <= nn_array(9) + nn_array(10) + nn_array(11) + nn_array(12);
sig_out(3) <= nn_array(13) + nn_array(14) + nn_array(15) + nn_array(16);
end Behavioral;
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--USE ieee.numeric_std.ALL;
ENTITY array_test_top_tb IS
END array_test_top_tb;
ARCHITECTURE behavior OF array_test_top_tb IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT array_test_top
PORT(
clk : IN std_logic;
reset : IN std_logic;
sig_out0 : OUT std_logic_vector(7 downto 0);
sig_out1 : OUT std_logic_vector(7 downto 0);
sig_out2 : OUT std_logic_vector(7 downto 0);
sig_out3 : OUT std_logic_vector(7 downto 0)
);
END COMPONENT;
--Inputs
signal clk : std_logic := '0';
signal reset : std_logic := '0';
--Outputs
signal sig_out0 : std_logic_vector(7 downto 0);
signal sig_out1 : std_logic_vector(7 downto 0);
signal sig_out2 : std_logic_vector(7 downto 0);
signal sig_out3 : std_logic_vector(7 downto 0);
-- Clock period definitions
constant clk_period : time := 10 ns;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: array_test_top PORT MAP (
clk => clk,
reset => reset,
sig_out0 => sig_out0,
sig_out1 => sig_out1,
sig_out2 => sig_out2,
sig_out3 => sig_out3
);
-- Clock process definitions
clk_process :process
begin
clk <= '0';
wait for clk_period/2;
clk <= '1';
wait for clk_period/2;
end process;
-- Stimulus process
stim_proc: process
begin
-- hold reset state for 100 ns.
reset <= '1';
wait for 100 ns;
wait for clk_period*10;
-- insert stimulus here
reset <= '0';
wait;
end process;
END;
* Accumulate
============
+------------------------------------------------------------------------------------------------+
| calling convention | parallel multi cycle, entry point, register outputs, start on rising edge |
| states | 4 |
| registers | 64 bits |
| clock cycles | 3 |
| ALU | 32 |
+------------------------------------------------------------------------------------------------+
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--USE ieee.numeric_std.ALL;
ENTITY Accumulate_tb IS
END Accumulate_tb;
ARCHITECTURE behavior OF Accumulate_tb IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT CHC_Accumulator_U_Accumulate
PORT(
CLOCK : IN std_logic;
DONE : OUT std_logic;
RESET : IN std_logic;
RESET_DONE : OUT std_logic;
START : IN std_logic;
TOTAL_O : OUT std_logic_vector(31 downto 0);
VALUE_I : IN std_logic_vector(31 downto 0)
);
END COMPONENT;
--Inputs
signal CLOCK : std_logic := '0';
signal RESET : std_logic := '0';
signal START : std_logic := '0';
signal VALUE_I : std_logic_vector(31 downto 0) := (others => '0');
--Outputs
signal DONE : std_logic;
signal RESET_DONE : std_logic;
signal TOTAL_O : std_logic_vector(31 downto 0);
-- Clock period definitions
constant CLOCK_period : time := 10 ns;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: CHC_Accumulator_U_Accumulate PORT MAP (
CLOCK => CLOCK,
DONE => DONE,
RESET => RESET,
RESET_DONE => RESET_DONE,
START => START,
TOTAL_O => TOTAL_O,
VALUE_I => VALUE_I
);
-- Clock process definitions
CLOCK_process :process
begin
CLOCK <= '0';
wait for CLOCK_period/2;
CLOCK <= '1';
wait for CLOCK_period/2;
end process;
-- Stimulus process
stim_proc: process
begin
RESET <= '1';
START <= '0';
VALUE_I <= CONV_STD_LOGIC_VECTOR(0,32);
-- hold reset state for 100 ns.
wait for 100 ns;
RESET <= '0';
wait for CLOCK_period*10;
-- insert stimulus here
START <= '1';
VALUE_I <= CONV_STD_LOGIC_VECTOR(64,32);
wait for CLOCK_period;
START <= '0';
wait for CLOCK_period*3;
START <= '1';
VALUE_I <= CONV_STD_LOGIC_VECTOR(128,32);
wait for CLOCK_period;
START <= '0';
wait;
end process;
END;
NET "SW0" LOC = "V8" | IOSTANDARD = LVTTL | PULLUP ;
NET "SW1" LOC = "U10"| IOSTANDARD = LVTTL | PULLUP ;
NET "SW2" LOC = "U8" | IOSTANDARD = LVTTL | PULLUP ;
NET "SW3" LOC = "T9" | IOSTANDARD = LVTTL | PULLUP ;
NET "LED3" LOC = "U19" | IOSTANDARD = LVTTL | SLEW = QUIETIO | DRIVE = 4 ;
NET "LED2" LOC = "U20" | IOSTANDARD = LVTTL | SLEW = QUIETIO | DRIVE = 4 ;
NET "LED1" LOC = "T19" | IOSTANDARD = LVTTL | SLEW = QUIETIO | DRIVE = 4 ;
NET "LED0" LOC = "R20" | IOSTANDARD = LVTTL | SLEW = QUIETIO | DRIVE = 4 ;
;...............................................................................
;Constraints File
; Device :
; Board :
; Project :
;
; Created 2012/04/21
;...............................................................................
;...............................................................................
Record=FileHeader | Id=DXP Constraints v1.0
;...............................................................................
Record=Constraint | TargetKind=Part | TargetId=XC3S700A-4FGG484C
Record=Constraint | TargetKind=Port | TargetId=LED[3..0] | FPGA_PINNUM=U19,U20,T19,R20 | FPGA_IOSTANDARD=LVTTL33,LVTTL33,LVTTL33,LVTTL33 | FPGA_DRIVE=4mA,4mA,4mA,4mA
Record=Constraint | TargetKind=Port | TargetId=SW[3..0] | FPGA_PINNUM=T9,U8,U10,V8 | FPGA_IOSTANDARD=LVTTL33,LVTTL33,LVTTL33,LVTTL33 | FPGA_PULLUP=True,True,True,True
Record=Constraint | TargetKind=Part | TargetId=XC3S700A-4FGG484C
Record=Constraint | TargetKind=Port | TargetId=LEDS[7..0] | FPGA_PINNUM=W21,Y22,V20,V19,U19,U20,T19,R20 | FPGA_IOSTANDARD=LVTTL33,LVTTL33,LVTTL33,LVTTL33,LVTTL33,LVTTL33,LVTTL33,LVTTL33 | FPGA_DRIVE=4mA,4mA,4mA,4mA,4mA,4mA,4mA,4mA
Record=Constraint | TargetKind=Port | TargetId=SW[7..0] | FPGA_PINNUM=,,,,,U8,U10,V8 | FPGA_IOSTANDARD=,,,,,LVTTL33,LVTTL33,LVTTL33
Record=Constraint | TargetKind=Port | TargetId=CLK_REF | FPGA_PINNUM=E12 | FPGA_IOSTANDARD=LVCMOS33
Record=Constraint | TargetKind=Port | TargetId=TEST_BUTTON | FPGA_PINNUM=T15 | FPGA_IOSTANDARD=LVTTL33
NET "SW<0>" LOC = "V8" | IOSTANDARD = LVTTL | PULLUP ;
NET "SW<1>" LOC = "U10"| IOSTANDARD = LVTTL | PULLUP ;
NET "SW<2>" LOC = "U8" | IOSTANDARD = LVTTL | PULLUP ;
NET "TEST_BUTTON" LOC = "T15" | IOSTANDARD = LVTTL | PULLDOWN ;
NET "LEDS<7>" LOC = "W21" | IOSTANDARD = LVTTL | SLEW = QUIETIO | DRIVE = 4 ;
NET "LEDS<6>" LOC = "Y22" | IOSTANDARD = LVTTL | SLEW = QUIETIO | DRIVE = 4 ;
NET "LEDS<5>" LOC = "V20" | IOSTANDARD = LVTTL | SLEW = QUIETIO | DRIVE = 4 ;
NET "LEDS<4>" LOC = "V19" | IOSTANDARD = LVTTL | SLEW = QUIETIO | DRIVE = 4 ;
NET "LEDS<3>" LOC = "U19" | IOSTANDARD = LVTTL | SLEW = QUIETIO | DRIVE = 4 ;
NET "LEDS<2>" LOC = "U20" | IOSTANDARD = LVTTL | SLEW = QUIETIO | DRIVE = 4 ;
NET "LEDS<1>" LOC = "T19" | IOSTANDARD = LVTTL | SLEW = QUIETIO | DRIVE = 4 ;
NET "LEDS<0>" LOC = "R20" | IOSTANDARD = LVTTL | SLEW = QUIETIO | DRIVE = 4 ;
NET "CLK_REF" LOC = "E12"| IOSTANDARD = LVCMOS33 ;
NET "CLK_REF" PERIOD = 20.0ns HIGH 40%;
Record=Constraint | TargetKind=Port | TargetId=LEDS[7..0] | FPGA_PINNUM=W21,Y22,V20,V19,U19,U20,T19,R20 | FPGA_IOSTANDARD=LVTTL33,LVTTL33,LVTTL33,LVTTL33,LVTTL33,LVTTL33,LVTTL33,LVTTL33 | FPGA_DRIVE=4mA,4mA,4mA,4mA,4mA,4mA,4mA,4mA
Record=Constraint | TargetKind=Port | TargetId=SW[7..0] | FPGA_PINNUM=,,,,,U8,U10,V8 | FPGA_IOSTANDARD=,,,,,LVTTL33,LVTTL33,LVTTL33
Record=Constraint | TargetKind=Port | TargetId=CLK_REF | FPGA_PINNUM=E12 | FPGA_IOSTANDARD=LVCMOS33
Record=Constraint | TargetKind=Port | TargetId=TEST_BUTTON | FPGA_PINNUM=T15 | FPGA_IOSTANDARD=LVTTL33
宣言部分
constant SLAVE_ADDR_NUMBER : integer := 2**(C_OFFSET_WIDTH - ADD_INC_OFFSET);
type ram_array_def is array (SLAVE_ADDR_NUMBER-1 downto 0) of bit_vector(C_M_AXI_DATA_WIDTH-1 downto 0);
signal ram_array : ram_array_def := (others => (others => '0'));
インスタンス部分
-- RAM
process (ACLK) begin
if ACLK'event and ACLK='1' then
if cdc_we='1' then
for i in 0 to C_M_AXI_DATA_WIDTH/8-1 loop
if M_AXI_WSTRB(i)='1' then -- Byte Enable
ram_array(CONV_INTEGER(wr_addr(C_OFFSET_WIDTH-1 downto ADD_INC_OFFSET)))(i*8+7 downto i*8) <= To_bitvector(M_AXI_WDATA(i*8+7 downto i*8));
end if;
end loop;
end if;
end if;
end process;
M_AXI_RDATA <= To_stdlogicvector(ram_array(CONV_INTEGER(rd_addr(C_OFFSET_WIDTH-1 downto ADD_INC_OFFSET))));
宣言部分
constant SLAVE_ADDR_NUMBER : integer := 2**(C_OFFSET_WIDTH - ADD_INC_OFFSET);
type ram_array_def is array (SLAVE_ADDR_NUMBER-1 downto 0) of std_logic_vector(C_M_AXI_DATA_WIDTH-1 downto 0);
signal ram_array : ram_array_def := (others => (others => '0'));
インスタンス部分
-- RAM
process (ACLK) begin
if ACLK'event and ACLK='1' then
if cdc_we='1' then
for i in 0 to C_M_AXI_DATA_WIDTH/8-1 loop
if M_AXI_WSTRB(i)='1' then -- Byte Enable
ram_array(CONV_INTEGER(wr_addr(C_OFFSET_WIDTH-1 downto ADD_INC_OFFSET)))(i*8+7 downto i*8) <= M_AXI_WDATA(i*8+7 downto i*8);
end if;
end loop;
end if;
end if;
end process;
M_AXI_RDATA <= ram_array(CONV_INTEGER(rd_addr(C_OFFSET_WIDTH-1 downto ADD_INC_OFFSET)));
-----------------------------------------------------------------------------
--
-- AXI Master用 Bus Function Mode (BFM)
--
-----------------------------------------------------------------------------
-- 2012/02/25 : M_AXI_AWBURST=1 (INCR) にのみ対応、AWSIZE, ARSIZE = 000 (1byte), 001 (2bytes), 010 (4bytes) のみ対応。
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_misc.all;
package m_seq_bfm_pack is
function M_SEQ16_BFM_F(mseq16in : std_logic_vector
)return std_logic_vector;
end package m_seq_bfm_pack;
package body m_seq_bfm_pack is
function M_SEQ16_BFM_F(mseq16in : std_logic_vector
)return std_logic_vector is
variable mseq16 : std_logic_vector(15 downto 0);
variable xor_result : std_logic;
begin
xor_result := mseq16in(15) xor mseq16in(12) xor mseq16in(10) xor mseq16in(8) xor mseq16in(7) xor mseq16in(6) xor mseq16in(3) xor mseq16in(2);
mseq16 := mseq16in(14 downto 0) & xor_result;
return mseq16;
end M_SEQ16_BFM_F;
end m_seq_bfm_pack;
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
use IEEE.math_real.all;
library work;
use work.m_seq_bfm_pack.all;
--library unisim;
--use unisim.vcomponents.all;
entity axi_master_bfm is
generic (
C_M_AXI_ID_WIDTH : integer := 1;
C_M_AXI_ADDR_WIDTH : integer := 32;
C_M_AXI_DATA_WIDTH : integer := 32;
C_M_AXI_AWUSER_WIDTH : integer := 1;
C_M_AXI_ARUSER_WIDTH : integer := 1;
C_M_AXI_WUSER_WIDTH : integer := 1;
C_M_AXI_RUSER_WIDTH : integer := 1;
C_M_AXI_BUSER_WIDTH : integer := 1;
C_M_AXI_TARGET : integer := 0;
C_OFFSET_WIDTH : integer := 10; -- 割り当てるRAMのアドレスのビット幅
C_M_AXI_BURST_LEN : integer := 256;
WRITE_RANDOM_WAIT : integer := 1; -- Write Transaction のデータ転送の時にランダムなWaitを発生させる=1, Waitしない=0
READ_RANDOM_WAIT : integer := 0 -- Read Transaction のデータ転送の時にランダムなWaitを発生させる=1, Waitしない=0
);
port(
-- System Signals
ACLK : in std_logic;
ARESETN : in std_logic;
-- Master Interface Write Address Ports
M_AXI_AWID : in std_logic_vector(C_M_AXI_ID_WIDTH-1 downto 0);
M_AXI_AWADDR : in std_logic_vector(C_M_AXI_ADDR_WIDTH-1 downto 0);
M_AXI_AWLEN : in std_logic_vector(8-1 downto 0);
M_AXI_AWSIZE : in std_logic_vector(3-1 downto 0);
M_AXI_AWBURST : in std_logic_vector(2-1 downto 0);
-- M_AXI_AWLOCK : in std_logic_vector(2-1 downto 0);
M_AXI_AWLOCK : in std_logic;
M_AXI_AWCACHE : in std_logic_vector(4-1 downto 0);
M_AXI_AWPROT : in std_logic_vector(3-1 downto 0);
M_AXI_AWQOS : in std_logic_vector(4-1 downto 0);
M_AXI_AWUSER : in std_logic_vector(C_M_AXI_AWUSER_WIDTH-1 downto 0);
M_AXI_AWVALID : in std_logic;
M_AXI_AWREADY : out std_logic;
-- Master Interface Write Data Ports
M_AXI_WDATA : in std_logic_vector(C_M_AXI_DATA_WIDTH-1 downto 0);
M_AXI_WSTRB : in std_logic_vector(C_M_AXI_DATA_WIDTH/8-1 downto 0);
M_AXI_WLAST : in std_logic;
M_AXI_WUSER : in std_logic_vector(C_M_AXI_WUSER_WIDTH-1 downto 0);
M_AXI_WVALID : in std_logic;
M_AXI_WREADY : out std_logic;
-- Master Interface Write Response Ports
M_AXI_BID : out std_logic_vector(C_M_AXI_ID_WIDTH-1 downto 0);
M_AXI_BRESP : out std_logic_vector(2-1 downto 0);
M_AXI_BUSER : out std_logic_vector(C_M_AXI_BUSER_WIDTH-1 downto 0);
M_AXI_BVALID : out std_logic;
M_AXI_BREADY : in std_logic;
-- Master Interface Read Address Ports
M_AXI_ARID : in std_logic_vector(C_M_AXI_ID_WIDTH-1 downto 0);
M_AXI_ARADDR : in std_logic_vector(C_M_AXI_ADDR_WIDTH-1 downto 0);
M_AXI_ARLEN : in std_logic_vector(8-1 downto 0);
M_AXI_ARSIZE : in std_logic_vector(3-1 downto 0);
M_AXI_ARBURST : in std_logic_vector(2-1 downto 0);
M_AXI_ARLOCK : in std_logic_vector(2-1 downto 0);
M_AXI_ARCACHE : in std_logic_vector(4-1 downto 0);
M_AXI_ARPROT : in std_logic_vector(3-1 downto 0);
M_AXI_ARQOS : in std_logic_vector(4-1 downto 0);
M_AXI_ARUSER : in std_logic_vector(C_M_AXI_ARUSER_WIDTH-1 downto 0);
M_AXI_ARVALID : in std_logic;
M_AXI_ARREADY : out std_logic;
-- Master Interface Read Data Ports
M_AXI_RID : out std_logic_vector(C_M_AXI_ID_WIDTH-1 downto 0);
M_AXI_RDATA : out std_logic_vector(C_M_AXI_DATA_WIDTH-1 downto 0);
M_AXI_RRESP : out std_logic_vector(2-1 downto 0);
M_AXI_RLAST : out std_logic;
M_AXI_RUSER : out std_logic_vector(C_M_AXI_RUSER_WIDTH-1 downto 0);
M_AXI_RVALID : out std_logic;
M_AXI_RREADY : in std_logic
);
end axi_master_bfm;
architecture implementation of axi_master_bfm is
constant AxBURST_FIXED : std_logic_vector := "00";
constant AxBURST_INCR : std_logic_vector := "01";
constant AxBURST_WRAP : std_logic_vector := "10";
constant RESP_OKAY : std_logic_vector := "00";
constant RESP_EXOKAY : std_logic_vector := "01";
constant RESP_SLVERR : std_logic_vector := "10";
constant RESP_DECERR : std_logic_vector := "11";
constant DATA_BUS_BYTES : natural := C_M_AXI_DATA_WIDTH/8; -- データバスのビット幅
constant ADD_INC_OFFSET : natural := natural(log(real(DATA_BUS_BYTES), 2.0));
-- RAMの生成
constant SLAVE_ADDR_NUMBER : integer := 2**(C_OFFSET_WIDTH - ADD_INC_OFFSET);
type ram_array_def is array (SLAVE_ADDR_NUMBER-1 downto 0) of bit_vector(C_M_AXI_DATA_WIDTH-1 downto 0);
signal ram_array : ram_array_def := (others => (others => '0'));
-- for write transaction
type write_transaction_state is (idle_wr, awr_wait, awr_accept, wr_burst);
type write_response_state is (idle_wres, bvalid_assert);
type write_wready_state is (idle_wrdy, wready_assert);
signal wrt_cs : write_transaction_state;
signal wrres : write_response_state;
signal wrwr : write_wready_state;
signal addr_inc_step_wr : integer := 1;
signal awready : std_logic;
signal wr_addr : std_logic_vector(C_OFFSET_WIDTH-1 downto 0);
signal wr_bid : std_logic_vector(C_M_AXI_ID_WIDTH-1 downto 0);
signal wr_bresp : std_logic_vector(1 downto 0);
signal wr_bvalid : std_logic;
signal m_seq16_wr : std_logic_vector(15 downto 0);
signal wready : std_logic;
type wready_state is (idle_wready, assert_wready, deassert_wready);
signal cs_wready : wready_state;
signal cdc_we : std_logic;
-- for read transaction
type read_transaction_state is (idle_rd, arr_wait, arr_accept, rd_burst);
type read_last_state is (idle_rlast, rlast_assert);
signal rdt_cs : read_transaction_state;
signal rdlast : read_last_state;
signal addr_inc_step_rd : integer := 1;
signal arready : std_logic;
signal rd_addr : std_logic_vector(C_OFFSET_WIDTH-1 downto 0);
signal rd_axi_count : std_logic_vector(7 downto 0);
signal rvalid : std_logic;
signal rlast : std_logic;
signal m_seq16_rd : std_logic_vector(15 downto 0);
type rvalid_state is (idle_rvalid, assert_rvalid, deassert_rvalid);
signal cs_rvalid : rvalid_state;
signal reset_1d, reset_2d, reset : std_logic := '1';
begin
-- ARESETN をACLK で同期化
process (ACLK) begin
if ACLK'event and ACLK='1' then
reset_1d <= not ARESETN;
reset_2d <= reset_1d;
end if;
end process;
reset <= reset_2d;
-- AXI4バス Write Transaction State Machine
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
wrt_cs <= idle_wr;
awready <= '0';
else
case (wrt_cs) is
when idle_wr =>
if M_AXI_AWVALID='1' then -- M_AXI_AWVALID が1にアサートされた
if rdt_cs=idle_rd then -- Read Transaction が終了している(Writeの方が優先順位が高い)
wrt_cs <= awr_accept;
awready <= '1';
else -- Read Transaction が終了していないのでWait
wrt_cs <= awr_wait;
end if;
end if;
when awr_wait => -- Read Transaction の終了待ち
if rdt_cs=idle_rd or rdt_cs=arr_wait then -- Read Transaction が終了
wrt_cs <= awr_accept;
awready <= '1';
end if;
when awr_accept => -- M_AXI_AWREADY をアサート
wrt_cs <= wr_burst;
awready <= '0';
when wr_burst => -- Writeデータの転送
if M_AXI_WLAST='1' and M_AXI_WVALID='1' and wready='1' then -- Write Transaction 終了
wrt_cs <= idle_wr;
end if;
end case;
end if;
end if;
end process;
M_AXI_AWREADY <= awready;
-- m_seq_wr、16ビットのM系列を計算する
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
m_seq16_wr <= (0 => '1', others => '0');
else
if WRITE_RANDOM_WAIT=1 then -- Write Transaction 時にランダムなWaitを挿入する
if wrt_cs=wr_burst and M_AXI_WVALID='1' then
m_seq16_wr <= M_SEQ16_BFM_F(m_seq16_wr);
end if;
else -- Wait無し
m_seq16_wr <= (others => '0');
end if;
end if;
end if;
end process;
-- wready の処理、M系列を計算して128以上だったらWaitする。
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
cs_wready <= idle_wready;
wready <= '0';
else
case (cs_wready) is
when idle_wready =>
if wrt_cs=awr_accept then -- 次はwr_burst
if m_seq16_wr(7)='0' then -- wready='1'
cs_wready <= assert_wready;
wready <= '1';
else -- m_seq16_wr(7)='1' then -- wready='0'
cs_wready <= deassert_wready;
wready <= '0';
end if;
end if;
when assert_wready => -- 一度wreadyがアサートされたら、1つのトランザクションが終了するまでwready='1'
if wrt_cs=wr_burst and M_AXI_WLAST='1' and M_AXI_WVALID='1' then -- 終了
cs_wready <= idle_wready;
wready <= '0';
elsif wrt_cs=wr_burst and M_AXI_WVALID='1' then -- 1つのトランザクション終了。
if m_seq16_wr(7)='1' then
cs_wready <= deassert_wready;
wready <= '0';
end if;
end if;
when deassert_wready =>
if m_seq16_wr(7)='0' then -- wready='1'
cs_wready <= assert_wready;
wready <= '1';
end if;
end case;
end if;
end if;
end process;
M_AXI_WREADY <= wready;
cdc_we <= '1' when wrt_cs=wr_burst and wready='1' and M_AXI_WVALID='1' else '0';
-- addr_inc_step_wr の処理
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
addr_inc_step_wr <= 1;
else
if wrt_cs=awr_accept then
case (M_AXI_AWSIZE) is
when "000" => -- 8ビット転送
addr_inc_step_wr <= 1;
when "001" => -- 16ビット転送
addr_inc_step_wr <= 2;
when "010" => -- 32ビット転送
addr_inc_step_wr <= 4;
when "011" => -- 64ビット転送
addr_inc_step_wr <= 8;
when "100" => -- 128ビット転送
addr_inc_step_wr <= 16;
when "101" => -- 256ビット転送
addr_inc_step_wr <= 32;
when "110" => -- 512ビット転送
addr_inc_step_wr <= 64;
when others => --"111" => -- 1024ビット転送
addr_inc_step_wr <= 128;
end case;
end if;
end if;
end if;
end process;
-- wr_addr の処理
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
wr_addr <= (others => '0');
else
if wrt_cs=awr_accept then
wr_addr <= M_AXI_AWADDR(C_OFFSET_WIDTH-1 downto 0);
elsif wrt_cs=wr_burst and M_AXI_WVALID='1' and wready='1' then -- アドレスを進める
wr_addr <= wr_addr + addr_inc_step_wr;
end if;
end if;
end if;
end process;
-- wr_bid の処理
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
wr_bid <= "0";
else
if wrt_cs=awr_accept then
wr_bid <= M_AXI_AWID;
end if;
end if;
end if;
end process;
M_AXI_BID <= wr_bid;
-- wr_bresp の処理
-- M_AXI_AWBURSTがINCRの時はOKAYを返す。それ以外はSLVERRを返す。
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
wr_bresp <= (others => '0');
else
if wrt_cs=awr_accept then
if M_AXI_AWBURST=AxBURST_INCR then -- バーストタイプがアドレス・インクリメントタイプ
wr_bresp <= RESP_OKAY; -- Write Transaction は成功
else
wr_bresp <= RESP_SLVERR; -- エラー
end if;
end if;
end if;
end if;
end process;
M_AXI_BRESP <= wr_bresp;
-- wr_bvalid の処理
-- Write Transaction State Machineには含まない。axi_master のシミュレーションを見ると1クロックで終了しているので、長い間、Master側の都合でWaitしていることは考えない。
-- 次のWrite転送まで遅延しているようであれば、Write Transaction State Machine に入れてブロックすることも考える必要がある。
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
wr_bvalid <= '0';
else
if M_AXI_WLAST='1' and M_AXI_WVALID='1' and wready='1' then -- Write Transaction 終了
wr_bvalid <= '1';
elsif wr_bvalid='1' and M_AXI_BREADY='1' then -- wr_bvalid が1でMaster側のReadyも1ならばWrite resonse channel の転送も終了
wr_bvalid <= '0';
end if;
end if;
end if;
end process;
M_AXI_BVALID <= wr_bvalid;
M_AXI_BUSER <= (others => '0');
-- AXI4バス Read Transaction State Machine
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
rdt_cs <= idle_rd;
arready <= '0';
else
case (rdt_cs) is
when idle_rd =>
if M_AXI_ARVALID='1' then -- Read Transaction 要求
if wrt_cs=idle_wr and M_AXI_AWVALID='0' then -- Write Transaction State Machine がidle でWrite要求もない
rdt_cs <= arr_accept;
arready <= '1';
else -- Write Transaction が終了していないのでWait
rdt_cs <= arr_wait;
end if;
end if;
when arr_wait => -- Write Transaction の終了待ち
if wrt_cs=idle_wr and M_AXI_AWVALID='0' then -- Write Transaction State Machine がidle でWrite要求もない
rdt_cs <= arr_accept;
arready <= '1';
end if;
when arr_accept => -- M_AXI_ARREADY をアサート
rdt_cs <= rd_burst;
arready <= '0';
when rd_burst => -- Readデータの転送
if rd_axi_count=0 and rvalid='1' and M_AXI_RREADY='1' then -- Read Transaction 終了
rdt_cs <= idle_rd;
end if;
end case;
end if;
end if;
end process;
M_AXI_ARREADY <= arready;
-- m_seq_rd、16ビットのM系列を計算する
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
m_seq16_rd <= (others => '1'); -- Writeとシードを変更する
else
if READ_RANDOM_WAIT=1 then -- Read Transaciton のデータ転送でランダムなWaitを挿入する場合
if rdt_cs=rd_burst and M_AXI_RREADY='1' then
m_seq16_rd <= M_SEQ16_BFM_F(m_seq16_rd);
end if;
else -- Wati無し
m_seq16_rd <= (others => '0');
end if;
end if;
end if;
end process;
-- rvalid の処理、M系列を計算して128以上だったらWaitする。
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
cs_rvalid <= idle_rvalid;
rvalid <= '0';
else
case (cs_rvalid) is
when idle_rvalid =>
if rdt_cs=arr_accept then -- 次はrd_burst
if m_seq16_rd(7)='0' then -- rvalid='1'
cs_rvalid <= assert_rvalid;
rvalid <= '1';
else -- m_seq16_rd(7)='1' then -- rvalid='0'
cs_rvalid <= deassert_rvalid;
rvalid <= '0';
end if;
end if;
when assert_rvalid => -- 一度rvalidがアサートされたら、1つのトランザクションが終了するまでrvalid='1'
if rdt_cs=rd_burst and rlast='1' and M_AXI_RREADY='1' then -- 終了
cs_rvalid <= idle_rvalid;
rvalid <= '0';
elsif rdt_cs=rd_burst and M_AXI_RREADY='1' then -- 1つのトランザクション終了。
if m_seq16_rd(7)='1' then
cs_rvalid <= deassert_rvalid;
rvalid <= '0';
end if;
end if;
when deassert_rvalid =>
if m_seq16_rd(7)='0' then -- rvalid='1'
cs_rvalid <= assert_rvalid;
rvalid <= '1';
end if;
end case;
end if;
end if;
end process;
M_AXI_RVALID <= rvalid;
-- addr_inc_step_rd の処理
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
addr_inc_step_rd <= 1;
else
if rdt_cs=arr_accept then
case (M_AXI_ARSIZE) is
when "000" => -- 8ビット転送
addr_inc_step_rd <= 1;
when "001" => -- 16ビット転送
addr_inc_step_rd <= 2;
when "010" => -- 32ビット転送
addr_inc_step_rd <= 4;
when "011" => -- 64ビット転送
addr_inc_step_rd <= 8;
when "100" => -- 128ビット転送
addr_inc_step_rd <= 16;
when "101" => -- 256ビット転送
addr_inc_step_rd <= 32;
when "110" => -- 512ビット転送
addr_inc_step_rd <= 64;
when others => -- "111" => -- 1024ビット転送
addr_inc_step_rd <= 128;
end case;
end if;
end if;
end if;
end process;
-- rd_addr の処理
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
rd_addr <= (others => '0');
else
if rdt_cs=arr_accept then
rd_addr <= M_AXI_ARADDR(C_OFFSET_WIDTH-1 downto 0);
elsif rdt_cs=rd_burst and M_AXI_RREADY='1' and rvalid='1' then
rd_addr <= rd_addr + addr_inc_step_rd;
end if;
end if;
end if;
end process;
-- rd_axi_count の処理(AXIバス側のデータカウント)
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
rd_axi_count <= (others => '0');
else
if rdt_cs=arr_accept then -- rd_axi_count のロード
rd_axi_count <= M_AXI_ARLEN;
elsif rdt_cs=rd_burst and rvalid='1' and M_AXI_RREADY='1' then -- Read Transaction が1つ終了
rd_axi_count <= rd_axi_count - 1;
end if;
end if;
end if;
end process;
-- rdlast State Machine
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
rdlast <= idle_rlast;
rlast <= '0';
else
case (rdlast) is
when idle_rlast =>
if rd_axi_count=1 and rvalid='1' and M_AXI_RREADY='1' then -- バーストする場合
rdlast <= rlast_assert;
rlast <= '1';
elsif rdt_cs=arr_accept and M_AXI_ARLEN=0 then -- 転送数が1の場合
rdlast <= rlast_assert;
rlast <= '1';
end if;
when rlast_assert =>
if rvalid='1' and M_AXI_RREADY='1' then -- Read Transaction 終了(rd_axi_count=0は決定)
rdlast <= idle_rlast;
rlast <= '0';
end if;
end case;
end if;
end if;
end process;
M_AXI_RLAST <= rlast;
-- M_AXI_RID, M_AXI_RUSER の処理
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
M_AXI_RID <= (others => '0');
else
if rdt_cs=arr_accept then
M_AXI_RID <= M_AXI_ARID;
end if;
end if;
end if;
end process;
M_AXI_RUSER <= (others => '0');
-- M_AXI_RRESP は、M_AXI_ARBURST がINCR の場合はOKAYを返す。それ以外はSLVERRを返す。
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
M_AXI_RRESP <= (others => '0');
else
if rdt_cs=arr_accept then
if M_AXI_ARBURST=AxBURST_INCR then
M_AXI_RRESP <= RESP_OKAY;
else
M_AXI_RRESP <= RESP_SLVERR;
end if;
end if;
end if;
end if;
end process;
-- RAM
process (ACLK) begin
if ACLK'event and ACLK='1' then
if cdc_we='1' then
for i in 0 to C_M_AXI_DATA_WIDTH/8-1 loop
if M_AXI_WSTRB(i)='1' then -- Byte Enable
ram_array(CONV_INTEGER(wr_addr(C_OFFSET_WIDTH-1 downto ADD_INC_OFFSET)))(i*8+7 downto i*8) <= To_bitvector(M_AXI_WDATA(i*8+7 downto i*8));
end if;
end loop;
end if;
end if;
end process;
M_AXI_RDATA <= To_stdlogicvector(ram_array(CONV_INTEGER(rd_addr(C_OFFSET_WIDTH-1 downto ADD_INC_OFFSET))));
end implementation;
`default_nettype none
`timescale 100ps / 1ps
module cdctest_axi_master_tb;
// Inputs
wire ACLK;
wire ARESETN;
wire M_AXI_AWREADY;
wire M_AXI_WREADY;
wire [0:0] M_AXI_BID;
wire [1:0] M_AXI_BRESP;
wire [0:0] M_AXI_BUSER;
wire M_AXI_BVALID;
wire M_AXI_ARREADY;
wire [0:0] M_AXI_RID;
wire [31:0] M_AXI_RDATA;
wire [1:0] M_AXI_RRESP;
wire M_AXI_RLAST;
wire [0:0] M_AXI_RUSER;
wire M_AXI_RVALID;
// Outputs
wire [0:0] M_AXI_AWID;
wire [31:0] M_AXI_AWADDR;
wire [7:0] M_AXI_AWLEN;
wire [2:0] M_AXI_AWSIZE;
wire [1:0] M_AXI_AWBURST;
wire M_AXI_AWLOCK;
wire [3:0] M_AXI_AWCACHE;
wire [2:0] M_AXI_AWPROT;
wire [3:0] M_AXI_AWQOS;
wire [0:0] M_AXI_AWUSER;
wire M_AXI_AWVALID;
wire [31:0] M_AXI_WDATA;
wire [3:0] M_AXI_WSTRB;
wire M_AXI_WLAST;
wire [0:0] M_AXI_WUSER;
wire M_AXI_WVALID;
wire M_AXI_BREADY;
wire [0:0] M_AXI_ARID;
wire [31:0] M_AXI_ARADDR;
wire [7:0] M_AXI_ARLEN;
wire [2:0] M_AXI_ARSIZE;
wire [1:0] M_AXI_ARBURST;
wire [1:0] M_AXI_ARLOCK;
wire [3:0] M_AXI_ARCACHE;
wire [2:0] M_AXI_ARPROT;
wire [3:0] M_AXI_ARQOS;
wire [0:0] M_AXI_ARUSER;
wire M_AXI_ARVALID;
wire M_AXI_RREADY;
wire wr_error;
wire rd_error;
// Instantiate the Unit Under Test (UUT_MASTER)
cdctest_axi_master uut_master (
.ACLK(ACLK),
.ARESETN(ARESETN),
.M_AXI_AWID(M_AXI_AWID),
.M_AXI_AWADDR(M_AXI_AWADDR),
.M_AXI_AWLEN(M_AXI_AWLEN),
.M_AXI_AWSIZE(M_AXI_AWSIZE),
.M_AXI_AWBURST(M_AXI_AWBURST),
.M_AXI_AWLOCK(M_AXI_AWLOCK),
.M_AXI_AWCACHE(M_AXI_AWCACHE),
.M_AXI_AWPROT(M_AXI_AWPROT),
.M_AXI_AWQOS(M_AXI_AWQOS),
.M_AXI_AWUSER(M_AXI_AWUSER),
.M_AXI_AWVALID(M_AXI_AWVALID),
.M_AXI_AWREADY(M_AXI_AWREADY),
.M_AXI_WDATA(M_AXI_WDATA),
.M_AXI_WSTRB(M_AXI_WSTRB),
.M_AXI_WLAST(M_AXI_WLAST),
.M_AXI_WUSER(M_AXI_WUSER),
.M_AXI_WVALID(M_AXI_WVALID),
.M_AXI_WREADY(M_AXI_WREADY),
.M_AXI_BID(M_AXI_BID),
.M_AXI_BRESP(M_AXI_BRESP),
.M_AXI_BUSER(M_AXI_BUSER),
.M_AXI_BVALID(M_AXI_BVALID),
.M_AXI_BREADY(M_AXI_BREADY),
.M_AXI_ARID(M_AXI_ARID),
.M_AXI_ARADDR(M_AXI_ARADDR),
.M_AXI_ARLEN(M_AXI_ARLEN),
.M_AXI_ARSIZE(M_AXI_ARSIZE),
.M_AXI_ARBURST(M_AXI_ARBURST),
.M_AXI_ARLOCK(M_AXI_ARLOCK),
.M_AXI_ARCACHE(M_AXI_ARCACHE),
.M_AXI_ARPROT(M_AXI_ARPROT),
.M_AXI_ARQOS(M_AXI_ARQOS),
.M_AXI_ARUSER(M_AXI_ARUSER),
.M_AXI_ARVALID(M_AXI_ARVALID),
.M_AXI_ARREADY(M_AXI_ARREADY),
.M_AXI_RID(M_AXI_RID),
.M_AXI_RDATA(M_AXI_RDATA),
.M_AXI_RRESP(M_AXI_RRESP),
.M_AXI_RLAST(M_AXI_RLAST),
.M_AXI_RUSER(M_AXI_RUSER),
.M_AXI_RVALID(M_AXI_RVALID),
.M_AXI_RREADY(M_AXI_RREADY),
.wr_error(wr_error),
.rd_error(rd_error)
);
// clk_gen のインスタンス
clk_gen #(
.CLK_PERIOD(100), // 10nsec, 100MHz
.CLK_DUTY_CYCLE(0.5),
.CLK_OFFSET(0),
.START_STATE(1'b0)
) ACLKi (
.clk_out(ACLK)
);
// reset_gen のインスタンス
reset_gen #(
.RESET_STATE(1'b0),
.RESET_TIME(1000) // 100nsec
) RESETi (
.reset_out(ARESETN)
);
// Instantiate the Unit Under Test (UUT_slave)
axi_master_bfm uut_slave (
.ACLK(ACLK),
.ARESETN(ARESETN),
.M_AXI_AWID(M_AXI_AWID),
.M_AXI_AWADDR(M_AXI_AWADDR),
.M_AXI_AWLEN(M_AXI_AWLEN),
.M_AXI_AWSIZE(M_AXI_AWSIZE),
.M_AXI_AWBURST(M_AXI_AWBURST),
.M_AXI_AWLOCK(M_AXI_AWLOCK),
.M_AXI_AWCACHE(M_AXI_AWCACHE),
.M_AXI_AWPROT(M_AXI_AWPROT),
.M_AXI_AWQOS(M_AXI_AWQOS),
.M_AXI_AWUSER(M_AXI_AWUSER),
.M_AXI_AWVALID(M_AXI_AWVALID),
.M_AXI_AWREADY(M_AXI_AWREADY),
.M_AXI_WDATA(M_AXI_WDATA),
.M_AXI_WSTRB(M_AXI_WSTRB),
.M_AXI_WLAST(M_AXI_WLAST),
.M_AXI_WUSER(M_AXI_WUSER),
.M_AXI_WVALID(M_AXI_WVALID),
.M_AXI_WREADY(M_AXI_WREADY),
.M_AXI_BID(M_AXI_BID),
.M_AXI_BRESP(M_AXI_BRESP),
.M_AXI_BUSER(M_AXI_BUSER),
.M_AXI_BVALID(M_AXI_BVALID),
.M_AXI_BREADY(M_AXI_BREADY),
.M_AXI_ARID(M_AXI_ARID),
.M_AXI_ARADDR(M_AXI_ARADDR),
.M_AXI_ARLEN(M_AXI_ARLEN),
.M_AXI_ARSIZE(M_AXI_ARSIZE),
.M_AXI_ARBURST(M_AXI_ARBURST),
.M_AXI_ARLOCK(M_AXI_ARLOCK),
.M_AXI_ARCACHE(M_AXI_ARCACHE),
.M_AXI_ARPROT(M_AXI_ARPROT),
.M_AXI_ARQOS(M_AXI_ARQOS),
.M_AXI_ARUSER(M_AXI_ARUSER),
.M_AXI_ARVALID(M_AXI_ARVALID),
.M_AXI_ARREADY(M_AXI_ARREADY),
.M_AXI_RID(M_AXI_RID),
.M_AXI_RDATA(M_AXI_RDATA),
.M_AXI_RRESP(M_AXI_RRESP),
.M_AXI_RLAST(M_AXI_RLAST),
.M_AXI_RUSER(M_AXI_RUSER),
.M_AXI_RVALID(M_AXI_RVALID),
.M_AXI_RREADY(M_AXI_RREADY)
);
endmodule
module clk_gen #(
parameter CLK_PERIOD = 100,
parameter real CLK_DUTY_CYCLE = 0.5,
parameter CLK_OFFSET = 0,
parameter START_STATE = 1'b0 )
(
output reg clk_out
);
begin
initial begin
#CLK_OFFSET;
forever
begin
clk_out = START_STATE;
#(CLK_PERIOD-(CLK_PERIOD*CLK_DUTY_CYCLE)) clk_out = ~START_STATE;
#(CLK_PERIOD*CLK_DUTY_CYCLE);
end
end
end
endmodule
module reset_gen #(
parameter RESET_STATE = 1'b1,
parameter RESET_TIME = 100 )
(
output reg reset_out
);
begin
initial begin
reset_out = RESET_STATE;
#RESET_TIME;
reset_out = ~RESET_STATE;
end
end
endmodule
`default_nettype wire
Release 13.4 Map O.87xd (nt)
Xilinx Mapping Report File for Design 'axi_master_bfm'
Design Information
------------------
Command Line : map -intstyle ise -p xc6slx45-csg324-2 -w -logic_opt off -ol
high -t 1 -xt 0 -register_duplication off -r 4 -global_opt off -mt off -ir off
-pr off -lc off -power off -o axi_master_bfm_map.ncd axi_master_bfm.ngd
axi_master_bfm.pcf
Target Device : xc6slx45
Target Package : csg324
Target Speed : -2
Mapper Version : spartan6 -- $Revision: 1.55 $
Mapped Date : SAT 14 APR 4:40:4 2012
Design Summary
--------------
Number of errors: 0
Number of warnings: 0
Slice Logic Utilization:
Number of Slice Registers: 2,121 out of 54,576 3%
Number used as Flip Flops: 2,121
Number used as Latches: 0
Number used as Latch-thrus: 0
Number used as AND/OR logics: 0
Number of Slice LUTs: 2,848 out of 27,288 10%
Number used as logic: 2,845 out of 27,288 10%
Number using O6 output only: 2,817
Number using O5 output only: 0
Number using O5 and O6: 28
Number used as ROM: 0
Number used as Memory: 1 out of 6,408 1%
Number used as Dual Port RAM: 0
Number used as Single Port RAM: 0
Number used as Shift Register: 1
Number using O6 output only: 1
Number using O5 output only: 0
Number using O5 and O6: 0
Number used exclusively as route-thrus: 2
Number with same-slice register load: 2
Number with same-slice carry load: 0
Number with other load: 0
Slice Logic Distribution:
Number of occupied Slices: 918 out of 6,822 13%
Nummber of MUXCYs used: 24 out of 13,644 1%
Number of LUT Flip Flop pairs used: 2,858
Number with an unused Flip Flop: 743 out of 2,858 25%
Number with an unused LUT: 10 out of 2,858 1%
Number of fully used LUT-FF pairs: 2,105 out of 2,858 73%
Number of unique control sets: 9
Number of slice register sites lost
to control set restrictions: 30 out of 54,576 1%
A LUT Flip Flop pair for this architecture represents one LUT paired with
one Flip Flop within a slice. A control set is a unique combination of
clock, reset, set, and enable signals for a registered element.
The Slice Logic Distribution report is not meaningful if the design is
over-mapped for a non-slice resource or if Placement fails.
IO Utilization:
Number of bonded IOBs: 126 out of 218 57%
Specific Feature Utilization:
Number of RAMB16BWERs: 0 out of 116 0%
Number of RAMB8BWERs: 0 out of 232 0%
Number of BUFIO2/BUFIO2_2CLKs: 0 out of 32 0%
Number of BUFIO2FB/BUFIO2FB_2CLKs: 0 out of 32 0%
Number of BUFG/BUFGMUXs: 1 out of 16 6%
Number used as BUFGs: 1
Number used as BUFGMUX: 0
Number of DCM/DCM_CLKGENs: 0 out of 8 0%
Number of ILOGIC2/ISERDES2s: 0 out of 376 0%
Number of IODELAY2/IODRP2/IODRP2_MCBs: 0 out of 376 0%
Number of OLOGIC2/OSERDES2s: 0 out of 376 0%
Number of BSCANs: 0 out of 4 0%
Number of BUFHs: 0 out of 256 0%
Number of BUFPLLs: 0 out of 8 0%
Number of BUFPLL_MCBs: 0 out of 4 0%
Number of DSP48A1s: 0 out of 58 0%
Number of ICAPs: 0 out of 1 0%
Number of MCBs: 0 out of 2 0%
Number of PCILOGICSEs: 0 out of 2 0%
Number of PLL_ADVs: 0 out of 4 0%
Number of PMVs: 0 out of 1 0%
Number of STARTUPs: 0 out of 1 0%
Number of SUSPEND_SYNCs: 0 out of 1 0%
Average Fanout of Non-Clock Nets: 5.80
Peak Memory Usage: 305 MB
Total REAL time to MAP completion: 1 mins 7 secs
Total CPU time to MAP completion: 1 mins 6 secs
constant SLAVE_ADDR_NUMBER : integer := 2**(C_OFFSET_WIDTH - ADD_INC_OFFSET);
type ram_array_def is array (SLAVE_ADDR_NUMBER-1 downto 0) of bit_vector(C_M_AXI_DATA_WIDTH-1 downto 0);
signal ram_array : ram_array_def;
...............
-- RAM
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
ram_array <= (others => (others => '0'));
else
if cdc_we='1' then
for i in 0 to C_M_AXI_DATA_WIDTH/8-1 loop
if M_AXI_WSTRB(i)='1' then -- Byte Enable
ram_array(CONV_INTEGER(wr_addr(C_OFFSET_WIDTH-1 downto ADD_INC_OFFSET)))(i*8+7 downto i*8) <= To_bitvector(M_AXI_WDATA(i*8+7 downto i*8));
end if;
end loop;
end if;
end if;
end if;
end process;
M_AXI_RDATA <= To_stdlogicvector(ram_array(CONV_INTEGER(rd_addr(C_OFFSET_WIDTH-1 downto ADD_INC_OFFSET))));
constant SLAVE_ADDR_NUMBER : integer := 2**(C_OFFSET_WIDTH - ADD_INC_OFFSET);
type ram_array_def is array (SLAVE_ADDR_NUMBER-1 downto 0) of bit_vector(C_M_AXI_DATA_WIDTH-1 downto 0);
signal ram_array : ram_array_def := (others => (others => '0'));
...............
-- RAM
process (ACLK) begin
if ACLK'event and ACLK='1' then
if cdc_we='1' then
for i in 0 to C_M_AXI_DATA_WIDTH/8-1 loop
if M_AXI_WSTRB(i)='1' then -- Byte Enable
ram_array(CONV_INTEGER(wr_addr(C_OFFSET_WIDTH-1 downto ADD_INC_OFFSET)))(i*8+7 downto i*8) <= To_bitvector(M_AXI_WDATA(i*8+7 downto i*8));
end if;
end loop;
end if;
end if;
end process;
M_AXI_RDATA <= To_stdlogicvector(ram_array(CONV_INTEGER(rd_addr(C_OFFSET_WIDTH-1 downto ADD_INC_OFFSET))));
Release 13.4 Map O.87xd (nt)
Xilinx Mapping Report File for Design 'axi_master_bfm'
Design Information
------------------
Command Line : map -intstyle ise -p xc6slx45-csg324-2 -w -logic_opt off -ol
high -t 1 -xt 0 -register_duplication off -r 4 -global_opt off -mt off -ir off
-pr off -lc off -power off -o axi_master_bfm_map.ncd axi_master_bfm.ngd
axi_master_bfm.pcf
Target Device : xc6slx45
Target Package : csg324
Target Speed : -2
Mapper Version : spartan6 -- $Revision: 1.55 $
Mapped Date : SAT 14 APR 5:5:44 2012
Design Summary
--------------
Number of errors: 0
Number of warnings: 0
Slice Logic Utilization:
Number of Slice Registers: 68 out of 54,576 1%
Number used as Flip Flops: 68
Number used as Latches: 0
Number used as Latch-thrus: 0
Number used as AND/OR logics: 0
Number of Slice LUTs: 174 out of 27,288 1%
Number used as logic: 109 out of 27,288 1%
Number using O6 output only: 86
Number using O5 output only: 0
Number using O5 and O6: 23
Number used as ROM: 0
Number used as Memory: 64 out of 6,408 1%
Number used as Dual Port RAM: 64
Number using O6 output only: 64
Number using O5 output only: 0
Number using O5 and O6: 0
Number used as Single Port RAM: 0
Number used as Shift Register: 0
Number used exclusively as route-thrus: 1
Number with same-slice register load: 1
Number with same-slice carry load: 0
Number with other load: 0
Slice Logic Distribution:
Number of occupied Slices: 78 out of 6,822 1%
Nummber of MUXCYs used: 24 out of 13,644 1%
Number of LUT Flip Flop pairs used: 183
Number with an unused Flip Flop: 117 out of 183 63%
Number with an unused LUT: 9 out of 183 4%
Number of fully used LUT-FF pairs: 57 out of 183 31%
Number of unique control sets: 11
Number of slice register sites lost
to control set restrictions: 44 out of 54,576 1%
A LUT Flip Flop pair for this architecture represents one LUT paired with
one Flip Flop within a slice. A control set is a unique combination of
clock, reset, set, and enable signals for a registered element.
The Slice Logic Distribution report is not meaningful if the design is
over-mapped for a non-slice resource or if Placement fails.
IO Utilization:
Number of bonded IOBs: 126 out of 218 57%
Specific Feature Utilization:
Number of RAMB16BWERs: 0 out of 116 0%
Number of RAMB8BWERs: 0 out of 232 0%
Number of BUFIO2/BUFIO2_2CLKs: 0 out of 32 0%
Number of BUFIO2FB/BUFIO2FB_2CLKs: 0 out of 32 0%
Number of BUFG/BUFGMUXs: 1 out of 16 6%
Number used as BUFGs: 1
Number used as BUFGMUX: 0
Number of DCM/DCM_CLKGENs: 0 out of 8 0%
Number of ILOGIC2/ISERDES2s: 0 out of 376 0%
Number of IODELAY2/IODRP2/IODRP2_MCBs: 0 out of 376 0%
Number of OLOGIC2/OSERDES2s: 0 out of 376 0%
Number of BSCANs: 0 out of 4 0%
Number of BUFHs: 0 out of 256 0%
Number of BUFPLLs: 0 out of 8 0%
Number of BUFPLL_MCBs: 0 out of 4 0%
Number of DSP48A1s: 0 out of 58 0%
Number of ICAPs: 0 out of 1 0%
Number of MCBs: 0 out of 2 0%
Number of PCILOGICSEs: 0 out of 2 0%
Number of PLL_ADVs: 0 out of 4 0%
Number of PMVs: 0 out of 1 0%
Number of STARTUPs: 0 out of 1 0%
Number of SUSPEND_SYNCs: 0 out of 1 0%
Average Fanout of Non-Clock Nets: 3.81
Peak Memory Usage: 279 MB
Total REAL time to MAP completion: 30 secs
Total CPU time to MAP completion: 29 secs
BEGIN cdctest_axi_master
...............
PORT wr_error = "", DIR = O
PORT rd_error = "", DIR = O
lib cdctest_axi_master_v1_00_a cdctest_axi_master.vhd vhdl
NET "cdctest_wr_error" LOC = "T3"; #PMOD for test
NET "cdctest_rd_error" LOC = "R3"; #PMOD for test
-- rd_cdc_count の処理(CDC側のデータカウント)
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
rd_cdc_count <= (others => '0');
else
if rdt_cs=arr_accept then -- ロード
rd_cdc_count <= S_AXI_ARLEN + 1;
elsif rdt_cs=rd_burst and rdfifo_almost_full='0' and rd_cdc_count/=0 then -- FIFOに余裕がある
rd_cdc_count <= rd_cdc_count - 1;
end if;
end if;
end if;
end process;
signal rd_cdc_count : std_logic_vector(7 downto 0);
signal rd_cdc_count : std_logic_vector(8 downto 0);
if rdt_cs=arr_accept then -- ロード
rd_cdc_count <= ('0'& S_AXI_ARLEN) + 1;
(2012/10/22:(注)この記事は全面的に書き換えた。理由はAXIの書き込みトランザクションにやるハンドシェークの依存関係を誤解していた。書き込みトランザクションにおいて、WVALIDをアサートする前に、AWREADYがアサートされるのを待っていてはダメだそうだ。デッドロック状態を引き起こす可能性があるそうだ。
-------------------------------------------------------------------------------
--
-- AXI Master
--
-- VHDL-Standard: VHDL'93
----------------------------------------------------------------------------
--
-- Structure:
-- cdctest_axi_master
--
----------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_misc.all;
package m_seq_pack is
function M_SEQ16_F(mseq16in : std_logic_vector
)return std_logic_vector;
end package m_seq_pack;
package body m_seq_pack is
function M_SEQ16_F(mseq16in : std_logic_vector
)return std_logic_vector is
variable mseq16 : std_logic_vector(15 downto 0);
variable xor_result : std_logic;
begin
xor_result := mseq16in(15) xor mseq16in(12) xor mseq16in(10) xor mseq16in(8) xor mseq16in(7) xor mseq16in(6) xor mseq16in(3) xor mseq16in(2);
mseq16 := mseq16in(14 downto 0) & xor_result;
return mseq16;
end M_SEQ16_F;
end m_seq_pack;
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
library work;
use work.m_seq_pack.all;
--library unisim;
--use unisim.vcomponents.all;
entity cdctest_axi_master is
generic(
C_M_AXI_THREAD_ID_WIDTH : integer := 1;
C_M_AXI_ADDR_WIDTH : integer := 32;
C_M_AXI_DATA_WIDTH : integer := 32;
C_M_AXI_AWUSER_WIDTH : integer := 1;
C_M_AXI_ARUSER_WIDTH : integer := 1;
C_M_AXI_WUSER_WIDTH : integer := 1;
C_M_AXI_RUSER_WIDTH : integer := 1;
C_M_AXI_BUSER_WIDTH : integer := 1
);
port(
-- System Signals
ACLK : in std_logic;
ARESETN : in std_logic;
-- Master Interface Write Address
M_AXI_AWID : out std_logic_vector(C_M_AXI_THREAD_ID_WIDTH-1 downto 0);
M_AXI_AWADDR : out std_logic_vector(C_M_AXI_ADDR_WIDTH-1 downto 0);
M_AXI_AWLEN : out std_logic_vector(8-1 downto 0);
M_AXI_AWSIZE : out std_logic_vector(3-1 downto 0);
M_AXI_AWBURST : out std_logic_vector(2-1 downto 0);
M_AXI_AWLOCK : out std_logic;
M_AXI_AWCACHE : out std_logic_vector(4-1 downto 0);
M_AXI_AWPROT : out std_logic_vector(3-1 downto 0);
-- AXI3 M_AXI_AWREGION:out std_logic_vector(4-1 downto 0);
M_AXI_AWQOS : out std_logic_vector(4-1 downto 0);
M_AXI_AWUSER : out std_logic_vector(C_M_AXI_AWUSER_WIDTH-1 downto 0);
M_AXI_AWVALID : out std_logic;
M_AXI_AWREADY : in std_logic;
-- Master Interface Write Data
-- AXI3 M_AXI_WID(C_M_AXI_THREAD_ID_WIDTH-1 downto 0);
M_AXI_WDATA : out std_logic_vector(C_M_AXI_DATA_WIDTH-1 downto 0);
M_AXI_WSTRB : out std_logic_vector(C_M_AXI_DATA_WIDTH/8-1 downto 0);
M_AXI_WLAST : out std_logic;
M_AXI_WUSER : out std_logic_vector(C_M_AXI_WUSER_WIDTH-1 downto 0);
M_AXI_WVALID : out std_logic;
M_AXI_WREADY : in std_logic;
-- Master Interface Write Response
M_AXI_BID : in std_logic_vector(C_M_AXI_THREAD_ID_WIDTH-1 downto 0);
M_AXI_BRESP : in std_logic_vector(2-1 downto 0);
M_AXI_BUSER : in std_logic_vector(C_M_AXI_BUSER_WIDTH-1 downto 0);
M_AXI_BVALID : in std_logic;
M_AXI_BREADY : out std_logic;
-- Master Interface Read Address
M_AXI_ARID : out std_logic_vector(C_M_AXI_THREAD_ID_WIDTH-1 downto 0);
M_AXI_ARADDR : out std_logic_vector(C_M_AXI_ADDR_WIDTH-1 downto 0);
M_AXI_ARLEN : out std_logic_vector(8-1 downto 0);
M_AXI_ARSIZE : out std_logic_vector(3-1 downto 0);
M_AXI_ARBURST : out std_logic_vector(2-1 downto 0);
M_AXI_ARLOCK : out std_logic_vector(2-1 downto 0);
M_AXI_ARCACHE : out std_logic_vector(4-1 downto 0);
M_AXI_ARPROT : out std_logic_vector(3-1 downto 0);
-- AXI3 M_AXI_ARREGION:out std_logic_vector(4-1 downto 0);
M_AXI_ARQOS : out std_logic_vector(4-1 downto 0);
M_AXI_ARUSER : out std_logic_vector(C_M_AXI_ARUSER_WIDTH-1 downto 0);
M_AXI_ARVALID : out std_logic;
M_AXI_ARREADY : in std_logic;
-- Master Interface Read Data
M_AXI_RID : in std_logic_vector(C_M_AXI_THREAD_ID_WIDTH-1 downto 0);
M_AXI_RDATA : in std_logic_vector(C_M_AXI_DATA_WIDTH-1 downto 0);
M_AXI_RRESP : in std_logic_vector(2-1 downto 0);
M_AXI_RLAST : in std_logic;
M_AXI_RUSER : in std_logic_vector(C_M_AXI_RUSER_WIDTH-1 downto 0);
M_AXI_RVALID : in std_logic;
M_AXI_RREADY : out std_logic;
-- Example Design only
wr_error : out std_logic;
rd_error : out std_logic
);
end cdctest_axi_master;
-------------------------------------------------------------------------------
-- Architecture
-------------------------------------------------------------------------------
architecture implementation of cdctest_axi_master is
constant RESP_OKAY : std_logic_vector := "00";
constant RESP_EXOKAY : std_logic_vector := "01";
constant RESP_SLVERR : std_logic_vector := "10";
constant RESP_DECERR : std_logic_vector := "11";
constant SVGA_ADDR_LIMIT : integer := 800/8*600/8*4; -- SVGAのアドレスリミット(横ドット数/1文字の横ドット数 * 縦ドット数/1文字の縦のドット数 * 1文字を表すバイト数)
constant DISP_INTERVAL_DIV : integer := 20000000; -- インプリメント 0.2sec
-- constant DISP_INTERVAL_DIV : integer := 3; -- シミュレーション
signal reset_1d, reset_2d, reset : std_logic;
type wr_rd_transaction_state is (write_state, read_state, wait_state);
signal wr_rd_cs : wr_rd_transaction_state;
type write_transaction_state is (idle_wr, awvalid_assert, data_write_hold, bready_assert, wr_tran_end);
signal wrt_cs : write_transaction_state;
type write_wvalid_state is (idle_wvalid, wvalid_assert, wvalid_hold);
signal wrt_wv_cs : write_wvalid_state;
signal awvalid, wvalid, bready : std_logic;
signal w_r_addr : std_logic_vector(31 downto 0);
signal write_data : std_logic_vector(15 downto 0);
signal awlen16 : std_logic_vector(15 downto 0);
signal awlen, write_count : std_logic_vector(7 downto 0);
signal wlast : std_logic;
type read_transaction_state is (idle_rd, arvalid_assert, data_read, rd_tran_end);
signal rdt_cs : read_transaction_state;
signal arvalid : std_logic;
signal arlen, read_count : std_logic_vector(7 downto 0);
signal read_data : std_logic_vector(15 downto 0);
signal rready : std_logic;
signal disp_count : integer;
signal disp_ena : std_logic;
begin
-- ARESETN をACLK で同期化
process (ACLK) begin
if ACLK'event and ACLK='1' then
reset_1d <= not ARESETN;
reset_2d <= reset_1d;
end if;
end process;
reset <= reset_2d;
-- インプリメントでは0.2秒に1回表示する
process(ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
disp_count <= 0;
disp_ena <= '0';
else
if disp_count = DISP_INTERVAL_DIV then
disp_count <= 0;
disp_ena <= '1';
else
disp_count <= disp_count + 1;
disp_ena <= '0';
end if;
end if;
end if;
end process;
-- Write, Read Transaction State Machine
-- Writeが終了したらReadを行う。シーケンシャルにWrite, Readを繰り返す。
process(ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
wr_rd_cs <= write_state;
else
case (wr_rd_cs) is
when write_state =>
if wrt_cs = wr_tran_end then
wr_rd_cs <= read_state;
end if;
when read_state =>
if rdt_cs = rd_tran_end then
wr_rd_cs <= wait_state;
end if;
when wait_state =>
if disp_ena='1' then
wr_rd_cs <= write_state;
end if;
end case;
end if;
end if;
end process;
-- Write
M_AXI_AWID <= "0";
M_AXI_AWSIZE <= "010"; -- 4bytes fixed
M_AXI_AWBURST <= "01"; -- INCR
M_AXI_AWLOCK <= '0'; -- Normal Access
M_AXI_AWCACHE <= "0010"; -- Normal Non-cacheable Non-bufferable
M_AXI_AWPROT <= "000"; -- Data access, Secure access, Unprivileged access
M_AXI_AWQOS <= "0000"; -- default
M_AXI_AWUSER <= "0";
M_AXI_WSTRB <= "1111";
M_AXI_WUSER <= "0";
-- AXI4バス Write Transaction State Machine
process(ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
wrt_cs <= idle_wr;
awvalid <= '0';
bready <= '0';
else
case(wrt_cs) is
when idle_wr =>
if wr_rd_cs = write_state then
wrt_cs <= awvalid_assert;
awvalid <= '1';
end if;
when awvalid_assert =>
if M_AXI_AWREADY='1' then
if wrt_wv_cs=wvalid_hold or (wrt_wv_cs=wvalid_assert and write_count=0 and M_AXI_WREADY='1') then
wrt_cs <= bready_assert;
bready <= '1';
else
wrt_cs <= data_write_hold;
end if;
awvalid <= '0';
end if;
when data_write_hold =>
if wrt_wv_cs=wvalid_hold or (wrt_wv_cs=wvalid_assert and write_count=0 and M_AXI_WREADY='1') then
wrt_cs <= bready_assert;
bready <= '1';
end if;
when bready_assert =>
if M_AXI_BVALID='1' then
wrt_cs <= wr_tran_end;
bready <= '0';
end if;
when wr_tran_end =>
wrt_cs <= idle_wr;
end case;
end if;
end if;
end process;
-- AXI4 バス Write Transaction WVALID State Machine
process(ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
wrt_wv_cs <= idle_wvalid;
wvalid <= '0';
else
case(wrt_wv_cs) is
when idle_wvalid =>
if wrt_cs=awvalid_assert then
wrt_wv_cs <= wvalid_assert;
wvalid <= '1';
end if;
when wvalid_assert =>
if write_count=0 and M_AXI_WREADY='1' then -- 終了
wrt_wv_cs <= wvalid_hold;
wvalid <= '0';
end if;
when wvalid_hold =>
if wrt_cs=bready_assert then
wrt_wv_cs <= idle_wvalid;
end if;
end case;
end if;
end if;
end process;
M_AXI_AWVALID <= awvalid;
M_AXI_WVALID <= wvalid;
M_AXI_BREADY <= bready;
-- w_r_addr の処理、Write Transaction が終了するたびにawlen+1を加える。加える途中でSVGA_ADDR_LIMITを超える時はどうするかだが、そこは無視する
process(ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
w_r_addr <= (others => '0');
else
if wrt_wv_cs=wvalid_assert and M_AXI_WREADY='1' then
w_r_addr <= w_r_addr + 4;
elsif wrt_cs=bready_assert and w_r_addr >= SVGA_ADDR_LIMIT then
w_r_addr <= (others => '0');
end if;
end if;
end if;
end process;
M_AXI_AWADDR <= w_r_addr;
-- M_AXI_AWLEN の値を決定する。M系列を使用してランダムな値とする
process(ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
awlen16 <= CONV_STD_LOGIC_VECTOR(1, 16); -- 0 はダメ
else
if wr_rd_cs=write_state and wrt_cs=idle_wr then
awlen16 <= M_SEQ16_F(awlen16);
end if;
end if;
end if;
end process;
awlen <= awlen16(7 downto 0);
M_AXI_AWLEN <= awlen;
-- write_data の処理、0から0xffffまで
process(ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
write_data <= (others => '0');
else
if wrt_wv_cs=wvalid_assert and M_AXI_WREADY='1' then
if write_data = x"FFFF" then -- 終了なのでクリア
write_data <= (others => '0'); -- これをしなくても0に戻るが将来他の値でリミットするためにコードを入れておく
else -- data write
write_data <= write_data + 1;
end if;
end if;
end if;
end if;
end process;
M_AXI_WDATA(31 downto 16) <= (others => '0');
M_AXI_WDATA(15 downto 0) <= write_data;
-- write_count の処理
process(ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
write_count <= (others => '0');
else
if wrt_cs=awvalid_assert then
write_count <= awlen;
elsif wrt_wv_cs=wvalid_assert and M_AXI_WREADY='1' then
write_count <= write_count - 1;
end if;
end if;
end if;
end process;
-- wlastの処理
process(ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
wlast <= '0';
else
if wrt_cs=awvalid_assert and awlen=0 and M_AXI_AWREADY='1' then -- awlen が0の時はデータ転送の最初からwlast をアサートする
wlast <= '1';
elsif wrt_wv_cs=wvalid_assert and write_count=1 and M_AXI_WREADY='1' then -- awlen が0で無い時はwrite_count が1でM_AXI_WREADY='1'の時、つまりwrite_count が0の時にwlastをアサートする
wlast <= '1';
elsif wrt_wv_cs=wvalid_assert and write_count=0 and M_AXI_WREADY='1' then -- データ転送が終了なのでwlast を0にする
wlast <= '0';
end if;
end if;
end if;
end process;
M_AXI_WLAST <= wlast;
-- wr_error の処理、M_AXI_BRESPがRESP_OKAY以外の時にwr_errorを点灯する
process(ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
wr_error <= '0';
else
if wrt_cs=bready_assert and M_AXI_BVALID='1' and M_AXI_BRESP/=RESP_OKAY then
wr_error <= '1';
end if;
end if;
end if;
end process;
-- Read
M_AXI_ARID <= "0";
M_AXI_ARLEN <= awlen;
M_AXI_ARSIZE <= "010"; -- 4bytes
M_AXI_ARBURST <= "01"; -- INCR
M_AXI_ARLOCK <= "00"; -- Normal Access
M_AXI_ARCACHE <= "0010"; -- Normal Non-cacheable Non-bufferable
M_AXI_ARPROT <= "000"; -- Data access, Secure access, Unprivileged access
M_AXI_ARQOS <= "0000"; -- default
M_AXI_ARUSER <= "0";
-- M_AXI_ARADDR の処理、M_AXI_AWVALIDが1の時のw_r_addr を保存しておく
process(ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
M_AXI_ARADDR <= (others => '0');
else
if awvalid='1' then
M_AXI_ARADDR <= w_r_addr;
end if;
end if;
end if;
end process;
-- AXI4バス Read Transaction State Machine
process(ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
rdt_cs <= idle_rd;
arvalid <= '0';
rready <= '0';
else
case rdt_cs is
when idle_rd =>
if wr_rd_cs=read_state then
rdt_cs <= arvalid_assert;
arvalid <= '1';
end if;
when arvalid_assert =>
if M_AXI_ARREADY='1' then
rdt_cs <= data_read;
arvalid <= '0';
rready <= '1';
end if;
when data_read =>
if read_count=0 and M_AXI_RVALID='1' then -- 終了
rdt_cs <= rd_tran_end;
rready <= '0';
end if;
when rd_tran_end =>
rdt_cs <= idle_rd;
end case;
end if;
end if;
end process;
M_AXI_ARVALID <= arvalid;
M_AXI_RREADY <= rready;
-- read_data の処理
process(ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
read_data <= (others => '0');
else
if rdt_cs=data_read and M_AXI_RVALID='1' then
if read_data=x"FFFF" then -- 終了なのでクリア
read_data <= (others => '0');
else -- data read
read_data <= read_data + 1;
end if;
end if;
end if;
end if;
end process;
-- read_count の処理
process(ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
read_count <= (others => '0');
else
if rdt_cs=arvalid_assert then
read_count <= awlen;
elsif rdt_cs=data_read and M_AXI_RVALID='1' then
read_count <= read_count - 1;
end if;
end if;
end if;
end process;
-- rd_error の処理
process(ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
rd_error <= '0';
else
if rdt_cs=data_read and M_AXI_RVALID='1' then -- Read Transaction
if M_AXI_RDATA(15 downto 0) /= read_data then
rd_error <= '1';
elsif M_AXI_RRESP /= RESP_OKAY then
rd_error <= '1';
end if;
end if;
end if;
end if;
end process;
end implementation;
constant DISP_INTERVAL_DIV : integer := 20000000; -- インプリメント 0.2sec
-- constant DISP_INTERVAL_DIV : integer := 3; -- シミュレーション
`default_nettype none
`timescale 100ps / 1ps
module cdctest_axi_master_tb;
// Inputs
wire ACLK;
wire ARESETN;
wire M_AXI_AWREADY;
wire M_AXI_WREADY;
wire [0:0] M_AXI_BID;
wire [1:0] M_AXI_BRESP;
wire [0:0] M_AXI_BUSER;
wire M_AXI_BVALID;
wire M_AXI_ARREADY;
wire [0:0] M_AXI_RID;
wire [31:0] M_AXI_RDATA;
wire [1:0] M_AXI_RRESP;
wire M_AXI_RLAST;
wire [0:0] M_AXI_RUSER;
wire M_AXI_RVALID;
// Outputs
wire [0:0] M_AXI_AWID;
wire [31:0] M_AXI_AWADDR;
wire [7:0] M_AXI_AWLEN;
wire [2:0] M_AXI_AWSIZE;
wire [1:0] M_AXI_AWBURST;
wire M_AXI_AWLOCK;
wire [3:0] M_AXI_AWCACHE;
wire [2:0] M_AXI_AWPROT;
wire [3:0] M_AXI_AWQOS;
wire [0:0] M_AXI_AWUSER;
wire M_AXI_AWVALID;
wire [31:0] M_AXI_WDATA;
wire [3:0] M_AXI_WSTRB;
wire M_AXI_WLAST;
wire [0:0] M_AXI_WUSER;
wire M_AXI_WVALID;
wire M_AXI_BREADY;
wire [0:0] M_AXI_ARID;
wire [31:0] M_AXI_ARADDR;
wire [7:0] M_AXI_ARLEN;
wire [2:0] M_AXI_ARSIZE;
wire [1:0] M_AXI_ARBURST;
wire [1:0] M_AXI_ARLOCK;
wire [3:0] M_AXI_ARCACHE;
wire [2:0] M_AXI_ARPROT;
wire [3:0] M_AXI_ARQOS;
wire [0:0] M_AXI_ARUSER;
wire M_AXI_ARVALID;
wire M_AXI_RREADY;
wire wr_error;
wire rd_error;
wire pixclk;
wire TMDS_tx_clk_p;
wire TMDS_tx_clk_n;
wire TMDS_tx_2_G_p;
wire TMDS_tx_2_G_n;
wire TMDS_tx_1_R_p;
wire TMDS_tx_1_R_n;
wire TMDS_tx_0_B_p;
wire TMDS_tx_0_B_n;
wire [3:0] S_AXI_AWREGION = 0;
wire [0:0] S_AXI_WID = 0;
wire [3:0] S_AXI_ARREGION = 0;
// Instantiate the Unit Under Test (UUT_MASTER)
cdctest_axi_master uut_master (
.ACLK(ACLK),
.ARESETN(ARESETN),
.M_AXI_AWID(M_AXI_AWID),
.M_AXI_AWADDR(M_AXI_AWADDR),
.M_AXI_AWLEN(M_AXI_AWLEN),
.M_AXI_AWSIZE(M_AXI_AWSIZE),
.M_AXI_AWBURST(M_AXI_AWBURST),
.M_AXI_AWLOCK(M_AXI_AWLOCK),
.M_AXI_AWCACHE(M_AXI_AWCACHE),
.M_AXI_AWPROT(M_AXI_AWPROT),
.M_AXI_AWQOS(M_AXI_AWQOS),
.M_AXI_AWUSER(M_AXI_AWUSER),
.M_AXI_AWVALID(M_AXI_AWVALID),
.M_AXI_AWREADY(M_AXI_AWREADY),
.M_AXI_WDATA(M_AXI_WDATA),
.M_AXI_WSTRB(M_AXI_WSTRB),
.M_AXI_WLAST(M_AXI_WLAST),
.M_AXI_WUSER(M_AXI_WUSER),
.M_AXI_WVALID(M_AXI_WVALID),
.M_AXI_WREADY(M_AXI_WREADY),
.M_AXI_BID(M_AXI_BID),
.M_AXI_BRESP(M_AXI_BRESP),
.M_AXI_BUSER(M_AXI_BUSER),
.M_AXI_BVALID(M_AXI_BVALID),
.M_AXI_BREADY(M_AXI_BREADY),
.M_AXI_ARID(M_AXI_ARID),
.M_AXI_ARADDR(M_AXI_ARADDR),
.M_AXI_ARLEN(M_AXI_ARLEN),
.M_AXI_ARSIZE(M_AXI_ARSIZE),
.M_AXI_ARBURST(M_AXI_ARBURST),
.M_AXI_ARLOCK(M_AXI_ARLOCK),
.M_AXI_ARCACHE(M_AXI_ARCACHE),
.M_AXI_ARPROT(M_AXI_ARPROT),
.M_AXI_ARQOS(M_AXI_ARQOS),
.M_AXI_ARUSER(M_AXI_ARUSER),
.M_AXI_ARVALID(M_AXI_ARVALID),
.M_AXI_ARREADY(M_AXI_ARREADY),
.M_AXI_RID(M_AXI_RID),
.M_AXI_RDATA(M_AXI_RDATA),
.M_AXI_RRESP(M_AXI_RRESP),
.M_AXI_RLAST(M_AXI_RLAST),
.M_AXI_RUSER(M_AXI_RUSER),
.M_AXI_RVALID(M_AXI_RVALID),
.M_AXI_RREADY(M_AXI_RREADY),
.wr_error(wr_error),
.rd_error(rd_error)
);
// clk_gen のインスタンス
clk_gen #(
.CLK_PERIOD(100), // 10nsec, 100MHz
.CLK_DUTY_CYCLE(0.5),
.CLK_OFFSET(0),
.START_STATE(1'b0)
) ACLKi (
.clk_out(ACLK)
);
clk_gen #(
.CLK_PERIOD(250), // 25nsec, 40MHz
.CLK_DUTY_CYCLE(0.5),
.CLK_OFFSET(0),
.START_STATE(1'b0)
) PIXCLKi (
.clk_out(pixclk)
);
// reset_gen のインスタンス
reset_gen #(
.RESET_STATE(1'b0),
.RESET_TIME(1000) // 100nsec
) RESETi (
.reset_out(ARESETN)
);
// Instantiate the Unit Under Test (UUT_slave)
CDC_axi_slave uut_slave (
.ACLK(ACLK),
.ARESETN(ARESETN),
.S_AXI_AWID(M_AXI_AWID),
.S_AXI_AWADDR(M_AXI_AWADDR),
.S_AXI_AWLEN(M_AXI_AWLEN),
.S_AXI_AWSIZE(M_AXI_AWSIZE),
.S_AXI_AWBURST(M_AXI_AWBURST),
.S_AXI_AWLOCK(2'b00),
.S_AXI_AWCACHE(M_AXI_AWCACHE),
.S_AXI_AWPROT(M_AXI_AWPROT),
.S_AXI_AWREGION(S_AXI_AWREGION),
.S_AXI_AWQOS(M_AXI_AWQOS),
.S_AXI_AWUSER(M_AXI_AWUSER),
.S_AXI_AWVALID(M_AXI_AWVALID),
.S_AXI_AWREADY(M_AXI_AWREADY),
.S_AXI_WID(S_AXI_WID),
.S_AXI_WDATA(M_AXI_WDATA),
.S_AXI_WSTRB(M_AXI_WSTRB),
.S_AXI_WLAST(M_AXI_WLAST),
.S_AXI_WUSER(M_AXI_WUSER),
.S_AXI_WVALID(M_AXI_WVALID),
.S_AXI_WREADY(M_AXI_WREADY),
.S_AXI_BID(M_AXI_BID),
.S_AXI_BRESP(M_AXI_BRESP),
.S_AXI_BUSER(M_AXI_BUSER),
.S_AXI_BVALID(M_AXI_BVALID),
.S_AXI_BREADY(M_AXI_BREADY),
.S_AXI_ARID(M_AXI_ARID),
.S_AXI_ARADDR(M_AXI_ARADDR),
.S_AXI_ARLEN(M_AXI_ARLEN),
.S_AXI_ARSIZE(M_AXI_ARSIZE),
.S_AXI_ARBURST(M_AXI_ARBURST),
.S_AXI_ARLOCK(M_AXI_ARLOCK),
.S_AXI_ARCACHE(M_AXI_ARCACHE),
.S_AXI_ARPROT(M_AXI_ARPROT),
.S_AXI_ARREGION(S_AXI_ARREGION),
.S_AXI_ARQOS(M_AXI_ARQOS),
.S_AXI_ARUSER(M_AXI_ARUSER),
.S_AXI_ARVALID(M_AXI_ARVALID),
.S_AXI_ARREADY(M_AXI_ARREADY),
.S_AXI_RID(M_AXI_RID),
.S_AXI_RDATA(M_AXI_RDATA),
.S_AXI_RRESP(M_AXI_RRESP),
.S_AXI_RLAST(M_AXI_RLAST),
.S_AXI_RUSER(M_AXI_RUSER),
.S_AXI_RVALID(M_AXI_RVALID),
.S_AXI_RREADY(M_AXI_RREADY),
.pixclk(pixclk),
.TMDS_tx_clk_p(TMDS_tx_clk_p),
.TMDS_tx_clk_n(TMDS_tx_clk_n),
.TMDS_tx_2_G_p(TMDS_tx_2_G_p),
.TMDS_tx_2_G_n(TMDS_tx_2_G_n),
.TMDS_tx_1_R_p(TMDS_tx_1_R_p),
.TMDS_tx_1_R_n(TMDS_tx_1_R_n),
.TMDS_tx_0_B_p(TMDS_tx_0_B_p),
.TMDS_tx_0_B_n(TMDS_tx_0_B_n)
);
endmodule
module clk_gen #(
parameter CLK_PERIOD = 100,
parameter real CLK_DUTY_CYCLE = 0.5,
parameter CLK_OFFSET = 0,
parameter START_STATE = 1'b0 )
(
output reg clk_out
);
begin
initial begin
#CLK_OFFSET;
forever
begin
clk_out = START_STATE;
#(CLK_PERIOD-(CLK_PERIOD*CLK_DUTY_CYCLE)) clk_out = ~START_STATE;
#(CLK_PERIOD*CLK_DUTY_CYCLE);
end
end
end
endmodule
module reset_gen #(
parameter RESET_STATE = 1'b1,
parameter RESET_TIME = 100 )
(
output reg reset_out
);
begin
initial begin
reset_out = RESET_STATE;
#RESET_TIME;
reset_out = ~RESET_STATE;
end
end
endmodule
`default_nettype wire
日 | 月 | 火 | 水 | 木 | 金 | 土 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | - | - | - | - | - |