mirror of
https://github.com/corundum/corundum.git
synced 2025-01-30 08:32:52 +08:00
added axis as a subproject
git-subtree-dir: lib/axis git-subtree-mainline: d64445b9e057cf97ae8fd57fbe83c5505c6ba45c git-subtree-split: ac2f7e546df3b7f4a936cdb4d558adc517c5ddb4
This commit is contained in:
commit
8214e2abf9
6
lib/axis/.gitignore
vendored
Normal file
6
lib/axis/.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
*~
|
||||
*.lxt
|
||||
*.pyc
|
||||
*.vvp
|
||||
*.kate-swp
|
||||
|
16
lib/axis/.travis.yml
Normal file
16
lib/axis/.travis.yml
Normal file
@ -0,0 +1,16 @@
|
||||
language: python
|
||||
python:
|
||||
- "2.7"
|
||||
virtualenv:
|
||||
system_site_packages: true
|
||||
before_install:
|
||||
- export d=`pwd`
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install -y iverilog
|
||||
- hg clone https://bitbucket.org/jandecaluwe/myhdl
|
||||
- cd $d/myhdl && sudo python setup.py install
|
||||
- cd $d/myhdl/cosimulation/icarus && make && sudo install -m 0755 -D ./myhdl.vpi /usr/lib/ivl/myhdl.vpi
|
||||
- cd $d
|
||||
script:
|
||||
- cd tb && py.test
|
||||
|
1
lib/axis/AUTHORS
Normal file
1
lib/axis/AUTHORS
Normal file
@ -0,0 +1 @@
|
||||
Alex Forencich <alex@alexforencich.com>
|
19
lib/axis/COPYING
Normal file
19
lib/axis/COPYING
Normal file
@ -0,0 +1,19 @@
|
||||
Copyright (c) 2014 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
2
lib/axis/README
Normal file
2
lib/axis/README
Normal file
@ -0,0 +1,2 @@
|
||||
Verilog AXI Stream components
|
||||
|
432
lib/axis/rtl/axis_adapter.v
Normal file
432
lib/axis/rtl/axis_adapter.v
Normal file
@ -0,0 +1,432 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
/*
|
||||
* AXI4-Stream bus width adapter
|
||||
*/
|
||||
module axis_adapter #
|
||||
(
|
||||
parameter INPUT_DATA_WIDTH = 8,
|
||||
parameter INPUT_KEEP_WIDTH = (INPUT_DATA_WIDTH/8),
|
||||
parameter OUTPUT_DATA_WIDTH = 8,
|
||||
parameter OUTPUT_KEEP_WIDTH = (OUTPUT_DATA_WIDTH/8)
|
||||
)
|
||||
(
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
|
||||
/*
|
||||
* AXI input
|
||||
*/
|
||||
input wire [INPUT_DATA_WIDTH-1:0] input_axis_tdata,
|
||||
input wire [INPUT_KEEP_WIDTH-1:0] input_axis_tkeep,
|
||||
input wire input_axis_tvalid,
|
||||
output wire input_axis_tready,
|
||||
input wire input_axis_tlast,
|
||||
input wire input_axis_tuser,
|
||||
|
||||
/*
|
||||
* AXI output
|
||||
*/
|
||||
output wire [OUTPUT_DATA_WIDTH-1:0] output_axis_tdata,
|
||||
output wire [OUTPUT_KEEP_WIDTH-1:0] output_axis_tkeep,
|
||||
output wire output_axis_tvalid,
|
||||
input wire output_axis_tready,
|
||||
output wire output_axis_tlast,
|
||||
output wire output_axis_tuser
|
||||
);
|
||||
|
||||
// bus word widths (must be identical)
|
||||
localparam INPUT_DATA_WORD_WIDTH = INPUT_DATA_WIDTH / INPUT_KEEP_WIDTH;
|
||||
localparam OUTPUT_DATA_WORD_WIDTH = OUTPUT_DATA_WIDTH / OUTPUT_KEEP_WIDTH;
|
||||
// output bus is wider
|
||||
localparam EXPAND_BUS = OUTPUT_KEEP_WIDTH > INPUT_KEEP_WIDTH;
|
||||
// total data and keep widths
|
||||
localparam DATA_WIDTH = EXPAND_BUS ? OUTPUT_DATA_WIDTH : INPUT_DATA_WIDTH;
|
||||
localparam KEEP_WIDTH = EXPAND_BUS ? OUTPUT_KEEP_WIDTH : INPUT_KEEP_WIDTH;
|
||||
// required number of cycles to match widths
|
||||
localparam CYCLE_COUNT = EXPAND_BUS ? (OUTPUT_KEEP_WIDTH / INPUT_KEEP_WIDTH) : (INPUT_KEEP_WIDTH / OUTPUT_KEEP_WIDTH);
|
||||
// data width and keep width per cycle
|
||||
localparam CYCLE_DATA_WIDTH = DATA_WIDTH / CYCLE_COUNT;
|
||||
localparam CYCLE_KEEP_WIDTH = KEEP_WIDTH / CYCLE_COUNT;
|
||||
|
||||
// bus width assertions
|
||||
initial begin
|
||||
if (INPUT_DATA_WORD_WIDTH * INPUT_KEEP_WIDTH != INPUT_DATA_WIDTH) begin
|
||||
$error("Error: input data width not evenly divisble");
|
||||
$finish;
|
||||
end
|
||||
|
||||
if (OUTPUT_DATA_WORD_WIDTH * OUTPUT_KEEP_WIDTH != OUTPUT_DATA_WIDTH) begin
|
||||
$error("Error: output data width not evenly divisble");
|
||||
$finish;
|
||||
end
|
||||
|
||||
if (INPUT_DATA_WORD_WIDTH != OUTPUT_DATA_WORD_WIDTH) begin
|
||||
$error("Error: word width mismatch");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
// state register
|
||||
localparam [2:0]
|
||||
STATE_IDLE = 3'd0,
|
||||
STATE_TRANSFER_IN = 3'd1,
|
||||
STATE_TRANSFER_OUT = 3'd2;
|
||||
|
||||
reg [2:0] state_reg = STATE_IDLE, state_next;
|
||||
|
||||
reg [7:0] cycle_count_reg = 0, cycle_count_next;
|
||||
|
||||
reg [DATA_WIDTH-1:0] temp_tdata_reg = 0, temp_tdata_next;
|
||||
reg [KEEP_WIDTH-1:0] temp_tkeep_reg = 0, temp_tkeep_next;
|
||||
reg temp_tlast_reg = 0, temp_tlast_next;
|
||||
reg temp_tuser_reg = 0, temp_tuser_next;
|
||||
|
||||
// internal datapath
|
||||
reg [OUTPUT_DATA_WIDTH-1:0] output_axis_tdata_int;
|
||||
reg [OUTPUT_KEEP_WIDTH-1:0] output_axis_tkeep_int;
|
||||
reg output_axis_tvalid_int;
|
||||
reg output_axis_tready_int = 0;
|
||||
reg output_axis_tlast_int;
|
||||
reg output_axis_tuser_int;
|
||||
wire output_axis_tready_int_early;
|
||||
|
||||
reg input_axis_tready_reg = 0, input_axis_tready_next;
|
||||
assign input_axis_tready = input_axis_tready_reg;
|
||||
|
||||
always @* begin
|
||||
state_next = 3'bz;
|
||||
|
||||
cycle_count_next = cycle_count_reg;
|
||||
|
||||
temp_tdata_next = temp_tdata_reg;
|
||||
temp_tkeep_next = temp_tkeep_reg;
|
||||
temp_tlast_next = temp_tlast_reg;
|
||||
temp_tuser_next = temp_tuser_reg;
|
||||
|
||||
output_axis_tdata_int = 0;
|
||||
output_axis_tkeep_int = 0;
|
||||
output_axis_tvalid_int = 0;
|
||||
output_axis_tlast_int = 0;
|
||||
output_axis_tuser_int = 0;
|
||||
|
||||
input_axis_tready_next = 0;
|
||||
|
||||
case (state_reg)
|
||||
STATE_IDLE: begin
|
||||
// idle state - no data in registers
|
||||
if (CYCLE_COUNT == 1) begin
|
||||
// output and input same width - just act like a register
|
||||
|
||||
// accept data next cycle if output register ready next cycle
|
||||
input_axis_tready_next = output_axis_tready_int_early;
|
||||
|
||||
// transfer through
|
||||
output_axis_tdata_int = input_axis_tdata;
|
||||
output_axis_tkeep_int = input_axis_tkeep;
|
||||
output_axis_tvalid_int = input_axis_tvalid;
|
||||
output_axis_tlast_int = input_axis_tlast;
|
||||
output_axis_tuser_int = input_axis_tuser;
|
||||
|
||||
state_next = STATE_IDLE;
|
||||
end else if (EXPAND_BUS) begin
|
||||
// output bus is wider
|
||||
|
||||
// accept new data
|
||||
input_axis_tready_next = 1;
|
||||
|
||||
if (input_axis_tvalid) begin
|
||||
// word transfer in - store it in data register
|
||||
|
||||
// pass complete input word, zero-extended to temp register
|
||||
temp_tdata_next = input_axis_tdata;
|
||||
temp_tkeep_next = input_axis_tkeep;
|
||||
temp_tlast_next = input_axis_tlast;
|
||||
temp_tuser_next = input_axis_tuser;
|
||||
|
||||
// first input cycle complete
|
||||
cycle_count_next = 1;
|
||||
|
||||
if (input_axis_tlast) begin
|
||||
// got last signal on first cycle, so output it
|
||||
input_axis_tready_next = 0;
|
||||
state_next = STATE_TRANSFER_OUT;
|
||||
end else begin
|
||||
// otherwise, transfer in the rest of the words
|
||||
input_axis_tready_next = 1;
|
||||
state_next = STATE_TRANSFER_IN;
|
||||
end
|
||||
end else begin
|
||||
state_next = STATE_IDLE;
|
||||
end
|
||||
end else begin
|
||||
// output bus is narrower
|
||||
|
||||
// accept new data
|
||||
input_axis_tready_next = 1;
|
||||
|
||||
if (input_axis_tvalid) begin
|
||||
// word transfer in - store it in data register
|
||||
cycle_count_next = 0;
|
||||
|
||||
// pass complete input word, zero-extended to temp register
|
||||
temp_tdata_next = input_axis_tdata;
|
||||
temp_tkeep_next = input_axis_tkeep;
|
||||
temp_tlast_next = input_axis_tlast;
|
||||
temp_tuser_next = input_axis_tuser;
|
||||
|
||||
// short-circuit and get first word out the door
|
||||
output_axis_tdata_int = input_axis_tdata;
|
||||
output_axis_tkeep_int = input_axis_tkeep;
|
||||
output_axis_tvalid_int = 1;
|
||||
output_axis_tlast_int = input_axis_tlast & ((CYCLE_COUNT == 1) | (input_axis_tkeep[CYCLE_KEEP_WIDTH-1:0] != {CYCLE_KEEP_WIDTH{1'b1}}));
|
||||
output_axis_tuser_int = input_axis_tuser & ((CYCLE_COUNT == 1) | (input_axis_tkeep[CYCLE_KEEP_WIDTH-1:0] != {CYCLE_KEEP_WIDTH{1'b1}}));
|
||||
|
||||
if (output_axis_tready_int) begin
|
||||
// if output register is ready for first word, then move on to the next one
|
||||
cycle_count_next = 1;
|
||||
end
|
||||
|
||||
// continue outputting words
|
||||
input_axis_tready_next = 0;
|
||||
state_next = STATE_TRANSFER_OUT;
|
||||
end else begin
|
||||
state_next = STATE_IDLE;
|
||||
end
|
||||
end
|
||||
end
|
||||
STATE_TRANSFER_IN: begin
|
||||
// transfer word to temp registers
|
||||
// only used when output is wider
|
||||
|
||||
// accept new data
|
||||
input_axis_tready_next = 1;
|
||||
|
||||
if (input_axis_tvalid) begin
|
||||
// word transfer in - store in data register
|
||||
|
||||
temp_tdata_next[cycle_count_reg*CYCLE_DATA_WIDTH +: CYCLE_DATA_WIDTH] = input_axis_tdata;
|
||||
temp_tkeep_next[cycle_count_reg*CYCLE_KEEP_WIDTH +: CYCLE_KEEP_WIDTH] = input_axis_tkeep;
|
||||
temp_tlast_next = input_axis_tlast;
|
||||
temp_tuser_next = input_axis_tuser;
|
||||
|
||||
cycle_count_next = cycle_count_reg + 1;
|
||||
|
||||
if ((cycle_count_reg == CYCLE_COUNT-1) | input_axis_tlast) begin
|
||||
// terminated by counter or tlast signal, output complete word
|
||||
// read input word next cycle if output will be ready
|
||||
input_axis_tready_next = output_axis_tready_int_early;
|
||||
state_next = STATE_TRANSFER_OUT;
|
||||
end else begin
|
||||
// more words to read
|
||||
input_axis_tready_next = 1;
|
||||
state_next = STATE_TRANSFER_IN;
|
||||
end
|
||||
end else begin
|
||||
state_next = STATE_TRANSFER_IN;
|
||||
end
|
||||
end
|
||||
STATE_TRANSFER_OUT: begin
|
||||
// transfer word to output registers
|
||||
|
||||
if (EXPAND_BUS) begin
|
||||
// output bus is wider
|
||||
|
||||
// do not accept new data
|
||||
input_axis_tready_next = 0;
|
||||
|
||||
// single-cycle output of entire stored word (output wider)
|
||||
output_axis_tdata_int = temp_tdata_reg;
|
||||
output_axis_tkeep_int = temp_tkeep_reg;
|
||||
output_axis_tvalid_int = 1;
|
||||
output_axis_tlast_int = temp_tlast_reg;
|
||||
output_axis_tuser_int = temp_tuser_reg;
|
||||
|
||||
if (output_axis_tready_int) begin
|
||||
// word transfer out
|
||||
|
||||
if (input_axis_tready & input_axis_tvalid) begin
|
||||
// word transfer in
|
||||
|
||||
// pass complete input word, zero-extended to temp register
|
||||
temp_tdata_next = input_axis_tdata;
|
||||
temp_tkeep_next = input_axis_tkeep;
|
||||
temp_tlast_next = input_axis_tlast;
|
||||
temp_tuser_next = input_axis_tuser;
|
||||
|
||||
// first input cycle complete
|
||||
cycle_count_next = 1;
|
||||
|
||||
if (input_axis_tlast) begin
|
||||
// got last signal on first cycle, so output it
|
||||
input_axis_tready_next = 0;
|
||||
state_next = STATE_TRANSFER_OUT;
|
||||
end else begin
|
||||
// otherwise, transfer in the rest of the words
|
||||
input_axis_tready_next = 1;
|
||||
state_next = STATE_TRANSFER_IN;
|
||||
end
|
||||
end else begin
|
||||
input_axis_tready_next = 1;
|
||||
state_next = STATE_IDLE;
|
||||
end
|
||||
end else begin
|
||||
state_next = STATE_TRANSFER_OUT;
|
||||
end
|
||||
end else begin
|
||||
// output bus is narrower
|
||||
|
||||
// do not accept new data
|
||||
input_axis_tready_next = 0;
|
||||
|
||||
// output current part of stored word (output narrower)
|
||||
output_axis_tdata_int = temp_tdata_reg[cycle_count_reg*CYCLE_DATA_WIDTH +: CYCLE_DATA_WIDTH];
|
||||
output_axis_tkeep_int = temp_tkeep_reg[cycle_count_reg*CYCLE_KEEP_WIDTH +: CYCLE_KEEP_WIDTH];
|
||||
output_axis_tvalid_int = 1;
|
||||
output_axis_tlast_int = temp_tlast_reg & ((cycle_count_reg == CYCLE_COUNT-1) | (temp_tkeep_reg[cycle_count_reg*CYCLE_KEEP_WIDTH +: CYCLE_KEEP_WIDTH] != {CYCLE_KEEP_WIDTH{1'b1}}));
|
||||
output_axis_tuser_int = temp_tuser_reg & ((cycle_count_reg == CYCLE_COUNT-1) | (temp_tkeep_reg[cycle_count_reg*CYCLE_KEEP_WIDTH +: CYCLE_KEEP_WIDTH] != {CYCLE_KEEP_WIDTH{1'b1}}));
|
||||
|
||||
if (output_axis_tready_int) begin
|
||||
// word transfer out
|
||||
|
||||
cycle_count_next = cycle_count_reg + 1;
|
||||
|
||||
if ((cycle_count_reg == CYCLE_COUNT-1) | (temp_tkeep_reg[cycle_count_reg*CYCLE_KEEP_WIDTH +: CYCLE_KEEP_WIDTH] != {CYCLE_KEEP_WIDTH{1'b1}})) begin
|
||||
// terminated by counter or tlast signal
|
||||
|
||||
input_axis_tready_next = 1;
|
||||
state_next = STATE_IDLE;
|
||||
end else begin
|
||||
// more words to write
|
||||
state_next = STATE_TRANSFER_OUT;
|
||||
end
|
||||
end else begin
|
||||
state_next = STATE_TRANSFER_OUT;
|
||||
end
|
||||
end
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
always @(posedge clk or posedge rst) begin
|
||||
if (rst) begin
|
||||
state_reg <= STATE_IDLE;
|
||||
cycle_count_reg <= 0;
|
||||
temp_tdata_reg <= 0;
|
||||
temp_tkeep_reg <= 0;
|
||||
temp_tlast_reg <= 0;
|
||||
temp_tuser_reg <= 0;
|
||||
input_axis_tready_reg <= 0;
|
||||
end else begin
|
||||
state_reg <= state_next;
|
||||
|
||||
input_axis_tready_reg <= input_axis_tready_next;
|
||||
|
||||
temp_tdata_reg <= temp_tdata_next;
|
||||
temp_tkeep_reg <= temp_tkeep_next;
|
||||
temp_tlast_reg <= temp_tlast_next;
|
||||
temp_tuser_reg <= temp_tuser_next;
|
||||
|
||||
cycle_count_reg <= cycle_count_next;
|
||||
end
|
||||
end
|
||||
|
||||
// output datapath logic
|
||||
reg [OUTPUT_DATA_WIDTH-1:0] output_axis_tdata_reg = 0;
|
||||
reg [OUTPUT_KEEP_WIDTH-1:0] output_axis_tkeep_reg = 0;
|
||||
reg output_axis_tvalid_reg = 0;
|
||||
reg output_axis_tlast_reg = 0;
|
||||
reg output_axis_tuser_reg = 0;
|
||||
|
||||
reg [OUTPUT_DATA_WIDTH-1:0] temp_axis_tdata_reg = 0;
|
||||
reg [OUTPUT_KEEP_WIDTH-1:0] temp_axis_tkeep_reg = 0;
|
||||
reg temp_axis_tvalid_reg = 0;
|
||||
reg temp_axis_tlast_reg = 0;
|
||||
reg temp_axis_tuser_reg = 0;
|
||||
|
||||
assign output_axis_tdata = output_axis_tdata_reg;
|
||||
assign output_axis_tkeep = output_axis_tkeep_reg;
|
||||
assign output_axis_tvalid = output_axis_tvalid_reg;
|
||||
assign output_axis_tlast = output_axis_tlast_reg;
|
||||
assign output_axis_tuser = output_axis_tuser_reg;
|
||||
|
||||
// enable ready input next cycle if output is ready or if there is space in both output registers or if there is space in the temp register that will not be filled next cycle
|
||||
assign output_axis_tready_int_early = output_axis_tready | (~temp_axis_tvalid_reg & ~output_axis_tvalid_reg) | (~temp_axis_tvalid_reg & ~output_axis_tvalid_int);
|
||||
|
||||
always @(posedge clk or posedge rst) begin
|
||||
if (rst) begin
|
||||
output_axis_tdata_reg <= 0;
|
||||
output_axis_tkeep_reg <= 0;
|
||||
output_axis_tvalid_reg <= 0;
|
||||
output_axis_tlast_reg <= 0;
|
||||
output_axis_tuser_reg <= 0;
|
||||
output_axis_tready_int <= 0;
|
||||
temp_axis_tdata_reg <= 0;
|
||||
temp_axis_tkeep_reg <= 0;
|
||||
temp_axis_tvalid_reg <= 0;
|
||||
temp_axis_tlast_reg <= 0;
|
||||
temp_axis_tuser_reg <= 0;
|
||||
end else begin
|
||||
// transfer sink ready state to source
|
||||
output_axis_tready_int <= output_axis_tready_int_early;
|
||||
|
||||
if (output_axis_tready_int) begin
|
||||
// input is ready
|
||||
if (output_axis_tready | ~output_axis_tvalid_reg) begin
|
||||
// output is ready or currently not valid, transfer data to output
|
||||
output_axis_tdata_reg <= output_axis_tdata_int;
|
||||
output_axis_tkeep_reg <= output_axis_tkeep_int;
|
||||
output_axis_tvalid_reg <= output_axis_tvalid_int;
|
||||
output_axis_tlast_reg <= output_axis_tlast_int;
|
||||
output_axis_tuser_reg <= output_axis_tuser_int;
|
||||
end else begin
|
||||
// output is not ready and currently valid, store input in temp
|
||||
temp_axis_tdata_reg <= output_axis_tdata_int;
|
||||
temp_axis_tkeep_reg <= output_axis_tkeep_int;
|
||||
temp_axis_tvalid_reg <= output_axis_tvalid_int;
|
||||
temp_axis_tlast_reg <= output_axis_tlast_int;
|
||||
temp_axis_tuser_reg <= output_axis_tuser_int;
|
||||
end
|
||||
end else if (output_axis_tready) begin
|
||||
// input is not ready, but output is ready
|
||||
output_axis_tdata_reg <= temp_axis_tdata_reg;
|
||||
output_axis_tkeep_reg <= temp_axis_tkeep_reg;
|
||||
output_axis_tvalid_reg <= temp_axis_tvalid_reg;
|
||||
output_axis_tlast_reg <= temp_axis_tlast_reg;
|
||||
output_axis_tuser_reg <= temp_axis_tuser_reg;
|
||||
temp_axis_tdata_reg <= 0;
|
||||
temp_axis_tkeep_reg <= 0;
|
||||
temp_axis_tvalid_reg <= 0;
|
||||
temp_axis_tlast_reg <= 0;
|
||||
temp_axis_tuser_reg <= 0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
128
lib/axis/rtl/axis_fifo.v
Normal file
128
lib/axis/rtl/axis_fifo.v
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
/*
|
||||
* AXI4-Stream FIFO
|
||||
*/
|
||||
module axis_fifo #
|
||||
(
|
||||
parameter ADDR_WIDTH = 12,
|
||||
parameter DATA_WIDTH = 8
|
||||
)
|
||||
(
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
|
||||
/*
|
||||
* AXI input
|
||||
*/
|
||||
input wire [DATA_WIDTH-1:0] input_axis_tdata,
|
||||
input wire input_axis_tvalid,
|
||||
output wire input_axis_tready,
|
||||
input wire input_axis_tlast,
|
||||
input wire input_axis_tuser,
|
||||
|
||||
/*
|
||||
* AXI output
|
||||
*/
|
||||
output wire [DATA_WIDTH-1:0] output_axis_tdata,
|
||||
output wire output_axis_tvalid,
|
||||
input wire output_axis_tready,
|
||||
output wire output_axis_tlast,
|
||||
output wire output_axis_tuser
|
||||
);
|
||||
|
||||
reg [ADDR_WIDTH-1:0] wr_ptr = {ADDR_WIDTH{1'b0}};
|
||||
reg [ADDR_WIDTH-1:0] rd_ptr = {ADDR_WIDTH{1'b0}};
|
||||
reg [ADDR_WIDTH-1:0] counter = {ADDR_WIDTH{1'b0}};
|
||||
|
||||
reg [DATA_WIDTH+2-1:0] data_out_reg = {1'b0, 1'b0, {DATA_WIDTH{1'b0}}};
|
||||
|
||||
//(* RAM_STYLE="BLOCK" *)
|
||||
reg [DATA_WIDTH+2-1:0] mem[(2**ADDR_WIDTH)-1:0];
|
||||
|
||||
reg output_read = 1'b0;
|
||||
|
||||
reg output_axis_tvalid_reg = 1'b0;
|
||||
|
||||
wire [DATA_WIDTH+2-1:0] data_in = {input_axis_tlast, input_axis_tuser, input_axis_tdata};
|
||||
|
||||
wire full = (counter == (2**ADDR_WIDTH)-1);
|
||||
wire empty = (counter == 0);
|
||||
|
||||
wire write = input_axis_tvalid & ~full;
|
||||
wire read = (output_axis_tready | ~output_axis_tvalid_reg) & ~empty;
|
||||
|
||||
assign {output_axis_tlast, output_axis_tuser, output_axis_tdata} = data_out_reg;
|
||||
|
||||
assign input_axis_tready = ~full;
|
||||
assign output_axis_tvalid = output_axis_tvalid_reg;
|
||||
|
||||
// write
|
||||
always @(posedge clk or posedge rst) begin
|
||||
if (rst) begin
|
||||
wr_ptr <= 0;
|
||||
end else if (write) begin
|
||||
mem[wr_ptr] <= data_in;
|
||||
wr_ptr <= wr_ptr + 1;
|
||||
end
|
||||
end
|
||||
|
||||
// read
|
||||
always @(posedge clk or posedge rst) begin
|
||||
if (rst) begin
|
||||
rd_ptr <= 0;
|
||||
end else if (read) begin
|
||||
data_out_reg <= mem[rd_ptr];
|
||||
rd_ptr <= rd_ptr + 1;
|
||||
end
|
||||
end
|
||||
|
||||
// counter
|
||||
always @(posedge clk or posedge rst) begin
|
||||
if (rst) begin
|
||||
counter <= 0;
|
||||
end else if (~read & write) begin
|
||||
counter <= counter + 1;
|
||||
end else if (read & ~write) begin
|
||||
counter <= counter - 1;
|
||||
end
|
||||
end
|
||||
|
||||
// source ready output
|
||||
always @(posedge clk or posedge rst) begin
|
||||
if (rst) begin
|
||||
output_axis_tvalid_reg <= 1'b0;
|
||||
end else if (output_axis_tready | ~output_axis_tvalid_reg) begin
|
||||
output_axis_tvalid_reg <= ~empty;
|
||||
end else begin
|
||||
output_axis_tvalid_reg <= output_axis_tvalid_reg;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
131
lib/axis/rtl/axis_fifo_64.v
Normal file
131
lib/axis/rtl/axis_fifo_64.v
Normal file
@ -0,0 +1,131 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
/*
|
||||
* AXI4-Stream FIFO (64 bit datapath)
|
||||
*/
|
||||
module axis_fifo_64 #
|
||||
(
|
||||
parameter ADDR_WIDTH = 12,
|
||||
parameter DATA_WIDTH = 64,
|
||||
parameter KEEP_WIDTH = (DATA_WIDTH/8)
|
||||
)
|
||||
(
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
|
||||
/*
|
||||
* AXI input
|
||||
*/
|
||||
input wire [DATA_WIDTH-1:0] input_axis_tdata,
|
||||
input wire [KEEP_WIDTH-1:0] input_axis_tkeep,
|
||||
input wire input_axis_tvalid,
|
||||
output wire input_axis_tready,
|
||||
input wire input_axis_tlast,
|
||||
input wire input_axis_tuser,
|
||||
|
||||
/*
|
||||
* AXI output
|
||||
*/
|
||||
output wire [DATA_WIDTH-1:0] output_axis_tdata,
|
||||
output wire [KEEP_WIDTH-1:0] output_axis_tkeep,
|
||||
output wire output_axis_tvalid,
|
||||
input wire output_axis_tready,
|
||||
output wire output_axis_tlast,
|
||||
output wire output_axis_tuser
|
||||
);
|
||||
|
||||
reg [ADDR_WIDTH-1:0] wr_ptr = {ADDR_WIDTH{1'b0}};
|
||||
reg [ADDR_WIDTH-1:0] rd_ptr = {ADDR_WIDTH{1'b0}};
|
||||
reg [ADDR_WIDTH-1:0] counter = {ADDR_WIDTH{1'b0}};
|
||||
|
||||
reg [DATA_WIDTH+KEEP_WIDTH+2-1:0] data_out_reg = {1'b0, 1'b0, {KEEP_WIDTH{1'b0}}, {DATA_WIDTH{1'b0}}};
|
||||
|
||||
//(* RAM_STYLE="BLOCK" *)
|
||||
reg [DATA_WIDTH+KEEP_WIDTH+2-1:0] mem[(2**ADDR_WIDTH)-1:0];
|
||||
|
||||
reg output_read = 1'b0;
|
||||
|
||||
reg output_axis_tvalid_reg = 1'b0;
|
||||
|
||||
wire [DATA_WIDTH+KEEP_WIDTH+2-1:0] data_in = {input_axis_tlast, input_axis_tuser, input_axis_tkeep, input_axis_tdata};
|
||||
|
||||
wire full = (counter == (2**ADDR_WIDTH)-1);
|
||||
wire empty = (counter == 0);
|
||||
|
||||
wire write = input_axis_tvalid & ~full;
|
||||
wire read = (output_axis_tready | ~output_axis_tvalid_reg) & ~empty;
|
||||
|
||||
assign {output_axis_tlast, output_axis_tuser, output_axis_tkeep, output_axis_tdata} = data_out_reg;
|
||||
|
||||
assign input_axis_tready = ~full;
|
||||
assign output_axis_tvalid = output_axis_tvalid_reg;
|
||||
|
||||
// write
|
||||
always @(posedge clk or posedge rst) begin
|
||||
if (rst) begin
|
||||
wr_ptr <= 0;
|
||||
end else if (write) begin
|
||||
mem[wr_ptr] <= data_in;
|
||||
wr_ptr <= wr_ptr + 1;
|
||||
end
|
||||
end
|
||||
|
||||
// read
|
||||
always @(posedge clk or posedge rst) begin
|
||||
if (rst) begin
|
||||
rd_ptr <= 0;
|
||||
end else if (read) begin
|
||||
data_out_reg <= mem[rd_ptr];
|
||||
rd_ptr <= rd_ptr + 1;
|
||||
end
|
||||
end
|
||||
|
||||
// counter
|
||||
always @(posedge clk or posedge rst) begin
|
||||
if (rst) begin
|
||||
counter <= 0;
|
||||
end else if (~read & write) begin
|
||||
counter <= counter + 1;
|
||||
end else if (read & ~write) begin
|
||||
counter <= counter - 1;
|
||||
end
|
||||
end
|
||||
|
||||
// source ready output
|
||||
always @(posedge clk or posedge rst) begin
|
||||
if (rst) begin
|
||||
output_axis_tvalid_reg <= 1'b0;
|
||||
end else if (output_axis_tready | ~output_axis_tvalid_reg) begin
|
||||
output_axis_tvalid_reg <= ~empty;
|
||||
end else begin
|
||||
output_axis_tvalid_reg <= output_axis_tvalid_reg;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
417
lib/axis/rtl/axis_frame_join.py
Executable file
417
lib/axis/rtl/axis_frame_join.py
Executable file
@ -0,0 +1,417 @@
|
||||
#!/usr/bin/env python
|
||||
"""axis_frame_join
|
||||
|
||||
Generates an AXI Stream frame join module with a specific number of input ports
|
||||
|
||||
Usage: axis_frame_join [OPTION]...
|
||||
-?, --help display this help and exit
|
||||
-p, --ports specify number of ports
|
||||
-n, --name specify module name
|
||||
-o, --output specify output file name
|
||||
"""
|
||||
|
||||
import io
|
||||
import sys
|
||||
import getopt
|
||||
from math import *
|
||||
from jinja2 import Template
|
||||
|
||||
class Usage(Exception):
|
||||
def __init__(self, msg):
|
||||
self.msg = msg
|
||||
|
||||
def main(argv=None):
|
||||
if argv is None:
|
||||
argv = sys.argv
|
||||
try:
|
||||
try:
|
||||
opts, args = getopt.getopt(argv[1:], "?n:p:o:", ["help", "name=", "ports=", "output="])
|
||||
except getopt.error as msg:
|
||||
raise Usage(msg)
|
||||
# more code, unchanged
|
||||
except Usage as err:
|
||||
print(err.msg, file=sys.stderr)
|
||||
print("for help use --help", file=sys.stderr)
|
||||
return 2
|
||||
|
||||
ports = 4
|
||||
name = None
|
||||
out_name = None
|
||||
|
||||
# process options
|
||||
for o, a in opts:
|
||||
if o in ('-?', '--help'):
|
||||
print(__doc__)
|
||||
sys.exit(0)
|
||||
if o in ('-p', '--ports'):
|
||||
ports = int(a)
|
||||
if o in ('-n', '--name'):
|
||||
name = a
|
||||
if o in ('-o', '--outputs'):
|
||||
out_name = a
|
||||
|
||||
if name is None:
|
||||
name = "axis_frame_join_{0}".format(ports)
|
||||
|
||||
if out_name is None:
|
||||
out_name = name + ".v"
|
||||
|
||||
print("Opening file '%s'..." % out_name)
|
||||
|
||||
try:
|
||||
out_file = open(out_name, 'w')
|
||||
except Exception as ex:
|
||||
print("Error opening \"%s\": %s" %(out_name, ex.strerror), file=sys.stderr)
|
||||
exit(1)
|
||||
|
||||
print("Generating {0} port AXI Stream frame joiner {1}...".format(ports, name))
|
||||
|
||||
select_width = ceil(log2(ports))
|
||||
|
||||
t = Template(u"""/*
|
||||
|
||||
Copyright (c) 2014 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
/*
|
||||
* AXI4-Stream {{n}} port frame joiner
|
||||
*/
|
||||
module {{name}} #
|
||||
(
|
||||
parameter ENABLE_TAG = 1
|
||||
)
|
||||
(
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
|
||||
/*
|
||||
* AXI inputs
|
||||
*/
|
||||
{%- for p in ports %}
|
||||
input wire [7:0] input_{{p}}_axis_tdata,
|
||||
input wire input_{{p}}_axis_tvalid,
|
||||
output wire input_{{p}}_axis_tready,
|
||||
input wire input_{{p}}_axis_tlast,
|
||||
input wire input_{{p}}_axis_tuser,
|
||||
{% endfor %}
|
||||
/*
|
||||
* AXI output
|
||||
*/
|
||||
output wire [7:0] output_axis_tdata,
|
||||
output wire output_axis_tvalid,
|
||||
input wire output_axis_tready,
|
||||
output wire output_axis_tlast,
|
||||
output wire output_axis_tuser,
|
||||
|
||||
/*
|
||||
* Configuration
|
||||
*/
|
||||
input wire [15:0] tag,
|
||||
|
||||
/*
|
||||
* Status signals
|
||||
*/
|
||||
output wire busy
|
||||
);
|
||||
|
||||
// state register
|
||||
localparam [1:0]
|
||||
STATE_IDLE = 2'd0,
|
||||
STATE_WRITE_TAG = 2'd1,
|
||||
STATE_TRANSFER = 2'd2;
|
||||
|
||||
reg [1:0] state_reg = STATE_IDLE, state_next;
|
||||
|
||||
reg [2:0] frame_ptr_reg = 0, frame_ptr_next;
|
||||
reg [{{w-1}}:0] port_sel_reg = 0, port_sel_next;
|
||||
|
||||
reg busy_reg = 0, busy_next;
|
||||
|
||||
reg [7:0] input_tdata;
|
||||
reg input_tvalid;
|
||||
reg input_tlast;
|
||||
reg input_tuser;
|
||||
|
||||
reg output_tuser_reg = 0, output_tuser_next;
|
||||
{% for p in ports %}
|
||||
reg input_{{p}}_axis_tready_reg = 0, input_{{p}}_axis_tready_next;
|
||||
{%- endfor %}
|
||||
|
||||
// internal datapath
|
||||
reg [7:0] output_axis_tdata_int;
|
||||
reg output_axis_tvalid_int;
|
||||
reg output_axis_tready_int = 0;
|
||||
reg output_axis_tlast_int;
|
||||
reg output_axis_tuser_int;
|
||||
wire output_axis_tready_int_early;
|
||||
{% for p in ports %}
|
||||
assign input_{{p}}_axis_tready = input_{{p}}_axis_tready_reg;
|
||||
{%- endfor %}
|
||||
|
||||
assign busy = busy_reg;
|
||||
|
||||
always @* begin
|
||||
// input port mux
|
||||
case (port_sel_reg)
|
||||
{%- for p in ports %}
|
||||
{{w}}'d{{p}}: begin
|
||||
input_tdata = input_{{p}}_axis_tdata;
|
||||
input_tvalid = input_{{p}}_axis_tvalid;
|
||||
input_tlast = input_{{p}}_axis_tlast;
|
||||
input_tuser = input_{{p}}_axis_tuser;
|
||||
end
|
||||
{%- endfor %}
|
||||
endcase
|
||||
end
|
||||
|
||||
always @* begin
|
||||
state_next = 2'bz;
|
||||
|
||||
frame_ptr_next = frame_ptr_reg;
|
||||
port_sel_next = port_sel_reg;
|
||||
{% for p in ports %}
|
||||
input_{{p}}_axis_tready_next = 0;
|
||||
{%- endfor %}
|
||||
|
||||
output_axis_tdata_int = 0;
|
||||
output_axis_tvalid_int = 0;
|
||||
output_axis_tlast_int = 0;
|
||||
output_axis_tuser_int = 0;
|
||||
|
||||
output_tuser_next = output_tuser_reg;
|
||||
|
||||
case (state_reg)
|
||||
STATE_IDLE: begin
|
||||
// idle state - wait for data
|
||||
frame_ptr_next = 0;
|
||||
port_sel_next = 0;
|
||||
output_tuser_next = 0;
|
||||
|
||||
if (ENABLE_TAG) begin
|
||||
// next cycle if started will send tag, so do not enable input
|
||||
input_0_axis_tready_next = 0;
|
||||
end else begin
|
||||
// next cycle if started will send data, so enable input
|
||||
input_0_axis_tready_next = output_axis_tready_int_early;
|
||||
end
|
||||
|
||||
if (input_0_axis_tvalid) begin
|
||||
// input 0 valid; start transferring data
|
||||
if (ENABLE_TAG) begin
|
||||
// tag enabled, so transmit it
|
||||
if (output_axis_tready_int) begin
|
||||
// output is ready, so short-circuit first tag byte
|
||||
frame_ptr_next = 1;
|
||||
output_axis_tdata_int = tag[15:8];
|
||||
output_axis_tvalid_int = 1;
|
||||
end
|
||||
|
||||
state_next = STATE_WRITE_TAG;
|
||||
end else begin
|
||||
// tag disabled, so transmit data
|
||||
if (output_axis_tready_int) begin
|
||||
// output is ready, so short-circuit first data byte
|
||||
output_axis_tdata_int = input_0_axis_tdata;
|
||||
output_axis_tvalid_int = 1;
|
||||
end
|
||||
state_next = STATE_TRANSFER;
|
||||
end
|
||||
end else begin
|
||||
state_next = STATE_IDLE;
|
||||
end
|
||||
end
|
||||
STATE_WRITE_TAG: begin
|
||||
// write tag data
|
||||
if (output_axis_tready_int) begin
|
||||
// output ready, so send tag byte
|
||||
state_next = STATE_WRITE_TAG;
|
||||
frame_ptr_next = frame_ptr_reg + 1;
|
||||
output_axis_tvalid_int = 1;
|
||||
case (frame_ptr_reg)
|
||||
2'd0: output_axis_tdata_int = tag[15:8];
|
||||
2'd1: begin
|
||||
// last tag byte - get ready to send data, enable input if ready
|
||||
output_axis_tdata_int = tag[7:0];
|
||||
input_0_axis_tready_next = output_axis_tready_int_early;
|
||||
state_next = STATE_TRANSFER;
|
||||
end
|
||||
endcase
|
||||
end else begin
|
||||
state_next = STATE_WRITE_TAG;
|
||||
end
|
||||
end
|
||||
STATE_TRANSFER: begin
|
||||
// transfer input data
|
||||
|
||||
// set ready for current input
|
||||
case (port_sel_reg)
|
||||
{%- for p in ports %}
|
||||
{{w}}'d{{p}}: input_{{p}}_axis_tready_next = output_axis_tready_int_early;
|
||||
{%- endfor %}
|
||||
endcase
|
||||
|
||||
if (input_tvalid & output_axis_tready_int) begin
|
||||
// output ready, transfer byte
|
||||
state_next = STATE_TRANSFER;
|
||||
output_axis_tdata_int = input_tdata;
|
||||
output_axis_tvalid_int = input_tvalid;
|
||||
|
||||
if (input_tlast) begin
|
||||
// last flag received, switch to next port
|
||||
port_sel_next = port_sel_reg + 1;
|
||||
// save tuser - assert tuser out if ANY tuser asserts received
|
||||
output_tuser_next = output_tuser_next | input_tuser;
|
||||
// disable input
|
||||
{%- for p in ports %}
|
||||
input_{{p}}_axis_tready_next = 0;
|
||||
{%- endfor %}
|
||||
|
||||
if (port_sel_reg == {{n-1}}) begin
|
||||
// last port - send tlast and tuser and revert to idle
|
||||
output_axis_tlast_int = 1;
|
||||
output_axis_tuser_int = output_tuser_next;
|
||||
state_next = STATE_IDLE;
|
||||
end else begin
|
||||
// otherwise, disable enable next port
|
||||
case (port_sel_next)
|
||||
{%- for p in ports %}
|
||||
{{w}}'d{{p}}: input_{{p}}_axis_tready_next = output_axis_tready_int_early;
|
||||
{%- endfor %}
|
||||
endcase
|
||||
end
|
||||
end
|
||||
end else begin
|
||||
state_next = STATE_TRANSFER;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
always @(posedge clk or posedge rst) begin
|
||||
if (rst) begin
|
||||
state_reg <= STATE_IDLE;
|
||||
frame_ptr_reg <= 0;
|
||||
port_sel_reg <= 0;
|
||||
{%- for p in ports %}
|
||||
input_{{p}}_axis_tready_reg <= 0;
|
||||
{%- endfor %}
|
||||
output_tuser_reg <= 0;
|
||||
busy_reg <= 0;
|
||||
end else begin
|
||||
state_reg <= state_next;
|
||||
|
||||
frame_ptr_reg <= frame_ptr_next;
|
||||
|
||||
port_sel_reg <= port_sel_next;
|
||||
{% for p in ports %}
|
||||
input_{{p}}_axis_tready_reg <= input_{{p}}_axis_tready_next;
|
||||
{%- endfor %}
|
||||
|
||||
output_tuser_reg <= output_tuser_next;
|
||||
|
||||
busy_reg <= state_next != STATE_IDLE;
|
||||
end
|
||||
end
|
||||
|
||||
// output datapath logic
|
||||
reg [7:0] output_axis_tdata_reg = 0;
|
||||
reg output_axis_tvalid_reg = 0;
|
||||
reg output_axis_tlast_reg = 0;
|
||||
reg output_axis_tuser_reg = 0;
|
||||
|
||||
reg [7:0] temp_axis_tdata_reg = 0;
|
||||
reg temp_axis_tvalid_reg = 0;
|
||||
reg temp_axis_tlast_reg = 0;
|
||||
reg temp_axis_tuser_reg = 0;
|
||||
|
||||
assign output_axis_tdata = output_axis_tdata_reg;
|
||||
assign output_axis_tvalid = output_axis_tvalid_reg;
|
||||
assign output_axis_tlast = output_axis_tlast_reg;
|
||||
assign output_axis_tuser = output_axis_tuser_reg;
|
||||
|
||||
// enable ready input next cycle if output is ready or if there is space in both output registers or if there is space in the temp register that will not be filled next cycle
|
||||
assign output_axis_tready_int_early = output_axis_tready | (~temp_axis_tvalid_reg & ~output_axis_tvalid_reg) | (~temp_axis_tvalid_reg & ~output_axis_tvalid_int);
|
||||
|
||||
always @(posedge clk or posedge rst) begin
|
||||
if (rst) begin
|
||||
output_axis_tdata_reg <= 0;
|
||||
output_axis_tvalid_reg <= 0;
|
||||
output_axis_tlast_reg <= 0;
|
||||
output_axis_tuser_reg <= 0;
|
||||
output_axis_tready_int <= 0;
|
||||
temp_axis_tdata_reg <= 0;
|
||||
temp_axis_tvalid_reg <= 0;
|
||||
temp_axis_tlast_reg <= 0;
|
||||
temp_axis_tuser_reg <= 0;
|
||||
end else begin
|
||||
// transfer sink ready state to source
|
||||
output_axis_tready_int <= output_axis_tready_int_early;
|
||||
|
||||
if (output_axis_tready_int) begin
|
||||
// input is ready
|
||||
if (output_axis_tready | ~output_axis_tvalid_reg) begin
|
||||
// output is ready or currently not valid, transfer data to output
|
||||
output_axis_tdata_reg <= output_axis_tdata_int;
|
||||
output_axis_tvalid_reg <= output_axis_tvalid_int;
|
||||
output_axis_tlast_reg <= output_axis_tlast_int;
|
||||
output_axis_tuser_reg <= output_axis_tuser_int;
|
||||
end else begin
|
||||
// output is not ready, store input in temp
|
||||
temp_axis_tdata_reg <= output_axis_tdata_int;
|
||||
temp_axis_tvalid_reg <= output_axis_tvalid_int;
|
||||
temp_axis_tlast_reg <= output_axis_tlast_int;
|
||||
temp_axis_tuser_reg <= output_axis_tuser_int;
|
||||
end
|
||||
end else if (output_axis_tready) begin
|
||||
// input is not ready, but output is ready
|
||||
output_axis_tdata_reg <= temp_axis_tdata_reg;
|
||||
output_axis_tvalid_reg <= temp_axis_tvalid_reg;
|
||||
output_axis_tlast_reg <= temp_axis_tlast_reg;
|
||||
output_axis_tuser_reg <= temp_axis_tuser_reg;
|
||||
temp_axis_tdata_reg <= 0;
|
||||
temp_axis_tvalid_reg <= 0;
|
||||
temp_axis_tlast_reg <= 0;
|
||||
temp_axis_tuser_reg <= 0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
""")
|
||||
|
||||
out_file.write(t.render(
|
||||
n=ports,
|
||||
w=select_width,
|
||||
name=name,
|
||||
ports=range(ports)
|
||||
))
|
||||
|
||||
print("Done")
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
|
377
lib/axis/rtl/axis_frame_join_4.v
Normal file
377
lib/axis/rtl/axis_frame_join_4.v
Normal file
@ -0,0 +1,377 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
/*
|
||||
* AXI4-Stream 4 port frame joiner
|
||||
*/
|
||||
module axis_frame_join_4 #
|
||||
(
|
||||
parameter ENABLE_TAG = 1
|
||||
)
|
||||
(
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
|
||||
/*
|
||||
* AXI inputs
|
||||
*/
|
||||
input wire [7:0] input_0_axis_tdata,
|
||||
input wire input_0_axis_tvalid,
|
||||
output wire input_0_axis_tready,
|
||||
input wire input_0_axis_tlast,
|
||||
input wire input_0_axis_tuser,
|
||||
|
||||
input wire [7:0] input_1_axis_tdata,
|
||||
input wire input_1_axis_tvalid,
|
||||
output wire input_1_axis_tready,
|
||||
input wire input_1_axis_tlast,
|
||||
input wire input_1_axis_tuser,
|
||||
|
||||
input wire [7:0] input_2_axis_tdata,
|
||||
input wire input_2_axis_tvalid,
|
||||
output wire input_2_axis_tready,
|
||||
input wire input_2_axis_tlast,
|
||||
input wire input_2_axis_tuser,
|
||||
|
||||
input wire [7:0] input_3_axis_tdata,
|
||||
input wire input_3_axis_tvalid,
|
||||
output wire input_3_axis_tready,
|
||||
input wire input_3_axis_tlast,
|
||||
input wire input_3_axis_tuser,
|
||||
|
||||
/*
|
||||
* AXI output
|
||||
*/
|
||||
output wire [7:0] output_axis_tdata,
|
||||
output wire output_axis_tvalid,
|
||||
input wire output_axis_tready,
|
||||
output wire output_axis_tlast,
|
||||
output wire output_axis_tuser,
|
||||
|
||||
/*
|
||||
* Configuration
|
||||
*/
|
||||
input wire [15:0] tag,
|
||||
|
||||
/*
|
||||
* Status signals
|
||||
*/
|
||||
output wire busy
|
||||
);
|
||||
|
||||
// state register
|
||||
localparam [1:0]
|
||||
STATE_IDLE = 2'd0,
|
||||
STATE_WRITE_TAG = 2'd1,
|
||||
STATE_TRANSFER = 2'd2;
|
||||
|
||||
reg [1:0] state_reg = STATE_IDLE, state_next;
|
||||
|
||||
reg [2:0] frame_ptr_reg = 0, frame_ptr_next;
|
||||
reg [1:0] port_sel_reg = 0, port_sel_next;
|
||||
|
||||
reg busy_reg = 0, busy_next;
|
||||
|
||||
reg [7:0] input_tdata;
|
||||
reg input_tvalid;
|
||||
reg input_tlast;
|
||||
reg input_tuser;
|
||||
|
||||
reg output_tuser_reg = 0, output_tuser_next;
|
||||
|
||||
reg input_0_axis_tready_reg = 0, input_0_axis_tready_next;
|
||||
reg input_1_axis_tready_reg = 0, input_1_axis_tready_next;
|
||||
reg input_2_axis_tready_reg = 0, input_2_axis_tready_next;
|
||||
reg input_3_axis_tready_reg = 0, input_3_axis_tready_next;
|
||||
|
||||
// internal datapath
|
||||
reg [7:0] output_axis_tdata_int;
|
||||
reg output_axis_tvalid_int;
|
||||
reg output_axis_tready_int = 0;
|
||||
reg output_axis_tlast_int;
|
||||
reg output_axis_tuser_int;
|
||||
wire output_axis_tready_int_early;
|
||||
|
||||
assign input_0_axis_tready = input_0_axis_tready_reg;
|
||||
assign input_1_axis_tready = input_1_axis_tready_reg;
|
||||
assign input_2_axis_tready = input_2_axis_tready_reg;
|
||||
assign input_3_axis_tready = input_3_axis_tready_reg;
|
||||
|
||||
assign busy = busy_reg;
|
||||
|
||||
always @* begin
|
||||
// input port mux
|
||||
case (port_sel_reg)
|
||||
2'd0: begin
|
||||
input_tdata = input_0_axis_tdata;
|
||||
input_tvalid = input_0_axis_tvalid;
|
||||
input_tlast = input_0_axis_tlast;
|
||||
input_tuser = input_0_axis_tuser;
|
||||
end
|
||||
2'd1: begin
|
||||
input_tdata = input_1_axis_tdata;
|
||||
input_tvalid = input_1_axis_tvalid;
|
||||
input_tlast = input_1_axis_tlast;
|
||||
input_tuser = input_1_axis_tuser;
|
||||
end
|
||||
2'd2: begin
|
||||
input_tdata = input_2_axis_tdata;
|
||||
input_tvalid = input_2_axis_tvalid;
|
||||
input_tlast = input_2_axis_tlast;
|
||||
input_tuser = input_2_axis_tuser;
|
||||
end
|
||||
2'd3: begin
|
||||
input_tdata = input_3_axis_tdata;
|
||||
input_tvalid = input_3_axis_tvalid;
|
||||
input_tlast = input_3_axis_tlast;
|
||||
input_tuser = input_3_axis_tuser;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
always @* begin
|
||||
state_next = 2'bz;
|
||||
|
||||
frame_ptr_next = frame_ptr_reg;
|
||||
port_sel_next = port_sel_reg;
|
||||
|
||||
input_0_axis_tready_next = 0;
|
||||
input_1_axis_tready_next = 0;
|
||||
input_2_axis_tready_next = 0;
|
||||
input_3_axis_tready_next = 0;
|
||||
|
||||
output_axis_tdata_int = 0;
|
||||
output_axis_tvalid_int = 0;
|
||||
output_axis_tlast_int = 0;
|
||||
output_axis_tuser_int = 0;
|
||||
|
||||
output_tuser_next = output_tuser_reg;
|
||||
|
||||
case (state_reg)
|
||||
STATE_IDLE: begin
|
||||
// idle state - wait for data
|
||||
frame_ptr_next = 0;
|
||||
port_sel_next = 0;
|
||||
output_tuser_next = 0;
|
||||
|
||||
if (ENABLE_TAG) begin
|
||||
// next cycle if started will send tag, so do not enable input
|
||||
input_0_axis_tready_next = 0;
|
||||
end else begin
|
||||
// next cycle if started will send data, so enable input
|
||||
input_0_axis_tready_next = output_axis_tready_int_early;
|
||||
end
|
||||
|
||||
if (input_0_axis_tvalid) begin
|
||||
// input 0 valid; start transferring data
|
||||
if (ENABLE_TAG) begin
|
||||
// tag enabled, so transmit it
|
||||
if (output_axis_tready_int) begin
|
||||
// output is ready, so short-circuit first tag byte
|
||||
frame_ptr_next = 1;
|
||||
output_axis_tdata_int = tag[15:8];
|
||||
output_axis_tvalid_int = 1;
|
||||
end
|
||||
|
||||
state_next = STATE_WRITE_TAG;
|
||||
end else begin
|
||||
// tag disabled, so transmit data
|
||||
if (output_axis_tready_int) begin
|
||||
// output is ready, so short-circuit first data byte
|
||||
output_axis_tdata_int = input_0_axis_tdata;
|
||||
output_axis_tvalid_int = 1;
|
||||
end
|
||||
state_next = STATE_TRANSFER;
|
||||
end
|
||||
end else begin
|
||||
state_next = STATE_IDLE;
|
||||
end
|
||||
end
|
||||
STATE_WRITE_TAG: begin
|
||||
// write tag data
|
||||
if (output_axis_tready_int) begin
|
||||
// output ready, so send tag byte
|
||||
state_next = STATE_WRITE_TAG;
|
||||
frame_ptr_next = frame_ptr_reg + 1;
|
||||
output_axis_tvalid_int = 1;
|
||||
case (frame_ptr_reg)
|
||||
2'd0: output_axis_tdata_int = tag[15:8];
|
||||
2'd1: begin
|
||||
// last tag byte - get ready to send data, enable input if ready
|
||||
output_axis_tdata_int = tag[7:0];
|
||||
input_0_axis_tready_next = output_axis_tready_int_early;
|
||||
state_next = STATE_TRANSFER;
|
||||
end
|
||||
endcase
|
||||
end else begin
|
||||
state_next = STATE_WRITE_TAG;
|
||||
end
|
||||
end
|
||||
STATE_TRANSFER: begin
|
||||
// transfer input data
|
||||
|
||||
// set ready for current input
|
||||
case (port_sel_reg)
|
||||
2'd0: input_0_axis_tready_next = output_axis_tready_int_early;
|
||||
2'd1: input_1_axis_tready_next = output_axis_tready_int_early;
|
||||
2'd2: input_2_axis_tready_next = output_axis_tready_int_early;
|
||||
2'd3: input_3_axis_tready_next = output_axis_tready_int_early;
|
||||
endcase
|
||||
|
||||
if (input_tvalid & output_axis_tready_int) begin
|
||||
// output ready, transfer byte
|
||||
state_next = STATE_TRANSFER;
|
||||
output_axis_tdata_int = input_tdata;
|
||||
output_axis_tvalid_int = input_tvalid;
|
||||
|
||||
if (input_tlast) begin
|
||||
// last flag received, switch to next port
|
||||
port_sel_next = port_sel_reg + 1;
|
||||
// save tuser - assert tuser out if ANY tuser asserts received
|
||||
output_tuser_next = output_tuser_next | input_tuser;
|
||||
// disable input
|
||||
input_0_axis_tready_next = 0;
|
||||
input_1_axis_tready_next = 0;
|
||||
input_2_axis_tready_next = 0;
|
||||
input_3_axis_tready_next = 0;
|
||||
|
||||
if (port_sel_reg == 3) begin
|
||||
// last port - send tlast and tuser and revert to idle
|
||||
output_axis_tlast_int = 1;
|
||||
output_axis_tuser_int = output_tuser_next;
|
||||
state_next = STATE_IDLE;
|
||||
end else begin
|
||||
// otherwise, disable enable next port
|
||||
case (port_sel_next)
|
||||
2'd0: input_0_axis_tready_next = output_axis_tready_int_early;
|
||||
2'd1: input_1_axis_tready_next = output_axis_tready_int_early;
|
||||
2'd2: input_2_axis_tready_next = output_axis_tready_int_early;
|
||||
2'd3: input_3_axis_tready_next = output_axis_tready_int_early;
|
||||
endcase
|
||||
end
|
||||
end
|
||||
end else begin
|
||||
state_next = STATE_TRANSFER;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
always @(posedge clk or posedge rst) begin
|
||||
if (rst) begin
|
||||
state_reg <= STATE_IDLE;
|
||||
frame_ptr_reg <= 0;
|
||||
port_sel_reg <= 0;
|
||||
input_0_axis_tready_reg <= 0;
|
||||
input_1_axis_tready_reg <= 0;
|
||||
input_2_axis_tready_reg <= 0;
|
||||
input_3_axis_tready_reg <= 0;
|
||||
output_tuser_reg <= 0;
|
||||
busy_reg <= 0;
|
||||
end else begin
|
||||
state_reg <= state_next;
|
||||
|
||||
frame_ptr_reg <= frame_ptr_next;
|
||||
|
||||
port_sel_reg <= port_sel_next;
|
||||
|
||||
input_0_axis_tready_reg <= input_0_axis_tready_next;
|
||||
input_1_axis_tready_reg <= input_1_axis_tready_next;
|
||||
input_2_axis_tready_reg <= input_2_axis_tready_next;
|
||||
input_3_axis_tready_reg <= input_3_axis_tready_next;
|
||||
|
||||
output_tuser_reg <= output_tuser_next;
|
||||
|
||||
busy_reg <= state_next != STATE_IDLE;
|
||||
end
|
||||
end
|
||||
|
||||
// output datapath logic
|
||||
reg [7:0] output_axis_tdata_reg = 0;
|
||||
reg output_axis_tvalid_reg = 0;
|
||||
reg output_axis_tlast_reg = 0;
|
||||
reg output_axis_tuser_reg = 0;
|
||||
|
||||
reg [7:0] temp_axis_tdata_reg = 0;
|
||||
reg temp_axis_tvalid_reg = 0;
|
||||
reg temp_axis_tlast_reg = 0;
|
||||
reg temp_axis_tuser_reg = 0;
|
||||
|
||||
assign output_axis_tdata = output_axis_tdata_reg;
|
||||
assign output_axis_tvalid = output_axis_tvalid_reg;
|
||||
assign output_axis_tlast = output_axis_tlast_reg;
|
||||
assign output_axis_tuser = output_axis_tuser_reg;
|
||||
|
||||
// enable ready input next cycle if output is ready or if there is space in both output registers or if there is space in the temp register that will not be filled next cycle
|
||||
assign output_axis_tready_int_early = output_axis_tready | (~temp_axis_tvalid_reg & ~output_axis_tvalid_reg) | (~temp_axis_tvalid_reg & ~output_axis_tvalid_int);
|
||||
|
||||
always @(posedge clk or posedge rst) begin
|
||||
if (rst) begin
|
||||
output_axis_tdata_reg <= 0;
|
||||
output_axis_tvalid_reg <= 0;
|
||||
output_axis_tlast_reg <= 0;
|
||||
output_axis_tuser_reg <= 0;
|
||||
output_axis_tready_int <= 0;
|
||||
temp_axis_tdata_reg <= 0;
|
||||
temp_axis_tvalid_reg <= 0;
|
||||
temp_axis_tlast_reg <= 0;
|
||||
temp_axis_tuser_reg <= 0;
|
||||
end else begin
|
||||
// transfer sink ready state to source
|
||||
output_axis_tready_int <= output_axis_tready_int_early;
|
||||
|
||||
if (output_axis_tready_int) begin
|
||||
// input is ready
|
||||
if (output_axis_tready | ~output_axis_tvalid_reg) begin
|
||||
// output is ready or currently not valid, transfer data to output
|
||||
output_axis_tdata_reg <= output_axis_tdata_int;
|
||||
output_axis_tvalid_reg <= output_axis_tvalid_int;
|
||||
output_axis_tlast_reg <= output_axis_tlast_int;
|
||||
output_axis_tuser_reg <= output_axis_tuser_int;
|
||||
end else begin
|
||||
// output is not ready, store input in temp
|
||||
temp_axis_tdata_reg <= output_axis_tdata_int;
|
||||
temp_axis_tvalid_reg <= output_axis_tvalid_int;
|
||||
temp_axis_tlast_reg <= output_axis_tlast_int;
|
||||
temp_axis_tuser_reg <= output_axis_tuser_int;
|
||||
end
|
||||
end else if (output_axis_tready) begin
|
||||
// input is not ready, but output is ready
|
||||
output_axis_tdata_reg <= temp_axis_tdata_reg;
|
||||
output_axis_tvalid_reg <= temp_axis_tvalid_reg;
|
||||
output_axis_tlast_reg <= temp_axis_tlast_reg;
|
||||
output_axis_tuser_reg <= temp_axis_tuser_reg;
|
||||
temp_axis_tdata_reg <= 0;
|
||||
temp_axis_tvalid_reg <= 0;
|
||||
temp_axis_tlast_reg <= 0;
|
||||
temp_axis_tuser_reg <= 0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
79
lib/axis/rtl/axis_ll_bridge.v
Normal file
79
lib/axis/rtl/axis_ll_bridge.v
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
/*
|
||||
* AXI4-Stream to LocalLink bridge
|
||||
*/
|
||||
module axis_ll_bridge #
|
||||
(
|
||||
parameter DATA_WIDTH = 8
|
||||
)
|
||||
(
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
|
||||
/*
|
||||
* AXI input
|
||||
*/
|
||||
input wire [DATA_WIDTH-1:0] axis_tdata,
|
||||
input wire axis_tvalid,
|
||||
output wire axis_tready,
|
||||
input wire axis_tlast,
|
||||
|
||||
/*
|
||||
* LocalLink output
|
||||
*/
|
||||
output wire [DATA_WIDTH-1:0] ll_data_out,
|
||||
output wire ll_sof_out_n,
|
||||
output wire ll_eof_out_n,
|
||||
output wire ll_src_rdy_out_n,
|
||||
input wire ll_dst_rdy_in_n
|
||||
);
|
||||
|
||||
reg last_tlast = 1'b1;
|
||||
|
||||
always @(posedge clk or posedge rst) begin
|
||||
if (rst) begin
|
||||
last_tlast = 1'b1;
|
||||
end else begin
|
||||
if (axis_tvalid & axis_tready) last_tlast = axis_tlast;
|
||||
end
|
||||
end
|
||||
|
||||
// high for packet length 1 -> cannot set SOF and EOF in same cycle
|
||||
// invalid packets are discarded
|
||||
wire invalid = axis_tvalid & axis_tlast & last_tlast;
|
||||
|
||||
assign axis_tready = ~ll_dst_rdy_in_n;
|
||||
|
||||
assign ll_data_out = axis_tdata;
|
||||
assign ll_sof_out_n = ~(last_tlast & axis_tvalid & ~invalid);
|
||||
assign ll_eof_out_n = ~(axis_tlast & ~invalid);
|
||||
assign ll_src_rdy_out_n = ~(axis_tvalid & ~invalid);
|
||||
|
||||
endmodule
|
188
lib/axis/rtl/axis_rate_limit.v
Normal file
188
lib/axis/rtl/axis_rate_limit.v
Normal file
@ -0,0 +1,188 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
/*
|
||||
* AXI4-Stream rate limiter
|
||||
*/
|
||||
module axis_rate_limit #
|
||||
(
|
||||
parameter DATA_WIDTH = 64,
|
||||
parameter KEEP_WIDTH = (DATA_WIDTH/8)
|
||||
)
|
||||
(
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
|
||||
/*
|
||||
* AXI input
|
||||
*/
|
||||
input wire [DATA_WIDTH-1:0] input_axis_tdata,
|
||||
input wire input_axis_tvalid,
|
||||
output wire input_axis_tready,
|
||||
input wire input_axis_tlast,
|
||||
input wire input_axis_tuser,
|
||||
|
||||
/*
|
||||
* AXI output
|
||||
*/
|
||||
output wire [DATA_WIDTH-1:0] output_axis_tdata,
|
||||
output wire output_axis_tvalid,
|
||||
input wire output_axis_tready,
|
||||
output wire output_axis_tlast,
|
||||
output wire output_axis_tuser,
|
||||
|
||||
/*
|
||||
* Configuration
|
||||
*/
|
||||
input wire [7:0] rate_num,
|
||||
input wire [7:0] rate_denom,
|
||||
input wire rate_by_frame
|
||||
);
|
||||
|
||||
// internal datapath
|
||||
reg [DATA_WIDTH-1:0] output_axis_tdata_int;
|
||||
reg output_axis_tvalid_int;
|
||||
reg output_axis_tready_int = 0;
|
||||
reg output_axis_tlast_int;
|
||||
reg output_axis_tuser_int;
|
||||
wire output_axis_tready_int_early;
|
||||
|
||||
reg [23:0] acc_reg = 0, acc_next;
|
||||
reg pause;
|
||||
reg frame_reg = 0, frame_next;
|
||||
|
||||
reg input_axis_tready_reg = 0, input_axis_tready_next;
|
||||
assign input_axis_tready = input_axis_tready_reg;
|
||||
|
||||
always @* begin
|
||||
acc_next = acc_reg;
|
||||
pause = 0;
|
||||
frame_next = frame_reg & ~input_axis_tlast;
|
||||
|
||||
if (acc_reg >= rate_num) begin
|
||||
acc_next = acc_reg - rate_num;
|
||||
end
|
||||
|
||||
if (input_axis_tready & input_axis_tvalid) begin
|
||||
// read input
|
||||
frame_next = ~input_axis_tlast;
|
||||
acc_next = acc_reg + (rate_denom - rate_num);
|
||||
end
|
||||
|
||||
if (acc_next >= rate_num) begin
|
||||
if (rate_by_frame) begin
|
||||
pause = ~frame_next;
|
||||
end else begin
|
||||
pause = 1;
|
||||
end
|
||||
end
|
||||
|
||||
input_axis_tready_next = output_axis_tready_int_early & ~pause;
|
||||
|
||||
output_axis_tdata_int = input_axis_tdata;
|
||||
output_axis_tvalid_int = input_axis_tvalid & input_axis_tready;
|
||||
output_axis_tlast_int = input_axis_tlast;
|
||||
output_axis_tuser_int = input_axis_tuser;
|
||||
end
|
||||
|
||||
always @(posedge clk or posedge rst) begin
|
||||
if (rst) begin
|
||||
acc_reg <= 0;
|
||||
frame_reg <= 0;
|
||||
input_axis_tready_reg <= 0;
|
||||
end else begin
|
||||
acc_reg <= acc_next;
|
||||
frame_reg <= frame_next;
|
||||
input_axis_tready_reg <= input_axis_tready_next;
|
||||
end
|
||||
end
|
||||
|
||||
// output datapath logic
|
||||
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = 0;
|
||||
reg output_axis_tvalid_reg = 0;
|
||||
reg output_axis_tlast_reg = 0;
|
||||
reg output_axis_tuser_reg = 0;
|
||||
|
||||
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = 0;
|
||||
reg temp_axis_tvalid_reg = 0;
|
||||
reg temp_axis_tlast_reg = 0;
|
||||
reg temp_axis_tuser_reg = 0;
|
||||
|
||||
assign output_axis_tdata = output_axis_tdata_reg;
|
||||
assign output_axis_tvalid = output_axis_tvalid_reg;
|
||||
assign output_axis_tlast = output_axis_tlast_reg;
|
||||
assign output_axis_tuser = output_axis_tuser_reg;
|
||||
|
||||
// enable ready input next cycle if output is ready or if there is space in both output registers or if there is space in the temp register that will not be filled next cycle
|
||||
assign output_axis_tready_int_early = output_axis_tready | (~temp_axis_tvalid_reg & ~output_axis_tvalid_reg) | (~temp_axis_tvalid_reg & ~output_axis_tvalid_int);
|
||||
|
||||
always @(posedge clk or posedge rst) begin
|
||||
if (rst) begin
|
||||
output_axis_tdata_reg <= 0;
|
||||
output_axis_tvalid_reg <= 0;
|
||||
output_axis_tlast_reg <= 0;
|
||||
output_axis_tuser_reg <= 0;
|
||||
output_axis_tready_int <= 0;
|
||||
temp_axis_tdata_reg <= 0;
|
||||
temp_axis_tvalid_reg <= 0;
|
||||
temp_axis_tlast_reg <= 0;
|
||||
temp_axis_tuser_reg <= 0;
|
||||
end else begin
|
||||
// transfer sink ready state to source
|
||||
output_axis_tready_int <= output_axis_tready_int_early;
|
||||
|
||||
if (output_axis_tready_int) begin
|
||||
// input is ready
|
||||
if (output_axis_tready | ~output_axis_tvalid_reg) begin
|
||||
// output is ready or currently not valid, transfer data to output
|
||||
output_axis_tdata_reg <= output_axis_tdata_int;
|
||||
output_axis_tvalid_reg <= output_axis_tvalid_int;
|
||||
output_axis_tlast_reg <= output_axis_tlast_int;
|
||||
output_axis_tuser_reg <= output_axis_tuser_int;
|
||||
end else begin
|
||||
// output is not ready, store input in temp
|
||||
temp_axis_tdata_reg <= output_axis_tdata_int;
|
||||
temp_axis_tvalid_reg <= output_axis_tvalid_int;
|
||||
temp_axis_tlast_reg <= output_axis_tlast_int;
|
||||
temp_axis_tuser_reg <= output_axis_tuser_int;
|
||||
end
|
||||
end else if (output_axis_tready) begin
|
||||
// input is not ready, but output is ready
|
||||
output_axis_tdata_reg <= temp_axis_tdata_reg;
|
||||
output_axis_tvalid_reg <= temp_axis_tvalid_reg;
|
||||
output_axis_tlast_reg <= temp_axis_tlast_reg;
|
||||
output_axis_tuser_reg <= temp_axis_tuser_reg;
|
||||
temp_axis_tdata_reg <= 0;
|
||||
temp_axis_tvalid_reg <= 0;
|
||||
temp_axis_tlast_reg <= 0;
|
||||
temp_axis_tuser_reg <= 0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
201
lib/axis/rtl/axis_rate_limit_64.v
Normal file
201
lib/axis/rtl/axis_rate_limit_64.v
Normal file
@ -0,0 +1,201 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
/*
|
||||
* AXI4-Stream rate limiter (64 bit datapath)
|
||||
*/
|
||||
module axis_rate_limit_64 #
|
||||
(
|
||||
parameter DATA_WIDTH = 64,
|
||||
parameter KEEP_WIDTH = (DATA_WIDTH/8)
|
||||
)
|
||||
(
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
|
||||
/*
|
||||
* AXI input
|
||||
*/
|
||||
input wire [DATA_WIDTH-1:0] input_axis_tdata,
|
||||
input wire [KEEP_WIDTH-1:0] input_axis_tkeep,
|
||||
input wire input_axis_tvalid,
|
||||
output wire input_axis_tready,
|
||||
input wire input_axis_tlast,
|
||||
input wire input_axis_tuser,
|
||||
|
||||
/*
|
||||
* AXI output
|
||||
*/
|
||||
output wire [DATA_WIDTH-1:0] output_axis_tdata,
|
||||
output wire [KEEP_WIDTH-1:0] output_axis_tkeep,
|
||||
output wire output_axis_tvalid,
|
||||
input wire output_axis_tready,
|
||||
output wire output_axis_tlast,
|
||||
output wire output_axis_tuser,
|
||||
|
||||
/*
|
||||
* Configuration
|
||||
*/
|
||||
input wire [7:0] rate_num,
|
||||
input wire [7:0] rate_denom,
|
||||
input wire rate_by_frame
|
||||
);
|
||||
|
||||
// internal datapath
|
||||
reg [DATA_WIDTH-1:0] output_axis_tdata_int;
|
||||
reg [KEEP_WIDTH-1:0] output_axis_tkeep_int;
|
||||
reg output_axis_tvalid_int;
|
||||
reg output_axis_tready_int = 0;
|
||||
reg output_axis_tlast_int;
|
||||
reg output_axis_tuser_int;
|
||||
wire output_axis_tready_int_early;
|
||||
|
||||
reg [23:0] acc_reg = 0, acc_next;
|
||||
reg pause;
|
||||
reg frame_reg = 0, frame_next;
|
||||
|
||||
reg input_axis_tready_reg = 0, input_axis_tready_next;
|
||||
assign input_axis_tready = input_axis_tready_reg;
|
||||
|
||||
always @* begin
|
||||
acc_next = acc_reg;
|
||||
pause = 0;
|
||||
frame_next = frame_reg & ~input_axis_tlast;
|
||||
|
||||
if (acc_reg >= rate_num) begin
|
||||
acc_next = acc_reg - rate_num;
|
||||
end
|
||||
|
||||
if (input_axis_tready & input_axis_tvalid) begin
|
||||
// read input
|
||||
frame_next = ~input_axis_tlast;
|
||||
acc_next = acc_reg + (rate_denom - rate_num);
|
||||
end
|
||||
|
||||
if (acc_next >= rate_num) begin
|
||||
if (rate_by_frame) begin
|
||||
pause = ~frame_next;
|
||||
end else begin
|
||||
pause = 1;
|
||||
end
|
||||
end
|
||||
|
||||
input_axis_tready_next = output_axis_tready_int_early & ~pause;
|
||||
|
||||
output_axis_tdata_int = input_axis_tdata;
|
||||
output_axis_tkeep_int = input_axis_tkeep;
|
||||
output_axis_tvalid_int = input_axis_tvalid & input_axis_tready;
|
||||
output_axis_tlast_int = input_axis_tlast;
|
||||
output_axis_tuser_int = input_axis_tuser;
|
||||
end
|
||||
|
||||
always @(posedge clk or posedge rst) begin
|
||||
if (rst) begin
|
||||
acc_reg <= 0;
|
||||
frame_reg <= 0;
|
||||
input_axis_tready_reg <= 0;
|
||||
end else begin
|
||||
acc_reg <= acc_next;
|
||||
frame_reg <= frame_next;
|
||||
input_axis_tready_reg <= input_axis_tready_next;
|
||||
end
|
||||
end
|
||||
|
||||
// output datapath logic
|
||||
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = 0;
|
||||
reg [KEEP_WIDTH-1:0] output_axis_tkeep_reg = 0;
|
||||
reg output_axis_tvalid_reg = 0;
|
||||
reg output_axis_tlast_reg = 0;
|
||||
reg output_axis_tuser_reg = 0;
|
||||
|
||||
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = 0;
|
||||
reg [KEEP_WIDTH-1:0] temp_axis_tkeep_reg = 0;
|
||||
reg temp_axis_tvalid_reg = 0;
|
||||
reg temp_axis_tlast_reg = 0;
|
||||
reg temp_axis_tuser_reg = 0;
|
||||
|
||||
assign output_axis_tdata = output_axis_tdata_reg;
|
||||
assign output_axis_tkeep = output_axis_tkeep_reg;
|
||||
assign output_axis_tvalid = output_axis_tvalid_reg;
|
||||
assign output_axis_tlast = output_axis_tlast_reg;
|
||||
assign output_axis_tuser = output_axis_tuser_reg;
|
||||
|
||||
// enable ready input next cycle if output is ready or if there is space in both output registers or if there is space in the temp register that will not be filled next cycle
|
||||
assign output_axis_tready_int_early = output_axis_tready | (~temp_axis_tvalid_reg & ~output_axis_tvalid_reg) | (~temp_axis_tvalid_reg & ~output_axis_tvalid_int);
|
||||
|
||||
always @(posedge clk or posedge rst) begin
|
||||
if (rst) begin
|
||||
output_axis_tdata_reg <= 0;
|
||||
output_axis_tkeep_reg <= 0;
|
||||
output_axis_tvalid_reg <= 0;
|
||||
output_axis_tlast_reg <= 0;
|
||||
output_axis_tuser_reg <= 0;
|
||||
output_axis_tready_int <= 0;
|
||||
temp_axis_tdata_reg <= 0;
|
||||
temp_axis_tkeep_reg <= 0;
|
||||
temp_axis_tvalid_reg <= 0;
|
||||
temp_axis_tlast_reg <= 0;
|
||||
temp_axis_tuser_reg <= 0;
|
||||
end else begin
|
||||
// transfer sink ready state to source
|
||||
output_axis_tready_int <= output_axis_tready_int_early;
|
||||
|
||||
if (output_axis_tready_int) begin
|
||||
// input is ready
|
||||
if (output_axis_tready | ~output_axis_tvalid_reg) begin
|
||||
// output is ready or currently not valid, transfer data to output
|
||||
output_axis_tdata_reg <= output_axis_tdata_int;
|
||||
output_axis_tkeep_reg <= output_axis_tkeep_int;
|
||||
output_axis_tvalid_reg <= output_axis_tvalid_int;
|
||||
output_axis_tlast_reg <= output_axis_tlast_int;
|
||||
output_axis_tuser_reg <= output_axis_tuser_int;
|
||||
end else begin
|
||||
// output is not ready, store input in temp
|
||||
temp_axis_tdata_reg <= output_axis_tdata_int;
|
||||
temp_axis_tkeep_reg <= output_axis_tkeep_int;
|
||||
temp_axis_tvalid_reg <= output_axis_tvalid_int;
|
||||
temp_axis_tlast_reg <= output_axis_tlast_int;
|
||||
temp_axis_tuser_reg <= output_axis_tuser_int;
|
||||
end
|
||||
end else if (output_axis_tready) begin
|
||||
// input is not ready, but output is ready
|
||||
output_axis_tdata_reg <= temp_axis_tdata_reg;
|
||||
output_axis_tkeep_reg <= temp_axis_tkeep_reg;
|
||||
output_axis_tvalid_reg <= temp_axis_tvalid_reg;
|
||||
output_axis_tlast_reg <= temp_axis_tlast_reg;
|
||||
output_axis_tuser_reg <= temp_axis_tuser_reg;
|
||||
temp_axis_tdata_reg <= 0;
|
||||
temp_axis_tkeep_reg <= 0;
|
||||
temp_axis_tvalid_reg <= 0;
|
||||
temp_axis_tlast_reg <= 0;
|
||||
temp_axis_tuser_reg <= 0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
124
lib/axis/rtl/axis_register.v
Normal file
124
lib/axis/rtl/axis_register.v
Normal file
@ -0,0 +1,124 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
/*
|
||||
* AXI4-Stream register
|
||||
*/
|
||||
module axis_register #
|
||||
(
|
||||
parameter DATA_WIDTH = 8
|
||||
)
|
||||
(
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
|
||||
/*
|
||||
* AXI input
|
||||
*/
|
||||
input wire [DATA_WIDTH-1:0] input_axis_tdata,
|
||||
input wire input_axis_tvalid,
|
||||
output wire input_axis_tready,
|
||||
input wire input_axis_tlast,
|
||||
input wire input_axis_tuser,
|
||||
|
||||
/*
|
||||
* AXI output
|
||||
*/
|
||||
output wire [DATA_WIDTH-1:0] output_axis_tdata,
|
||||
output wire output_axis_tvalid,
|
||||
input wire output_axis_tready,
|
||||
output wire output_axis_tlast,
|
||||
output wire output_axis_tuser
|
||||
);
|
||||
|
||||
// datapath registers
|
||||
reg input_axis_tready_reg = 0;
|
||||
|
||||
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = 0;
|
||||
reg output_axis_tvalid_reg = 0;
|
||||
reg output_axis_tlast_reg = 0;
|
||||
reg output_axis_tuser_reg = 0;
|
||||
|
||||
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = 0;
|
||||
reg temp_axis_tvalid_reg = 0;
|
||||
reg temp_axis_tlast_reg = 0;
|
||||
reg temp_axis_tuser_reg = 0;
|
||||
|
||||
assign input_axis_tready = input_axis_tready_reg;
|
||||
|
||||
assign output_axis_tdata = output_axis_tdata_reg;
|
||||
assign output_axis_tvalid = output_axis_tvalid_reg;
|
||||
assign output_axis_tlast = output_axis_tlast_reg;
|
||||
assign output_axis_tuser = output_axis_tuser_reg;
|
||||
|
||||
always @(posedge clk or posedge rst) begin
|
||||
if (rst) begin
|
||||
input_axis_tready_reg <= 0;
|
||||
output_axis_tdata_reg <= 0;
|
||||
output_axis_tvalid_reg <= 0;
|
||||
output_axis_tlast_reg <= 0;
|
||||
output_axis_tuser_reg <= 0;
|
||||
temp_axis_tdata_reg <= 0;
|
||||
temp_axis_tvalid_reg <= 0;
|
||||
temp_axis_tlast_reg <= 0;
|
||||
temp_axis_tuser_reg <= 0;
|
||||
end else begin
|
||||
// transfer sink ready state to source
|
||||
// enable ready input next cycle if output is ready or if there is space in both output registers or if there is space in the temp register that will not be filled next cycle
|
||||
input_axis_tready_reg <= output_axis_tready | (~temp_axis_tvalid_reg & ~output_axis_tvalid_reg) | (~temp_axis_tvalid_reg & ~input_axis_tvalid);
|
||||
|
||||
if (input_axis_tready_reg) begin
|
||||
// input is ready
|
||||
if (output_axis_tready | ~output_axis_tvalid_reg) begin
|
||||
// output is ready or currently not valid, transfer data to output
|
||||
output_axis_tdata_reg <= input_axis_tdata;
|
||||
output_axis_tvalid_reg <= input_axis_tvalid;
|
||||
output_axis_tlast_reg <= input_axis_tlast;
|
||||
output_axis_tuser_reg <= input_axis_tuser;
|
||||
end else begin
|
||||
// output is not ready, store input in temp
|
||||
temp_axis_tdata_reg <= input_axis_tdata;
|
||||
temp_axis_tvalid_reg <= input_axis_tvalid;
|
||||
temp_axis_tlast_reg <= input_axis_tlast;
|
||||
temp_axis_tuser_reg <= input_axis_tuser;
|
||||
end
|
||||
end else if (output_axis_tready) begin
|
||||
// input is not ready, but output is ready
|
||||
output_axis_tdata_reg <= temp_axis_tdata_reg;
|
||||
output_axis_tvalid_reg <= temp_axis_tvalid_reg;
|
||||
output_axis_tlast_reg <= temp_axis_tlast_reg;
|
||||
output_axis_tuser_reg <= temp_axis_tuser_reg;
|
||||
temp_axis_tdata_reg <= 0;
|
||||
temp_axis_tvalid_reg <= 0;
|
||||
temp_axis_tlast_reg <= 0;
|
||||
temp_axis_tuser_reg <= 0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
136
lib/axis/rtl/axis_register_64.v
Normal file
136
lib/axis/rtl/axis_register_64.v
Normal file
@ -0,0 +1,136 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
/*
|
||||
* AXI4-Stream register (64 bit datapath)
|
||||
*/
|
||||
module axis_register_64 #
|
||||
(
|
||||
parameter DATA_WIDTH = 64,
|
||||
parameter KEEP_WIDTH = (DATA_WIDTH/8)
|
||||
)
|
||||
(
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
|
||||
/*
|
||||
* AXI input
|
||||
*/
|
||||
input wire [DATA_WIDTH-1:0] input_axis_tdata,
|
||||
input wire [KEEP_WIDTH-1:0] input_axis_tkeep,
|
||||
input wire input_axis_tvalid,
|
||||
output wire input_axis_tready,
|
||||
input wire input_axis_tlast,
|
||||
input wire input_axis_tuser,
|
||||
|
||||
/*
|
||||
* AXI output
|
||||
*/
|
||||
output wire [DATA_WIDTH-1:0] output_axis_tdata,
|
||||
output wire [KEEP_WIDTH-1:0] output_axis_tkeep,
|
||||
output wire output_axis_tvalid,
|
||||
input wire output_axis_tready,
|
||||
output wire output_axis_tlast,
|
||||
output wire output_axis_tuser
|
||||
);
|
||||
|
||||
// datapath registers
|
||||
reg input_axis_tready_reg = 0;
|
||||
|
||||
reg [DATA_WIDTH-1:0] output_axis_tdata_reg = 0;
|
||||
reg [KEEP_WIDTH-1:0] output_axis_tkeep_reg = 0;
|
||||
reg output_axis_tvalid_reg = 0;
|
||||
reg output_axis_tlast_reg = 0;
|
||||
reg output_axis_tuser_reg = 0;
|
||||
|
||||
reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = 0;
|
||||
reg [KEEP_WIDTH-1:0] temp_axis_tkeep_reg = 0;
|
||||
reg temp_axis_tvalid_reg = 0;
|
||||
reg temp_axis_tlast_reg = 0;
|
||||
reg temp_axis_tuser_reg = 0;
|
||||
|
||||
assign input_axis_tready = input_axis_tready_reg;
|
||||
|
||||
assign output_axis_tdata = output_axis_tdata_reg;
|
||||
assign output_axis_tkeep = output_axis_tkeep_reg;
|
||||
assign output_axis_tvalid = output_axis_tvalid_reg;
|
||||
assign output_axis_tlast = output_axis_tlast_reg;
|
||||
assign output_axis_tuser = output_axis_tuser_reg;
|
||||
|
||||
always @(posedge clk or posedge rst) begin
|
||||
if (rst) begin
|
||||
input_axis_tready_reg <= 0;
|
||||
output_axis_tdata_reg <= 0;
|
||||
output_axis_tkeep_reg <= 0;
|
||||
output_axis_tvalid_reg <= 0;
|
||||
output_axis_tlast_reg <= 0;
|
||||
output_axis_tuser_reg <= 0;
|
||||
temp_axis_tdata_reg <= 0;
|
||||
temp_axis_tkeep_reg <= 0;
|
||||
temp_axis_tvalid_reg <= 0;
|
||||
temp_axis_tlast_reg <= 0;
|
||||
temp_axis_tuser_reg <= 0;
|
||||
end else begin
|
||||
// transfer sink ready state to source
|
||||
// enable ready input next cycle if output is ready or if there is space in both output registers or if there is space in the temp register that will not be filled next cycle
|
||||
input_axis_tready_reg <= output_axis_tready | (~temp_axis_tvalid_reg & ~output_axis_tvalid_reg) | (~temp_axis_tvalid_reg & ~input_axis_tvalid);
|
||||
|
||||
if (input_axis_tready_reg) begin
|
||||
// input is ready
|
||||
if (output_axis_tready | ~output_axis_tvalid_reg) begin
|
||||
// output is ready or currently not valid, transfer data to output
|
||||
output_axis_tdata_reg <= input_axis_tdata;
|
||||
output_axis_tkeep_reg <= input_axis_tkeep;
|
||||
output_axis_tvalid_reg <= input_axis_tvalid;
|
||||
output_axis_tlast_reg <= input_axis_tlast;
|
||||
output_axis_tuser_reg <= input_axis_tuser;
|
||||
end else begin
|
||||
// output is not ready, store input in temp
|
||||
temp_axis_tdata_reg <= input_axis_tdata;
|
||||
temp_axis_tkeep_reg <= input_axis_tkeep;
|
||||
temp_axis_tvalid_reg <= input_axis_tvalid;
|
||||
temp_axis_tlast_reg <= input_axis_tlast;
|
||||
temp_axis_tuser_reg <= input_axis_tuser;
|
||||
end
|
||||
end else if (output_axis_tready) begin
|
||||
// input is not ready, but output is ready
|
||||
output_axis_tdata_reg <= temp_axis_tdata_reg;
|
||||
output_axis_tkeep_reg <= temp_axis_tkeep_reg;
|
||||
output_axis_tvalid_reg <= temp_axis_tvalid_reg;
|
||||
output_axis_tlast_reg <= temp_axis_tlast_reg;
|
||||
output_axis_tuser_reg <= temp_axis_tuser_reg;
|
||||
temp_axis_tdata_reg <= 0;
|
||||
temp_axis_tkeep_reg <= 0;
|
||||
temp_axis_tvalid_reg <= 0;
|
||||
temp_axis_tlast_reg <= 0;
|
||||
temp_axis_tuser_reg <= 0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
317
lib/axis/rtl/axis_stat_counter.v
Normal file
317
lib/axis/rtl/axis_stat_counter.v
Normal file
@ -0,0 +1,317 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
/*
|
||||
* AXI4-Stream statistics counter
|
||||
*/
|
||||
module axis_stat_counter #
|
||||
(
|
||||
parameter DATA_WIDTH = 64,
|
||||
parameter KEEP_WIDTH = (DATA_WIDTH/8)
|
||||
)
|
||||
(
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
|
||||
/*
|
||||
* AXI monitor
|
||||
*/
|
||||
input wire [KEEP_WIDTH-1:0] monitor_axis_tkeep,
|
||||
input wire monitor_axis_tvalid,
|
||||
input wire monitor_axis_tready,
|
||||
input wire monitor_axis_tlast,
|
||||
|
||||
/*
|
||||
* AXI status data output
|
||||
*/
|
||||
output wire [7:0] output_axis_tdata,
|
||||
output wire output_axis_tvalid,
|
||||
input wire output_axis_tready,
|
||||
output wire output_axis_tlast,
|
||||
output wire output_axis_tuser,
|
||||
|
||||
/*
|
||||
* Configuration
|
||||
*/
|
||||
input wire [15:0] tag,
|
||||
input wire trigger,
|
||||
|
||||
/*
|
||||
* Status
|
||||
*/
|
||||
output wire busy
|
||||
);
|
||||
|
||||
// state register
|
||||
localparam [1:0]
|
||||
STATE_IDLE = 2'd0,
|
||||
STATE_OUTPUT_DATA = 2'd1;
|
||||
|
||||
reg [1:0] state_reg = STATE_IDLE, state_next;
|
||||
|
||||
reg [31:0] tick_count_reg = 0, tick_count_next;
|
||||
reg [31:0] byte_count_reg = 0, byte_count_next;
|
||||
reg [31:0] frame_count_reg = 0, frame_count_next;
|
||||
reg frame_reg = 0, frame_next;
|
||||
|
||||
reg store_output;
|
||||
reg [5:0] frame_ptr_reg = 0, frame_ptr_next;
|
||||
|
||||
reg [31:0] tick_count_output_reg = 0;
|
||||
reg [31:0] byte_count_output_reg = 0;
|
||||
reg [31:0] frame_count_output_reg = 0;
|
||||
|
||||
reg busy_reg = 0;
|
||||
|
||||
// internal datapath
|
||||
reg [7:0] output_axis_tdata_int;
|
||||
reg output_axis_tvalid_int;
|
||||
reg output_axis_tready_int = 0;
|
||||
reg output_axis_tlast_int;
|
||||
reg output_axis_tuser_int;
|
||||
wire output_axis_tready_int_early;
|
||||
|
||||
assign busy = busy_reg;
|
||||
|
||||
function [3:0] keep2count;
|
||||
input [7:0] k;
|
||||
case (k)
|
||||
8'b00000000: keep2count = 0;
|
||||
8'b00000001: keep2count = 1;
|
||||
8'b00000011: keep2count = 2;
|
||||
8'b00000111: keep2count = 3;
|
||||
8'b00001111: keep2count = 4;
|
||||
8'b00011111: keep2count = 5;
|
||||
8'b00111111: keep2count = 6;
|
||||
8'b01111111: keep2count = 7;
|
||||
8'b11111111: keep2count = 8;
|
||||
endcase
|
||||
endfunction
|
||||
|
||||
function [7:0] count2keep;
|
||||
input [3:0] k;
|
||||
case (k)
|
||||
4'd0: count2keep = 8'b00000000;
|
||||
4'd1: count2keep = 8'b00000001;
|
||||
4'd2: count2keep = 8'b00000011;
|
||||
4'd3: count2keep = 8'b00000111;
|
||||
4'd4: count2keep = 8'b00001111;
|
||||
4'd5: count2keep = 8'b00011111;
|
||||
4'd6: count2keep = 8'b00111111;
|
||||
4'd7: count2keep = 8'b01111111;
|
||||
4'd8: count2keep = 8'b11111111;
|
||||
endcase
|
||||
endfunction
|
||||
|
||||
always @* begin
|
||||
state_next = 2'bz;
|
||||
|
||||
tick_count_next = tick_count_reg;
|
||||
byte_count_next = byte_count_reg;
|
||||
frame_count_next = frame_count_reg;
|
||||
frame_next = frame_reg;
|
||||
|
||||
output_axis_tdata_int = 0;
|
||||
output_axis_tvalid_int = 0;
|
||||
output_axis_tlast_int = 0;
|
||||
output_axis_tuser_int = 0;
|
||||
|
||||
store_output = 0;
|
||||
|
||||
frame_ptr_next = frame_ptr_reg;
|
||||
|
||||
// data readout
|
||||
|
||||
case (state_reg)
|
||||
STATE_IDLE: begin
|
||||
if (trigger) begin
|
||||
store_output = 1;
|
||||
tick_count_next = 0;
|
||||
byte_count_next = 0;
|
||||
frame_count_next = 0;
|
||||
frame_ptr_next = 0;
|
||||
|
||||
if (output_axis_tready_int) begin
|
||||
frame_ptr_next = 1;
|
||||
output_axis_tdata_int = tag[15:8];
|
||||
output_axis_tvalid_int = 1;
|
||||
end
|
||||
|
||||
state_next = STATE_OUTPUT_DATA;
|
||||
end else begin
|
||||
state_next = STATE_IDLE;
|
||||
end
|
||||
end
|
||||
STATE_OUTPUT_DATA: begin
|
||||
if (output_axis_tready_int) begin
|
||||
state_next = STATE_OUTPUT_DATA;
|
||||
frame_ptr_next = frame_ptr_reg + 1;
|
||||
output_axis_tvalid_int = 1;
|
||||
case (frame_ptr_reg)
|
||||
5'd00: output_axis_tdata_int = tag[15:8];
|
||||
5'd01: output_axis_tdata_int = tag[7:0];
|
||||
5'd02: output_axis_tdata_int = tick_count_output_reg[31:24];
|
||||
5'd03: output_axis_tdata_int = tick_count_output_reg[23:16];
|
||||
5'd04: output_axis_tdata_int = tick_count_output_reg[15: 8];
|
||||
5'd05: output_axis_tdata_int = tick_count_output_reg[ 7: 0];
|
||||
5'd06: output_axis_tdata_int = byte_count_output_reg[31:24];
|
||||
5'd07: output_axis_tdata_int = byte_count_output_reg[23:16];
|
||||
5'd08: output_axis_tdata_int = byte_count_output_reg[15: 8];
|
||||
5'd09: output_axis_tdata_int = byte_count_output_reg[ 7: 0];
|
||||
5'd10: output_axis_tdata_int = frame_count_output_reg[31:24];
|
||||
5'd11: output_axis_tdata_int = frame_count_output_reg[23:16];
|
||||
5'd12: output_axis_tdata_int = frame_count_output_reg[15: 8];
|
||||
5'd13: begin
|
||||
output_axis_tdata_int = frame_count_output_reg[ 7: 0];
|
||||
output_axis_tlast_int = 1;
|
||||
state_next = STATE_IDLE;
|
||||
end
|
||||
endcase
|
||||
end else begin
|
||||
state_next = STATE_OUTPUT_DATA;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
|
||||
// stats collection
|
||||
|
||||
// increment tick count by number of words that can be transferred per cycle
|
||||
tick_count_next = tick_count_next + KEEP_WIDTH;
|
||||
|
||||
if (monitor_axis_tready & monitor_axis_tvalid) begin
|
||||
// valid transfer cycle
|
||||
|
||||
// increment byte count by number of words transferred
|
||||
byte_count_next = byte_count_next + keep2count(monitor_axis_tkeep);
|
||||
|
||||
// count frames
|
||||
if (monitor_axis_tlast) begin
|
||||
// end of frame
|
||||
frame_next = 0;
|
||||
end else if (~frame_reg) begin
|
||||
// first word after end of frame
|
||||
frame_count_next = frame_count_next + 1;
|
||||
frame_next = 1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk or posedge rst) begin
|
||||
if (rst) begin
|
||||
state_reg <= STATE_IDLE;
|
||||
tick_count_reg <= 0;
|
||||
byte_count_reg <= 0;
|
||||
frame_count_reg <= 0;
|
||||
frame_reg <= 0;
|
||||
frame_ptr_reg <= 0;
|
||||
busy_reg <= 0;
|
||||
tick_count_output_reg <= 0;
|
||||
byte_count_output_reg <= 0;
|
||||
frame_count_output_reg <= 0;
|
||||
end else begin
|
||||
state_reg <= state_next;
|
||||
tick_count_reg <= tick_count_next;
|
||||
byte_count_reg <= byte_count_next;
|
||||
frame_count_reg <= frame_count_next;
|
||||
frame_reg <= frame_next;
|
||||
frame_ptr_reg <= frame_ptr_next;
|
||||
|
||||
busy_reg <= state_next != STATE_IDLE;
|
||||
|
||||
if (store_output) begin
|
||||
tick_count_output_reg <= tick_count_reg;
|
||||
byte_count_output_reg <= byte_count_reg;
|
||||
frame_count_output_reg <= frame_count_reg;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// output datapath logic
|
||||
reg [7:0] output_axis_tdata_reg = 0;
|
||||
reg output_axis_tvalid_reg = 0;
|
||||
reg output_axis_tlast_reg = 0;
|
||||
reg output_axis_tuser_reg = 0;
|
||||
|
||||
reg [7:0] temp_axis_tdata_reg = 0;
|
||||
reg temp_axis_tvalid_reg = 0;
|
||||
reg temp_axis_tlast_reg = 0;
|
||||
reg temp_axis_tuser_reg = 0;
|
||||
|
||||
assign output_axis_tdata = output_axis_tdata_reg;
|
||||
assign output_axis_tvalid = output_axis_tvalid_reg;
|
||||
assign output_axis_tlast = output_axis_tlast_reg;
|
||||
assign output_axis_tuser = output_axis_tuser_reg;
|
||||
|
||||
// enable ready input next cycle if output is ready or if there is space in both output registers or if there is space in the temp register that will not be filled next cycle
|
||||
assign output_axis_tready_int_early = output_axis_tready | (~temp_axis_tvalid_reg & ~output_axis_tvalid_reg) | (~temp_axis_tvalid_reg & ~output_axis_tvalid_int);
|
||||
|
||||
always @(posedge clk or posedge rst) begin
|
||||
if (rst) begin
|
||||
output_axis_tdata_reg <= 0;
|
||||
output_axis_tvalid_reg <= 0;
|
||||
output_axis_tlast_reg <= 0;
|
||||
output_axis_tuser_reg <= 0;
|
||||
output_axis_tready_int <= 0;
|
||||
temp_axis_tdata_reg <= 0;
|
||||
temp_axis_tvalid_reg <= 0;
|
||||
temp_axis_tlast_reg <= 0;
|
||||
temp_axis_tuser_reg <= 0;
|
||||
end else begin
|
||||
// transfer sink ready state to source
|
||||
output_axis_tready_int <= output_axis_tready_int_early;
|
||||
|
||||
if (output_axis_tready_int) begin
|
||||
// input is ready
|
||||
if (output_axis_tready | ~output_axis_tvalid_reg) begin
|
||||
// output is ready or currently not valid, transfer data to output
|
||||
output_axis_tdata_reg <= output_axis_tdata_int;
|
||||
output_axis_tvalid_reg <= output_axis_tvalid_int;
|
||||
output_axis_tlast_reg <= output_axis_tlast_int;
|
||||
output_axis_tuser_reg <= output_axis_tuser_int;
|
||||
end else begin
|
||||
// output is not ready, store input in temp
|
||||
temp_axis_tdata_reg <= output_axis_tdata_int;
|
||||
temp_axis_tvalid_reg <= output_axis_tvalid_int;
|
||||
temp_axis_tlast_reg <= output_axis_tlast_int;
|
||||
temp_axis_tuser_reg <= output_axis_tuser_int;
|
||||
end
|
||||
end else if (output_axis_tready) begin
|
||||
// input is not ready, but output is ready
|
||||
output_axis_tdata_reg <= temp_axis_tdata_reg;
|
||||
output_axis_tvalid_reg <= temp_axis_tvalid_reg;
|
||||
output_axis_tlast_reg <= temp_axis_tlast_reg;
|
||||
output_axis_tuser_reg <= temp_axis_tuser_reg;
|
||||
temp_axis_tdata_reg <= 0;
|
||||
temp_axis_tvalid_reg <= 0;
|
||||
temp_axis_tlast_reg <= 0;
|
||||
temp_axis_tuser_reg <= 0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
64
lib/axis/rtl/ll_axis_bridge.v
Normal file
64
lib/axis/rtl/ll_axis_bridge.v
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
/*
|
||||
* LocalLink to AXI4-Stream bridge
|
||||
*/
|
||||
module ll_axis_bridge #
|
||||
(
|
||||
parameter DATA_WIDTH = 8
|
||||
)
|
||||
(
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
|
||||
/*
|
||||
* LocalLink input
|
||||
*/
|
||||
input wire [DATA_WIDTH-1:0] ll_data_in,
|
||||
input wire ll_sof_in_n,
|
||||
input wire ll_eof_in_n,
|
||||
input wire ll_src_rdy_in_n,
|
||||
output wire ll_dst_rdy_out_n,
|
||||
|
||||
/*
|
||||
* AXI output
|
||||
*/
|
||||
output wire [DATA_WIDTH-1:0] axis_tdata,
|
||||
output wire axis_tvalid,
|
||||
input wire axis_tready,
|
||||
output wire axis_tlast
|
||||
);
|
||||
|
||||
assign axis_tdata = ll_data_in;
|
||||
assign axis_tvalid = ~ll_src_rdy_in_n;
|
||||
assign axis_tlast = ~ll_eof_in_n;
|
||||
|
||||
assign ll_dst_rdy_out_n = ~axis_tready;
|
||||
|
||||
endmodule
|
257
lib/axis/tb/axis_ep.py
Normal file
257
lib/axis/tb/axis_ep.py
Normal file
@ -0,0 +1,257 @@
|
||||
"""
|
||||
|
||||
Copyright (c) 2014 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
"""
|
||||
|
||||
from myhdl import *
|
||||
|
||||
class AXIStreamFrame(object):
|
||||
def __init__(self, data=b'', keep=None, user=None):
|
||||
self.N = 8
|
||||
self.M = 1
|
||||
self.WL = 8
|
||||
self.data = b''
|
||||
self.keep = None
|
||||
self.user = None
|
||||
|
||||
if type(data) is bytes or type(data) is bytearray:
|
||||
self.data = bytearray(data)
|
||||
if type(data) is AXIStreamFrame:
|
||||
self.N = data.N
|
||||
self.WL = data.WL
|
||||
self.data = bytearray(data.data)
|
||||
if data.keep is not None:
|
||||
self.keep = list(data.keep)
|
||||
if data.user is not None:
|
||||
if type(data.user) is int or type(data.user) is bool:
|
||||
self.user = data.user
|
||||
else:
|
||||
self.user = list(data.user)
|
||||
|
||||
def build(self):
|
||||
if self.data is None:
|
||||
return
|
||||
|
||||
f = list(self.data)
|
||||
tdata = []
|
||||
tkeep = []
|
||||
tuser = []
|
||||
i = 0
|
||||
|
||||
assert_tuser = False
|
||||
if (type(self.user) is int or type(self.user) is bool) and self.user:
|
||||
assert_tuser = True
|
||||
self.user = None
|
||||
|
||||
while len(f) > 0:
|
||||
data = 0
|
||||
keep = 0
|
||||
for j in range(self.M):
|
||||
data = data | (f.pop(0) << (j*self.WL))
|
||||
keep = keep | (1 << j)
|
||||
if len(f) == 0: break
|
||||
tdata.append(data)
|
||||
if self.keep is None:
|
||||
tkeep.append(keep)
|
||||
else:
|
||||
tkeep.append(self.keep[i])
|
||||
if self.user is None:
|
||||
tuser.append(0)
|
||||
else:
|
||||
tuser.append(self.user[i])
|
||||
i += 1
|
||||
|
||||
if assert_tuser:
|
||||
tuser[-1] = 1
|
||||
self.user = 1
|
||||
|
||||
return tdata, tkeep, tuser
|
||||
|
||||
def parse(self, tdata, tkeep, tuser):
|
||||
if tdata is None or tkeep is None or tuser is None:
|
||||
return
|
||||
if len(tdata) != len(tkeep) or len(tdata) != len(tuser):
|
||||
raise Exception("Invalid data")
|
||||
|
||||
self.data = []
|
||||
self.keep = []
|
||||
self.user = []
|
||||
mask = 2**self.WL-1
|
||||
|
||||
for i in range(len(tdata)):
|
||||
for j in range(self.M):
|
||||
if tkeep[i] & (1 << j):
|
||||
self.data.append((tdata[i] >> (j*self.WL)) & mask)
|
||||
self.keep.append(tkeep[i])
|
||||
self.user.append(tuser[i])
|
||||
|
||||
if self.WL == 8:
|
||||
self.data = bytearray(self.data)
|
||||
|
||||
def __eq__(self, other):
|
||||
if type(other) is AXIStreamFrame:
|
||||
return self.data == other.data
|
||||
|
||||
def __repr__(self):
|
||||
return 'AXIStreamFrame(data=%s, keep=%s, user=%s)' % (repr(self.data), repr(self.keep), repr(self.user))
|
||||
|
||||
def __iter__(self):
|
||||
return self.data.__iter__()
|
||||
|
||||
def AXIStreamSource(clk, rst,
|
||||
tdata=None,
|
||||
tkeep=Signal(bool(True)),
|
||||
tvalid=Signal(bool(False)),
|
||||
tready=Signal(bool(True)),
|
||||
tlast=Signal(bool(False)),
|
||||
tuser=Signal(bool(False)),
|
||||
fifo=None,
|
||||
pause=0,
|
||||
name=None):
|
||||
|
||||
tready_int = Signal(bool(False))
|
||||
tvalid_int = Signal(bool(False))
|
||||
|
||||
@always_comb
|
||||
def pause_logic():
|
||||
tready_int.next = tready and not pause
|
||||
tvalid.next = tvalid_int and not pause
|
||||
|
||||
@instance
|
||||
def logic():
|
||||
frame = AXIStreamFrame()
|
||||
data = []
|
||||
keep = []
|
||||
user = []
|
||||
N = len(tdata)
|
||||
M = 1
|
||||
b = False
|
||||
if tkeep is not None:
|
||||
M = len(tkeep)
|
||||
WL = (len(tdata)+M-1)/M
|
||||
if WL == 8:
|
||||
b = True
|
||||
|
||||
while True:
|
||||
yield clk.posedge, rst.posedge
|
||||
|
||||
if rst:
|
||||
tdata.next = 0
|
||||
tkeep.next = 0
|
||||
tvalid_int.next = False
|
||||
tlast.next = False
|
||||
else:
|
||||
if tready_int and tvalid:
|
||||
if len(data) > 0:
|
||||
tdata.next = data.pop(0)
|
||||
tkeep.next = keep.pop(0)
|
||||
tuser.next = user.pop(0)
|
||||
tvalid_int.next = True
|
||||
tlast.next = len(data) == 0
|
||||
else:
|
||||
tvalid_int.next = False
|
||||
tlast.next = False
|
||||
if (tlast and tready_int and tvalid) or not tvalid_int:
|
||||
if not fifo.empty():
|
||||
frame = fifo.get()
|
||||
frame = AXIStreamFrame(frame)
|
||||
frame.N = N
|
||||
frame.M = M
|
||||
frame.WL = WL
|
||||
frame.build()
|
||||
if name is not None:
|
||||
print("[%s] Sending frame %s" % (name, repr(frame)))
|
||||
data, keep, user = frame.build()
|
||||
tdata.next = data.pop(0)
|
||||
tkeep.next = keep.pop(0)
|
||||
tuser.next = user.pop(0)
|
||||
tvalid_int.next = True
|
||||
tlast.next = len(data) == 0
|
||||
|
||||
return logic, pause_logic
|
||||
|
||||
|
||||
def AXIStreamSink(clk, rst,
|
||||
tdata=None,
|
||||
tkeep=Signal(bool(True)),
|
||||
tvalid=Signal(bool(True)),
|
||||
tready=Signal(bool(True)),
|
||||
tlast=Signal(bool(True)),
|
||||
tuser=Signal(bool(False)),
|
||||
fifo=None,
|
||||
pause=0,
|
||||
name=None):
|
||||
|
||||
tready_int = Signal(bool(False))
|
||||
tvalid_int = Signal(bool(False))
|
||||
|
||||
@always_comb
|
||||
def pause_logic():
|
||||
tready.next = tready_int and not pause
|
||||
tvalid_int.next = tvalid and not pause
|
||||
|
||||
@instance
|
||||
def logic():
|
||||
frame = AXIStreamFrame()
|
||||
data = []
|
||||
keep = []
|
||||
user = []
|
||||
N = len(tdata)
|
||||
M = 1
|
||||
b = False
|
||||
M = len(tkeep)
|
||||
WL = (len(tdata)+M-1)/M
|
||||
if WL == 8:
|
||||
b = True
|
||||
|
||||
while True:
|
||||
yield clk.posedge, rst.posedge
|
||||
|
||||
if rst:
|
||||
tready_int.next = False
|
||||
frame = AXIStreamFrame()
|
||||
data = []
|
||||
keep = []
|
||||
user = []
|
||||
else:
|
||||
tready_int.next = True
|
||||
|
||||
if tvalid_int:
|
||||
data.append(int(tdata))
|
||||
keep.append(int(tkeep))
|
||||
user.append(int(tuser))
|
||||
if tlast:
|
||||
frame.N = N
|
||||
frame.M = M
|
||||
frame.WL = WL
|
||||
frame.parse(data, keep, user)
|
||||
if fifo is not None:
|
||||
fifo.put(frame)
|
||||
if name is not None:
|
||||
print("[%s] Got frame %s" % (name, repr(frame)))
|
||||
frame = AXIStreamFrame()
|
||||
data = []
|
||||
keep = []
|
||||
user = []
|
||||
|
||||
return logic, pause_logic
|
||||
|
123
lib/axis/tb/ll_ep.py
Normal file
123
lib/axis/tb/ll_ep.py
Normal file
@ -0,0 +1,123 @@
|
||||
"""
|
||||
|
||||
Copyright (c) 2014 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
"""
|
||||
|
||||
from myhdl import *
|
||||
|
||||
def LocalLinkSource(clk, rst,
|
||||
data_out,
|
||||
sof_out_n,
|
||||
eof_out_n,
|
||||
src_rdy_out_n,
|
||||
dst_rdy_in_n,
|
||||
fifo,
|
||||
pause=0,
|
||||
name=None):
|
||||
|
||||
src_rdy_out_n_int = Signal(bool(True))
|
||||
dst_rdy_in_n_int = Signal(bool(True))
|
||||
|
||||
@always_comb
|
||||
def pause_logic():
|
||||
dst_rdy_in_n_int.next = dst_rdy_in_n or pause
|
||||
src_rdy_out_n.next = src_rdy_out_n_int or pause
|
||||
|
||||
@instance
|
||||
def logic():
|
||||
frame = []
|
||||
|
||||
while True:
|
||||
yield clk.posedge, rst.posedge
|
||||
|
||||
if rst:
|
||||
data_out.next = 0
|
||||
src_rdy_out_n_int.next = True
|
||||
sof_out_n.next = True
|
||||
eof_out_n.next = True
|
||||
else:
|
||||
if not dst_rdy_in_n_int and not src_rdy_out_n:
|
||||
if len(frame) > 0:
|
||||
data_out.next = frame.pop(0)
|
||||
src_rdy_out_n_int.next = False
|
||||
sof_out_n.next = True
|
||||
eof_out_n.next = len(frame) != 0
|
||||
else:
|
||||
src_rdy_out_n_int.next = True
|
||||
eof_out_n.next = True
|
||||
if (not eof_out_n and not dst_rdy_in_n_int and not src_rdy_out_n) or src_rdy_out_n_int:
|
||||
if not fifo.empty():
|
||||
frame = fifo.get()
|
||||
if name is not None:
|
||||
print("[%s] Sending frame %s" % (name, repr(frame)))
|
||||
data_out.next = frame.pop(0)
|
||||
src_rdy_out_n_int.next = False
|
||||
sof_out_n.next = False
|
||||
eof_out_n.next = len(frame) != 0
|
||||
|
||||
return logic, pause_logic
|
||||
|
||||
|
||||
def LocalLinkSink(clk, rst,
|
||||
data_in,
|
||||
sof_in_n,
|
||||
eof_in_n,
|
||||
src_rdy_in_n,
|
||||
dst_rdy_out_n,
|
||||
fifo=None,
|
||||
pause=0,
|
||||
name=None):
|
||||
|
||||
src_rdy_in_n_int = Signal(bool(True))
|
||||
dst_rdy_out_n_int = Signal(bool(True))
|
||||
|
||||
@always_comb
|
||||
def pause_logic():
|
||||
dst_rdy_out_n.next = dst_rdy_out_n_int or pause
|
||||
src_rdy_in_n_int.next = src_rdy_in_n or pause
|
||||
|
||||
@instance
|
||||
def logic():
|
||||
frame = []
|
||||
|
||||
while True:
|
||||
yield clk.posedge, rst.posedge
|
||||
|
||||
if rst:
|
||||
dst_rdy_out_n_int.next = True
|
||||
frame = []
|
||||
else:
|
||||
dst_rdy_out_n_int.next = False
|
||||
|
||||
if not src_rdy_in_n_int:
|
||||
if not sof_in_n:
|
||||
frame = []
|
||||
frame.append(int(data_in))
|
||||
if not eof_in_n:
|
||||
if fifo is not None:
|
||||
fifo.put(frame)
|
||||
if name is not None:
|
||||
print("[%s] Got frame %s" % (name, repr(frame)))
|
||||
frame = []
|
||||
|
||||
return logic, pause_logic
|
||||
|
318
lib/axis/tb/test_axis_adapter_64_8.py
Executable file
318
lib/axis/tb/test_axis_adapter_64_8.py
Executable file
@ -0,0 +1,318 @@
|
||||
#!/usr/bin/env python2
|
||||
"""
|
||||
|
||||
Copyright (c) 2014 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
"""
|
||||
|
||||
from myhdl import *
|
||||
import os
|
||||
from Queue import Queue
|
||||
|
||||
import axis_ep
|
||||
|
||||
module = 'axis_adapter'
|
||||
|
||||
srcs = []
|
||||
|
||||
srcs.append("../rtl/%s.v" % module)
|
||||
srcs.append("test_%s_64_8.v" % module)
|
||||
|
||||
src = ' '.join(srcs)
|
||||
|
||||
build_cmd = "iverilog -o test_%s.vvp %s" % (module, src)
|
||||
|
||||
def dut_axis_adapter_64_8(clk,
|
||||
rst,
|
||||
current_test,
|
||||
|
||||
input_axis_tdata,
|
||||
input_axis_tkeep,
|
||||
input_axis_tvalid,
|
||||
input_axis_tready,
|
||||
input_axis_tlast,
|
||||
input_axis_tuser,
|
||||
|
||||
output_axis_tdata,
|
||||
output_axis_tkeep,
|
||||
output_axis_tvalid,
|
||||
output_axis_tready,
|
||||
output_axis_tlast,
|
||||
output_axis_tuser):
|
||||
|
||||
if os.system(build_cmd):
|
||||
raise Exception("Error running build command")
|
||||
return Cosimulation("vvp -m myhdl test_%s.vvp -lxt2" % module,
|
||||
clk=clk,
|
||||
rst=rst,
|
||||
current_test=current_test,
|
||||
|
||||
input_axis_tdata=input_axis_tdata,
|
||||
input_axis_tkeep=input_axis_tkeep,
|
||||
input_axis_tvalid=input_axis_tvalid,
|
||||
input_axis_tready=input_axis_tready,
|
||||
input_axis_tlast=input_axis_tlast,
|
||||
input_axis_tuser=input_axis_tuser,
|
||||
|
||||
output_axis_tdata=output_axis_tdata,
|
||||
output_axis_tkeep=output_axis_tkeep,
|
||||
output_axis_tvalid=output_axis_tvalid,
|
||||
output_axis_tready=output_axis_tready,
|
||||
output_axis_tlast=output_axis_tlast,
|
||||
output_axis_tuser=output_axis_tuser)
|
||||
|
||||
def bench():
|
||||
|
||||
# Inputs
|
||||
clk = Signal(bool(0))
|
||||
rst = Signal(bool(0))
|
||||
current_test = Signal(intbv(0)[8:])
|
||||
|
||||
input_axis_tdata = Signal(intbv(0)[64:])
|
||||
input_axis_tkeep = Signal(intbv(0)[8:])
|
||||
input_axis_tvalid = Signal(bool(0))
|
||||
input_axis_tlast = Signal(bool(0))
|
||||
input_axis_tuser = Signal(bool(0))
|
||||
output_axis_tready = Signal(bool(0))
|
||||
|
||||
# Outputs
|
||||
input_axis_tready = Signal(bool(0))
|
||||
output_axis_tdata = Signal(intbv(0)[8:])
|
||||
output_axis_tkeep = Signal(intbv(0)[1:])
|
||||
output_axis_tvalid = Signal(bool(0))
|
||||
output_axis_tlast = Signal(bool(0))
|
||||
output_axis_tuser = Signal(bool(0))
|
||||
|
||||
# sources and sinks
|
||||
source_queue = Queue()
|
||||
source_pause = Signal(bool(0))
|
||||
sink_queue = Queue()
|
||||
sink_pause = Signal(bool(0))
|
||||
|
||||
source = axis_ep.AXIStreamSource(clk,
|
||||
rst,
|
||||
tdata=input_axis_tdata,
|
||||
tkeep=input_axis_tkeep,
|
||||
tvalid=input_axis_tvalid,
|
||||
tready=input_axis_tready,
|
||||
tlast=input_axis_tlast,
|
||||
tuser=input_axis_tuser,
|
||||
fifo=source_queue,
|
||||
pause=source_pause,
|
||||
name='source')
|
||||
|
||||
sink = axis_ep.AXIStreamSink(clk,
|
||||
rst,
|
||||
tdata=output_axis_tdata,
|
||||
tkeep=output_axis_tkeep,
|
||||
tvalid=output_axis_tvalid,
|
||||
tready=output_axis_tready,
|
||||
tlast=output_axis_tlast,
|
||||
tuser=output_axis_tuser,
|
||||
fifo=sink_queue,
|
||||
pause=sink_pause,
|
||||
name='sink')
|
||||
|
||||
# DUT
|
||||
dut = dut_axis_adapter_64_8(clk,
|
||||
rst,
|
||||
current_test,
|
||||
|
||||
input_axis_tdata,
|
||||
input_axis_tkeep,
|
||||
input_axis_tvalid,
|
||||
input_axis_tready,
|
||||
input_axis_tlast,
|
||||
input_axis_tuser,
|
||||
|
||||
output_axis_tdata,
|
||||
output_axis_tkeep,
|
||||
output_axis_tvalid,
|
||||
output_axis_tready,
|
||||
output_axis_tlast,
|
||||
output_axis_tuser)
|
||||
|
||||
@always(delay(4))
|
||||
def clkgen():
|
||||
clk.next = not clk
|
||||
|
||||
def wait_normal():
|
||||
while input_axis_tvalid or output_axis_tvalid:
|
||||
yield clk.posedge
|
||||
|
||||
def wait_pause_source():
|
||||
while input_axis_tvalid or output_axis_tvalid:
|
||||
source_pause.next = True
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
source_pause.next = False
|
||||
yield clk.posedge
|
||||
|
||||
def wait_pause_sink():
|
||||
while input_axis_tvalid or output_axis_tvalid:
|
||||
sink_pause.next = True
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
sink_pause.next = False
|
||||
yield clk.posedge
|
||||
|
||||
@instance
|
||||
def check():
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
rst.next = 1
|
||||
yield clk.posedge
|
||||
rst.next = 0
|
||||
yield clk.posedge
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
|
||||
for payload_len in range(1,18):
|
||||
yield clk.posedge
|
||||
print("test 1: test packet, length %d" % payload_len)
|
||||
current_test.next = 1
|
||||
|
||||
test_frame = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
bytearray(range(payload_len)))
|
||||
|
||||
for wait in wait_normal, wait_pause_source, wait_pause_sink:
|
||||
source_queue.put(test_frame)
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
yield wait()
|
||||
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame
|
||||
|
||||
assert sink_queue.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 2: back-to-back packets, length %d" % payload_len)
|
||||
current_test.next = 2
|
||||
|
||||
test_frame1 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
bytearray(range(payload_len)))
|
||||
test_frame2 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
bytearray(range(payload_len)))
|
||||
|
||||
for wait in wait_normal, wait_pause_source, wait_pause_sink:
|
||||
source_queue.put(test_frame1)
|
||||
source_queue.put(test_frame2)
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
yield wait()
|
||||
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame1
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame2
|
||||
|
||||
assert sink_queue.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 3: tuser assert, length %d" % payload_len)
|
||||
current_test.next = 3
|
||||
|
||||
test_frame1 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
bytearray(range(payload_len)))
|
||||
test_frame2 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
bytearray(range(payload_len)))
|
||||
|
||||
test_frame1.user = 1
|
||||
|
||||
for wait in wait_normal, wait_pause_source, wait_pause_sink:
|
||||
source_queue.put(test_frame1)
|
||||
source_queue.put(test_frame2)
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
yield wait()
|
||||
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame1
|
||||
assert rx_frame.user[-1]
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame2
|
||||
|
||||
assert sink_queue.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
raise StopSimulation
|
||||
|
||||
return dut, source, sink, clkgen, check
|
||||
|
||||
def test_bench():
|
||||
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
||||
sim = Simulation(bench())
|
||||
sim.run()
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("Running test...")
|
||||
test_bench()
|
||||
|
105
lib/axis/tb/test_axis_adapter_64_8.v
Normal file
105
lib/axis/tb/test_axis_adapter_64_8.v
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`timescale 1 ns / 1 ps
|
||||
|
||||
module test_axis_adapter_64_8;
|
||||
|
||||
// parameters
|
||||
localparam INPUT_DATA_WIDTH = 64;
|
||||
localparam INPUT_KEEP_WIDTH = (INPUT_DATA_WIDTH/8);
|
||||
localparam OUTPUT_DATA_WIDTH = 8;
|
||||
localparam OUTPUT_KEEP_WIDTH = (OUTPUT_DATA_WIDTH/8);
|
||||
|
||||
// Inputs
|
||||
reg clk = 0;
|
||||
reg rst = 0;
|
||||
reg [7:0] current_test = 0;
|
||||
|
||||
reg [INPUT_DATA_WIDTH-1:0] input_axis_tdata = 0;
|
||||
reg [INPUT_KEEP_WIDTH-1:0] input_axis_tkeep = 0;
|
||||
reg input_axis_tvalid = 0;
|
||||
reg input_axis_tlast = 0;
|
||||
reg input_axis_tuser = 0;
|
||||
reg output_axis_tready = 0;
|
||||
|
||||
// Outputs
|
||||
wire input_axis_tready;
|
||||
wire [OUTPUT_DATA_WIDTH-1:0] output_axis_tdata;
|
||||
wire [OUTPUT_KEEP_WIDTH-1:0] output_axis_tkeep;
|
||||
wire output_axis_tvalid;
|
||||
wire output_axis_tlast;
|
||||
wire output_axis_tuser;
|
||||
|
||||
initial begin
|
||||
// myhdl integration
|
||||
$from_myhdl(clk,
|
||||
rst,
|
||||
current_test,
|
||||
input_axis_tdata,
|
||||
input_axis_tkeep,
|
||||
input_axis_tvalid,
|
||||
input_axis_tlast,
|
||||
input_axis_tuser,
|
||||
output_axis_tready);
|
||||
$to_myhdl(input_axis_tready,
|
||||
output_axis_tdata,
|
||||
output_axis_tkeep,
|
||||
output_axis_tvalid,
|
||||
output_axis_tlast,
|
||||
output_axis_tuser);
|
||||
|
||||
// dump file
|
||||
$dumpfile("test_axis_adapter_64_8.lxt");
|
||||
$dumpvars(0, test_axis_adapter_64_8);
|
||||
end
|
||||
|
||||
axis_adapter #(
|
||||
.INPUT_DATA_WIDTH(INPUT_DATA_WIDTH),
|
||||
.INPUT_KEEP_WIDTH(INPUT_KEEP_WIDTH),
|
||||
.OUTPUT_DATA_WIDTH(OUTPUT_DATA_WIDTH),
|
||||
.OUTPUT_KEEP_WIDTH(OUTPUT_KEEP_WIDTH)
|
||||
)
|
||||
UUT (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
// AXI input
|
||||
.input_axis_tdata(input_axis_tdata),
|
||||
.input_axis_tkeep(input_axis_tkeep),
|
||||
.input_axis_tvalid(input_axis_tvalid),
|
||||
.input_axis_tready(input_axis_tready),
|
||||
.input_axis_tlast(input_axis_tlast),
|
||||
.input_axis_tuser(input_axis_tuser),
|
||||
// AXI output
|
||||
.output_axis_tdata(output_axis_tdata),
|
||||
.output_axis_tkeep(output_axis_tkeep),
|
||||
.output_axis_tvalid(output_axis_tvalid),
|
||||
.output_axis_tready(output_axis_tready),
|
||||
.output_axis_tlast(output_axis_tlast),
|
||||
.output_axis_tuser(output_axis_tuser)
|
||||
);
|
||||
|
||||
endmodule
|
318
lib/axis/tb/test_axis_adapter_8_64.py
Executable file
318
lib/axis/tb/test_axis_adapter_8_64.py
Executable file
@ -0,0 +1,318 @@
|
||||
#!/usr/bin/env python2
|
||||
"""
|
||||
|
||||
Copyright (c) 2014 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
"""
|
||||
|
||||
from myhdl import *
|
||||
import os
|
||||
from Queue import Queue
|
||||
|
||||
import axis_ep
|
||||
|
||||
module = 'axis_adapter'
|
||||
|
||||
srcs = []
|
||||
|
||||
srcs.append("../rtl/%s.v" % module)
|
||||
srcs.append("test_%s_8_64.v" % module)
|
||||
|
||||
src = ' '.join(srcs)
|
||||
|
||||
build_cmd = "iverilog -o test_%s.vvp %s" % (module, src)
|
||||
|
||||
def dut_axis_adapter_8_64(clk,
|
||||
rst,
|
||||
current_test,
|
||||
|
||||
input_axis_tdata,
|
||||
input_axis_tkeep,
|
||||
input_axis_tvalid,
|
||||
input_axis_tready,
|
||||
input_axis_tlast,
|
||||
input_axis_tuser,
|
||||
|
||||
output_axis_tdata,
|
||||
output_axis_tkeep,
|
||||
output_axis_tvalid,
|
||||
output_axis_tready,
|
||||
output_axis_tlast,
|
||||
output_axis_tuser):
|
||||
|
||||
if os.system(build_cmd):
|
||||
raise Exception("Error running build command")
|
||||
return Cosimulation("vvp -m myhdl test_%s.vvp -lxt2" % module,
|
||||
clk=clk,
|
||||
rst=rst,
|
||||
current_test=current_test,
|
||||
|
||||
input_axis_tdata=input_axis_tdata,
|
||||
input_axis_tkeep=input_axis_tkeep,
|
||||
input_axis_tvalid=input_axis_tvalid,
|
||||
input_axis_tready=input_axis_tready,
|
||||
input_axis_tlast=input_axis_tlast,
|
||||
input_axis_tuser=input_axis_tuser,
|
||||
|
||||
output_axis_tdata=output_axis_tdata,
|
||||
output_axis_tkeep=output_axis_tkeep,
|
||||
output_axis_tvalid=output_axis_tvalid,
|
||||
output_axis_tready=output_axis_tready,
|
||||
output_axis_tlast=output_axis_tlast,
|
||||
output_axis_tuser=output_axis_tuser)
|
||||
|
||||
def bench():
|
||||
|
||||
# Inputs
|
||||
clk = Signal(bool(0))
|
||||
rst = Signal(bool(0))
|
||||
current_test = Signal(intbv(0)[8:])
|
||||
|
||||
input_axis_tdata = Signal(intbv(0)[8:])
|
||||
input_axis_tkeep = Signal(intbv(0)[1:])
|
||||
input_axis_tvalid = Signal(bool(0))
|
||||
input_axis_tlast = Signal(bool(0))
|
||||
input_axis_tuser = Signal(bool(0))
|
||||
output_axis_tready = Signal(bool(0))
|
||||
|
||||
# Outputs
|
||||
input_axis_tready = Signal(bool(0))
|
||||
output_axis_tdata = Signal(intbv(0)[64:])
|
||||
output_axis_tkeep = Signal(intbv(0)[8:])
|
||||
output_axis_tvalid = Signal(bool(0))
|
||||
output_axis_tlast = Signal(bool(0))
|
||||
output_axis_tuser = Signal(bool(0))
|
||||
|
||||
# sources and sinks
|
||||
source_queue = Queue()
|
||||
source_pause = Signal(bool(0))
|
||||
sink_queue = Queue()
|
||||
sink_pause = Signal(bool(0))
|
||||
|
||||
source = axis_ep.AXIStreamSource(clk,
|
||||
rst,
|
||||
tdata=input_axis_tdata,
|
||||
tkeep=input_axis_tkeep,
|
||||
tvalid=input_axis_tvalid,
|
||||
tready=input_axis_tready,
|
||||
tlast=input_axis_tlast,
|
||||
tuser=input_axis_tuser,
|
||||
fifo=source_queue,
|
||||
pause=source_pause,
|
||||
name='source')
|
||||
|
||||
sink = axis_ep.AXIStreamSink(clk,
|
||||
rst,
|
||||
tdata=output_axis_tdata,
|
||||
tkeep=output_axis_tkeep,
|
||||
tvalid=output_axis_tvalid,
|
||||
tready=output_axis_tready,
|
||||
tlast=output_axis_tlast,
|
||||
tuser=output_axis_tuser,
|
||||
fifo=sink_queue,
|
||||
pause=sink_pause,
|
||||
name='sink')
|
||||
|
||||
# DUT
|
||||
dut = dut_axis_adapter_8_64(clk,
|
||||
rst,
|
||||
current_test,
|
||||
|
||||
input_axis_tdata,
|
||||
input_axis_tkeep,
|
||||
input_axis_tvalid,
|
||||
input_axis_tready,
|
||||
input_axis_tlast,
|
||||
input_axis_tuser,
|
||||
|
||||
output_axis_tdata,
|
||||
output_axis_tkeep,
|
||||
output_axis_tvalid,
|
||||
output_axis_tready,
|
||||
output_axis_tlast,
|
||||
output_axis_tuser)
|
||||
|
||||
@always(delay(4))
|
||||
def clkgen():
|
||||
clk.next = not clk
|
||||
|
||||
def wait_normal():
|
||||
while input_axis_tvalid or output_axis_tvalid:
|
||||
yield clk.posedge
|
||||
|
||||
def wait_pause_source():
|
||||
while input_axis_tvalid or output_axis_tvalid:
|
||||
source_pause.next = True
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
source_pause.next = False
|
||||
yield clk.posedge
|
||||
|
||||
def wait_pause_sink():
|
||||
while input_axis_tvalid or output_axis_tvalid:
|
||||
sink_pause.next = True
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
sink_pause.next = False
|
||||
yield clk.posedge
|
||||
|
||||
@instance
|
||||
def check():
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
rst.next = 1
|
||||
yield clk.posedge
|
||||
rst.next = 0
|
||||
yield clk.posedge
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
|
||||
for payload_len in range(1,18):
|
||||
yield clk.posedge
|
||||
print("test 1: test packet, length %d" % payload_len)
|
||||
current_test.next = 1
|
||||
|
||||
test_frame = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
bytearray(range(payload_len)))
|
||||
|
||||
for wait in wait_normal, wait_pause_source, wait_pause_sink:
|
||||
source_queue.put(test_frame)
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
yield wait()
|
||||
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame
|
||||
|
||||
assert sink_queue.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 2: back-to-back packets, length %d" % payload_len)
|
||||
current_test.next = 2
|
||||
|
||||
test_frame1 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
bytearray(range(payload_len)))
|
||||
test_frame2 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
bytearray(range(payload_len)))
|
||||
|
||||
for wait in wait_normal, wait_pause_source, wait_pause_sink:
|
||||
source_queue.put(test_frame1)
|
||||
source_queue.put(test_frame2)
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
yield wait()
|
||||
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame1
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame2
|
||||
|
||||
assert sink_queue.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 3: tuser assert, length %d" % payload_len)
|
||||
current_test.next = 3
|
||||
|
||||
test_frame1 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
bytearray(range(payload_len)))
|
||||
test_frame2 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
bytearray(range(payload_len)))
|
||||
|
||||
test_frame1.user = 1
|
||||
|
||||
for wait in wait_normal, wait_pause_source, wait_pause_sink:
|
||||
source_queue.put(test_frame1)
|
||||
source_queue.put(test_frame2)
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
yield wait()
|
||||
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame1
|
||||
assert rx_frame.user[-1]
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame2
|
||||
|
||||
assert sink_queue.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
raise StopSimulation
|
||||
|
||||
return dut, source, sink, clkgen, check
|
||||
|
||||
def test_bench():
|
||||
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
||||
sim = Simulation(bench())
|
||||
sim.run()
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("Running test...")
|
||||
test_bench()
|
||||
|
105
lib/axis/tb/test_axis_adapter_8_64.v
Normal file
105
lib/axis/tb/test_axis_adapter_8_64.v
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`timescale 1 ns / 1 ps
|
||||
|
||||
module test_axis_adapter_8_64;
|
||||
|
||||
// parameters
|
||||
localparam INPUT_DATA_WIDTH = 8;
|
||||
localparam INPUT_KEEP_WIDTH = (INPUT_DATA_WIDTH/8);
|
||||
localparam OUTPUT_DATA_WIDTH = 64;
|
||||
localparam OUTPUT_KEEP_WIDTH = (OUTPUT_DATA_WIDTH/8);
|
||||
|
||||
// Inputs
|
||||
reg clk = 0;
|
||||
reg rst = 0;
|
||||
reg [7:0] current_test = 0;
|
||||
|
||||
reg [INPUT_DATA_WIDTH-1:0] input_axis_tdata = 0;
|
||||
reg [INPUT_KEEP_WIDTH-1:0] input_axis_tkeep = 0;
|
||||
reg input_axis_tvalid = 0;
|
||||
reg input_axis_tlast = 0;
|
||||
reg input_axis_tuser = 0;
|
||||
reg output_axis_tready = 0;
|
||||
|
||||
// Outputs
|
||||
wire input_axis_tready;
|
||||
wire [OUTPUT_DATA_WIDTH-1:0] output_axis_tdata;
|
||||
wire [OUTPUT_KEEP_WIDTH-1:0] output_axis_tkeep;
|
||||
wire output_axis_tvalid;
|
||||
wire output_axis_tlast;
|
||||
wire output_axis_tuser;
|
||||
|
||||
initial begin
|
||||
// myhdl integration
|
||||
$from_myhdl(clk,
|
||||
rst,
|
||||
current_test,
|
||||
input_axis_tdata,
|
||||
input_axis_tkeep,
|
||||
input_axis_tvalid,
|
||||
input_axis_tlast,
|
||||
input_axis_tuser,
|
||||
output_axis_tready);
|
||||
$to_myhdl(input_axis_tready,
|
||||
output_axis_tdata,
|
||||
output_axis_tkeep,
|
||||
output_axis_tvalid,
|
||||
output_axis_tlast,
|
||||
output_axis_tuser);
|
||||
|
||||
// dump file
|
||||
$dumpfile("test_axis_adapter_8_64.lxt");
|
||||
$dumpvars(0, test_axis_adapter_8_64);
|
||||
end
|
||||
|
||||
axis_adapter #(
|
||||
.INPUT_DATA_WIDTH(INPUT_DATA_WIDTH),
|
||||
.INPUT_KEEP_WIDTH(INPUT_KEEP_WIDTH),
|
||||
.OUTPUT_DATA_WIDTH(OUTPUT_DATA_WIDTH),
|
||||
.OUTPUT_KEEP_WIDTH(OUTPUT_KEEP_WIDTH)
|
||||
)
|
||||
UUT (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
// AXI input
|
||||
.input_axis_tdata(input_axis_tdata),
|
||||
.input_axis_tkeep(input_axis_tkeep),
|
||||
.input_axis_tvalid(input_axis_tvalid),
|
||||
.input_axis_tready(input_axis_tready),
|
||||
.input_axis_tlast(input_axis_tlast),
|
||||
.input_axis_tuser(input_axis_tuser),
|
||||
// AXI output
|
||||
.output_axis_tdata(output_axis_tdata),
|
||||
.output_axis_tkeep(output_axis_tkeep),
|
||||
.output_axis_tvalid(output_axis_tvalid),
|
||||
.output_axis_tready(output_axis_tready),
|
||||
.output_axis_tlast(output_axis_tlast),
|
||||
.output_axis_tuser(output_axis_tuser)
|
||||
);
|
||||
|
||||
endmodule
|
396
lib/axis/tb/test_axis_fifo.py
Executable file
396
lib/axis/tb/test_axis_fifo.py
Executable file
@ -0,0 +1,396 @@
|
||||
#!/usr/bin/env python2
|
||||
"""
|
||||
|
||||
Copyright (c) 2014 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
"""
|
||||
|
||||
from myhdl import *
|
||||
import os
|
||||
from Queue import Queue
|
||||
|
||||
import axis_ep
|
||||
|
||||
module = 'axis_fifo'
|
||||
|
||||
srcs = []
|
||||
|
||||
srcs.append("../rtl/%s.v" % module)
|
||||
srcs.append("test_%s.v" % module)
|
||||
|
||||
src = ' '.join(srcs)
|
||||
|
||||
build_cmd = "iverilog -o test_%s.vvp %s" % (module, src)
|
||||
|
||||
def dut_axis_fifo(clk,
|
||||
rst,
|
||||
current_test,
|
||||
|
||||
input_axis_tdata,
|
||||
input_axis_tvalid,
|
||||
input_axis_tready,
|
||||
input_axis_tlast,
|
||||
input_axis_tuser,
|
||||
|
||||
output_axis_tdata,
|
||||
output_axis_tvalid,
|
||||
output_axis_tready,
|
||||
output_axis_tlast,
|
||||
output_axis_tuser):
|
||||
|
||||
if os.system(build_cmd):
|
||||
raise Exception("Error running build command")
|
||||
return Cosimulation("vvp -m myhdl test_%s.vvp -lxt2" % module,
|
||||
clk=clk,
|
||||
rst=rst,
|
||||
current_test=current_test,
|
||||
|
||||
input_axis_tdata=input_axis_tdata,
|
||||
input_axis_tvalid=input_axis_tvalid,
|
||||
input_axis_tready=input_axis_tready,
|
||||
input_axis_tlast=input_axis_tlast,
|
||||
input_axis_tuser=input_axis_tuser,
|
||||
|
||||
output_axis_tdata=output_axis_tdata,
|
||||
output_axis_tvalid=output_axis_tvalid,
|
||||
output_axis_tready=output_axis_tready,
|
||||
output_axis_tlast=output_axis_tlast,
|
||||
output_axis_tuser=output_axis_tuser)
|
||||
|
||||
def bench():
|
||||
|
||||
# Inputs
|
||||
clk = Signal(bool(0))
|
||||
rst = Signal(bool(0))
|
||||
current_test = Signal(intbv(0)[8:])
|
||||
|
||||
input_axis_tdata = Signal(intbv(0)[8:])
|
||||
input_axis_tvalid = Signal(bool(0))
|
||||
input_axis_tlast = Signal(bool(0))
|
||||
input_axis_tuser = Signal(bool(0))
|
||||
output_axis_tready = Signal(bool(0))
|
||||
|
||||
# Outputs
|
||||
input_axis_tready = Signal(bool(0))
|
||||
output_axis_tdata = Signal(intbv(0)[8:])
|
||||
output_axis_tvalid = Signal(bool(0))
|
||||
output_axis_tlast = Signal(bool(0))
|
||||
output_axis_tuser = Signal(bool(0))
|
||||
|
||||
# sources and sinks
|
||||
source_queue = Queue()
|
||||
source_pause = Signal(bool(0))
|
||||
sink_queue = Queue()
|
||||
sink_pause = Signal(bool(0))
|
||||
|
||||
source = axis_ep.AXIStreamSource(clk,
|
||||
rst,
|
||||
tdata=input_axis_tdata,
|
||||
tvalid=input_axis_tvalid,
|
||||
tready=input_axis_tready,
|
||||
tlast=input_axis_tlast,
|
||||
tuser=input_axis_tuser,
|
||||
fifo=source_queue,
|
||||
pause=source_pause,
|
||||
name='source')
|
||||
|
||||
sink = axis_ep.AXIStreamSink(clk,
|
||||
rst,
|
||||
tdata=output_axis_tdata,
|
||||
tvalid=output_axis_tvalid,
|
||||
tready=output_axis_tready,
|
||||
tlast=output_axis_tlast,
|
||||
tuser=output_axis_tuser,
|
||||
fifo=sink_queue,
|
||||
pause=sink_pause,
|
||||
name='sink')
|
||||
|
||||
# DUT
|
||||
dut = dut_axis_fifo(clk,
|
||||
rst,
|
||||
current_test,
|
||||
|
||||
input_axis_tdata,
|
||||
input_axis_tvalid,
|
||||
input_axis_tready,
|
||||
input_axis_tlast,
|
||||
input_axis_tuser,
|
||||
|
||||
output_axis_tdata,
|
||||
output_axis_tvalid,
|
||||
output_axis_tready,
|
||||
output_axis_tlast,
|
||||
output_axis_tuser)
|
||||
|
||||
@always(delay(4))
|
||||
def clkgen():
|
||||
clk.next = not clk
|
||||
|
||||
@instance
|
||||
def check():
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
rst.next = 1
|
||||
yield clk.posedge
|
||||
rst.next = 0
|
||||
yield clk.posedge
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
|
||||
yield clk.posedge
|
||||
|
||||
yield clk.posedge
|
||||
print("test 1: test packet")
|
||||
current_test.next = 1
|
||||
|
||||
test_frame = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
source_queue.put(test_frame)
|
||||
yield clk.posedge
|
||||
|
||||
yield output_axis_tlast.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 2: longer packet")
|
||||
current_test.next = 2
|
||||
|
||||
test_frame = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
bytearray(range(256)))
|
||||
source_queue.put(test_frame)
|
||||
yield clk.posedge
|
||||
|
||||
yield output_axis_tlast.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame
|
||||
|
||||
yield clk.posedge
|
||||
print("test 3: test packet with pauses")
|
||||
current_test.next = 3
|
||||
|
||||
test_frame = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
source_queue.put(test_frame)
|
||||
yield clk.posedge
|
||||
|
||||
yield delay(64)
|
||||
yield clk.posedge
|
||||
source_pause.next = True
|
||||
yield delay(32)
|
||||
yield clk.posedge
|
||||
source_pause.next = False
|
||||
|
||||
yield delay(64)
|
||||
yield clk.posedge
|
||||
sink_pause.next = True
|
||||
yield delay(32)
|
||||
yield clk.posedge
|
||||
sink_pause.next = False
|
||||
|
||||
yield output_axis_tlast.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 4: back-to-back packets")
|
||||
current_test.next = 4
|
||||
|
||||
test_frame1 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x01\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
test_frame2 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x02\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
source_queue.put(test_frame1)
|
||||
source_queue.put(test_frame2)
|
||||
yield clk.posedge
|
||||
|
||||
yield output_axis_tlast.posedge
|
||||
yield clk.posedge
|
||||
yield output_axis_tlast.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame1
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame2
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 5: alternate pause source")
|
||||
current_test.next = 5
|
||||
|
||||
test_frame1 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x01\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
test_frame2 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x02\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
source_queue.put(test_frame1)
|
||||
source_queue.put(test_frame2)
|
||||
yield clk.posedge
|
||||
|
||||
while input_axis_tvalid or output_axis_tvalid:
|
||||
source_pause.next = True
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
source_pause.next = False
|
||||
yield clk.posedge
|
||||
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame1
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame2
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 6: alternate pause sink")
|
||||
current_test.next = 6
|
||||
|
||||
test_frame1 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x01\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
test_frame2 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x02\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
source_queue.put(test_frame1)
|
||||
source_queue.put(test_frame2)
|
||||
yield clk.posedge
|
||||
|
||||
while input_axis_tvalid or output_axis_tvalid:
|
||||
sink_pause.next = True
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
sink_pause.next = False
|
||||
yield clk.posedge
|
||||
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame1
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame2
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 7: tuser assert")
|
||||
current_test.next = 7
|
||||
|
||||
test_frame = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
test_frame.user = 1
|
||||
source_queue.put(test_frame)
|
||||
yield clk.posedge
|
||||
|
||||
yield output_axis_tlast.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame
|
||||
assert rx_frame.user[-1]
|
||||
|
||||
yield delay(100)
|
||||
|
||||
raise StopSimulation
|
||||
|
||||
return dut, source, sink, clkgen, check
|
||||
|
||||
def test_bench():
|
||||
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
||||
sim = Simulation(bench())
|
||||
sim.run()
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("Running test...")
|
||||
test_bench()
|
||||
|
91
lib/axis/tb/test_axis_fifo.v
Normal file
91
lib/axis/tb/test_axis_fifo.v
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`timescale 1 ns / 1 ps
|
||||
|
||||
module test_axis_fifo;
|
||||
|
||||
// Inputs
|
||||
reg clk = 0;
|
||||
reg rst = 0;
|
||||
reg [7:0] current_test = 0;
|
||||
|
||||
reg [7:0] input_axis_tdata = 0;
|
||||
reg input_axis_tvalid = 0;
|
||||
reg input_axis_tlast = 0;
|
||||
reg input_axis_tuser = 0;
|
||||
reg output_axis_tready = 0;
|
||||
|
||||
// Outputs
|
||||
wire input_axis_tready;
|
||||
wire [7:0] output_axis_tdata;
|
||||
wire output_axis_tvalid;
|
||||
wire output_axis_tlast;
|
||||
wire output_axis_tuser;
|
||||
|
||||
initial begin
|
||||
// myhdl integration
|
||||
$from_myhdl(clk,
|
||||
rst,
|
||||
current_test,
|
||||
input_axis_tdata,
|
||||
input_axis_tvalid,
|
||||
input_axis_tlast,
|
||||
input_axis_tuser,
|
||||
output_axis_tready);
|
||||
$to_myhdl(input_axis_tready,
|
||||
output_axis_tdata,
|
||||
output_axis_tvalid,
|
||||
output_axis_tlast,
|
||||
output_axis_tuser);
|
||||
|
||||
// dump file
|
||||
$dumpfile("test_axis_fifo.lxt");
|
||||
$dumpvars(0, test_axis_fifo);
|
||||
end
|
||||
|
||||
axis_fifo #(
|
||||
.ADDR_WIDTH(2),
|
||||
.DATA_WIDTH(8)
|
||||
)
|
||||
UUT (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
// AXI input
|
||||
.input_axis_tdata(input_axis_tdata),
|
||||
.input_axis_tvalid(input_axis_tvalid),
|
||||
.input_axis_tready(input_axis_tready),
|
||||
.input_axis_tlast(input_axis_tlast),
|
||||
.input_axis_tuser(input_axis_tuser),
|
||||
// AXI output
|
||||
.output_axis_tdata(output_axis_tdata),
|
||||
.output_axis_tvalid(output_axis_tvalid),
|
||||
.output_axis_tready(output_axis_tready),
|
||||
.output_axis_tlast(output_axis_tlast),
|
||||
.output_axis_tuser(output_axis_tuser)
|
||||
);
|
||||
|
||||
endmodule
|
406
lib/axis/tb/test_axis_fifo_64.py
Executable file
406
lib/axis/tb/test_axis_fifo_64.py
Executable file
@ -0,0 +1,406 @@
|
||||
#!/usr/bin/env python2
|
||||
"""
|
||||
|
||||
Copyright (c) 2014 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
"""
|
||||
|
||||
from myhdl import *
|
||||
import os
|
||||
from Queue import Queue
|
||||
|
||||
import axis_ep
|
||||
|
||||
module = 'axis_fifo_64'
|
||||
|
||||
srcs = []
|
||||
|
||||
srcs.append("../rtl/%s.v" % module)
|
||||
srcs.append("test_%s.v" % module)
|
||||
|
||||
src = ' '.join(srcs)
|
||||
|
||||
build_cmd = "iverilog -o test_%s.vvp %s" % (module, src)
|
||||
|
||||
def dut_axis_fifo_64(clk,
|
||||
rst,
|
||||
current_test,
|
||||
|
||||
input_axis_tdata,
|
||||
input_axis_tkeep,
|
||||
input_axis_tvalid,
|
||||
input_axis_tready,
|
||||
input_axis_tlast,
|
||||
input_axis_tuser,
|
||||
|
||||
output_axis_tdata,
|
||||
output_axis_tkeep,
|
||||
output_axis_tvalid,
|
||||
output_axis_tready,
|
||||
output_axis_tlast,
|
||||
output_axis_tuser):
|
||||
|
||||
if os.system(build_cmd):
|
||||
raise Exception("Error running build command")
|
||||
return Cosimulation("vvp -m myhdl test_%s.vvp -lxt2" % module,
|
||||
clk=clk,
|
||||
rst=rst,
|
||||
current_test=current_test,
|
||||
|
||||
input_axis_tdata=input_axis_tdata,
|
||||
input_axis_tkeep=input_axis_tkeep,
|
||||
input_axis_tvalid=input_axis_tvalid,
|
||||
input_axis_tready=input_axis_tready,
|
||||
input_axis_tlast=input_axis_tlast,
|
||||
input_axis_tuser=input_axis_tuser,
|
||||
|
||||
output_axis_tdata=output_axis_tdata,
|
||||
output_axis_tkeep=output_axis_tkeep,
|
||||
output_axis_tvalid=output_axis_tvalid,
|
||||
output_axis_tready=output_axis_tready,
|
||||
output_axis_tlast=output_axis_tlast,
|
||||
output_axis_tuser=output_axis_tuser)
|
||||
|
||||
def bench():
|
||||
|
||||
# Inputs
|
||||
clk = Signal(bool(0))
|
||||
rst = Signal(bool(0))
|
||||
current_test = Signal(intbv(0)[8:])
|
||||
|
||||
input_axis_tdata = Signal(intbv(0)[64:])
|
||||
input_axis_tkeep = Signal(intbv(0)[8:])
|
||||
input_axis_tvalid = Signal(bool(0))
|
||||
input_axis_tlast = Signal(bool(0))
|
||||
input_axis_tuser = Signal(bool(0))
|
||||
output_axis_tready = Signal(bool(0))
|
||||
|
||||
# Outputs
|
||||
input_axis_tready = Signal(bool(0))
|
||||
output_axis_tdata = Signal(intbv(0)[64:])
|
||||
output_axis_tkeep = Signal(intbv(0)[8:])
|
||||
output_axis_tvalid = Signal(bool(0))
|
||||
output_axis_tlast = Signal(bool(0))
|
||||
output_axis_tuser = Signal(bool(0))
|
||||
|
||||
# sources and sinks
|
||||
source_queue = Queue()
|
||||
source_pause = Signal(bool(0))
|
||||
sink_queue = Queue()
|
||||
sink_pause = Signal(bool(0))
|
||||
|
||||
source = axis_ep.AXIStreamSource(clk,
|
||||
rst,
|
||||
tdata=input_axis_tdata,
|
||||
tkeep=input_axis_tkeep,
|
||||
tvalid=input_axis_tvalid,
|
||||
tready=input_axis_tready,
|
||||
tlast=input_axis_tlast,
|
||||
tuser=input_axis_tuser,
|
||||
fifo=source_queue,
|
||||
pause=source_pause,
|
||||
name='source')
|
||||
|
||||
sink = axis_ep.AXIStreamSink(clk,
|
||||
rst,
|
||||
tdata=output_axis_tdata,
|
||||
tkeep=output_axis_tkeep,
|
||||
tvalid=output_axis_tvalid,
|
||||
tready=output_axis_tready,
|
||||
tlast=output_axis_tlast,
|
||||
tuser=output_axis_tuser,
|
||||
fifo=sink_queue,
|
||||
pause=sink_pause,
|
||||
name='sink')
|
||||
|
||||
# DUT
|
||||
dut = dut_axis_fifo_64(clk,
|
||||
rst,
|
||||
current_test,
|
||||
|
||||
input_axis_tdata,
|
||||
input_axis_tkeep,
|
||||
input_axis_tvalid,
|
||||
input_axis_tready,
|
||||
input_axis_tlast,
|
||||
input_axis_tuser,
|
||||
|
||||
output_axis_tdata,
|
||||
output_axis_tkeep,
|
||||
output_axis_tvalid,
|
||||
output_axis_tready,
|
||||
output_axis_tlast,
|
||||
output_axis_tuser)
|
||||
|
||||
@always(delay(4))
|
||||
def clkgen():
|
||||
clk.next = not clk
|
||||
|
||||
@instance
|
||||
def check():
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
rst.next = 1
|
||||
yield clk.posedge
|
||||
rst.next = 0
|
||||
yield clk.posedge
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
|
||||
yield clk.posedge
|
||||
|
||||
yield clk.posedge
|
||||
print("test 1: test packet")
|
||||
current_test.next = 1
|
||||
|
||||
test_frame = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
source_queue.put(test_frame)
|
||||
yield clk.posedge
|
||||
|
||||
yield output_axis_tlast.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 2: longer packet")
|
||||
current_test.next = 2
|
||||
|
||||
test_frame = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
bytearray(range(256)))
|
||||
source_queue.put(test_frame)
|
||||
yield clk.posedge
|
||||
|
||||
yield output_axis_tlast.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame
|
||||
|
||||
yield clk.posedge
|
||||
print("test 3: test packet with pauses")
|
||||
current_test.next = 3
|
||||
|
||||
test_frame = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
bytearray(range(256)))
|
||||
source_queue.put(test_frame)
|
||||
yield clk.posedge
|
||||
|
||||
yield delay(64)
|
||||
yield clk.posedge
|
||||
source_pause.next = True
|
||||
yield delay(32)
|
||||
yield clk.posedge
|
||||
source_pause.next = False
|
||||
|
||||
yield delay(64)
|
||||
yield clk.posedge
|
||||
sink_pause.next = True
|
||||
yield delay(32)
|
||||
yield clk.posedge
|
||||
sink_pause.next = False
|
||||
|
||||
yield output_axis_tlast.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 4: back-to-back packets")
|
||||
current_test.next = 4
|
||||
|
||||
test_frame1 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x01\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
test_frame2 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x02\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
source_queue.put(test_frame1)
|
||||
source_queue.put(test_frame2)
|
||||
yield clk.posedge
|
||||
|
||||
yield output_axis_tlast.posedge
|
||||
yield clk.posedge
|
||||
yield output_axis_tlast.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame1
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame2
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 5: alternate pause source")
|
||||
current_test.next = 5
|
||||
|
||||
test_frame1 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x01\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
test_frame2 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x02\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
source_queue.put(test_frame1)
|
||||
source_queue.put(test_frame2)
|
||||
yield clk.posedge
|
||||
|
||||
while input_axis_tvalid or output_axis_tvalid:
|
||||
source_pause.next = True
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
source_pause.next = False
|
||||
yield clk.posedge
|
||||
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame1
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame2
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 6: alternate pause sink")
|
||||
current_test.next = 6
|
||||
|
||||
test_frame1 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x01\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
test_frame2 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x02\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
source_queue.put(test_frame1)
|
||||
source_queue.put(test_frame2)
|
||||
yield clk.posedge
|
||||
|
||||
while input_axis_tvalid or output_axis_tvalid:
|
||||
sink_pause.next = True
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
sink_pause.next = False
|
||||
yield clk.posedge
|
||||
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame1
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame2
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 7: tuser assert")
|
||||
current_test.next = 7
|
||||
|
||||
test_frame = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
test_frame.user = 1
|
||||
source_queue.put(test_frame)
|
||||
yield clk.posedge
|
||||
|
||||
yield output_axis_tlast.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame
|
||||
assert rx_frame.user[-1]
|
||||
|
||||
yield delay(100)
|
||||
|
||||
raise StopSimulation
|
||||
|
||||
return dut, source, sink, clkgen, check
|
||||
|
||||
def test_bench():
|
||||
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
||||
sim = Simulation(bench())
|
||||
sim.run()
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("Running test...")
|
||||
test_bench()
|
||||
|
97
lib/axis/tb/test_axis_fifo_64.v
Normal file
97
lib/axis/tb/test_axis_fifo_64.v
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`timescale 1 ns / 1 ps
|
||||
|
||||
module test_axis_fifo_64;
|
||||
|
||||
// Inputs
|
||||
reg clk = 0;
|
||||
reg rst = 0;
|
||||
reg [7:0] current_test = 0;
|
||||
|
||||
reg [63:0] input_axis_tdata = 0;
|
||||
reg [7:0] input_axis_tkeep = 0;
|
||||
reg input_axis_tvalid = 0;
|
||||
reg input_axis_tlast = 0;
|
||||
reg input_axis_tuser = 0;
|
||||
reg output_axis_tready = 0;
|
||||
|
||||
// Outputs
|
||||
wire input_axis_tready;
|
||||
wire [63:0] output_axis_tdata;
|
||||
wire [7:0] output_axis_tkeep;
|
||||
wire output_axis_tvalid;
|
||||
wire output_axis_tlast;
|
||||
wire output_axis_tuser;
|
||||
|
||||
initial begin
|
||||
// myhdl integration
|
||||
$from_myhdl(clk,
|
||||
rst,
|
||||
current_test,
|
||||
input_axis_tdata,
|
||||
input_axis_tkeep,
|
||||
input_axis_tvalid,
|
||||
input_axis_tlast,
|
||||
input_axis_tuser,
|
||||
output_axis_tready);
|
||||
$to_myhdl(input_axis_tready,
|
||||
output_axis_tdata,
|
||||
output_axis_tkeep,
|
||||
output_axis_tvalid,
|
||||
output_axis_tlast,
|
||||
output_axis_tuser);
|
||||
|
||||
// dump file
|
||||
$dumpfile("test_axis_fifo_64.lxt");
|
||||
$dumpvars(0, test_axis_fifo_64);
|
||||
end
|
||||
|
||||
axis_fifo_64 #(
|
||||
.ADDR_WIDTH(2),
|
||||
.DATA_WIDTH(64)
|
||||
)
|
||||
UUT (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
// AXI input
|
||||
.input_axis_tdata(input_axis_tdata),
|
||||
.input_axis_tkeep(input_axis_tkeep),
|
||||
.input_axis_tvalid(input_axis_tvalid),
|
||||
.input_axis_tready(input_axis_tready),
|
||||
.input_axis_tlast(input_axis_tlast),
|
||||
.input_axis_tuser(input_axis_tuser),
|
||||
// AXI output
|
||||
.output_axis_tdata(output_axis_tdata),
|
||||
.output_axis_tkeep(output_axis_tkeep),
|
||||
.output_axis_tvalid(output_axis_tvalid),
|
||||
.output_axis_tready(output_axis_tready),
|
||||
.output_axis_tlast(output_axis_tlast),
|
||||
.output_axis_tuser(output_axis_tuser)
|
||||
);
|
||||
|
||||
endmodule
|
555
lib/axis/tb/test_axis_frame_join_4.py
Executable file
555
lib/axis/tb/test_axis_frame_join_4.py
Executable file
@ -0,0 +1,555 @@
|
||||
#!/usr/bin/env python2
|
||||
"""
|
||||
|
||||
Copyright (c) 2014 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
"""
|
||||
|
||||
from myhdl import *
|
||||
import os
|
||||
from Queue import Queue
|
||||
import struct
|
||||
|
||||
import axis_ep
|
||||
|
||||
module = 'axis_frame_join_4'
|
||||
|
||||
srcs = []
|
||||
|
||||
srcs.append("../rtl/%s.v" % module)
|
||||
srcs.append("test_%s.v" % module)
|
||||
|
||||
src = ' '.join(srcs)
|
||||
|
||||
build_cmd = "iverilog -o test_%s.vvp %s" % (module, src)
|
||||
|
||||
def dut_axis_frame_join_4(clk,
|
||||
rst,
|
||||
current_test,
|
||||
|
||||
input_0_axis_tdata,
|
||||
input_0_axis_tvalid,
|
||||
input_0_axis_tready,
|
||||
input_0_axis_tlast,
|
||||
input_0_axis_tuser,
|
||||
|
||||
input_1_axis_tdata,
|
||||
input_1_axis_tvalid,
|
||||
input_1_axis_tready,
|
||||
input_1_axis_tlast,
|
||||
input_1_axis_tuser,
|
||||
|
||||
input_2_axis_tdata,
|
||||
input_2_axis_tvalid,
|
||||
input_2_axis_tready,
|
||||
input_2_axis_tlast,
|
||||
input_2_axis_tuser,
|
||||
|
||||
input_3_axis_tdata,
|
||||
input_3_axis_tvalid,
|
||||
input_3_axis_tready,
|
||||
input_3_axis_tlast,
|
||||
input_3_axis_tuser,
|
||||
|
||||
output_axis_tdata,
|
||||
output_axis_tvalid,
|
||||
output_axis_tready,
|
||||
output_axis_tlast,
|
||||
output_axis_tuser,
|
||||
|
||||
tag,
|
||||
busy):
|
||||
|
||||
if os.system(build_cmd):
|
||||
raise Exception("Error running build command")
|
||||
return Cosimulation("vvp -m myhdl test_%s.vvp -lxt2" % module,
|
||||
clk=clk,
|
||||
rst=rst,
|
||||
current_test=current_test,
|
||||
|
||||
input_0_axis_tdata=input_0_axis_tdata,
|
||||
input_0_axis_tvalid=input_0_axis_tvalid,
|
||||
input_0_axis_tready=input_0_axis_tready,
|
||||
input_0_axis_tlast=input_0_axis_tlast,
|
||||
input_0_axis_tuser=input_0_axis_tuser,
|
||||
|
||||
input_1_axis_tdata=input_1_axis_tdata,
|
||||
input_1_axis_tvalid=input_1_axis_tvalid,
|
||||
input_1_axis_tready=input_1_axis_tready,
|
||||
input_1_axis_tlast=input_1_axis_tlast,
|
||||
input_1_axis_tuser=input_1_axis_tuser,
|
||||
|
||||
input_2_axis_tdata=input_2_axis_tdata,
|
||||
input_2_axis_tvalid=input_2_axis_tvalid,
|
||||
input_2_axis_tready=input_2_axis_tready,
|
||||
input_2_axis_tlast=input_2_axis_tlast,
|
||||
input_2_axis_tuser=input_2_axis_tuser,
|
||||
|
||||
input_3_axis_tdata=input_3_axis_tdata,
|
||||
input_3_axis_tvalid=input_3_axis_tvalid,
|
||||
input_3_axis_tready=input_3_axis_tready,
|
||||
input_3_axis_tlast=input_3_axis_tlast,
|
||||
input_3_axis_tuser=input_3_axis_tuser,
|
||||
|
||||
output_axis_tdata=output_axis_tdata,
|
||||
output_axis_tvalid=output_axis_tvalid,
|
||||
output_axis_tready=output_axis_tready,
|
||||
output_axis_tlast=output_axis_tlast,
|
||||
output_axis_tuser=output_axis_tuser,
|
||||
|
||||
tag=tag,
|
||||
busy=busy)
|
||||
|
||||
def bench():
|
||||
|
||||
# Inputs
|
||||
clk = Signal(bool(0))
|
||||
rst = Signal(bool(0))
|
||||
current_test = Signal(intbv(0)[8:])
|
||||
|
||||
input_0_axis_tdata = Signal(intbv(0)[8:])
|
||||
input_0_axis_tvalid = Signal(bool(0))
|
||||
input_0_axis_tlast = Signal(bool(0))
|
||||
input_0_axis_tuser = Signal(bool(0))
|
||||
input_1_axis_tdata = Signal(intbv(0)[8:])
|
||||
input_1_axis_tvalid = Signal(bool(0))
|
||||
input_1_axis_tlast = Signal(bool(0))
|
||||
input_1_axis_tuser = Signal(bool(0))
|
||||
input_2_axis_tdata = Signal(intbv(0)[8:])
|
||||
input_2_axis_tvalid = Signal(bool(0))
|
||||
input_2_axis_tlast = Signal(bool(0))
|
||||
input_2_axis_tuser = Signal(bool(0))
|
||||
input_3_axis_tdata = Signal(intbv(0)[8:])
|
||||
input_3_axis_tvalid = Signal(bool(0))
|
||||
input_3_axis_tlast = Signal(bool(0))
|
||||
input_3_axis_tuser = Signal(bool(0))
|
||||
output_axis_tready = Signal(bool(0))
|
||||
tag = Signal(intbv(0)[15:])
|
||||
|
||||
# Outputs
|
||||
input_0_axis_tready = Signal(bool(0))
|
||||
input_1_axis_tready = Signal(bool(0))
|
||||
input_2_axis_tready = Signal(bool(0))
|
||||
input_3_axis_tready = Signal(bool(0))
|
||||
output_axis_tdata = Signal(intbv(0)[8:])
|
||||
output_axis_tvalid = Signal(bool(0))
|
||||
output_axis_tlast = Signal(bool(0))
|
||||
output_axis_tuser = Signal(bool(0))
|
||||
busy = Signal(bool(0))
|
||||
|
||||
# sources and sinks
|
||||
source_0_queue = Queue()
|
||||
source_0_pause = Signal(bool(0))
|
||||
source_1_queue = Queue()
|
||||
source_1_pause = Signal(bool(0))
|
||||
source_2_queue = Queue()
|
||||
source_2_pause = Signal(bool(0))
|
||||
source_3_queue = Queue()
|
||||
source_3_pause = Signal(bool(0))
|
||||
sink_queue = Queue()
|
||||
sink_pause = Signal(bool(0))
|
||||
|
||||
source_0 = axis_ep.AXIStreamSource(clk,
|
||||
rst,
|
||||
tdata=input_0_axis_tdata,
|
||||
tvalid=input_0_axis_tvalid,
|
||||
tready=input_0_axis_tready,
|
||||
tlast=input_0_axis_tlast,
|
||||
tuser=input_0_axis_tuser,
|
||||
fifo=source_0_queue,
|
||||
pause=source_0_pause,
|
||||
name='source_0')
|
||||
|
||||
source_1 = axis_ep.AXIStreamSource(clk,
|
||||
rst,
|
||||
tdata=input_1_axis_tdata,
|
||||
tvalid=input_1_axis_tvalid,
|
||||
tready=input_1_axis_tready,
|
||||
tlast=input_1_axis_tlast,
|
||||
tuser=input_1_axis_tuser,
|
||||
fifo=source_1_queue,
|
||||
pause=source_1_pause,
|
||||
name='source_1')
|
||||
|
||||
source_2 = axis_ep.AXIStreamSource(clk,
|
||||
rst,
|
||||
tdata=input_2_axis_tdata,
|
||||
tvalid=input_2_axis_tvalid,
|
||||
tready=input_2_axis_tready,
|
||||
tlast=input_2_axis_tlast,
|
||||
tuser=input_2_axis_tuser,
|
||||
fifo=source_2_queue,
|
||||
pause=source_2_pause,
|
||||
name='source_2')
|
||||
|
||||
source_3 = axis_ep.AXIStreamSource(clk,
|
||||
rst,
|
||||
tdata=input_3_axis_tdata,
|
||||
tvalid=input_3_axis_tvalid,
|
||||
tready=input_3_axis_tready,
|
||||
tlast=input_3_axis_tlast,
|
||||
tuser=input_3_axis_tuser,
|
||||
fifo=source_3_queue,
|
||||
pause=source_3_pause,
|
||||
name='source_3')
|
||||
|
||||
sink = axis_ep.AXIStreamSink(clk,
|
||||
rst,
|
||||
tdata=output_axis_tdata,
|
||||
tvalid=output_axis_tvalid,
|
||||
tready=output_axis_tready,
|
||||
tlast=output_axis_tlast,
|
||||
tuser=output_axis_tuser,
|
||||
fifo=sink_queue,
|
||||
pause=sink_pause,
|
||||
name='sink')
|
||||
|
||||
# DUT
|
||||
dut = dut_axis_frame_join_4(clk,
|
||||
rst,
|
||||
current_test,
|
||||
|
||||
input_0_axis_tdata,
|
||||
input_0_axis_tvalid,
|
||||
input_0_axis_tready,
|
||||
input_0_axis_tlast,
|
||||
input_0_axis_tuser,
|
||||
|
||||
input_1_axis_tdata,
|
||||
input_1_axis_tvalid,
|
||||
input_1_axis_tready,
|
||||
input_1_axis_tlast,
|
||||
input_1_axis_tuser,
|
||||
|
||||
input_2_axis_tdata,
|
||||
input_2_axis_tvalid,
|
||||
input_2_axis_tready,
|
||||
input_2_axis_tlast,
|
||||
input_2_axis_tuser,
|
||||
|
||||
input_3_axis_tdata,
|
||||
input_3_axis_tvalid,
|
||||
input_3_axis_tready,
|
||||
input_3_axis_tlast,
|
||||
input_3_axis_tuser,
|
||||
|
||||
output_axis_tdata,
|
||||
output_axis_tvalid,
|
||||
output_axis_tready,
|
||||
output_axis_tlast,
|
||||
output_axis_tuser,
|
||||
|
||||
tag,
|
||||
busy)
|
||||
|
||||
@always(delay(4))
|
||||
def clkgen():
|
||||
clk.next = not clk
|
||||
|
||||
@instance
|
||||
def check():
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
rst.next = 1
|
||||
yield clk.posedge
|
||||
rst.next = 0
|
||||
yield clk.posedge
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
|
||||
yield clk.posedge
|
||||
tag.next = 1
|
||||
|
||||
yield clk.posedge
|
||||
print("test 1: test packet")
|
||||
current_test.next = 1
|
||||
|
||||
test_frame_0 = axis_ep.AXIStreamFrame('\x00\xAA\xBB\xCC\xDD\x00')
|
||||
test_frame_1 = axis_ep.AXIStreamFrame('\x01\xAA\xBB\xCC\xDD\x01')
|
||||
test_frame_2 = axis_ep.AXIStreamFrame('\x02\xAA\xBB\xCC\xDD\x02')
|
||||
test_frame_3 = axis_ep.AXIStreamFrame('\x03\xAA\xBB\xCC\xDD\x03')
|
||||
source_0_queue.put(test_frame_0)
|
||||
source_1_queue.put(test_frame_1)
|
||||
source_2_queue.put(test_frame_2)
|
||||
source_3_queue.put(test_frame_3)
|
||||
yield clk.posedge
|
||||
|
||||
yield output_axis_tlast.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame.data == struct.pack('>H', tag) + test_frame_0.data + test_frame_1.data + test_frame_2.data + test_frame_3.data
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 2: longer packet")
|
||||
current_test.next = 2
|
||||
|
||||
test_frame_0 = axis_ep.AXIStreamFrame('\x00' + bytearray(range(256)) + '\x00')
|
||||
test_frame_1 = axis_ep.AXIStreamFrame('\x01\xAA\xBB\xCC\xDD\x01')
|
||||
test_frame_2 = axis_ep.AXIStreamFrame('\x02\xAA\xBB\xCC\xDD\x02')
|
||||
test_frame_3 = axis_ep.AXIStreamFrame('\x03\xAA\xBB\xCC\xDD\x03')
|
||||
source_0_queue.put(test_frame_0)
|
||||
source_1_queue.put(test_frame_1)
|
||||
source_2_queue.put(test_frame_2)
|
||||
source_3_queue.put(test_frame_3)
|
||||
yield clk.posedge
|
||||
|
||||
yield output_axis_tlast.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame.data == struct.pack('>H', tag) + test_frame_0.data + test_frame_1.data + test_frame_2.data + test_frame_3.data
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 3: test packet with pauses")
|
||||
current_test.next = 3
|
||||
|
||||
test_frame_0 = axis_ep.AXIStreamFrame('\x00\xAA\xBB\xCC\xDD\x00')
|
||||
test_frame_1 = axis_ep.AXIStreamFrame('\x01\xAA\xBB\xCC\xDD\x01')
|
||||
test_frame_2 = axis_ep.AXIStreamFrame('\x02\xAA\xBB\xCC\xDD\x02')
|
||||
test_frame_3 = axis_ep.AXIStreamFrame('\x03\xAA\xBB\xCC\xDD\x03')
|
||||
source_0_queue.put(test_frame_0)
|
||||
source_1_queue.put(test_frame_1)
|
||||
source_2_queue.put(test_frame_2)
|
||||
source_3_queue.put(test_frame_3)
|
||||
yield clk.posedge
|
||||
|
||||
yield delay(64)
|
||||
yield clk.posedge
|
||||
source_1_pause.next = True
|
||||
yield delay(32)
|
||||
yield clk.posedge
|
||||
source_1_pause.next = False
|
||||
|
||||
yield delay(64)
|
||||
yield clk.posedge
|
||||
sink_pause.next = True
|
||||
yield delay(32)
|
||||
yield clk.posedge
|
||||
sink_pause.next = False
|
||||
|
||||
yield output_axis_tlast.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame.data == struct.pack('>H', tag) + test_frame_0.data + test_frame_1.data + test_frame_2.data + test_frame_3.data
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 4: back-to-back packets")
|
||||
current_test.next = 4
|
||||
|
||||
test_frame_0a = axis_ep.AXIStreamFrame('\x00\xAA\xBB\xCC\xDD\x00')
|
||||
test_frame_0b = axis_ep.AXIStreamFrame('\x00\xAA\xBB\xCC\xDD\x00')
|
||||
test_frame_1a = axis_ep.AXIStreamFrame('\x01\xAA\xBB\xCC\xDD\x01')
|
||||
test_frame_1b = axis_ep.AXIStreamFrame('\x01\xAA\xBB\xCC\xDD\x01')
|
||||
test_frame_2a = axis_ep.AXIStreamFrame('\x02\xAA\xBB\xCC\xDD\x02')
|
||||
test_frame_2b = axis_ep.AXIStreamFrame('\x02\xAA\xBB\xCC\xDD\x02')
|
||||
test_frame_3a = axis_ep.AXIStreamFrame('\x03\xAA\xBB\xCC\xDD\x03')
|
||||
test_frame_3b = axis_ep.AXIStreamFrame('\x03\xAA\xBB\xCC\xDD\x03')
|
||||
source_0_queue.put(test_frame_0a)
|
||||
source_0_queue.put(test_frame_0b)
|
||||
source_1_queue.put(test_frame_1a)
|
||||
source_1_queue.put(test_frame_1b)
|
||||
source_2_queue.put(test_frame_2a)
|
||||
source_2_queue.put(test_frame_2b)
|
||||
source_3_queue.put(test_frame_3a)
|
||||
source_3_queue.put(test_frame_3b)
|
||||
yield clk.posedge
|
||||
|
||||
yield output_axis_tlast.posedge
|
||||
yield clk.posedge
|
||||
yield output_axis_tlast.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame.data == struct.pack('>H', tag) + test_frame_0a.data + test_frame_1a.data + test_frame_2a.data + test_frame_3a.data
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame.data == struct.pack('>H', tag) + test_frame_0b.data + test_frame_1b.data + test_frame_2b.data + test_frame_3b.data
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 5: alternate pause source")
|
||||
current_test.next = 5
|
||||
|
||||
test_frame_0a = axis_ep.AXIStreamFrame('\x00\xAA\xBB\xCC\xDD\x00')
|
||||
test_frame_0b = axis_ep.AXIStreamFrame('\x00\xAA\xBB\xCC\xDD\x00')
|
||||
test_frame_1a = axis_ep.AXIStreamFrame('\x01\xAA\xBB\xCC\xDD\x01')
|
||||
test_frame_1b = axis_ep.AXIStreamFrame('\x01\xAA\xBB\xCC\xDD\x01')
|
||||
test_frame_2a = axis_ep.AXIStreamFrame('\x02\xAA\xBB\xCC\xDD\x02')
|
||||
test_frame_2b = axis_ep.AXIStreamFrame('\x02\xAA\xBB\xCC\xDD\x02')
|
||||
test_frame_3a = axis_ep.AXIStreamFrame('\x03\xAA\xBB\xCC\xDD\x03')
|
||||
test_frame_3b = axis_ep.AXIStreamFrame('\x03\xAA\xBB\xCC\xDD\x03')
|
||||
source_0_queue.put(test_frame_0a)
|
||||
source_0_queue.put(test_frame_0b)
|
||||
source_1_queue.put(test_frame_1a)
|
||||
source_1_queue.put(test_frame_1b)
|
||||
source_2_queue.put(test_frame_2a)
|
||||
source_2_queue.put(test_frame_2b)
|
||||
source_3_queue.put(test_frame_3a)
|
||||
source_3_queue.put(test_frame_3b)
|
||||
yield clk.posedge
|
||||
|
||||
while input_3_axis_tvalid or output_axis_tvalid:
|
||||
source_0_pause.next = True
|
||||
source_1_pause.next = True
|
||||
source_2_pause.next = True
|
||||
source_3_pause.next = True
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
source_0_pause.next = False
|
||||
source_1_pause.next = False
|
||||
source_2_pause.next = False
|
||||
source_3_pause.next = False
|
||||
yield clk.posedge
|
||||
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame.data == struct.pack('>H', tag) + test_frame_0a.data + test_frame_1a.data + test_frame_2a.data + test_frame_3a.data
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame.data == struct.pack('>H', tag) + test_frame_0b.data + test_frame_1b.data + test_frame_2b.data + test_frame_3b.data
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 6: alternate pause sink")
|
||||
current_test.next = 6
|
||||
|
||||
test_frame_0a = axis_ep.AXIStreamFrame('\x00\xAA\xBB\xCC\xDD\x00')
|
||||
test_frame_0b = axis_ep.AXIStreamFrame('\x00\xAA\xBB\xCC\xDD\x00')
|
||||
test_frame_1a = axis_ep.AXIStreamFrame('\x01\xAA\xBB\xCC\xDD\x01')
|
||||
test_frame_1b = axis_ep.AXIStreamFrame('\x01\xAA\xBB\xCC\xDD\x01')
|
||||
test_frame_2a = axis_ep.AXIStreamFrame('\x02\xAA\xBB\xCC\xDD\x02')
|
||||
test_frame_2b = axis_ep.AXIStreamFrame('\x02\xAA\xBB\xCC\xDD\x02')
|
||||
test_frame_3a = axis_ep.AXIStreamFrame('\x03\xAA\xBB\xCC\xDD\x03')
|
||||
test_frame_3b = axis_ep.AXIStreamFrame('\x03\xAA\xBB\xCC\xDD\x03')
|
||||
source_0_queue.put(test_frame_0a)
|
||||
source_0_queue.put(test_frame_0b)
|
||||
source_1_queue.put(test_frame_1a)
|
||||
source_1_queue.put(test_frame_1b)
|
||||
source_2_queue.put(test_frame_2a)
|
||||
source_2_queue.put(test_frame_2b)
|
||||
source_3_queue.put(test_frame_3a)
|
||||
source_3_queue.put(test_frame_3b)
|
||||
yield clk.posedge
|
||||
|
||||
while input_3_axis_tvalid or output_axis_tvalid:
|
||||
sink_pause.next = True
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
sink_pause.next = False
|
||||
yield clk.posedge
|
||||
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame.data == struct.pack('>H', tag) + test_frame_0a.data + test_frame_1a.data + test_frame_2a.data + test_frame_3a.data
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame.data == struct.pack('>H', tag) + test_frame_0b.data + test_frame_1b.data + test_frame_2b.data + test_frame_3b.data
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 7: tuser assert")
|
||||
current_test.next = 7
|
||||
|
||||
test_frame_0 = axis_ep.AXIStreamFrame('\x00\xAA\xBB\xCC\xDD\x00')
|
||||
test_frame_1 = axis_ep.AXIStreamFrame('\x01\xAA\xBB\xCC\xDD\x01')
|
||||
test_frame_2 = axis_ep.AXIStreamFrame('\x02\xAA\xBB\xCC\xDD\x02')
|
||||
test_frame_3 = axis_ep.AXIStreamFrame('\x03\xAA\xBB\xCC\xDD\x03')
|
||||
test_frame_0.user = 1
|
||||
source_0_queue.put(test_frame_0)
|
||||
source_1_queue.put(test_frame_1)
|
||||
source_2_queue.put(test_frame_2)
|
||||
source_3_queue.put(test_frame_3)
|
||||
yield clk.posedge
|
||||
|
||||
yield output_axis_tlast.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame.data == struct.pack('>H', tag) + test_frame_0.data + test_frame_1.data + test_frame_2.data + test_frame_3.data
|
||||
assert rx_frame.user[-1]
|
||||
|
||||
yield delay(100)
|
||||
|
||||
raise StopSimulation
|
||||
|
||||
return dut, source_0, source_1, source_2, source_3, sink, clkgen, check
|
||||
|
||||
def test_bench():
|
||||
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
||||
sim = Simulation(bench())
|
||||
sim.run()
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("Running test...")
|
||||
test_bench()
|
||||
|
143
lib/axis/tb/test_axis_frame_join_4.v
Normal file
143
lib/axis/tb/test_axis_frame_join_4.v
Normal file
@ -0,0 +1,143 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`timescale 1 ns / 1 ps
|
||||
|
||||
module test_axis_frame_join_4;
|
||||
|
||||
// Inputs
|
||||
reg clk = 0;
|
||||
reg rst = 0;
|
||||
reg [7:0] current_test = 0;
|
||||
|
||||
reg [7:0] input_0_axis_tdata = 8'd0;
|
||||
reg input_0_axis_tvalid = 1'b0;
|
||||
reg input_0_axis_tlast = 1'b0;
|
||||
reg input_0_axis_tuser = 1'b0;
|
||||
reg [7:0] input_1_axis_tdata = 8'd0;
|
||||
reg input_1_axis_tvalid = 1'b0;
|
||||
reg input_1_axis_tlast = 1'b0;
|
||||
reg input_1_axis_tuser = 1'b0;
|
||||
reg [7:0] input_2_axis_tdata = 8'd0;
|
||||
reg input_2_axis_tvalid = 1'b0;
|
||||
reg input_2_axis_tlast = 1'b0;
|
||||
reg input_2_axis_tuser = 1'b0;
|
||||
reg [7:0] input_3_axis_tdata = 8'd0;
|
||||
reg input_3_axis_tvalid = 1'b0;
|
||||
reg input_3_axis_tlast = 1'b0;
|
||||
reg input_3_axis_tuser = 1'b0;
|
||||
reg output_axis_tready = 1'b0;
|
||||
reg [15:0] tag = 0;
|
||||
|
||||
// Outputs
|
||||
wire input_0_axis_tready;
|
||||
wire input_1_axis_tready;
|
||||
wire input_2_axis_tready;
|
||||
wire input_3_axis_tready;
|
||||
wire [7:0] output_axis_tdata;
|
||||
wire output_axis_tvalid;
|
||||
wire output_axis_tlast;
|
||||
wire output_axis_tuser;
|
||||
wire busy;
|
||||
|
||||
initial begin
|
||||
// myhdl integration
|
||||
$from_myhdl(clk,
|
||||
rst,
|
||||
current_test,
|
||||
input_0_axis_tdata,
|
||||
input_0_axis_tvalid,
|
||||
input_0_axis_tlast,
|
||||
input_0_axis_tuser,
|
||||
input_1_axis_tdata,
|
||||
input_1_axis_tvalid,
|
||||
input_1_axis_tlast,
|
||||
input_1_axis_tuser,
|
||||
input_2_axis_tdata,
|
||||
input_2_axis_tvalid,
|
||||
input_2_axis_tlast,
|
||||
input_2_axis_tuser,
|
||||
input_3_axis_tdata,
|
||||
input_3_axis_tvalid,
|
||||
input_3_axis_tlast,
|
||||
input_3_axis_tuser,
|
||||
output_axis_tready,
|
||||
tag);
|
||||
$to_myhdl(input_0_axis_tready,
|
||||
input_1_axis_tready,
|
||||
input_2_axis_tready,
|
||||
input_3_axis_tready,
|
||||
output_axis_tdata,
|
||||
output_axis_tvalid,
|
||||
output_axis_tlast,
|
||||
output_axis_tuser,
|
||||
busy);
|
||||
|
||||
// dump file
|
||||
$dumpfile("test_axis_frame_join_4.lxt");
|
||||
$dumpvars(0, test_axis_frame_join_4);
|
||||
end
|
||||
|
||||
axis_frame_join_4 #(
|
||||
.ENABLE_TAG(1)
|
||||
)
|
||||
UUT (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
// axi input
|
||||
.input_0_axis_tdata(input_0_axis_tdata),
|
||||
.input_0_axis_tvalid(input_0_axis_tvalid),
|
||||
.input_0_axis_tready(input_0_axis_tready),
|
||||
.input_0_axis_tlast(input_0_axis_tlast),
|
||||
.input_0_axis_tuser(input_0_axis_tuser),
|
||||
.input_1_axis_tdata(input_1_axis_tdata),
|
||||
.input_1_axis_tvalid(input_1_axis_tvalid),
|
||||
.input_1_axis_tready(input_1_axis_tready),
|
||||
.input_1_axis_tlast(input_1_axis_tlast),
|
||||
.input_1_axis_tuser(input_1_axis_tuser),
|
||||
.input_2_axis_tdata(input_2_axis_tdata),
|
||||
.input_2_axis_tvalid(input_2_axis_tvalid),
|
||||
.input_2_axis_tready(input_2_axis_tready),
|
||||
.input_2_axis_tlast(input_2_axis_tlast),
|
||||
.input_2_axis_tuser(input_2_axis_tuser),
|
||||
.input_3_axis_tdata(input_3_axis_tdata),
|
||||
.input_3_axis_tvalid(input_3_axis_tvalid),
|
||||
.input_3_axis_tready(input_3_axis_tready),
|
||||
.input_3_axis_tlast(input_3_axis_tlast),
|
||||
.input_3_axis_tuser(input_3_axis_tuser),
|
||||
// axi output
|
||||
.output_axis_tdata(output_axis_tdata),
|
||||
.output_axis_tvalid(output_axis_tvalid),
|
||||
.output_axis_tready(output_axis_tready),
|
||||
.output_axis_tlast(output_axis_tlast),
|
||||
.output_axis_tuser(output_axis_tuser),
|
||||
// config
|
||||
.tag(tag),
|
||||
// status
|
||||
.busy(busy)
|
||||
);
|
||||
|
||||
endmodule
|
232
lib/axis/tb/test_axis_ll_bridge.py
Executable file
232
lib/axis/tb/test_axis_ll_bridge.py
Executable file
@ -0,0 +1,232 @@
|
||||
#!/usr/bin/env python2
|
||||
"""
|
||||
|
||||
Copyright (c) 2014 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
"""
|
||||
|
||||
from myhdl import *
|
||||
import os
|
||||
from Queue import Queue
|
||||
|
||||
import axis_ep
|
||||
import ll_ep
|
||||
|
||||
module = 'axis_ll_bridge'
|
||||
|
||||
srcs = []
|
||||
|
||||
srcs.append("../rtl/%s.v" % module)
|
||||
srcs.append("test_%s.v" % module)
|
||||
|
||||
src = ' '.join(srcs)
|
||||
|
||||
build_cmd = "iverilog -o test_%s.vvp %s" % (module, src)
|
||||
|
||||
def dut_axis_ll_bridge(clk,
|
||||
rst,
|
||||
current_test,
|
||||
|
||||
axis_tdata,
|
||||
axis_tvalid,
|
||||
axis_tready,
|
||||
axis_tlast,
|
||||
|
||||
ll_data_out,
|
||||
ll_sof_out_n,
|
||||
ll_eof_out_n,
|
||||
ll_src_rdy_out_n,
|
||||
ll_dst_rdy_in_n):
|
||||
|
||||
if os.system(build_cmd):
|
||||
raise Exception("Error running build command")
|
||||
return Cosimulation("vvp -m myhdl test_%s.vvp -lxt2" % module,
|
||||
clk=clk,
|
||||
rst=rst,
|
||||
current_test=current_test,
|
||||
|
||||
axis_tdata=axis_tdata,
|
||||
axis_tvalid=axis_tvalid,
|
||||
axis_tready=axis_tready,
|
||||
axis_tlast=axis_tlast,
|
||||
|
||||
ll_data_out=ll_data_out,
|
||||
ll_sof_out_n=ll_sof_out_n,
|
||||
ll_eof_out_n=ll_eof_out_n,
|
||||
ll_src_rdy_out_n=ll_src_rdy_out_n,
|
||||
ll_dst_rdy_in_n=ll_dst_rdy_in_n)
|
||||
|
||||
def bench():
|
||||
|
||||
# Inputs
|
||||
clk = Signal(bool(0))
|
||||
rst = Signal(bool(0))
|
||||
current_test = Signal(intbv(0)[8:])
|
||||
|
||||
axis_tdata = Signal(intbv(0)[8:])
|
||||
axis_tvalid = Signal(bool(0))
|
||||
axis_tlast = Signal(bool(0))
|
||||
ll_dst_rdy_in_n = Signal(bool(1))
|
||||
|
||||
# Outputs
|
||||
ll_data_out = Signal(intbv(0)[8:])
|
||||
ll_sof_out_n = Signal(bool(1))
|
||||
ll_eof_out_n = Signal(bool(1))
|
||||
ll_src_rdy_out_n = Signal(bool(1))
|
||||
axis_tready = Signal(bool(0))
|
||||
|
||||
# sources and sinks
|
||||
source_queue = Queue()
|
||||
source_pause = Signal(bool(0))
|
||||
sink_queue = Queue()
|
||||
sink_pause = Signal(bool(0))
|
||||
|
||||
source = axis_ep.AXIStreamSource(clk,
|
||||
rst,
|
||||
tdata=axis_tdata,
|
||||
tvalid=axis_tvalid,
|
||||
tready=axis_tready,
|
||||
tlast=axis_tlast,
|
||||
fifo=source_queue,
|
||||
pause=source_pause,
|
||||
name='source')
|
||||
|
||||
sink = ll_ep.LocalLinkSink(clk,
|
||||
rst,
|
||||
data_in=ll_data_out,
|
||||
sof_in_n=ll_sof_out_n,
|
||||
eof_in_n=ll_eof_out_n,
|
||||
src_rdy_in_n=ll_src_rdy_out_n,
|
||||
dst_rdy_out_n=ll_dst_rdy_in_n,
|
||||
fifo=sink_queue,
|
||||
pause=sink_pause,
|
||||
name='sink')
|
||||
|
||||
# DUT
|
||||
dut = dut_axis_ll_bridge(clk,
|
||||
rst,
|
||||
current_test,
|
||||
|
||||
axis_tdata,
|
||||
axis_tvalid,
|
||||
axis_tready,
|
||||
axis_tlast,
|
||||
|
||||
ll_data_out,
|
||||
ll_sof_out_n,
|
||||
ll_eof_out_n,
|
||||
ll_src_rdy_out_n,
|
||||
ll_dst_rdy_in_n)
|
||||
|
||||
@always(delay(4))
|
||||
def clkgen():
|
||||
clk.next = not clk
|
||||
|
||||
@instance
|
||||
def check():
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
rst.next = 1
|
||||
yield clk.posedge
|
||||
rst.next = 0
|
||||
yield clk.posedge
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
|
||||
yield clk.posedge
|
||||
|
||||
yield clk.posedge
|
||||
print("test 1: test packet")
|
||||
current_test.next = 1
|
||||
|
||||
source_queue.put(bytearray('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10'))
|
||||
yield clk.posedge
|
||||
|
||||
yield ll_eof_out_n.negedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert bytearray(rx_frame) == ('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 2: test packet with pauses")
|
||||
current_test.next = 2
|
||||
|
||||
source_queue.put(bytearray('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10'))
|
||||
yield clk.posedge
|
||||
|
||||
yield delay(64)
|
||||
yield clk.posedge
|
||||
source_pause.next = True
|
||||
yield delay(32)
|
||||
yield clk.posedge
|
||||
source_pause.next = False
|
||||
|
||||
yield delay(64)
|
||||
yield clk.posedge
|
||||
sink_pause.next = True
|
||||
yield delay(32)
|
||||
yield clk.posedge
|
||||
sink_pause.next = False
|
||||
|
||||
yield ll_eof_out_n.negedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert bytearray(rx_frame) == ('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
|
||||
yield delay(100)
|
||||
|
||||
raise StopSimulation
|
||||
|
||||
return dut, source, sink, clkgen, check
|
||||
|
||||
def test_bench():
|
||||
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
||||
sim = Simulation(bench())
|
||||
sim.run()
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("Running test...")
|
||||
test_bench()
|
||||
|
85
lib/axis/tb/test_axis_ll_bridge.v
Normal file
85
lib/axis/tb/test_axis_ll_bridge.v
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`timescale 1 ns / 1 ps
|
||||
|
||||
module test_axis_ll_bridge;
|
||||
|
||||
// Inputs
|
||||
reg clk = 0;
|
||||
reg rst = 0;
|
||||
reg [7:0] current_test = 0;
|
||||
|
||||
reg [7:0] axis_tdata = 8'd0;
|
||||
reg axis_tvalid = 1'b0;
|
||||
reg axis_tlast = 1'b0;
|
||||
reg ll_dst_rdy_in_n = 1'b1;
|
||||
|
||||
// Outputs
|
||||
wire [7:0] ll_data_out;
|
||||
wire ll_sof_out_n;
|
||||
wire ll_eof_out_n;
|
||||
wire ll_src_rdy_out_n;
|
||||
wire axis_tready;
|
||||
|
||||
initial begin
|
||||
// myhdl integration
|
||||
$from_myhdl(clk,
|
||||
rst,
|
||||
current_test,
|
||||
axis_tdata,
|
||||
axis_tvalid,
|
||||
axis_tlast,
|
||||
ll_dst_rdy_in_n);
|
||||
$to_myhdl(ll_data_out,
|
||||
ll_sof_out_n,
|
||||
ll_eof_out_n,
|
||||
ll_src_rdy_out_n,
|
||||
axis_tready);
|
||||
|
||||
// dump file
|
||||
$dumpfile("test_axis_ll_bridge.lxt");
|
||||
$dumpvars(0, test_axis_ll_bridge);
|
||||
end
|
||||
|
||||
axis_ll_bridge
|
||||
UUT (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
// axi input
|
||||
.axis_tdata(axis_tdata),
|
||||
.axis_tvalid(axis_tvalid),
|
||||
.axis_tready(axis_tready),
|
||||
.axis_tlast(axis_tlast),
|
||||
// locallink output
|
||||
.ll_data_out(ll_data_out),
|
||||
.ll_sof_out_n(ll_sof_out_n),
|
||||
.ll_eof_out_n(ll_eof_out_n),
|
||||
.ll_src_rdy_out_n(ll_src_rdy_out_n),
|
||||
.ll_dst_rdy_in_n(ll_dst_rdy_in_n)
|
||||
);
|
||||
|
||||
endmodule
|
532
lib/axis/tb/test_axis_rate_limit.py
Executable file
532
lib/axis/tb/test_axis_rate_limit.py
Executable file
@ -0,0 +1,532 @@
|
||||
#!/usr/bin/env python2
|
||||
"""
|
||||
|
||||
Copyright (c) 2014 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
"""
|
||||
|
||||
from myhdl import *
|
||||
import os
|
||||
from Queue import Queue
|
||||
|
||||
import axis_ep
|
||||
|
||||
module = 'axis_rate_limit'
|
||||
|
||||
srcs = []
|
||||
|
||||
srcs.append("../rtl/%s.v" % module)
|
||||
srcs.append("test_%s.v" % module)
|
||||
|
||||
src = ' '.join(srcs)
|
||||
|
||||
build_cmd = "iverilog -o test_%s.vvp %s" % (module, src)
|
||||
|
||||
def dut_axis_rate_limit(clk,
|
||||
rst,
|
||||
current_test,
|
||||
|
||||
input_axis_tdata,
|
||||
input_axis_tvalid,
|
||||
input_axis_tready,
|
||||
input_axis_tlast,
|
||||
input_axis_tuser,
|
||||
|
||||
output_axis_tdata,
|
||||
output_axis_tvalid,
|
||||
output_axis_tready,
|
||||
output_axis_tlast,
|
||||
output_axis_tuser,
|
||||
|
||||
rate_num,
|
||||
rate_denom,
|
||||
rate_by_frame):
|
||||
|
||||
if os.system(build_cmd):
|
||||
raise Exception("Error running build command")
|
||||
return Cosimulation("vvp -m myhdl test_%s.vvp -lxt2" % module,
|
||||
clk=clk,
|
||||
rst=rst,
|
||||
current_test=current_test,
|
||||
|
||||
input_axis_tdata=input_axis_tdata,
|
||||
input_axis_tvalid=input_axis_tvalid,
|
||||
input_axis_tready=input_axis_tready,
|
||||
input_axis_tlast=input_axis_tlast,
|
||||
input_axis_tuser=input_axis_tuser,
|
||||
|
||||
output_axis_tdata=output_axis_tdata,
|
||||
output_axis_tvalid=output_axis_tvalid,
|
||||
output_axis_tready=output_axis_tready,
|
||||
output_axis_tlast=output_axis_tlast,
|
||||
output_axis_tuser=output_axis_tuser,
|
||||
|
||||
rate_num=rate_num,
|
||||
rate_denom=rate_denom,
|
||||
rate_by_frame=rate_by_frame)
|
||||
|
||||
def bench():
|
||||
|
||||
# Inputs
|
||||
clk = Signal(bool(0))
|
||||
rst = Signal(bool(0))
|
||||
current_test = Signal(intbv(0)[8:])
|
||||
|
||||
input_axis_tdata = Signal(intbv(0)[8:])
|
||||
input_axis_tvalid = Signal(bool(0))
|
||||
input_axis_tlast = Signal(bool(0))
|
||||
input_axis_tuser = Signal(bool(0))
|
||||
output_axis_tready = Signal(bool(0))
|
||||
|
||||
rate_num = Signal(intbv(0)[8:])
|
||||
rate_denom = Signal(intbv(0)[8:])
|
||||
rate_by_frame = Signal(bool(0))
|
||||
|
||||
# Outputs
|
||||
input_axis_tready = Signal(bool(0))
|
||||
output_axis_tdata = Signal(intbv(0)[8:])
|
||||
output_axis_tvalid = Signal(bool(0))
|
||||
output_axis_tlast = Signal(bool(0))
|
||||
output_axis_tuser = Signal(bool(0))
|
||||
|
||||
# sources and sinks
|
||||
source_queue = Queue()
|
||||
source_pause = Signal(bool(0))
|
||||
sink_queue = Queue()
|
||||
sink_pause = Signal(bool(0))
|
||||
|
||||
source = axis_ep.AXIStreamSource(clk,
|
||||
rst,
|
||||
tdata=input_axis_tdata,
|
||||
tvalid=input_axis_tvalid,
|
||||
tready=input_axis_tready,
|
||||
tlast=input_axis_tlast,
|
||||
tuser=input_axis_tuser,
|
||||
fifo=source_queue,
|
||||
pause=source_pause,
|
||||
name='source')
|
||||
|
||||
sink = axis_ep.AXIStreamSink(clk,
|
||||
rst,
|
||||
tdata=output_axis_tdata,
|
||||
tvalid=output_axis_tvalid,
|
||||
tready=output_axis_tready,
|
||||
tlast=output_axis_tlast,
|
||||
tuser=output_axis_tuser,
|
||||
fifo=sink_queue,
|
||||
pause=sink_pause,
|
||||
name='sink')
|
||||
|
||||
# DUT
|
||||
dut = dut_axis_rate_limit(clk,
|
||||
rst,
|
||||
current_test,
|
||||
|
||||
input_axis_tdata,
|
||||
input_axis_tvalid,
|
||||
input_axis_tready,
|
||||
input_axis_tlast,
|
||||
input_axis_tuser,
|
||||
|
||||
output_axis_tdata,
|
||||
output_axis_tvalid,
|
||||
output_axis_tready,
|
||||
output_axis_tlast,
|
||||
output_axis_tuser,
|
||||
|
||||
rate_num,
|
||||
rate_denom,
|
||||
rate_by_frame)
|
||||
|
||||
@always(delay(4))
|
||||
def clkgen():
|
||||
clk.next = not clk
|
||||
|
||||
reset_stats = Signal(bool(False))
|
||||
cur_frame = Signal(bool(False))
|
||||
tick_count = Signal(intbv(0))
|
||||
byte_count = Signal(intbv(0))
|
||||
frame_count = Signal(intbv(0))
|
||||
|
||||
@always(clk.posedge)
|
||||
def monitor():
|
||||
ctc = int(tick_count)
|
||||
cbc = int(byte_count)
|
||||
cfc = int(frame_count)
|
||||
if reset_stats:
|
||||
ctc = 0
|
||||
cbc = 0
|
||||
cfc = 0
|
||||
reset_stats.next = 0
|
||||
ctc += 1
|
||||
if output_axis_tready and output_axis_tvalid:
|
||||
cbc += 1
|
||||
if output_axis_tlast:
|
||||
cur_frame.next = False
|
||||
elif not cur_frame:
|
||||
cfc += 1
|
||||
cur_frame.next = True
|
||||
tick_count.next = ctc
|
||||
byte_count.next = cbc
|
||||
frame_count.next = cfc
|
||||
|
||||
@instance
|
||||
def check():
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
rst.next = 1
|
||||
yield clk.posedge
|
||||
rst.next = 0
|
||||
yield clk.posedge
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
|
||||
yield clk.posedge
|
||||
rate_num.next = 1
|
||||
rate_denom.next = 4
|
||||
rate_by_frame.next = 1
|
||||
|
||||
for frame_mode in (True, False):
|
||||
print("test frame mode %s" % frame_mode)
|
||||
rate_by_frame.next = frame_mode
|
||||
|
||||
rate_num.next = 1
|
||||
rate_denom.next = 4
|
||||
|
||||
yield clk.posedge
|
||||
print("test 1: test packet")
|
||||
current_test.next = 1
|
||||
|
||||
test_frame = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
source_queue.put(test_frame)
|
||||
yield clk.posedge
|
||||
|
||||
while input_axis_tvalid or output_axis_tvalid:
|
||||
yield clk.posedge
|
||||
while not input_axis_tready:
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 2: longer packet")
|
||||
current_test.next = 2
|
||||
|
||||
test_frame = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
bytearray(range(256)))
|
||||
source_queue.put(test_frame)
|
||||
yield clk.posedge
|
||||
|
||||
while input_axis_tvalid or output_axis_tvalid:
|
||||
yield clk.posedge
|
||||
while not input_axis_tready:
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame
|
||||
|
||||
yield clk.posedge
|
||||
print("test 3: test packet with pauses")
|
||||
current_test.next = 3
|
||||
|
||||
test_frame = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
bytearray(range(256)))
|
||||
source_queue.put(test_frame)
|
||||
yield clk.posedge
|
||||
|
||||
yield delay(64)
|
||||
yield clk.posedge
|
||||
source_pause.next = True
|
||||
yield delay(32)
|
||||
yield clk.posedge
|
||||
source_pause.next = False
|
||||
|
||||
yield delay(64)
|
||||
yield clk.posedge
|
||||
sink_pause.next = True
|
||||
yield delay(32)
|
||||
yield clk.posedge
|
||||
sink_pause.next = False
|
||||
|
||||
while input_axis_tvalid or output_axis_tvalid:
|
||||
yield clk.posedge
|
||||
while not input_axis_tready:
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 4: back-to-back packets")
|
||||
current_test.next = 4
|
||||
|
||||
test_frame1 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x01\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
test_frame2 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x02\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
source_queue.put(test_frame1)
|
||||
source_queue.put(test_frame2)
|
||||
yield clk.posedge
|
||||
|
||||
while input_axis_tvalid or output_axis_tvalid:
|
||||
yield clk.posedge
|
||||
while not input_axis_tready:
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame1
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame2
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 5: alternate pause source")
|
||||
current_test.next = 5
|
||||
|
||||
test_frame1 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x01\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
test_frame2 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x02\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
source_queue.put(test_frame1)
|
||||
source_queue.put(test_frame2)
|
||||
yield clk.posedge
|
||||
|
||||
while input_axis_tvalid or output_axis_tvalid:
|
||||
source_pause.next = True
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
source_pause.next = False
|
||||
yield clk.posedge
|
||||
|
||||
while input_axis_tvalid or output_axis_tvalid:
|
||||
yield clk.posedge
|
||||
while not input_axis_tready:
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame1
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame2
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 6: alternate pause sink")
|
||||
current_test.next = 6
|
||||
|
||||
test_frame1 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x01\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
test_frame2 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x02\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
source_queue.put(test_frame1)
|
||||
source_queue.put(test_frame2)
|
||||
yield clk.posedge
|
||||
|
||||
while input_axis_tvalid or output_axis_tvalid:
|
||||
sink_pause.next = True
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
sink_pause.next = False
|
||||
yield clk.posedge
|
||||
|
||||
while input_axis_tvalid or output_axis_tvalid:
|
||||
yield clk.posedge
|
||||
while not input_axis_tready:
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame1
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame2
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 7: tuser assert")
|
||||
current_test.next = 7
|
||||
|
||||
test_frame = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
test_frame.user = 1
|
||||
source_queue.put(test_frame)
|
||||
yield clk.posedge
|
||||
|
||||
while input_axis_tvalid or output_axis_tvalid:
|
||||
yield clk.posedge
|
||||
while not input_axis_tready:
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame
|
||||
assert rx_frame.user[-1]
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 8: various lengths and delays")
|
||||
current_test.next = 8
|
||||
|
||||
for rate in ((1,1), (1,2), (1,10), (2,3)):
|
||||
print("test 8 rate %d / %d" % rate)
|
||||
rate_num.next = rate[0]
|
||||
rate_denom.next = rate[1]
|
||||
|
||||
reset_stats.next = 1
|
||||
yield clk.posedge
|
||||
start_time = now()
|
||||
|
||||
lens = [32, 48, 64, 96, 128, 256]
|
||||
test_frame = []
|
||||
|
||||
for i in range(len(lens)):
|
||||
test_frame.append(axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
bytearray(range(lens[i]))))
|
||||
|
||||
for f in test_frame:
|
||||
source_queue.put(f)
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
while input_axis_tvalid or output_axis_tvalid:
|
||||
yield clk.posedge
|
||||
while not input_axis_tready:
|
||||
yield clk.posedge
|
||||
|
||||
stop_time = now()
|
||||
|
||||
rx_frame = []
|
||||
|
||||
for i in range(len(lens)):
|
||||
if not sink_queue.empty():
|
||||
rx_frame.append(sink_queue.get())
|
||||
|
||||
assert len(rx_frame) == len(test_frame)
|
||||
|
||||
for i in range(len(lens)):
|
||||
assert rx_frame[i] == test_frame[i]
|
||||
|
||||
cycle = (stop_time - start_time) / 8
|
||||
|
||||
print("cycles %d" % cycle)
|
||||
print("tick count %d" % tick_count)
|
||||
print("byte count %d" % byte_count)
|
||||
print("frame count %d" % frame_count)
|
||||
|
||||
assert tick_count == cycle
|
||||
assert byte_count == sum(len(f.data) for f in test_frame)
|
||||
assert frame_count == len(test_frame)
|
||||
|
||||
test_rate = 1.0 * rate_num / rate_denom
|
||||
meas_rate = 1.0 * byte_count / tick_count
|
||||
error = (test_rate - meas_rate) / test_rate
|
||||
|
||||
print("test rate %f" % test_rate)
|
||||
print("meas rate %f" % meas_rate)
|
||||
print("error %f%%" % (error*100))
|
||||
|
||||
assert abs(error) < 0.1
|
||||
|
||||
yield delay(100)
|
||||
|
||||
raise StopSimulation
|
||||
|
||||
return dut, source, sink, clkgen, monitor, check
|
||||
|
||||
def test_bench():
|
||||
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
||||
sim = Simulation(bench())
|
||||
sim.run()
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("Running test...")
|
||||
test_bench()
|
||||
|
100
lib/axis/tb/test_axis_rate_limit.v
Normal file
100
lib/axis/tb/test_axis_rate_limit.v
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`timescale 1 ns / 1 ps
|
||||
|
||||
module test_axis_rate_limit;
|
||||
|
||||
// Inputs
|
||||
reg clk = 0;
|
||||
reg rst = 0;
|
||||
reg [7:0] current_test = 0;
|
||||
|
||||
reg [7:0] input_axis_tdata = 8'd0;
|
||||
reg input_axis_tvalid = 1'b0;
|
||||
reg input_axis_tlast = 1'b0;
|
||||
reg input_axis_tuser = 1'b0;
|
||||
reg output_axis_tready = 1'b0;
|
||||
reg [7:0] rate_num = 0;
|
||||
reg [7:0] rate_denom = 0;
|
||||
reg rate_by_frame = 0;
|
||||
|
||||
// Outputs
|
||||
wire input_axis_tready;
|
||||
wire [7:0] output_axis_tdata;
|
||||
wire output_axis_tvalid;
|
||||
wire output_axis_tlast;
|
||||
wire output_axis_tuser;
|
||||
|
||||
initial begin
|
||||
// myhdl integration
|
||||
$from_myhdl(clk,
|
||||
rst,
|
||||
current_test,
|
||||
input_axis_tdata,
|
||||
input_axis_tvalid,
|
||||
input_axis_tlast,
|
||||
input_axis_tuser,
|
||||
output_axis_tready,
|
||||
rate_num,
|
||||
rate_denom,
|
||||
rate_by_frame);
|
||||
$to_myhdl(input_axis_tready,
|
||||
output_axis_tdata,
|
||||
output_axis_tvalid,
|
||||
output_axis_tlast,
|
||||
output_axis_tuser);
|
||||
|
||||
// dump file
|
||||
$dumpfile("test_axis_rate_limit.lxt");
|
||||
$dumpvars(0, test_axis_rate_limit);
|
||||
end
|
||||
|
||||
axis_rate_limit #(
|
||||
.DATA_WIDTH(8)
|
||||
)
|
||||
UUT (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
// axi input
|
||||
.input_axis_tdata(input_axis_tdata),
|
||||
.input_axis_tvalid(input_axis_tvalid),
|
||||
.input_axis_tready(input_axis_tready),
|
||||
.input_axis_tlast(input_axis_tlast),
|
||||
.input_axis_tuser(input_axis_tuser),
|
||||
// axi output
|
||||
.output_axis_tdata(output_axis_tdata),
|
||||
.output_axis_tvalid(output_axis_tvalid),
|
||||
.output_axis_tready(output_axis_tready),
|
||||
.output_axis_tlast(output_axis_tlast),
|
||||
.output_axis_tuser(output_axis_tuser),
|
||||
// configuration
|
||||
.rate_num(rate_num),
|
||||
.rate_denom(rate_denom),
|
||||
.rate_by_frame(rate_by_frame)
|
||||
);
|
||||
|
||||
endmodule
|
542
lib/axis/tb/test_axis_rate_limit_64.py
Executable file
542
lib/axis/tb/test_axis_rate_limit_64.py
Executable file
@ -0,0 +1,542 @@
|
||||
#!/usr/bin/env python2
|
||||
"""
|
||||
|
||||
Copyright (c) 2014 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
"""
|
||||
|
||||
from myhdl import *
|
||||
import os
|
||||
from Queue import Queue
|
||||
|
||||
import axis_ep
|
||||
|
||||
module = 'axis_rate_limit_64'
|
||||
|
||||
srcs = []
|
||||
|
||||
srcs.append("../rtl/%s.v" % module)
|
||||
srcs.append("test_%s.v" % module)
|
||||
|
||||
src = ' '.join(srcs)
|
||||
|
||||
build_cmd = "iverilog -o test_%s.vvp %s" % (module, src)
|
||||
|
||||
def dut_axis_rate_limit_64(clk,
|
||||
rst,
|
||||
current_test,
|
||||
|
||||
input_axis_tdata,
|
||||
input_axis_tkeep,
|
||||
input_axis_tvalid,
|
||||
input_axis_tready,
|
||||
input_axis_tlast,
|
||||
input_axis_tuser,
|
||||
|
||||
output_axis_tdata,
|
||||
output_axis_tkeep,
|
||||
output_axis_tvalid,
|
||||
output_axis_tready,
|
||||
output_axis_tlast,
|
||||
output_axis_tuser,
|
||||
|
||||
rate_num,
|
||||
rate_denom,
|
||||
rate_by_frame):
|
||||
|
||||
if os.system(build_cmd):
|
||||
raise Exception("Error running build command")
|
||||
return Cosimulation("vvp -m myhdl test_%s.vvp -lxt2" % module,
|
||||
clk=clk,
|
||||
rst=rst,
|
||||
current_test=current_test,
|
||||
|
||||
input_axis_tdata=input_axis_tdata,
|
||||
input_axis_tkeep=input_axis_tkeep,
|
||||
input_axis_tvalid=input_axis_tvalid,
|
||||
input_axis_tready=input_axis_tready,
|
||||
input_axis_tlast=input_axis_tlast,
|
||||
input_axis_tuser=input_axis_tuser,
|
||||
|
||||
output_axis_tdata=output_axis_tdata,
|
||||
output_axis_tkeep=output_axis_tkeep,
|
||||
output_axis_tvalid=output_axis_tvalid,
|
||||
output_axis_tready=output_axis_tready,
|
||||
output_axis_tlast=output_axis_tlast,
|
||||
output_axis_tuser=output_axis_tuser,
|
||||
|
||||
rate_num=rate_num,
|
||||
rate_denom=rate_denom,
|
||||
rate_by_frame=rate_by_frame)
|
||||
|
||||
def bench():
|
||||
|
||||
# Inputs
|
||||
clk = Signal(bool(0))
|
||||
rst = Signal(bool(0))
|
||||
current_test = Signal(intbv(0)[8:])
|
||||
|
||||
input_axis_tdata = Signal(intbv(0)[64:])
|
||||
input_axis_tkeep = Signal(intbv(0)[8:])
|
||||
input_axis_tvalid = Signal(bool(0))
|
||||
input_axis_tlast = Signal(bool(0))
|
||||
input_axis_tuser = Signal(bool(0))
|
||||
output_axis_tready = Signal(bool(0))
|
||||
|
||||
rate_num = Signal(intbv(0)[8:])
|
||||
rate_denom = Signal(intbv(0)[8:])
|
||||
rate_by_frame = Signal(bool(0))
|
||||
|
||||
# Outputs
|
||||
input_axis_tready = Signal(bool(0))
|
||||
output_axis_tdata = Signal(intbv(0)[64:])
|
||||
output_axis_tkeep = Signal(intbv(0)[8:])
|
||||
output_axis_tvalid = Signal(bool(0))
|
||||
output_axis_tlast = Signal(bool(0))
|
||||
output_axis_tuser = Signal(bool(0))
|
||||
|
||||
# sources and sinks
|
||||
source_queue = Queue()
|
||||
source_pause = Signal(bool(0))
|
||||
sink_queue = Queue()
|
||||
sink_pause = Signal(bool(0))
|
||||
|
||||
source = axis_ep.AXIStreamSource(clk,
|
||||
rst,
|
||||
tdata=input_axis_tdata,
|
||||
tkeep=input_axis_tkeep,
|
||||
tvalid=input_axis_tvalid,
|
||||
tready=input_axis_tready,
|
||||
tlast=input_axis_tlast,
|
||||
tuser=input_axis_tuser,
|
||||
fifo=source_queue,
|
||||
pause=source_pause,
|
||||
name='source')
|
||||
|
||||
sink = axis_ep.AXIStreamSink(clk,
|
||||
rst,
|
||||
tdata=output_axis_tdata,
|
||||
tkeep=output_axis_tkeep,
|
||||
tvalid=output_axis_tvalid,
|
||||
tready=output_axis_tready,
|
||||
tlast=output_axis_tlast,
|
||||
tuser=output_axis_tuser,
|
||||
fifo=sink_queue,
|
||||
pause=sink_pause,
|
||||
name='sink')
|
||||
|
||||
# DUT
|
||||
dut = dut_axis_rate_limit_64(clk,
|
||||
rst,
|
||||
current_test,
|
||||
|
||||
input_axis_tdata,
|
||||
input_axis_tkeep,
|
||||
input_axis_tvalid,
|
||||
input_axis_tready,
|
||||
input_axis_tlast,
|
||||
input_axis_tuser,
|
||||
|
||||
output_axis_tdata,
|
||||
output_axis_tkeep,
|
||||
output_axis_tvalid,
|
||||
output_axis_tready,
|
||||
output_axis_tlast,
|
||||
output_axis_tuser,
|
||||
|
||||
rate_num,
|
||||
rate_denom,
|
||||
rate_by_frame)
|
||||
|
||||
@always(delay(4))
|
||||
def clkgen():
|
||||
clk.next = not clk
|
||||
|
||||
reset_stats = Signal(bool(False))
|
||||
cur_frame = Signal(bool(False))
|
||||
tick_count = Signal(intbv(0))
|
||||
byte_count = Signal(intbv(0))
|
||||
frame_count = Signal(intbv(0))
|
||||
|
||||
@always(clk.posedge)
|
||||
def monitor():
|
||||
ctc = int(tick_count)
|
||||
cbc = int(byte_count)
|
||||
cfc = int(frame_count)
|
||||
if reset_stats:
|
||||
ctc = 0
|
||||
cbc = 0
|
||||
cfc = 0
|
||||
reset_stats.next = 0
|
||||
ctc += len(output_axis_tkeep)
|
||||
if output_axis_tready and output_axis_tvalid:
|
||||
cbc += bin(output_axis_tkeep).count('1')
|
||||
if output_axis_tlast:
|
||||
cur_frame.next = False
|
||||
elif not cur_frame:
|
||||
cfc += 1
|
||||
cur_frame.next = True
|
||||
tick_count.next = ctc
|
||||
byte_count.next = cbc
|
||||
frame_count.next = cfc
|
||||
|
||||
@instance
|
||||
def check():
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
rst.next = 1
|
||||
yield clk.posedge
|
||||
rst.next = 0
|
||||
yield clk.posedge
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
|
||||
yield clk.posedge
|
||||
rate_num.next = 1
|
||||
rate_denom.next = 4
|
||||
rate_by_frame.next = 1
|
||||
|
||||
for frame_mode in (True, False):
|
||||
print("test frame mode %s" % frame_mode)
|
||||
rate_by_frame.next = frame_mode
|
||||
|
||||
rate_num.next = 1
|
||||
rate_denom.next = 4
|
||||
|
||||
yield clk.posedge
|
||||
print("test 1: test packet")
|
||||
current_test.next = 1
|
||||
|
||||
test_frame = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
source_queue.put(test_frame)
|
||||
yield clk.posedge
|
||||
|
||||
while input_axis_tvalid or output_axis_tvalid:
|
||||
yield clk.posedge
|
||||
while not input_axis_tready:
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 2: longer packet")
|
||||
current_test.next = 2
|
||||
|
||||
test_frame = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
bytearray(range(256)))
|
||||
source_queue.put(test_frame)
|
||||
yield clk.posedge
|
||||
|
||||
while input_axis_tvalid or output_axis_tvalid:
|
||||
yield clk.posedge
|
||||
while not input_axis_tready:
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame
|
||||
|
||||
yield clk.posedge
|
||||
print("test 3: test packet with pauses")
|
||||
current_test.next = 3
|
||||
|
||||
test_frame = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
bytearray(range(256)))
|
||||
source_queue.put(test_frame)
|
||||
yield clk.posedge
|
||||
|
||||
yield delay(64)
|
||||
yield clk.posedge
|
||||
source_pause.next = True
|
||||
yield delay(32)
|
||||
yield clk.posedge
|
||||
source_pause.next = False
|
||||
|
||||
yield delay(64)
|
||||
yield clk.posedge
|
||||
sink_pause.next = True
|
||||
yield delay(32)
|
||||
yield clk.posedge
|
||||
sink_pause.next = False
|
||||
|
||||
while input_axis_tvalid or output_axis_tvalid:
|
||||
yield clk.posedge
|
||||
while not input_axis_tready:
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 4: back-to-back packets")
|
||||
current_test.next = 4
|
||||
|
||||
test_frame1 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x01\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
test_frame2 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x02\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
source_queue.put(test_frame1)
|
||||
source_queue.put(test_frame2)
|
||||
yield clk.posedge
|
||||
|
||||
while input_axis_tvalid or output_axis_tvalid:
|
||||
yield clk.posedge
|
||||
while not input_axis_tready:
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame1
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame2
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 5: alternate pause source")
|
||||
current_test.next = 5
|
||||
|
||||
test_frame1 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x01\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
test_frame2 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x02\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
source_queue.put(test_frame1)
|
||||
source_queue.put(test_frame2)
|
||||
yield clk.posedge
|
||||
|
||||
while input_axis_tvalid or output_axis_tvalid:
|
||||
source_pause.next = True
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
source_pause.next = False
|
||||
yield clk.posedge
|
||||
|
||||
while input_axis_tvalid or output_axis_tvalid:
|
||||
yield clk.posedge
|
||||
while not input_axis_tready:
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame1
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame2
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 6: alternate pause sink")
|
||||
current_test.next = 6
|
||||
|
||||
test_frame1 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x01\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
test_frame2 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x02\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
source_queue.put(test_frame1)
|
||||
source_queue.put(test_frame2)
|
||||
yield clk.posedge
|
||||
|
||||
while input_axis_tvalid or output_axis_tvalid:
|
||||
sink_pause.next = True
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
sink_pause.next = False
|
||||
yield clk.posedge
|
||||
|
||||
while input_axis_tvalid or output_axis_tvalid:
|
||||
yield clk.posedge
|
||||
while not input_axis_tready:
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame1
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame2
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 7: tuser assert")
|
||||
current_test.next = 7
|
||||
|
||||
test_frame = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
test_frame.user = 1
|
||||
source_queue.put(test_frame)
|
||||
yield clk.posedge
|
||||
|
||||
while input_axis_tvalid or output_axis_tvalid:
|
||||
yield clk.posedge
|
||||
while not input_axis_tready:
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame
|
||||
assert rx_frame.user[-1]
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 8: various lengths and delays")
|
||||
current_test.next = 8
|
||||
|
||||
for rate in ((1,1), (1,2), (1,10), (2,3)):
|
||||
print("test 8 rate %d / %d" % rate)
|
||||
rate_num.next = rate[0]
|
||||
rate_denom.next = rate[1]
|
||||
|
||||
reset_stats.next = 1
|
||||
yield clk.posedge
|
||||
start_time = now()
|
||||
|
||||
lens = [32, 48, 64, 96, 128, 256]
|
||||
test_frame = []
|
||||
|
||||
for i in range(len(lens)):
|
||||
test_frame.append(axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
bytearray(range(lens[i]))))
|
||||
|
||||
for f in test_frame:
|
||||
source_queue.put(f)
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
while input_axis_tvalid or output_axis_tvalid:
|
||||
yield clk.posedge
|
||||
while not input_axis_tready:
|
||||
yield clk.posedge
|
||||
|
||||
stop_time = now()
|
||||
|
||||
rx_frame = []
|
||||
|
||||
for i in range(len(lens)):
|
||||
if not sink_queue.empty():
|
||||
rx_frame.append(sink_queue.get())
|
||||
|
||||
assert len(rx_frame) == len(test_frame)
|
||||
|
||||
for i in range(len(lens)):
|
||||
assert rx_frame[i] == test_frame[i]
|
||||
|
||||
cycle = (stop_time - start_time) / 8
|
||||
|
||||
print("cycles %d" % cycle)
|
||||
print("tick count %d" % tick_count)
|
||||
print("byte count %d" % byte_count)
|
||||
print("frame count %d" % frame_count)
|
||||
|
||||
assert tick_count == cycle*8
|
||||
assert byte_count == sum(len(f.data) for f in test_frame)
|
||||
assert frame_count == len(test_frame)
|
||||
|
||||
test_rate = 1.0 * rate_num / rate_denom
|
||||
meas_rate = 1.0 * byte_count / tick_count
|
||||
error = (test_rate - meas_rate) / test_rate
|
||||
|
||||
print("test rate %f" % test_rate)
|
||||
print("meas rate %f" % meas_rate)
|
||||
print("error %f%%" % (error*100))
|
||||
|
||||
assert abs(error) < 0.1
|
||||
|
||||
yield delay(100)
|
||||
|
||||
raise StopSimulation
|
||||
|
||||
return dut, source, sink, clkgen, monitor, check
|
||||
|
||||
def test_bench():
|
||||
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
||||
sim = Simulation(bench())
|
||||
sim.run()
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("Running test...")
|
||||
test_bench()
|
||||
|
106
lib/axis/tb/test_axis_rate_limit_64.v
Normal file
106
lib/axis/tb/test_axis_rate_limit_64.v
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`timescale 1 ns / 1 ps
|
||||
|
||||
module test_axis_rate_limit_64;
|
||||
|
||||
// Inputs
|
||||
reg clk = 0;
|
||||
reg rst = 0;
|
||||
reg [7:0] current_test = 0;
|
||||
|
||||
reg [63:0] input_axis_tdata = 8'd0;
|
||||
reg [7:0] input_axis_tkeep = 8'd0;
|
||||
reg input_axis_tvalid = 1'b0;
|
||||
reg input_axis_tlast = 1'b0;
|
||||
reg input_axis_tuser = 1'b0;
|
||||
reg output_axis_tready = 1'b0;
|
||||
reg [7:0] rate_num = 0;
|
||||
reg [7:0] rate_denom = 0;
|
||||
reg rate_by_frame = 0;
|
||||
|
||||
// Outputs
|
||||
wire input_axis_tready;
|
||||
wire [63:0] output_axis_tdata;
|
||||
wire [7:0] output_axis_tkeep;
|
||||
wire output_axis_tvalid;
|
||||
wire output_axis_tlast;
|
||||
wire output_axis_tuser;
|
||||
|
||||
initial begin
|
||||
// myhdl integration
|
||||
$from_myhdl(clk,
|
||||
rst,
|
||||
current_test,
|
||||
input_axis_tdata,
|
||||
input_axis_tkeep,
|
||||
input_axis_tvalid,
|
||||
input_axis_tlast,
|
||||
input_axis_tuser,
|
||||
output_axis_tready,
|
||||
rate_num,
|
||||
rate_denom,
|
||||
rate_by_frame);
|
||||
$to_myhdl(input_axis_tready,
|
||||
output_axis_tdata,
|
||||
output_axis_tkeep,
|
||||
output_axis_tvalid,
|
||||
output_axis_tlast,
|
||||
output_axis_tuser);
|
||||
|
||||
// dump file
|
||||
$dumpfile("test_axis_rate_limit_64.lxt");
|
||||
$dumpvars(0, test_axis_rate_limit_64);
|
||||
end
|
||||
|
||||
axis_rate_limit_64 #(
|
||||
.DATA_WIDTH(64)
|
||||
)
|
||||
UUT (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
// axi input
|
||||
.input_axis_tdata(input_axis_tdata),
|
||||
.input_axis_tkeep(input_axis_tkeep),
|
||||
.input_axis_tvalid(input_axis_tvalid),
|
||||
.input_axis_tready(input_axis_tready),
|
||||
.input_axis_tlast(input_axis_tlast),
|
||||
.input_axis_tuser(input_axis_tuser),
|
||||
// axi output
|
||||
.output_axis_tdata(output_axis_tdata),
|
||||
.output_axis_tkeep(output_axis_tkeep),
|
||||
.output_axis_tvalid(output_axis_tvalid),
|
||||
.output_axis_tready(output_axis_tready),
|
||||
.output_axis_tlast(output_axis_tlast),
|
||||
.output_axis_tuser(output_axis_tuser),
|
||||
// configuration
|
||||
.rate_num(rate_num),
|
||||
.rate_denom(rate_denom),
|
||||
.rate_by_frame(rate_by_frame)
|
||||
);
|
||||
|
||||
endmodule
|
396
lib/axis/tb/test_axis_register.py
Executable file
396
lib/axis/tb/test_axis_register.py
Executable file
@ -0,0 +1,396 @@
|
||||
#!/usr/bin/env python2
|
||||
"""
|
||||
|
||||
Copyright (c) 2014 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
"""
|
||||
|
||||
from myhdl import *
|
||||
import os
|
||||
from Queue import Queue
|
||||
|
||||
import axis_ep
|
||||
|
||||
module = 'axis_register'
|
||||
|
||||
srcs = []
|
||||
|
||||
srcs.append("../rtl/%s.v" % module)
|
||||
srcs.append("test_%s.v" % module)
|
||||
|
||||
src = ' '.join(srcs)
|
||||
|
||||
build_cmd = "iverilog -o test_%s.vvp %s" % (module, src)
|
||||
|
||||
def dut_axis_register(clk,
|
||||
rst,
|
||||
current_test,
|
||||
|
||||
input_axis_tdata,
|
||||
input_axis_tvalid,
|
||||
input_axis_tready,
|
||||
input_axis_tlast,
|
||||
input_axis_tuser,
|
||||
|
||||
output_axis_tdata,
|
||||
output_axis_tvalid,
|
||||
output_axis_tready,
|
||||
output_axis_tlast,
|
||||
output_axis_tuser):
|
||||
|
||||
if os.system(build_cmd):
|
||||
raise Exception("Error running build command")
|
||||
return Cosimulation("vvp -m myhdl test_%s.vvp -lxt2" % module,
|
||||
clk=clk,
|
||||
rst=rst,
|
||||
current_test=current_test,
|
||||
|
||||
input_axis_tdata=input_axis_tdata,
|
||||
input_axis_tvalid=input_axis_tvalid,
|
||||
input_axis_tready=input_axis_tready,
|
||||
input_axis_tlast=input_axis_tlast,
|
||||
input_axis_tuser=input_axis_tuser,
|
||||
|
||||
output_axis_tdata=output_axis_tdata,
|
||||
output_axis_tvalid=output_axis_tvalid,
|
||||
output_axis_tready=output_axis_tready,
|
||||
output_axis_tlast=output_axis_tlast,
|
||||
output_axis_tuser=output_axis_tuser)
|
||||
|
||||
def bench():
|
||||
|
||||
# Inputs
|
||||
clk = Signal(bool(0))
|
||||
rst = Signal(bool(0))
|
||||
current_test = Signal(intbv(0)[8:])
|
||||
|
||||
input_axis_tdata = Signal(intbv(0)[8:])
|
||||
input_axis_tvalid = Signal(bool(0))
|
||||
input_axis_tlast = Signal(bool(0))
|
||||
input_axis_tuser = Signal(bool(0))
|
||||
output_axis_tready = Signal(bool(0))
|
||||
|
||||
# Outputs
|
||||
input_axis_tready = Signal(bool(0))
|
||||
output_axis_tdata = Signal(intbv(0)[8:])
|
||||
output_axis_tvalid = Signal(bool(0))
|
||||
output_axis_tlast = Signal(bool(0))
|
||||
output_axis_tuser = Signal(bool(0))
|
||||
|
||||
# sources and sinks
|
||||
source_queue = Queue()
|
||||
source_pause = Signal(bool(0))
|
||||
sink_queue = Queue()
|
||||
sink_pause = Signal(bool(0))
|
||||
|
||||
source = axis_ep.AXIStreamSource(clk,
|
||||
rst,
|
||||
tdata=input_axis_tdata,
|
||||
tvalid=input_axis_tvalid,
|
||||
tready=input_axis_tready,
|
||||
tlast=input_axis_tlast,
|
||||
tuser=input_axis_tuser,
|
||||
fifo=source_queue,
|
||||
pause=source_pause,
|
||||
name='source')
|
||||
|
||||
sink = axis_ep.AXIStreamSink(clk,
|
||||
rst,
|
||||
tdata=output_axis_tdata,
|
||||
tvalid=output_axis_tvalid,
|
||||
tready=output_axis_tready,
|
||||
tlast=output_axis_tlast,
|
||||
tuser=output_axis_tuser,
|
||||
fifo=sink_queue,
|
||||
pause=sink_pause,
|
||||
name='sink')
|
||||
|
||||
# DUT
|
||||
dut = dut_axis_register(clk,
|
||||
rst,
|
||||
current_test,
|
||||
|
||||
input_axis_tdata,
|
||||
input_axis_tvalid,
|
||||
input_axis_tready,
|
||||
input_axis_tlast,
|
||||
input_axis_tuser,
|
||||
|
||||
output_axis_tdata,
|
||||
output_axis_tvalid,
|
||||
output_axis_tready,
|
||||
output_axis_tlast,
|
||||
output_axis_tuser)
|
||||
|
||||
@always(delay(4))
|
||||
def clkgen():
|
||||
clk.next = not clk
|
||||
|
||||
@instance
|
||||
def check():
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
rst.next = 1
|
||||
yield clk.posedge
|
||||
rst.next = 0
|
||||
yield clk.posedge
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
|
||||
yield clk.posedge
|
||||
|
||||
yield clk.posedge
|
||||
print("test 1: test packet")
|
||||
current_test.next = 1
|
||||
|
||||
test_frame = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
source_queue.put(test_frame)
|
||||
yield clk.posedge
|
||||
|
||||
yield output_axis_tlast.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 2: longer packet")
|
||||
current_test.next = 2
|
||||
|
||||
test_frame = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
bytearray(range(256)))
|
||||
source_queue.put(test_frame)
|
||||
yield clk.posedge
|
||||
|
||||
yield output_axis_tlast.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame
|
||||
|
||||
yield clk.posedge
|
||||
print("test 3: test packet with pauses")
|
||||
current_test.next = 3
|
||||
|
||||
test_frame = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
source_queue.put(test_frame)
|
||||
yield clk.posedge
|
||||
|
||||
yield delay(64)
|
||||
yield clk.posedge
|
||||
source_pause.next = True
|
||||
yield delay(32)
|
||||
yield clk.posedge
|
||||
source_pause.next = False
|
||||
|
||||
yield delay(64)
|
||||
yield clk.posedge
|
||||
sink_pause.next = True
|
||||
yield delay(32)
|
||||
yield clk.posedge
|
||||
sink_pause.next = False
|
||||
|
||||
yield output_axis_tlast.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 4: back-to-back packets")
|
||||
current_test.next = 4
|
||||
|
||||
test_frame1 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x01\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
test_frame2 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x02\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
source_queue.put(test_frame1)
|
||||
source_queue.put(test_frame2)
|
||||
yield clk.posedge
|
||||
|
||||
yield output_axis_tlast.posedge
|
||||
yield clk.posedge
|
||||
yield output_axis_tlast.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame1
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame2
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 5: alternate pause source")
|
||||
current_test.next = 5
|
||||
|
||||
test_frame1 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x01\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
test_frame2 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x02\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
source_queue.put(test_frame1)
|
||||
source_queue.put(test_frame2)
|
||||
yield clk.posedge
|
||||
|
||||
while input_axis_tvalid or output_axis_tvalid:
|
||||
source_pause.next = True
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
source_pause.next = False
|
||||
yield clk.posedge
|
||||
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame1
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame2
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 6: alternate pause sink")
|
||||
current_test.next = 6
|
||||
|
||||
test_frame1 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x01\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
test_frame2 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x02\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
source_queue.put(test_frame1)
|
||||
source_queue.put(test_frame2)
|
||||
yield clk.posedge
|
||||
|
||||
while input_axis_tvalid or output_axis_tvalid:
|
||||
sink_pause.next = True
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
sink_pause.next = False
|
||||
yield clk.posedge
|
||||
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame1
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame2
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 7: tuser assert")
|
||||
current_test.next = 7
|
||||
|
||||
test_frame = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
test_frame.user = 1
|
||||
source_queue.put(test_frame)
|
||||
yield clk.posedge
|
||||
|
||||
yield output_axis_tlast.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame
|
||||
assert rx_frame.user[-1]
|
||||
|
||||
yield delay(100)
|
||||
|
||||
raise StopSimulation
|
||||
|
||||
return dut, source, sink, clkgen, check
|
||||
|
||||
def test_bench():
|
||||
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
||||
sim = Simulation(bench())
|
||||
sim.run()
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("Running test...")
|
||||
test_bench()
|
||||
|
90
lib/axis/tb/test_axis_register.v
Normal file
90
lib/axis/tb/test_axis_register.v
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`timescale 1 ns / 1 ps
|
||||
|
||||
module test_axis_register;
|
||||
|
||||
// Inputs
|
||||
reg clk = 0;
|
||||
reg rst = 0;
|
||||
reg [7:0] current_test = 0;
|
||||
|
||||
reg [7:0] input_axis_tdata = 8'd0;
|
||||
reg input_axis_tvalid = 1'b0;
|
||||
reg input_axis_tlast = 1'b0;
|
||||
reg input_axis_tuser = 1'b0;
|
||||
reg output_axis_tready = 1'b0;
|
||||
|
||||
// Outputs
|
||||
wire input_axis_tready;
|
||||
wire [7:0] output_axis_tdata;
|
||||
wire output_axis_tvalid;
|
||||
wire output_axis_tlast;
|
||||
wire output_axis_tuser;
|
||||
|
||||
initial begin
|
||||
// myhdl integration
|
||||
$from_myhdl(clk,
|
||||
rst,
|
||||
current_test,
|
||||
input_axis_tdata,
|
||||
input_axis_tvalid,
|
||||
input_axis_tlast,
|
||||
input_axis_tuser,
|
||||
output_axis_tready);
|
||||
$to_myhdl(input_axis_tready,
|
||||
output_axis_tdata,
|
||||
output_axis_tvalid,
|
||||
output_axis_tlast,
|
||||
output_axis_tuser);
|
||||
|
||||
// dump file
|
||||
$dumpfile("test_axis_register.lxt");
|
||||
$dumpvars(0, test_axis_register);
|
||||
end
|
||||
|
||||
axis_register #(
|
||||
.DATA_WIDTH(8)
|
||||
)
|
||||
UUT (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
// axi input
|
||||
.input_axis_tdata(input_axis_tdata),
|
||||
.input_axis_tvalid(input_axis_tvalid),
|
||||
.input_axis_tready(input_axis_tready),
|
||||
.input_axis_tlast(input_axis_tlast),
|
||||
.input_axis_tuser(input_axis_tuser),
|
||||
// axi output
|
||||
.output_axis_tdata(output_axis_tdata),
|
||||
.output_axis_tvalid(output_axis_tvalid),
|
||||
.output_axis_tready(output_axis_tready),
|
||||
.output_axis_tlast(output_axis_tlast),
|
||||
.output_axis_tuser(output_axis_tuser)
|
||||
);
|
||||
|
||||
endmodule
|
406
lib/axis/tb/test_axis_register_64.py
Executable file
406
lib/axis/tb/test_axis_register_64.py
Executable file
@ -0,0 +1,406 @@
|
||||
#!/usr/bin/env python2
|
||||
"""
|
||||
|
||||
Copyright (c) 2014 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
"""
|
||||
|
||||
from myhdl import *
|
||||
import os
|
||||
from Queue import Queue
|
||||
|
||||
import axis_ep
|
||||
|
||||
module = 'axis_register_64'
|
||||
|
||||
srcs = []
|
||||
|
||||
srcs.append("../rtl/%s.v" % module)
|
||||
srcs.append("test_%s.v" % module)
|
||||
|
||||
src = ' '.join(srcs)
|
||||
|
||||
build_cmd = "iverilog -o test_%s.vvp %s" % (module, src)
|
||||
|
||||
def dut_axis_register_64(clk,
|
||||
rst,
|
||||
current_test,
|
||||
|
||||
input_axis_tdata,
|
||||
input_axis_tkeep,
|
||||
input_axis_tvalid,
|
||||
input_axis_tready,
|
||||
input_axis_tlast,
|
||||
input_axis_tuser,
|
||||
|
||||
output_axis_tdata,
|
||||
output_axis_tkeep,
|
||||
output_axis_tvalid,
|
||||
output_axis_tready,
|
||||
output_axis_tlast,
|
||||
output_axis_tuser):
|
||||
|
||||
if os.system(build_cmd):
|
||||
raise Exception("Error running build command")
|
||||
return Cosimulation("vvp -m myhdl test_%s.vvp -lxt2" % module,
|
||||
clk=clk,
|
||||
rst=rst,
|
||||
current_test=current_test,
|
||||
|
||||
input_axis_tdata=input_axis_tdata,
|
||||
input_axis_tkeep=input_axis_tkeep,
|
||||
input_axis_tvalid=input_axis_tvalid,
|
||||
input_axis_tready=input_axis_tready,
|
||||
input_axis_tlast=input_axis_tlast,
|
||||
input_axis_tuser=input_axis_tuser,
|
||||
|
||||
output_axis_tdata=output_axis_tdata,
|
||||
output_axis_tkeep=output_axis_tkeep,
|
||||
output_axis_tvalid=output_axis_tvalid,
|
||||
output_axis_tready=output_axis_tready,
|
||||
output_axis_tlast=output_axis_tlast,
|
||||
output_axis_tuser=output_axis_tuser)
|
||||
|
||||
def bench():
|
||||
|
||||
# Inputs
|
||||
clk = Signal(bool(0))
|
||||
rst = Signal(bool(0))
|
||||
current_test = Signal(intbv(0)[8:])
|
||||
|
||||
input_axis_tdata = Signal(intbv(0)[64:])
|
||||
input_axis_tkeep = Signal(intbv(0)[8:])
|
||||
input_axis_tvalid = Signal(bool(0))
|
||||
input_axis_tlast = Signal(bool(0))
|
||||
input_axis_tuser = Signal(bool(0))
|
||||
output_axis_tready = Signal(bool(0))
|
||||
|
||||
# Outputs
|
||||
input_axis_tready = Signal(bool(0))
|
||||
output_axis_tdata = Signal(intbv(0)[64:])
|
||||
output_axis_tkeep = Signal(intbv(0)[8:])
|
||||
output_axis_tvalid = Signal(bool(0))
|
||||
output_axis_tlast = Signal(bool(0))
|
||||
output_axis_tuser = Signal(bool(0))
|
||||
|
||||
# sources and sinks
|
||||
source_queue = Queue()
|
||||
source_pause = Signal(bool(0))
|
||||
sink_queue = Queue()
|
||||
sink_pause = Signal(bool(0))
|
||||
|
||||
source = axis_ep.AXIStreamSource(clk,
|
||||
rst,
|
||||
tdata=input_axis_tdata,
|
||||
tkeep=input_axis_tkeep,
|
||||
tvalid=input_axis_tvalid,
|
||||
tready=input_axis_tready,
|
||||
tlast=input_axis_tlast,
|
||||
tuser=input_axis_tuser,
|
||||
fifo=source_queue,
|
||||
pause=source_pause,
|
||||
name='source')
|
||||
|
||||
sink = axis_ep.AXIStreamSink(clk,
|
||||
rst,
|
||||
tdata=output_axis_tdata,
|
||||
tkeep=output_axis_tkeep,
|
||||
tvalid=output_axis_tvalid,
|
||||
tready=output_axis_tready,
|
||||
tlast=output_axis_tlast,
|
||||
tuser=output_axis_tuser,
|
||||
fifo=sink_queue,
|
||||
pause=sink_pause,
|
||||
name='sink')
|
||||
|
||||
# DUT
|
||||
dut = dut_axis_register_64(clk,
|
||||
rst,
|
||||
current_test,
|
||||
|
||||
input_axis_tdata,
|
||||
input_axis_tkeep,
|
||||
input_axis_tvalid,
|
||||
input_axis_tready,
|
||||
input_axis_tlast,
|
||||
input_axis_tuser,
|
||||
|
||||
output_axis_tdata,
|
||||
output_axis_tkeep,
|
||||
output_axis_tvalid,
|
||||
output_axis_tready,
|
||||
output_axis_tlast,
|
||||
output_axis_tuser)
|
||||
|
||||
@always(delay(4))
|
||||
def clkgen():
|
||||
clk.next = not clk
|
||||
|
||||
@instance
|
||||
def check():
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
rst.next = 1
|
||||
yield clk.posedge
|
||||
rst.next = 0
|
||||
yield clk.posedge
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
|
||||
yield clk.posedge
|
||||
|
||||
yield clk.posedge
|
||||
print("test 1: test packet")
|
||||
current_test.next = 1
|
||||
|
||||
test_frame = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
source_queue.put(test_frame)
|
||||
yield clk.posedge
|
||||
|
||||
yield output_axis_tlast.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 2: longer packet")
|
||||
current_test.next = 2
|
||||
|
||||
test_frame = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
bytearray(range(256)))
|
||||
source_queue.put(test_frame)
|
||||
yield clk.posedge
|
||||
|
||||
yield output_axis_tlast.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame
|
||||
|
||||
yield clk.posedge
|
||||
print("test 3: test packet with pauses")
|
||||
current_test.next = 3
|
||||
|
||||
test_frame = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
bytearray(range(256)))
|
||||
source_queue.put(test_frame)
|
||||
yield clk.posedge
|
||||
|
||||
yield delay(64)
|
||||
yield clk.posedge
|
||||
source_pause.next = True
|
||||
yield delay(32)
|
||||
yield clk.posedge
|
||||
source_pause.next = False
|
||||
|
||||
yield delay(64)
|
||||
yield clk.posedge
|
||||
sink_pause.next = True
|
||||
yield delay(32)
|
||||
yield clk.posedge
|
||||
sink_pause.next = False
|
||||
|
||||
yield output_axis_tlast.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 4: back-to-back packets")
|
||||
current_test.next = 4
|
||||
|
||||
test_frame1 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x01\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
test_frame2 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x02\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
source_queue.put(test_frame1)
|
||||
source_queue.put(test_frame2)
|
||||
yield clk.posedge
|
||||
|
||||
yield output_axis_tlast.posedge
|
||||
yield clk.posedge
|
||||
yield output_axis_tlast.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame1
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame2
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 5: alternate pause source")
|
||||
current_test.next = 5
|
||||
|
||||
test_frame1 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x01\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
test_frame2 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x02\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
source_queue.put(test_frame1)
|
||||
source_queue.put(test_frame2)
|
||||
yield clk.posedge
|
||||
|
||||
while input_axis_tvalid or output_axis_tvalid:
|
||||
source_pause.next = True
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
source_pause.next = False
|
||||
yield clk.posedge
|
||||
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame1
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame2
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 6: alternate pause sink")
|
||||
current_test.next = 6
|
||||
|
||||
test_frame1 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x01\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
test_frame2 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x02\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
source_queue.put(test_frame1)
|
||||
source_queue.put(test_frame2)
|
||||
yield clk.posedge
|
||||
|
||||
while input_axis_tvalid or output_axis_tvalid:
|
||||
sink_pause.next = True
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
sink_pause.next = False
|
||||
yield clk.posedge
|
||||
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame1
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame2
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 7: tuser assert")
|
||||
current_test.next = 7
|
||||
|
||||
test_frame = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
test_frame.user = 1
|
||||
source_queue.put(test_frame)
|
||||
yield clk.posedge
|
||||
|
||||
yield output_axis_tlast.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert rx_frame == test_frame
|
||||
assert rx_frame.user[-1]
|
||||
|
||||
yield delay(100)
|
||||
|
||||
raise StopSimulation
|
||||
|
||||
return dut, source, sink, clkgen, check
|
||||
|
||||
def test_bench():
|
||||
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
||||
sim = Simulation(bench())
|
||||
sim.run()
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("Running test...")
|
||||
test_bench()
|
||||
|
96
lib/axis/tb/test_axis_register_64.v
Normal file
96
lib/axis/tb/test_axis_register_64.v
Normal file
@ -0,0 +1,96 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`timescale 1 ns / 1 ps
|
||||
|
||||
module test_axis_register_64;
|
||||
|
||||
// Inputs
|
||||
reg clk = 0;
|
||||
reg rst = 0;
|
||||
reg [7:0] current_test = 0;
|
||||
|
||||
reg [63:0] input_axis_tdata = 8'd0;
|
||||
reg [7:0] input_axis_tkeep = 8'd0;
|
||||
reg input_axis_tvalid = 1'b0;
|
||||
reg input_axis_tlast = 1'b0;
|
||||
reg input_axis_tuser = 1'b0;
|
||||
reg output_axis_tready = 1'b0;
|
||||
|
||||
// Outputs
|
||||
wire input_axis_tready;
|
||||
wire [63:0] output_axis_tdata;
|
||||
wire [7:0] output_axis_tkeep;
|
||||
wire output_axis_tvalid;
|
||||
wire output_axis_tlast;
|
||||
wire output_axis_tuser;
|
||||
|
||||
initial begin
|
||||
// myhdl integration
|
||||
$from_myhdl(clk,
|
||||
rst,
|
||||
current_test,
|
||||
input_axis_tdata,
|
||||
input_axis_tkeep,
|
||||
input_axis_tvalid,
|
||||
input_axis_tlast,
|
||||
input_axis_tuser,
|
||||
output_axis_tready);
|
||||
$to_myhdl(input_axis_tready,
|
||||
output_axis_tdata,
|
||||
output_axis_tkeep,
|
||||
output_axis_tvalid,
|
||||
output_axis_tlast,
|
||||
output_axis_tuser);
|
||||
|
||||
// dump file
|
||||
$dumpfile("test_axis_register_64.lxt");
|
||||
$dumpvars(0, test_axis_register_64);
|
||||
end
|
||||
|
||||
axis_register_64 #(
|
||||
.DATA_WIDTH(64)
|
||||
)
|
||||
UUT (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
// axi input
|
||||
.input_axis_tdata(input_axis_tdata),
|
||||
.input_axis_tkeep(input_axis_tkeep),
|
||||
.input_axis_tvalid(input_axis_tvalid),
|
||||
.input_axis_tready(input_axis_tready),
|
||||
.input_axis_tlast(input_axis_tlast),
|
||||
.input_axis_tuser(input_axis_tuser),
|
||||
// axi output
|
||||
.output_axis_tdata(output_axis_tdata),
|
||||
.output_axis_tkeep(output_axis_tkeep),
|
||||
.output_axis_tvalid(output_axis_tvalid),
|
||||
.output_axis_tready(output_axis_tready),
|
||||
.output_axis_tlast(output_axis_tlast),
|
||||
.output_axis_tuser(output_axis_tuser)
|
||||
);
|
||||
|
||||
endmodule
|
792
lib/axis/tb/test_axis_stat_counter.py
Executable file
792
lib/axis/tb/test_axis_stat_counter.py
Executable file
@ -0,0 +1,792 @@
|
||||
#!/usr/bin/env python2
|
||||
"""
|
||||
|
||||
Copyright (c) 2014 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
"""
|
||||
|
||||
from myhdl import *
|
||||
import os
|
||||
from Queue import Queue
|
||||
import struct
|
||||
|
||||
import axis_ep
|
||||
|
||||
module = 'axis_stat_counter'
|
||||
|
||||
srcs = []
|
||||
|
||||
srcs.append("../rtl/%s.v" % module)
|
||||
srcs.append("test_%s.v" % module)
|
||||
|
||||
src = ' '.join(srcs)
|
||||
|
||||
build_cmd = "iverilog -o test_%s.vvp %s" % (module, src)
|
||||
|
||||
def dut_axis_stat_counter(clk,
|
||||
rst,
|
||||
current_test,
|
||||
|
||||
monitor_axis_tdata,
|
||||
monitor_axis_tkeep,
|
||||
monitor_axis_tvalid,
|
||||
monitor_axis_tready,
|
||||
monitor_axis_tlast,
|
||||
monitor_axis_tuser,
|
||||
|
||||
output_axis_tdata,
|
||||
output_axis_tvalid,
|
||||
output_axis_tready,
|
||||
output_axis_tlast,
|
||||
output_axis_tuser,
|
||||
|
||||
tag,
|
||||
trigger,
|
||||
busy):
|
||||
|
||||
if os.system(build_cmd):
|
||||
raise Exception("Error running build command")
|
||||
return Cosimulation("vvp -m myhdl test_%s.vvp -lxt2" % module,
|
||||
clk=clk,
|
||||
rst=rst,
|
||||
current_test=current_test,
|
||||
|
||||
monitor_axis_tdata=monitor_axis_tdata,
|
||||
monitor_axis_tkeep=monitor_axis_tkeep,
|
||||
monitor_axis_tvalid=monitor_axis_tvalid,
|
||||
monitor_axis_tready=monitor_axis_tready,
|
||||
monitor_axis_tlast=monitor_axis_tlast,
|
||||
monitor_axis_tuser=monitor_axis_tuser,
|
||||
|
||||
output_axis_tdata=output_axis_tdata,
|
||||
output_axis_tvalid=output_axis_tvalid,
|
||||
output_axis_tready=output_axis_tready,
|
||||
output_axis_tlast=output_axis_tlast,
|
||||
output_axis_tuser=output_axis_tuser,
|
||||
|
||||
tag=tag,
|
||||
trigger=trigger,
|
||||
busy=busy)
|
||||
|
||||
def bench():
|
||||
|
||||
# Inputs
|
||||
clk = Signal(bool(0))
|
||||
rst = Signal(bool(0))
|
||||
current_test = Signal(intbv(0)[8:])
|
||||
|
||||
monitor_axis_tdata = Signal(intbv(0)[64:])
|
||||
monitor_axis_tkeep = Signal(intbv(0)[8:])
|
||||
monitor_axis_tvalid = Signal(bool(0))
|
||||
monitor_axis_tready = Signal(bool(0))
|
||||
monitor_axis_tlast = Signal(bool(0))
|
||||
monitor_axis_tuser = Signal(bool(0))
|
||||
output_axis_tready = Signal(bool(0))
|
||||
|
||||
tag = Signal(intbv(16)[16:])
|
||||
trigger = Signal(bool(0))
|
||||
|
||||
# Outputs
|
||||
output_axis_tdata = Signal(intbv(0)[8:])
|
||||
output_axis_tvalid = Signal(bool(0))
|
||||
output_axis_tlast = Signal(bool(0))
|
||||
output_axis_tuser = Signal(bool(0))
|
||||
busy = Signal(bool(0))
|
||||
|
||||
# sources and sinks
|
||||
source_queue = Queue()
|
||||
source_pause = Signal(bool(0))
|
||||
monitor_sink_queue = Queue()
|
||||
monitor_sink_pause = Signal(bool(0))
|
||||
sink_queue = Queue()
|
||||
sink_pause = Signal(bool(0))
|
||||
|
||||
source = axis_ep.AXIStreamSource(clk,
|
||||
rst,
|
||||
tdata=monitor_axis_tdata,
|
||||
tkeep=monitor_axis_tkeep,
|
||||
tvalid=monitor_axis_tvalid,
|
||||
tready=monitor_axis_tready,
|
||||
tlast=monitor_axis_tlast,
|
||||
tuser=monitor_axis_tuser,
|
||||
fifo=source_queue,
|
||||
pause=source_pause,
|
||||
name='source')
|
||||
|
||||
monitor_sink = axis_ep.AXIStreamSink(clk,
|
||||
rst,
|
||||
tdata=monitor_axis_tdata,
|
||||
tkeep=monitor_axis_tkeep,
|
||||
tvalid=monitor_axis_tvalid,
|
||||
tready=monitor_axis_tready,
|
||||
tlast=monitor_axis_tlast,
|
||||
tuser=monitor_axis_tuser,
|
||||
fifo=monitor_sink_queue,
|
||||
pause=monitor_sink_pause,
|
||||
name='monitor_sink')
|
||||
|
||||
sink = axis_ep.AXIStreamSink(clk,
|
||||
rst,
|
||||
tdata=output_axis_tdata,
|
||||
tvalid=output_axis_tvalid,
|
||||
tready=output_axis_tready,
|
||||
tlast=output_axis_tlast,
|
||||
tuser=output_axis_tuser,
|
||||
fifo=sink_queue,
|
||||
pause=sink_pause,
|
||||
name='sink')
|
||||
|
||||
# DUT
|
||||
dut = dut_axis_stat_counter(clk,
|
||||
rst,
|
||||
current_test,
|
||||
|
||||
monitor_axis_tdata,
|
||||
monitor_axis_tkeep,
|
||||
monitor_axis_tvalid,
|
||||
monitor_axis_tready,
|
||||
monitor_axis_tlast,
|
||||
monitor_axis_tuser,
|
||||
|
||||
output_axis_tdata,
|
||||
output_axis_tvalid,
|
||||
output_axis_tready,
|
||||
output_axis_tlast,
|
||||
output_axis_tuser,
|
||||
|
||||
tag,
|
||||
trigger,
|
||||
busy)
|
||||
|
||||
@always(delay(4))
|
||||
def clkgen():
|
||||
clk.next = not clk
|
||||
|
||||
@instance
|
||||
def check():
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
rst.next = 1
|
||||
yield clk.posedge
|
||||
rst.next = 0
|
||||
yield clk.posedge
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
|
||||
yield clk.posedge
|
||||
tag.next = 1
|
||||
|
||||
yield clk.posedge
|
||||
print("test 1: test tick timer")
|
||||
current_test.next = 1
|
||||
|
||||
yield clk.posedge
|
||||
start_time = now()
|
||||
trigger.next = 1
|
||||
yield clk.posedge
|
||||
trigger.next = 0
|
||||
|
||||
for i in range(100-1):
|
||||
yield clk.posedge
|
||||
|
||||
stop_time = now()
|
||||
trigger.next = 1
|
||||
yield clk.posedge
|
||||
trigger.next = 0
|
||||
yield clk.posedge
|
||||
|
||||
while output_axis_tvalid:
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
# discard first trigger output
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
# check second trigger output
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
rx_frame_values = struct.unpack(">HLLL", bytes(rx_frame.data))
|
||||
cycles = (stop_time - start_time) / 8
|
||||
print(rx_frame_values)
|
||||
|
||||
assert rx_frame_values[0] == 1
|
||||
assert rx_frame_values[1] == cycles*8
|
||||
assert rx_frame_values[1] == 100*8
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 2: pause sink")
|
||||
current_test.next = 2
|
||||
|
||||
yield clk.posedge
|
||||
start_time = now()
|
||||
trigger.next = 1
|
||||
yield clk.posedge
|
||||
trigger.next = 0
|
||||
|
||||
for i in range(100-1):
|
||||
yield clk.posedge
|
||||
|
||||
stop_time = now()
|
||||
trigger.next = 1
|
||||
yield clk.posedge
|
||||
trigger.next = 0
|
||||
|
||||
while trigger or output_axis_tvalid:
|
||||
sink_pause.next = True
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
sink_pause.next = False
|
||||
yield clk.posedge
|
||||
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
# discard first trigger output
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
# check second trigger output
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
rx_frame_values = struct.unpack(">HLLL", bytes(rx_frame.data))
|
||||
cycles = (stop_time - start_time) / 8
|
||||
print(rx_frame_values)
|
||||
|
||||
assert rx_frame_values[0] == 1
|
||||
assert rx_frame_values[1] == cycles*8
|
||||
assert rx_frame_values[1] == 100*8
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 3: test packet")
|
||||
current_test.next = 3
|
||||
|
||||
yield clk.posedge
|
||||
start_time = now()
|
||||
trigger.next = 1
|
||||
yield clk.posedge
|
||||
trigger.next = 0
|
||||
|
||||
test_frame = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
source_queue.put(test_frame)
|
||||
yield clk.posedge
|
||||
|
||||
while monitor_axis_tvalid:
|
||||
yield clk.posedge
|
||||
|
||||
while output_axis_tvalid:
|
||||
yield clk.posedge
|
||||
|
||||
yield clk.posedge
|
||||
stop_time = now()
|
||||
trigger.next = 1
|
||||
yield clk.posedge
|
||||
trigger.next = 0
|
||||
yield clk.posedge
|
||||
|
||||
while output_axis_tvalid:
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
# discard first trigger output
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
# check second trigger output
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
rx_frame_values = struct.unpack(">HLLL", bytes(rx_frame.data))
|
||||
cycles = (stop_time - start_time) / 8
|
||||
print(rx_frame_values)
|
||||
|
||||
assert rx_frame_values[0] == 1
|
||||
assert rx_frame_values[1] == cycles*8
|
||||
assert rx_frame_values[2] == len(test_frame.data)
|
||||
assert rx_frame_values[3] == 1
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 4: longer packet")
|
||||
current_test.next = 4
|
||||
|
||||
yield clk.posedge
|
||||
start_time = now()
|
||||
trigger.next = 1
|
||||
yield clk.posedge
|
||||
trigger.next = 0
|
||||
|
||||
test_frame = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
bytearray(range(256)))
|
||||
source_queue.put(test_frame)
|
||||
yield clk.posedge
|
||||
|
||||
while monitor_axis_tvalid:
|
||||
yield clk.posedge
|
||||
|
||||
while output_axis_tvalid:
|
||||
yield clk.posedge
|
||||
|
||||
yield clk.posedge
|
||||
stop_time = now()
|
||||
trigger.next = 1
|
||||
yield clk.posedge
|
||||
trigger.next = 0
|
||||
yield clk.posedge
|
||||
|
||||
while output_axis_tvalid:
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
# discard first trigger output
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
# check second trigger output
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
rx_frame_values = struct.unpack(">HLLL", bytes(rx_frame.data))
|
||||
cycles = (stop_time - start_time) / 8
|
||||
print(rx_frame_values)
|
||||
|
||||
assert rx_frame_values[0] == 1
|
||||
assert rx_frame_values[1] == cycles*8
|
||||
assert rx_frame_values[2] == len(test_frame.data)
|
||||
assert rx_frame_values[3] == 1
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 5: test packet with pauses")
|
||||
current_test.next = 5
|
||||
|
||||
yield clk.posedge
|
||||
start_time = now()
|
||||
trigger.next = 1
|
||||
yield clk.posedge
|
||||
trigger.next = 0
|
||||
|
||||
test_frame = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
bytearray(range(256)))
|
||||
source_queue.put(test_frame)
|
||||
yield clk.posedge
|
||||
|
||||
yield delay(64)
|
||||
yield clk.posedge
|
||||
source_pause.next = True
|
||||
yield delay(32)
|
||||
yield clk.posedge
|
||||
source_pause.next = False
|
||||
|
||||
yield delay(64)
|
||||
yield clk.posedge
|
||||
monitor_sink_pause.next = True
|
||||
yield delay(32)
|
||||
yield clk.posedge
|
||||
monitor_sink_pause.next = False
|
||||
|
||||
while monitor_axis_tvalid:
|
||||
yield clk.posedge
|
||||
|
||||
while output_axis_tvalid:
|
||||
yield clk.posedge
|
||||
|
||||
yield clk.posedge
|
||||
stop_time = now()
|
||||
trigger.next = 1
|
||||
yield clk.posedge
|
||||
trigger.next = 0
|
||||
yield clk.posedge
|
||||
|
||||
while output_axis_tvalid:
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
# discard first trigger output
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
# check second trigger output
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
rx_frame_values = struct.unpack(">HLLL", bytes(rx_frame.data))
|
||||
cycles = (stop_time - start_time) / 8
|
||||
print(rx_frame_values)
|
||||
|
||||
assert rx_frame_values[0] == 1
|
||||
assert rx_frame_values[1] == cycles*8
|
||||
assert rx_frame_values[2] == len(test_frame.data)
|
||||
assert rx_frame_values[3] == 1
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 6: back-to-back packets")
|
||||
current_test.next = 6
|
||||
|
||||
yield clk.posedge
|
||||
start_time = now()
|
||||
trigger.next = 1
|
||||
yield clk.posedge
|
||||
trigger.next = 0
|
||||
|
||||
test_frame1 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x01\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
test_frame2 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x02\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
source_queue.put(test_frame1)
|
||||
source_queue.put(test_frame2)
|
||||
yield clk.posedge
|
||||
|
||||
while monitor_axis_tvalid:
|
||||
yield clk.posedge
|
||||
|
||||
while output_axis_tvalid:
|
||||
yield clk.posedge
|
||||
|
||||
yield clk.posedge
|
||||
stop_time = now()
|
||||
trigger.next = 1
|
||||
yield clk.posedge
|
||||
trigger.next = 0
|
||||
yield clk.posedge
|
||||
|
||||
while output_axis_tvalid:
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
# discard first trigger output
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
# check second trigger output
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
rx_frame_values = struct.unpack(">HLLL", bytes(rx_frame.data))
|
||||
cycles = (stop_time - start_time) / 8
|
||||
print(rx_frame_values)
|
||||
|
||||
assert rx_frame_values[0] == 1
|
||||
assert rx_frame_values[1] == cycles*8
|
||||
assert rx_frame_values[2] == len(test_frame1.data) + len(test_frame2.data)
|
||||
assert rx_frame_values[3] == 2
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 7: alternate pause source")
|
||||
current_test.next = 7
|
||||
|
||||
yield clk.posedge
|
||||
start_time = now()
|
||||
trigger.next = 1
|
||||
yield clk.posedge
|
||||
trigger.next = 0
|
||||
|
||||
test_frame1 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x01\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
test_frame2 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x02\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
source_queue.put(test_frame1)
|
||||
source_queue.put(test_frame2)
|
||||
yield clk.posedge
|
||||
|
||||
while monitor_axis_tvalid:
|
||||
yield clk.posedge
|
||||
|
||||
while output_axis_tvalid:
|
||||
yield clk.posedge
|
||||
|
||||
yield clk.posedge
|
||||
stop_time = now()
|
||||
trigger.next = 1
|
||||
yield clk.posedge
|
||||
trigger.next = 0
|
||||
yield clk.posedge
|
||||
|
||||
while output_axis_tvalid:
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
# discard first trigger output
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
# check second trigger output
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
rx_frame_values = struct.unpack(">HLLL", bytes(rx_frame.data))
|
||||
cycles = (stop_time - start_time) / 8
|
||||
print(rx_frame_values)
|
||||
|
||||
assert rx_frame_values[0] == 1
|
||||
assert rx_frame_values[1] == cycles*8
|
||||
assert rx_frame_values[2] == len(test_frame1.data) + len(test_frame2.data)
|
||||
assert rx_frame_values[3] == 2
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 8: alternate pause sink")
|
||||
current_test.next = 8
|
||||
|
||||
yield clk.posedge
|
||||
start_time = now()
|
||||
trigger.next = 1
|
||||
yield clk.posedge
|
||||
trigger.next = 0
|
||||
|
||||
test_frame1 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x01\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
test_frame2 = axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x02\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
source_queue.put(test_frame1)
|
||||
source_queue.put(test_frame2)
|
||||
yield clk.posedge
|
||||
|
||||
while monitor_axis_tvalid:
|
||||
yield clk.posedge
|
||||
|
||||
while output_axis_tvalid:
|
||||
yield clk.posedge
|
||||
|
||||
yield clk.posedge
|
||||
stop_time = now()
|
||||
trigger.next = 1
|
||||
yield clk.posedge
|
||||
trigger.next = 0
|
||||
yield clk.posedge
|
||||
|
||||
while output_axis_tvalid:
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
# discard first trigger output
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
# check second trigger output
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
rx_frame_values = struct.unpack(">HLLL", bytes(rx_frame.data))
|
||||
cycles = (stop_time - start_time) / 8
|
||||
print(rx_frame_values)
|
||||
|
||||
assert rx_frame_values[0] == 1
|
||||
assert rx_frame_values[1] == cycles*8
|
||||
assert rx_frame_values[2] == len(test_frame1.data) + len(test_frame2.data)
|
||||
assert rx_frame_values[3] == 2
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 9: various length packets")
|
||||
current_test.next = 9
|
||||
|
||||
yield clk.posedge
|
||||
start_time = now()
|
||||
trigger.next = 1
|
||||
yield clk.posedge
|
||||
trigger.next = 0
|
||||
|
||||
lens = [32, 48, 96, 128, 256]
|
||||
test_frame = []
|
||||
|
||||
for i in range(len(lens)):
|
||||
test_frame.append(axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
bytearray(range(lens[i]))))
|
||||
|
||||
for f in test_frame:
|
||||
source_queue.put(f)
|
||||
yield clk.posedge
|
||||
|
||||
while monitor_axis_tvalid:
|
||||
yield clk.posedge
|
||||
|
||||
while output_axis_tvalid:
|
||||
yield clk.posedge
|
||||
|
||||
yield clk.posedge
|
||||
stop_time = now()
|
||||
trigger.next = 1
|
||||
yield clk.posedge
|
||||
trigger.next = 0
|
||||
yield clk.posedge
|
||||
|
||||
while output_axis_tvalid:
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
# discard first trigger output
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
# check second trigger output
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
rx_frame_values = struct.unpack(">HLLL", bytes(rx_frame.data))
|
||||
cycles = (stop_time - start_time) / 8
|
||||
print(rx_frame_values)
|
||||
|
||||
assert rx_frame_values[0] == 1
|
||||
assert rx_frame_values[1] == cycles*8
|
||||
assert rx_frame_values[2] == sum(len(f.data) for f in test_frame)
|
||||
assert rx_frame_values[3] == len(test_frame)
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 10: various length packets with intermediate trigger")
|
||||
current_test.next = 10
|
||||
|
||||
yield clk.posedge
|
||||
start_time = now()
|
||||
trigger.next = 1
|
||||
yield clk.posedge
|
||||
trigger.next = 0
|
||||
|
||||
lens = [32, 48, 96, 128, 256]
|
||||
test_frame = []
|
||||
|
||||
for i in range(len(lens)):
|
||||
test_frame.append(axis_ep.AXIStreamFrame('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
bytearray(range(lens[i]))))
|
||||
|
||||
for f in test_frame:
|
||||
source_queue.put(f)
|
||||
yield clk.posedge
|
||||
|
||||
yield delay(200)
|
||||
|
||||
yield clk.posedge
|
||||
trigger_time = now()
|
||||
trigger.next = 1
|
||||
yield clk.posedge
|
||||
trigger.next = 0
|
||||
yield clk.posedge
|
||||
|
||||
while monitor_axis_tvalid:
|
||||
yield clk.posedge
|
||||
|
||||
while output_axis_tvalid:
|
||||
yield clk.posedge
|
||||
|
||||
yield clk.posedge
|
||||
stop_time = now()
|
||||
trigger.next = 1
|
||||
yield clk.posedge
|
||||
trigger.next = 0
|
||||
yield clk.posedge
|
||||
|
||||
while output_axis_tvalid:
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
# discard first trigger output
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
# check second trigger output
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
# check second trigger output
|
||||
if not sink_queue.empty():
|
||||
rx_frame2 = sink_queue.get()
|
||||
|
||||
rx_frame_values = struct.unpack(">HLLL", bytes(rx_frame.data))
|
||||
cycles = (stop_time - start_time) / 8
|
||||
cycles1 = (trigger_time - start_time) / 8
|
||||
print(rx_frame_values)
|
||||
|
||||
rx_frame2_values = struct.unpack(">HLLL", bytes(rx_frame2.data))
|
||||
cycles2 = (stop_time - trigger_time) / 8
|
||||
print(rx_frame2_values)
|
||||
|
||||
assert rx_frame_values[0] == 1
|
||||
assert rx_frame2_values[0] == 1
|
||||
assert rx_frame_values[1] == cycles1*8
|
||||
assert rx_frame2_values[1] == cycles2*8
|
||||
assert rx_frame_values[1] + rx_frame2_values[1] == cycles*8
|
||||
assert rx_frame_values[2] + rx_frame2_values[2] == sum(len(f.data) for f in test_frame)
|
||||
assert rx_frame_values[3] + rx_frame2_values[3] == len(test_frame)
|
||||
|
||||
yield delay(100)
|
||||
|
||||
raise StopSimulation
|
||||
|
||||
return dut, source, monitor_sink, sink, clkgen, check
|
||||
|
||||
def test_bench():
|
||||
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
||||
sim = Simulation(bench())
|
||||
sim.run()
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("Running test...")
|
||||
test_bench()
|
||||
|
102
lib/axis/tb/test_axis_stat_counter.v
Normal file
102
lib/axis/tb/test_axis_stat_counter.v
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`timescale 1 ns / 1 ps
|
||||
|
||||
module test_axis_stat_counter;
|
||||
|
||||
// Inputs
|
||||
reg clk = 0;
|
||||
reg rst = 0;
|
||||
reg [7:0] current_test = 0;
|
||||
|
||||
reg [63:0] monitor_axis_tdata = 8'd0;
|
||||
reg [7:0] monitor_axis_tkeep = 8'd0;
|
||||
reg monitor_axis_tvalid = 1'b0;
|
||||
reg monitor_axis_tready = 1'b0;
|
||||
reg monitor_axis_tlast = 1'b0;
|
||||
reg monitor_axis_tuser = 1'b0;
|
||||
reg output_axis_tready = 1'b0;
|
||||
reg [15:0] tag = 0;
|
||||
reg trigger = 0;
|
||||
|
||||
// Outputs
|
||||
wire [7:0] output_axis_tdata;
|
||||
wire output_axis_tvalid;
|
||||
wire output_axis_tlast;
|
||||
wire output_axis_tuser;
|
||||
wire busy;
|
||||
|
||||
initial begin
|
||||
// myhdl integration
|
||||
$from_myhdl(clk,
|
||||
rst,
|
||||
current_test,
|
||||
monitor_axis_tdata,
|
||||
monitor_axis_tkeep,
|
||||
monitor_axis_tvalid,
|
||||
monitor_axis_tready,
|
||||
monitor_axis_tlast,
|
||||
monitor_axis_tuser,
|
||||
output_axis_tready,
|
||||
tag,
|
||||
trigger);
|
||||
$to_myhdl(output_axis_tdata,
|
||||
output_axis_tvalid,
|
||||
output_axis_tlast,
|
||||
output_axis_tuser,
|
||||
busy);
|
||||
|
||||
// dump file
|
||||
$dumpfile("test_axis_stat_counter.lxt");
|
||||
$dumpvars(0, test_axis_stat_counter);
|
||||
end
|
||||
|
||||
axis_stat_counter #(
|
||||
.DATA_WIDTH(64)
|
||||
)
|
||||
UUT (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
// axi monitor input
|
||||
.monitor_axis_tkeep(monitor_axis_tkeep),
|
||||
.monitor_axis_tvalid(monitor_axis_tvalid),
|
||||
.monitor_axis_tready(monitor_axis_tready),
|
||||
.monitor_axis_tlast(monitor_axis_tlast),
|
||||
// axi output
|
||||
.output_axis_tdata(output_axis_tdata),
|
||||
.output_axis_tvalid(output_axis_tvalid),
|
||||
.output_axis_tready(output_axis_tready),
|
||||
.output_axis_tlast(output_axis_tlast),
|
||||
.output_axis_tuser(output_axis_tuser),
|
||||
// configuration
|
||||
.tag(tag),
|
||||
.trigger(trigger),
|
||||
// status
|
||||
.busy(busy)
|
||||
);
|
||||
|
||||
endmodule
|
231
lib/axis/tb/test_ll_axis_bridge.py
Executable file
231
lib/axis/tb/test_ll_axis_bridge.py
Executable file
@ -0,0 +1,231 @@
|
||||
#!/usr/bin/env python2
|
||||
"""
|
||||
|
||||
Copyright (c) 2014 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
"""
|
||||
|
||||
from myhdl import *
|
||||
import os
|
||||
from Queue import Queue
|
||||
|
||||
import axis_ep
|
||||
import ll_ep
|
||||
|
||||
module = 'll_axis_bridge'
|
||||
|
||||
srcs = []
|
||||
|
||||
srcs.append("../rtl/%s.v" % module)
|
||||
srcs.append("test_%s.v" % module)
|
||||
|
||||
src = ' '.join(srcs)
|
||||
|
||||
build_cmd = "iverilog -o test_%s.vvp %s" % (module, src)
|
||||
|
||||
def dut_ll_axis_bridge(clk,
|
||||
rst,
|
||||
current_test,
|
||||
|
||||
ll_data_in,
|
||||
ll_sof_in_n,
|
||||
ll_eof_in_n,
|
||||
ll_src_rdy_in_n,
|
||||
ll_dst_rdy_out_n,
|
||||
|
||||
axis_tdata,
|
||||
axis_tvalid,
|
||||
axis_tready,
|
||||
axis_tlast):
|
||||
|
||||
os.system(build_cmd)
|
||||
return Cosimulation("vvp -m myhdl test_%s.vvp -lxt2" % module,
|
||||
clk=clk,
|
||||
rst=rst,
|
||||
current_test=current_test,
|
||||
|
||||
ll_data_in=ll_data_in,
|
||||
ll_sof_in_n=ll_sof_in_n,
|
||||
ll_eof_in_n=ll_eof_in_n,
|
||||
ll_src_rdy_in_n=ll_src_rdy_in_n,
|
||||
ll_dst_rdy_out_n=ll_dst_rdy_out_n,
|
||||
|
||||
axis_tdata=axis_tdata,
|
||||
axis_tvalid=axis_tvalid,
|
||||
axis_tready=axis_tready,
|
||||
axis_tlast=axis_tlast)
|
||||
|
||||
def bench():
|
||||
|
||||
# Inputs
|
||||
clk = Signal(bool(0))
|
||||
rst = Signal(bool(0))
|
||||
current_test = Signal(intbv(0)[8:])
|
||||
|
||||
ll_data_in = Signal(intbv(0)[8:])
|
||||
ll_sof_in_n = Signal(bool(1))
|
||||
ll_eof_in_n = Signal(bool(1))
|
||||
ll_src_rdy_in_n = Signal(bool(1))
|
||||
axis_tready = Signal(bool(0))
|
||||
|
||||
# Outputs
|
||||
axis_tdata = Signal(intbv(0)[8:])
|
||||
axis_tvalid = Signal(bool(0))
|
||||
axis_tlast = Signal(bool(0))
|
||||
ll_dst_rdy_out_n = Signal(bool(1))
|
||||
|
||||
# sources and sinks
|
||||
source_queue = Queue()
|
||||
source_pause = Signal(bool(0))
|
||||
sink_queue = Queue()
|
||||
sink_pause = Signal(bool(0))
|
||||
|
||||
source = ll_ep.LocalLinkSource(clk,
|
||||
rst,
|
||||
data_out=ll_data_in,
|
||||
sof_out_n=ll_sof_in_n,
|
||||
eof_out_n=ll_eof_in_n,
|
||||
src_rdy_out_n=ll_src_rdy_in_n,
|
||||
dst_rdy_in_n=ll_dst_rdy_out_n,
|
||||
fifo=source_queue,
|
||||
pause=source_pause,
|
||||
name='source')
|
||||
|
||||
sink = axis_ep.AXIStreamSink(clk,
|
||||
rst,
|
||||
tdata=axis_tdata,
|
||||
tvalid=axis_tvalid,
|
||||
tready=axis_tready,
|
||||
tlast=axis_tlast,
|
||||
fifo=sink_queue,
|
||||
pause=sink_pause,
|
||||
name='sink')
|
||||
|
||||
# DUT
|
||||
dut = dut_ll_axis_bridge(clk,
|
||||
rst,
|
||||
current_test,
|
||||
|
||||
ll_data_in,
|
||||
ll_sof_in_n,
|
||||
ll_eof_in_n,
|
||||
ll_src_rdy_in_n,
|
||||
ll_dst_rdy_out_n,
|
||||
|
||||
axis_tdata,
|
||||
axis_tvalid,
|
||||
axis_tready,
|
||||
axis_tlast)
|
||||
|
||||
@always(delay(4))
|
||||
def clkgen():
|
||||
clk.next = not clk
|
||||
|
||||
@instance
|
||||
def check():
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
rst.next = 1
|
||||
yield clk.posedge
|
||||
rst.next = 0
|
||||
yield clk.posedge
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
|
||||
yield clk.posedge
|
||||
|
||||
yield clk.posedge
|
||||
print("test 1: test packet")
|
||||
current_test.next = 1
|
||||
|
||||
source_queue.put(bytearray('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10'))
|
||||
yield clk.posedge
|
||||
|
||||
yield axis_tlast.negedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert bytearray(rx_frame) == ('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 2: test packet with pauses")
|
||||
current_test.next = 2
|
||||
|
||||
source_queue.put(bytearray('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10'))
|
||||
yield clk.posedge
|
||||
|
||||
yield delay(64)
|
||||
yield clk.posedge
|
||||
source_pause.next = True
|
||||
yield delay(32)
|
||||
yield clk.posedge
|
||||
source_pause.next = False
|
||||
|
||||
yield delay(64)
|
||||
yield clk.posedge
|
||||
sink_pause.next = True
|
||||
yield delay(32)
|
||||
yield clk.posedge
|
||||
sink_pause.next = False
|
||||
|
||||
yield axis_tlast.negedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = None
|
||||
if not sink_queue.empty():
|
||||
rx_frame = sink_queue.get()
|
||||
|
||||
assert bytearray(rx_frame) == ('\xDA\xD1\xD2\xD3\xD4\xD5' +
|
||||
'\x5A\x51\x52\x53\x54\x55' +
|
||||
'\x80\x00' +
|
||||
'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10')
|
||||
|
||||
yield delay(100)
|
||||
|
||||
raise StopSimulation
|
||||
|
||||
return dut, source, sink, clkgen, check
|
||||
|
||||
def test_bench():
|
||||
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
||||
sim = Simulation(bench())
|
||||
sim.run()
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("Running test...")
|
||||
test_bench()
|
||||
|
85
lib/axis/tb/test_ll_axis_bridge.v
Normal file
85
lib/axis/tb/test_ll_axis_bridge.v
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`timescale 1 ns / 1 ps
|
||||
|
||||
module test_ll_axis_bridge;
|
||||
|
||||
// Inputs
|
||||
reg clk = 0;
|
||||
reg rst = 0;
|
||||
reg [7:0] current_test = 0;
|
||||
|
||||
reg [7:0] ll_data_in = 0;
|
||||
reg ll_sof_in_n = 1;
|
||||
reg ll_eof_in_n = 1;
|
||||
reg ll_src_rdy_in_n = 1;
|
||||
reg axis_tready = 0;
|
||||
|
||||
// Outputs
|
||||
wire ll_dst_rdy_out_n;
|
||||
wire [7:0] axis_tdata;
|
||||
wire axis_tvalid;
|
||||
wire axis_tlast;
|
||||
|
||||
initial begin
|
||||
// myhdl integration
|
||||
$from_myhdl(clk,
|
||||
rst,
|
||||
current_test,
|
||||
ll_data_in,
|
||||
ll_sof_in_n,
|
||||
ll_eof_in_n,
|
||||
ll_src_rdy_in_n,
|
||||
axis_tready);
|
||||
$to_myhdl(axis_tdata,
|
||||
axis_tvalid,
|
||||
axis_tlast,
|
||||
ll_dst_rdy_out_n);
|
||||
|
||||
// dump file
|
||||
$dumpfile("test_ll_axis_bridge.lxt");
|
||||
$dumpvars(0, test_ll_axis_bridge);
|
||||
end
|
||||
|
||||
ll_axis_bridge
|
||||
UUT (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
// locallink input
|
||||
.ll_data_in(ll_data_in),
|
||||
.ll_sof_in_n(ll_sof_in_n),
|
||||
.ll_eof_in_n(ll_eof_in_n),
|
||||
.ll_src_rdy_in_n(ll_src_rdy_in_n),
|
||||
.ll_dst_rdy_out_n(ll_dst_rdy_out_n),
|
||||
// axi output
|
||||
.axis_tdata(axis_tdata),
|
||||
.axis_tvalid(axis_tvalid),
|
||||
.axis_tready(axis_tready),
|
||||
.axis_tlast(axis_tlast)
|
||||
);
|
||||
|
||||
endmodule
|
Loading…
x
Reference in New Issue
Block a user