1
0
mirror of https://github.com/bmartini/zynq-axis.git synced 2024-09-05 19:19:27 +08:00

Merge branch 'update-axis'

More robust configuration that will allow for the use of the AXIS module in a
scatter/gather operation. Will be able to handle contiguous streams of
read/write data even when they are part of different configurations.
This commit is contained in:
Berin Martini 2018-07-21 14:53:18 -07:00
commit 61089223ef
20 changed files with 1077 additions and 995 deletions

View File

@ -11,7 +11,8 @@
* Author:
* Berin Martini (berin.martini@gmail.com)
*/
`ifndef _axis_ `define _axis_
`ifndef _axis_
`define _axis_
`include "axis_write.v"
@ -19,14 +20,15 @@
module axis #(
parameter
BUF_CFG_AWIDTH = 5,
BUF_AWIDTH = 9,
CONFIG_ID_WR = 1,
CONFIG_ID_RD = 2,
CONFIG_ADDR = 23,
CONFIG_DATA = 24,
CONFIG_AWIDTH = 5,
CONFIG_DWIDTH = 32,
CFG_ID_WR = 1,
CFG_ID_RD = 2,
CFG_ADDR = 23,
CFG_DATA = 24,
CFG_AWIDTH = 5,
CFG_DWIDTH = 32,
STREAM_WIDTH = 32,
@ -38,8 +40,8 @@ module axis #(
input rst,
// configuation
input [CONFIG_AWIDTH-1:0] cfg_addr,
input [CONFIG_DWIDTH-1:0] cfg_data,
input [CFG_AWIDTH-1:0] cfg_addr,
input [CFG_DWIDTH-1:0] cfg_data,
input cfg_valid,
// stream interface
@ -119,6 +121,24 @@ module axis #(
* Implementation
*/
reg [CFG_AWIDTH-1:0] cfg_addr_r;
reg [CFG_DWIDTH-1:0] cfg_data_r;
reg cfg_valid_r;
// register for improved timing
always @(posedge clk)
if (rst) cfg_valid_r <= 1'b0;
else cfg_valid_r <= cfg_valid;
// register for improved timing
always @(posedge clk) begin
cfg_addr_r <= cfg_addr;
cfg_data_r <= cfg_data;
end
// write path static values
assign axi_awlock = 1'h0; // NORMAL_ACCESS
assign axi_awcache = 4'h0; // NON_CACHE_NON_BUFFER
@ -126,8 +146,6 @@ module axis #(
assign axi_awburst = 2'h1; // INCREMENTING
assign axi_awqos = 4'h0; // NOT_QOS_PARTICIPANT
assign axi_awsize = BURST_SIZE;
assign axi_awid = {AXI_ID_WIDTH{1'b0}};
assign axi_wid = {AXI_ID_WIDTH{1'b0}};
assign axi_wstrb = {(AXI_DATA_WIDTH/8){1'b1}};
// read path static values
@ -137,7 +155,6 @@ module axis #(
assign axi_arburst = 2'h1; // INCREMENTING
assign axi_arqos = 4'h0; // NOT_QOS_PARTICIPANT
assign axi_arsize = BURST_SIZE;
assign axi_arid = {AXI_ID_WIDTH{1'b0}};
// assume that all writes are successful and therefore do not need to
@ -146,14 +163,16 @@ module axis #(
axis_write #(
.BUF_CFG_AWIDTH (BUF_CFG_AWIDTH),
.BUF_AWIDTH (BUF_AWIDTH),
.CONFIG_ID (CONFIG_ID_WR),
.CONFIG_ADDR (CONFIG_ADDR),
.CONFIG_DATA (CONFIG_DATA),
.CONFIG_AWIDTH (CONFIG_AWIDTH),
.CONFIG_DWIDTH (CONFIG_DWIDTH),
.CFG_ID (CFG_ID_WR),
.CFG_ADDR (CFG_ADDR),
.CFG_DATA (CFG_DATA),
.CFG_AWIDTH (CFG_AWIDTH),
.CFG_DWIDTH (CFG_DWIDTH),
.AXI_ID_WIDTH (AXI_ID_WIDTH),
.AXI_LEN_WIDTH (AXI_LEN_WIDTH),
.AXI_ADDR_WIDTH (AXI_ADDR_WIDTH),
.AXI_DATA_WIDTH (AXI_DATA_WIDTH),
@ -162,17 +181,20 @@ module axis #(
.clk (clk),
.rst (rst),
.cfg_addr (cfg_addr),
.cfg_data (cfg_data),
.cfg_valid (cfg_valid),
.cfg_addr (cfg_addr_r),
.cfg_data (cfg_data_r),
.cfg_valid (cfg_valid_r),
.cfg_ready (),
.axi_awready (axi_awready),
.axi_awid (axi_awid),
.axi_awaddr (axi_awaddr),
.axi_awlen (axi_awlen),
.axi_awvalid (axi_awvalid),
.axi_awready (axi_awready),
.axi_wlast (axi_wlast),
.axi_wid (axi_wid),
.axi_wdata (axi_wdata),
.axi_wlast (axi_wlast),
.axi_wvalid (axi_wvalid),
.axi_wready (axi_wready),
@ -183,14 +205,16 @@ module axis #(
axis_read #(
.BUF_CFG_AWIDTH (BUF_CFG_AWIDTH),
.BUF_AWIDTH (BUF_AWIDTH),
.CONFIG_ID (CONFIG_ID_RD),
.CONFIG_ADDR (CONFIG_ADDR),
.CONFIG_DATA (CONFIG_DATA),
.CONFIG_AWIDTH (CONFIG_AWIDTH),
.CONFIG_DWIDTH (CONFIG_DWIDTH),
.CFG_ID (CFG_ID_RD),
.CFG_ADDR (CFG_ADDR),
.CFG_DATA (CFG_DATA),
.CFG_AWIDTH (CFG_AWIDTH),
.CFG_DWIDTH (CFG_DWIDTH),
.AXI_ID_WIDTH (AXI_ID_WIDTH),
.AXI_LEN_WIDTH (AXI_LEN_WIDTH),
.AXI_ADDR_WIDTH (AXI_ADDR_WIDTH),
.AXI_DATA_WIDTH (AXI_DATA_WIDTH),
@ -199,16 +223,19 @@ module axis #(
.clk (clk),
.rst (rst),
.cfg_addr (cfg_addr),
.cfg_data (cfg_data),
.cfg_valid (cfg_valid),
.cfg_addr (cfg_addr_r),
.cfg_data (cfg_data_r),
.cfg_valid (cfg_valid_r),
.cfg_ready (),
.axi_arready (axi_arready),
.axi_arid (axi_arid),
.axi_araddr (axi_araddr),
.axi_arlen (axi_arlen),
.axi_arvalid (axi_arvalid),
.axi_arready (axi_arready),
.axi_rdata (axi_rdata),
.axi_rlast (axi_rlast),
.axi_rvalid (axi_rvalid),
.axi_rready (axi_rready),

View File

@ -14,12 +14,17 @@
* Author:
* Berin Martini (berin.martini@gmail.com)
*/
`ifndef _axis_addr_ `define _axis_addr_
`ifndef _axis_addr_
`define _axis_addr_
`include "fifo_simple.v"
`define MIN(p,q) (p)<(q)?(p):(q)
module axis_addr
#(parameter
CONFIG_DWIDTH = 32,
BUF_CFG_AWIDTH = 5,
CFG_DWIDTH = 32,
WIDTH_RATIO = 16,
CONVERT_SHIFT = 3,
AXI_LEN_WIDTH = 8,
@ -28,10 +33,10 @@ module axis_addr
(input clk,
input rst,
input [CONFIG_DWIDTH-1:0] cfg_address,
input [CONFIG_DWIDTH-1:0] cfg_length,
input cfg_valid,
output cfg_ready,
input [CFG_DWIDTH-1:0] cfg_address,
input [CFG_DWIDTH-1:0] cfg_length,
input cfg_val,
output cfg_rdy,
input axi_aready,
output [AXI_ADDR_WIDTH-1:0] axi_aaddr,
@ -43,11 +48,12 @@ module axis_addr
* Local parameters
*/
localparam BURST_NB_WIDTH = CONFIG_DWIDTH-AXI_LEN_WIDTH;
localparam AWIDTH = `MIN(CFG_DWIDTH, AXI_ADDR_WIDTH);
localparam BURST_NB_WIDTH = CFG_DWIDTH-AXI_LEN_WIDTH;
localparam BURST_LENGTH = 1<<AXI_LEN_WIDTH;
localparam
IDLE = 0,
CONFIG = 0,
SETUP = 1,
BURST = 2,
LAST = 3,
@ -68,6 +74,13 @@ module axis_addr
reg [4:0] state;
reg [4:0] state_nx;
wire cfg_buf_pop;
wire cfg_buf_full;
wire cfg_buf_empty;
wire [CFG_DWIDTH-1:0] cfg_buf_address;
wire [CFG_DWIDTH-1:0] cfg_buf_length;
reg cfg_buf_valid;
reg last_en;
reg [AXI_LEN_WIDTH-1:0] last_nb;
@ -76,61 +89,71 @@ module axis_addr
reg [BURST_NB_WIDTH-1:0] burst_cnt;
wire burst_done;
reg [CONFIG_DWIDTH-1:0] cfg_length_r;
reg cfg_valid_r;
reg [AXI_ADDR_WIDTH-1:0] axi_address;
reg [CFG_DWIDTH-1:0] axi_length;
reg axi_valid;
reg cfg_done;
reg [CONFIG_DWIDTH-1:0] axi_address;
/**
* Implementation
*/
assign cfg_ready = state[IDLE];
assign axi_aaddr = axi_address;
assign cfg_rdy = ~cfg_buf_full;
assign axi_alen = state[BURST] ? (BURST_LENGTH-1) : last_nb;
assign axi_avalid = state[BURST] | state[LAST];
fifo_simple #(
.DATA_WIDTH (2*CFG_DWIDTH),
.ADDR_WIDTH (BUF_CFG_AWIDTH))
cfg_buffer_ (
.clk (clk),
.rst (rst),
assign burst_done = (burst_nb == burst_cnt);
.count (),
.empty (cfg_buf_empty),
.empty_a (),
.full (cfg_buf_full),
.full_a (),
.push_data ({cfg_address, cfg_length}),
.push (cfg_val),
.pop_data ({cfg_buf_address, cfg_buf_length}),
.pop (cfg_buf_pop)
);
assign cfg_buf_pop = ~cfg_buf_empty & state[CONFIG];
always @(posedge clk)
if (rst) cfg_valid_r <= 1'b0;
else cfg_valid_r <= cfg_valid;
if (rst) begin
cfg_buf_valid <= 1'b0;
axi_valid <= 1'b0;
cfg_done <= 1'b0;
end
else begin
cfg_buf_valid <= cfg_buf_pop;
axi_valid <= cfg_buf_valid;
cfg_done <= axi_valid;
end
always @(posedge clk)
if (cfg_valid) begin
if (cfg_buf_valid) begin
// the shift converts from number of stream elements to number of
// bursts to be sent to the memory after stream is packed. adding a
// bit to the length ensures that the shift rounds up
cfg_length_r <= (cfg_length+WIDTH_RATIO-1) >> CONVERT_SHIFT;
axi_length <= (cfg_buf_length+WIDTH_RATIO-1) >> CONVERT_SHIFT;
end
always @(posedge clk)
if (rst) cfg_done <= 1'b0;
else cfg_done <= cfg_valid_r;
always @(posedge clk)
if (cfg_valid_r) begin
last_en <= |(cfg_length_r[AXI_LEN_WIDTH-1:0]);
last_nb <= cfg_length_r[AXI_LEN_WIDTH-1:0]-1;
burst_en <= |(cfg_length_r[AXI_LEN_WIDTH +: BURST_NB_WIDTH]);
burst_nb <= cfg_length_r[AXI_LEN_WIDTH +: BURST_NB_WIDTH]-1;
end
always @(posedge clk)
if (cfg_valid) begin
axi_address <= cfg_address;
if (cfg_buf_valid) begin
axi_address <= {AXI_ADDR_WIDTH{1'b0}};
axi_address[AWIDTH-1:0] <= cfg_buf_address[AWIDTH-1:0];
end
else if (axi_aready & state[BURST]) begin
// e.g. each burst has 256 long words & each long word has 32 bytes
@ -139,7 +162,17 @@ module axis_addr
always @(posedge clk)
if (state[IDLE]) begin
if (axi_valid) begin
last_en <= |(axi_length[AXI_LEN_WIDTH-1:0]);
last_nb <= axi_length[AXI_LEN_WIDTH-1:0]-1;
burst_en <= |(axi_length[AXI_LEN_WIDTH +: BURST_NB_WIDTH]);
burst_nb <= axi_length[AXI_LEN_WIDTH +: BURST_NB_WIDTH]-1;
end
always @(posedge clk)
if (axi_valid) begin
burst_cnt <= 'b0;
end
else if (axi_aready & state[BURST]) begin
@ -147,10 +180,13 @@ module axis_addr
end
assign burst_done = (burst_nb == burst_cnt);
always @(posedge clk)
if (rst) begin
state <= 'b0;
state[IDLE] <= 1'b1;
state <= 'b0;
state[CONFIG] <= 1'b1;
end
else state <= state_nx;
@ -159,11 +195,11 @@ module axis_addr
state_nx = 'b0;
case (1'b1)
state[IDLE] : begin
if (cfg_valid) begin
state[CONFIG] : begin
if ( ~cfg_buf_empty) begin
state_nx[SETUP] = 1'b1;
end
else state_nx[IDLE] = 1'b1;
else state_nx[CONFIG] = 1'b1;
end
state[SETUP] : begin
if (cfg_done & burst_en) begin
@ -190,15 +226,24 @@ module axis_addr
else state_nx[LAST] = 1'b1;
end
state[DONE] : begin
state_nx[IDLE] = 1'b1;
state_nx[CONFIG] = 1'b1;
end
default : begin
state_nx[IDLE] = 1'b1;
state_nx[CONFIG] = 1'b1;
end
endcase
end
assign axi_aaddr = axi_address;
assign axi_alen = state[BURST] ? (BURST_LENGTH-1) : last_nb;
assign axi_avalid = state[BURST] | state[LAST];
endmodule
`undef MIN
`endif // `ifndef _axis_addr_

View File

@ -50,7 +50,7 @@ module axis_addr_tb;
* Local parameters
*/
localparam CONFIG_DWIDTH = 32;
localparam CFG_DWIDTH = 32;
localparam WIDTH_RATIO = 16;
localparam AXI_LEN_WIDTH = 8;
localparam AXI_ADDR_WIDTH = 32;
@ -67,10 +67,10 @@ module axis_addr_tb;
reg rst;
reg [CONFIG_DWIDTH-1:0] cfg_address;
reg [CONFIG_DWIDTH-1:0] cfg_length;
reg cfg_valid;
wire cfg_ready;
reg [CFG_DWIDTH-1:0] cfg_address;
reg [CFG_DWIDTH-1:0] cfg_length;
reg cfg_val;
wire cfg_rdy;
reg axi_aready;
wire [AXI_ADDR_WIDTH-1:0] axi_aaddr;
@ -83,7 +83,7 @@ module axis_addr_tb;
*/
axis_addr #(
.CONFIG_DWIDTH (CONFIG_DWIDTH),
.CFG_DWIDTH (CFG_DWIDTH),
.WIDTH_RATIO (WIDTH_RATIO),
.CONVERT_SHIFT ($clog2(WIDTH_RATIO)),
.AXI_LEN_WIDTH (AXI_LEN_WIDTH),
@ -94,8 +94,8 @@ module axis_addr_tb;
.cfg_address (cfg_address),
.cfg_length (cfg_length),
.cfg_valid (cfg_valid),
.cfg_ready (cfg_ready),
.cfg_val (cfg_val),
.cfg_rdy (cfg_rdy),
.axi_aready (axi_aready),
.axi_aaddr (axi_aaddr),
@ -116,8 +116,8 @@ module axis_addr_tb;
"\t%d\t%d\t%b\t%b",
cfg_address,
cfg_length,
cfg_valid,
cfg_ready,
cfg_val,
cfg_rdy,
"\t%d\t%d\t%b\t%b",
axi_aaddr,
@ -169,7 +169,7 @@ module axis_addr_tb;
cfg_address = 'b0;
cfg_length = 'b0;
cfg_valid = 'b0;
cfg_val = 'b0;
axi_aready = 'b0;
//end init
@ -193,11 +193,11 @@ module axis_addr_tb;
cfg_address <= 255;
//cfg_length <= 8;
cfg_length <= 256+256+64;
cfg_valid <= 1'b1;
cfg_val <= 1'b1;
@(negedge clk);
cfg_address <= 'b0;
cfg_length <= 'b0;
cfg_valid <= 1'b0;
cfg_val <= 1'b0;
repeat(5) @(negedge clk);

View File

@ -1,107 +0,0 @@
/**
* Module:
* axis_deserializer
*
* Description:
* Deserializes multiple 'up' flow bus data words into a single, larger
* 'down' data words. Arranges them first to the right and moving left.
*
* If there is a pause in the incoming 'up' stream the values already written
* into the larger 'down' word will stay until enough 'up' data has been sent
* in to complete the 'down' word unless a 'up_last' signal forces the down
* transfer. The module will stall when the down_ready flag deasserts.
*
* Testbench:
* axis_deserializer_tb.v
*
* Created:
* Thu Nov 6 17:29:58 EST 2014
*
* Authors:
* Berin Martini (berin.martini@gmail.com)
*/
`ifndef _axis_deserializer_ `define _axis_deserializer_
module axis_deserializer
#(parameter
DATA_NB = 2,
DATA_WIDTH = 8)
(input clk,
input rst,
output up_ready,
input up_valid,
input [DATA_WIDTH-1:0] up_data,
input up_last,
input down_ready,
output reg down_valid,
output reg [(DATA_WIDTH*DATA_NB)-1:0] down_data,
output reg down_last
);
/**
* Local parameters
*/
`ifdef VERBOSE
initial $display("\using 'axis_deserializer' with %0d words\n", DATA_NB);
`endif
/**
* Internal signals
*/
genvar ii;
wire [DATA_NB:0] token_i;
reg [DATA_NB-1:0] token;
/**
* Implementation
*/
assign token_i = {token, token[DATA_NB-1]};
assign up_ready = down_ready;
always @(posedge clk)
if (rst) down_last <= 1'b0;
else if (down_ready) down_last <= up_last;
always @(posedge clk)
if (rst) down_valid <= 1'b0;
else if (down_ready) begin
down_valid <= (token[DATA_NB-1] & up_valid) | up_last;
end
always @(posedge clk)
if (rst | (down_ready & up_last)) token <= 'b1;
else if (down_ready & up_valid) begin
token <= token_i[0 +: DATA_NB];
end
generate
for (ii=0; ii<DATA_NB; ii=ii+1) begin : CONCAT_
always @(posedge clk)
if (down_ready & token[ii]) begin
down_data[ii*DATA_WIDTH +: DATA_WIDTH] <= up_data;
end
end
endgenerate
endmodule
`endif // `ifndef _axis_deserializer_

231
hdl/axis/axis_gbox.v Normal file
View File

@ -0,0 +1,231 @@
/**
* Module:
* axis_gbox
*
* Description:
* The AXIS Gear Box will serializes or deserializes a stream of data
* depending of the relative widths of the streams. Is only one register deep.
*
* Serializes the 'up' data word into multiple smaller 'down' data words. The
* module will stall when the dn_rdy flag deasserts.
*
* Deserializes multiple 'up' flow bus data words into a single, larger
* 'down' data words. Arranges them first to the right and moving left. If
* there is a pause in the incoming 'up' stream the values already written
* into the larger 'down' word will stay until enough 'up' data has been sent
* in to complete the 'down' word unless a 'up_last' signal forces the down
* transfer. The module will stall when the 'dn_rdy' flag deasserts.
*
* Testbench:
* axis_gbox_tb.v
*
* Created:
* Sun Jun 3 17:57:34 PDT 2018
*
* Authors:
* Berin Martini (berin.martini@gmail.com)
*/
`ifndef _axis_gbox_
`define _axis_gbox_
module axis_gbox
#(parameter
DATA_UP_WIDTH = 2,
DATA_DN_WIDTH = 8)
(input clk,
input rst,
input [DATA_UP_WIDTH-1:0] up_data,
input up_last,
input up_val,
output up_rdy,
output [DATA_DN_WIDTH-1:0] dn_data,
output dn_last,
output dn_val,
input dn_rdy
);
/**
* Local parameters
*/
`ifdef VERBOSE
initial begin
$display("<axis_gbox> up words: %d, dn word: %d\n"
, DATA_UP_WIDTH
, DATA_DN_WIDTH
);
`endif
/**
* Internal signals
*/
/**
* Implementation
*/
generate
if (DATA_UP_WIDTH == DATA_DN_WIDTH) begin : PASS_
reg [DATA_DN_WIDTH-1:0] dn_data_i;
reg dn_last_i;
reg dn_val_i;
assign up_rdy = dn_rdy;
assign dn_data = dn_data_i;
assign dn_last = dn_last_i & dn_rdy;
assign dn_val = dn_val_i & dn_rdy;
always @(posedge clk)
if (dn_rdy & up_val) begin
dn_data_i <= up_data;
end
always @(posedge clk)
if (rst) dn_last_i <= 1'b0;
else if (dn_rdy) dn_last_i <= up_val & up_last;
always @(posedge clk)
if (rst) dn_val_i <= 1'b0;
else if (dn_rdy) dn_val_i <= up_val;
end
else if (DATA_UP_WIDTH > DATA_DN_WIDTH) begin : SERIAL_
localparam DATA_NB = DATA_UP_WIDTH/DATA_DN_WIDTH;
wire [2*DATA_NB-1:0] token_nx;
reg [DATA_NB-1:0] token;
reg [DATA_UP_WIDTH-1:0] serial_data;
reg [DATA_NB-1:0] serial_last;
reg [DATA_NB-1:0] serial_valid;
assign up_rdy = dn_rdy & token[0];
assign dn_data = serial_data[0 +: DATA_DN_WIDTH];
assign dn_last = serial_last[0] & dn_rdy;
assign dn_val = serial_valid[0] & dn_rdy;
assign token_nx = {token, token};
always @(posedge clk)
if (rst) token <= 'b1;
else if (dn_rdy) begin
if ( ~token[0] | (up_rdy & up_val)) begin
token <= token_nx[DATA_NB-1 +: DATA_NB];
end
end
always @(posedge clk)
if (dn_rdy) begin
serial_data <= serial_data >> DATA_DN_WIDTH;
if (up_rdy & up_val) begin
serial_data <= up_data;
end
end
always @(posedge clk)
if (rst) serial_last <= 'b0;
else if (dn_rdy) begin
serial_last <= serial_last >> 1;
if (up_rdy & up_val & up_last) begin
serial_last <= 'b0;
serial_last[DATA_NB-1] <= 1'b1;
end
end
always @(posedge clk)
if (rst) serial_valid <= 'b0;
else if (dn_rdy) begin
serial_valid <= serial_valid >> 1;
if (up_rdy & up_val) begin
serial_valid <= {DATA_NB{1'b1}};
end
end
end
else if (DATA_UP_WIDTH < DATA_DN_WIDTH) begin : DSERIAL_
localparam DATA_NB = DATA_DN_WIDTH/DATA_UP_WIDTH;
integer ii;
wire [2*DATA_NB-1:0] token_nx;
reg [DATA_NB-1:0] token;
reg [DATA_DN_WIDTH-1:0] dn_data_i;
reg dn_last_i;
reg dn_val_i;
assign up_rdy = dn_rdy;
assign dn_data = dn_data_i;
assign dn_last = dn_last_i & dn_rdy;
assign dn_val = dn_val_i & dn_rdy;
assign token_nx = {token, token};
always @(posedge clk)
if (rst) dn_last_i <= 1'b0;
else if (dn_rdy) begin
dn_last_i <= up_val & up_last;
end
always @(posedge clk)
if (rst) dn_val_i <= 1'b0;
else if (dn_rdy) begin
dn_val_i <= (token[DATA_NB-1] & up_val) | (up_val & up_last);
end
always @(posedge clk)
if (rst | (dn_rdy & up_val & up_last)) token <= 'b1;
else if (dn_rdy & up_val) begin
token <= token_nx[DATA_NB-1 +: DATA_NB];
end
always @(posedge clk)
for (ii=0; ii<DATA_NB; ii=ii+1) begin
if (dn_rdy & token[ii]) begin
dn_data_i[ii*DATA_UP_WIDTH +: DATA_UP_WIDTH] <= up_data;
end
end
end
endgenerate
endmodule
`endif // `ifndef _axis_gbox_

View File

@ -1,9 +1,9 @@
/**
* Testbench for:
* axis_deserializer
* axis_gbox
*
* Created:
* Thu Nov 6 17:29:45 EST 2014
* Sun Jun 3 17:57:21 PDT 2018
*
* Author:
* Berin Martini (berin.martini@gmail.com)
@ -15,9 +15,9 @@
//`define VERBOSE
`include "axis_deserializer.v"
`include "axis_gbox.v"
module axis_deserializer_tb;
module axis_gbox_tb;
/**
* Clock and control functions
@ -50,15 +50,22 @@ module axis_deserializer_tb;
* Local parameters
*/
localparam DATA_NB = 3;
localparam DATA_WIDTH = 8;
localparam DATA_UP_WIDTH = 24;
localparam DATA_DN_WIDTH = 8;
localparam DATA_NB = DATA_UP_WIDTH/DATA_DN_WIDTH;
//localparam DATA_UP_WIDTH = 8;
//localparam DATA_DN_WIDTH = 24;
//localparam DATA_NB = DATA_DN_WIDTH/DATA_UP_WIDTH;
localparam STREAM_LENGTH = 256;
localparam STREAM_WIDTH = (DATA_DN_WIDTH < DATA_UP_WIDTH) ?
DATA_DN_WIDTH : DATA_UP_WIDTH ;
`ifdef TB_VERBOSE
initial begin
$display("Testbench for unit 'axis_deserializer' data width: %d, nb: %d",
DATA_WIDTH, DATA_NB);
$display("Testbench for unit 'axis_gbox' data up width: %d, down: %d",
DATA_UP_WIDTH, DATA_DN_WIDTH);
end
`endif
@ -67,41 +74,41 @@ module axis_deserializer_tb;
* signals, registers and wires
*/
reg rst;
reg rst;
reg [DATA_WIDTH-1:0] up_data;
reg up_valid;
wire up_ready;
reg up_last;
wire [DATA_UP_WIDTH-1:0] up_data;
reg up_last;
wire up_val;
wire up_rdy;
wire [DATA_NB*DATA_WIDTH-1:0] down_data;
wire down_valid;
reg down_ready;
wire down_last;
wire [DATA_DN_WIDTH-1:0] dn_data;
wire dn_last;
wire dn_val;
reg dn_rdy;
reg [DATA_WIDTH-1:0] stream [0:STREAM_LENGTH-1];
integer cnt;
reg [STREAM_WIDTH-1:0] stream [0:STREAM_LENGTH-1];
integer cnt;
/**
* Unit under test
*/
axis_deserializer #(
.DATA_NB (DATA_NB),
.DATA_WIDTH (DATA_WIDTH))
axis_gbox #(
.DATA_UP_WIDTH (DATA_UP_WIDTH),
.DATA_DN_WIDTH (DATA_DN_WIDTH))
uut (
.clk (clk),
.rst (rst),
.up_data (up_data),
.up_valid (up_valid),
.up_ready (up_ready),
.up_last (up_last),
.up_val (up_val),
.up_rdy (up_rdy),
.down_data (down_data),
.down_valid (down_valid),
.down_ready (down_ready),
.down_last (down_last)
.dn_data (dn_data),
.dn_last (dn_last),
.dn_val (dn_val),
.dn_rdy (dn_rdy)
);
@ -114,20 +121,21 @@ module axis_deserializer_tb;
"%d\t%d",
$time, rst,
"\t%x\t%b\t%b\t%b",
"\tu: %x",
up_data,
up_valid,
up_ready,
"\tv %b\tr %b\tl %b",
up_val,
up_rdy,
up_last,
"\t%x\t%b\t%b\t%b",
down_data,
down_valid,
down_ready,
down_last,
dn_data,
dn_val,
dn_rdy,
dn_last,
);
endtask // display_signals
task display_header;
@ -135,7 +143,7 @@ module axis_deserializer_tb;
"\t\ttime\trst",
"\tu_d",
"\tu_v",
"\t\tu_v",
"\tu_r",
"\tu_l",
@ -152,25 +160,17 @@ module axis_deserializer_tb;
* Testbench program
*/
assign up_data = {stream[cnt]+4'd2, stream[cnt]+4'd1, stream[cnt]};
//assign up_data = stream[cnt];
assign up_val = 1'b1;
always @(posedge clk)
if (up_ready) begin
if (up_rdy & up_val) begin
cnt <= cnt + 1;
end
always @(posedge clk)
up_data <= stream[cnt];
always @(posedge clk) begin
up_valid <= 1'b0;
if (up_ready) begin
up_valid <= 1'b1;
end
end
initial begin
// init values
@ -178,12 +178,12 @@ module axis_deserializer_tb;
rst = 0;
up_last = 'b0;
down_ready = 'b0;
dn_rdy = 'b0;
cnt = 0;
repeat (STREAM_LENGTH) begin
stream[cnt] = cnt + 1;
stream[cnt] = (DATA_NB*cnt)+1;
//stream[cnt] = cnt + 1;
cnt = cnt + 1;
end
cnt = 0;
@ -203,9 +203,10 @@ module axis_deserializer_tb;
$display("test continuous ready");
`endif
down_ready <= 1'b1;
@(negedge clk);
dn_rdy <= 1'b1;
repeat(20) @(negedge clk);
down_ready <= 1'b0;
dn_rdy <= 1'b0;
repeat(10) @(negedge clk);
@ -213,41 +214,28 @@ module axis_deserializer_tb;
$display("test non-continuous ready");
`endif
down_ready <= 1'b1;
dn_rdy <= 1'b1;
repeat(20) @(negedge clk);
down_ready <= 1'b0;
dn_rdy <= 1'b0;
up_last <= 1'b1;
@(negedge clk);
down_ready <= 1'b1;
dn_rdy <= 1'b1;
repeat (3) @(negedge clk);
up_last <= 1'b0;
repeat(5) @(negedge clk);
down_ready <= 1'b0;
dn_rdy <= 1'b0;
repeat(5) @(negedge clk);
down_ready <= 1'b1;
dn_rdy <= 1'b1;
repeat(5) @(negedge clk);
down_ready <= 1'b0;
dn_rdy <= 1'b0;
repeat(10) @(negedge clk);
down_ready <= 1'b1;
dn_rdy <= 1'b1;
@(negedge clk);
down_ready <= 1'b0;
repeat(10) @(negedge clk);
`ifdef TB_VERBOSE
$display("test continuous ready with unalined last");
`endif
cnt <= 0;
repeat(3) @(negedge clk);
down_ready <= 1'b1;
//repeat(15) @(negedge clk);
repeat(16) @(negedge clk);
//repeat(17) @(negedge clk);
//repeat(18) @(negedge clk);
up_last <= 1'b1;
dn_rdy <= 1'b0;
@(negedge clk);
up_last <= 1'b0;
repeat(5) @(negedge clk);
down_ready <= 1'b0;
dn_rdy <= 1'b1;
@(negedge clk);
dn_rdy <= 1'b0;
repeat(10) @(negedge clk);

View File

@ -7,7 +7,7 @@
* the large words that are returned by the AXI into a system stream.
*
* Test bench:
* axis_write_tb.v
* axis_read_tb.v
*
* Created:
* Fri Nov 7 17:23:00 EST 2014
@ -15,7 +15,8 @@
* Author:
* Berin Martini (berin.martini@gmail.com)
*/
`ifndef _axis_read_ `define _axis_read_
`ifndef _axis_read_
`define _axis_read_
`include "axis_addr.v"
@ -23,14 +24,16 @@
module axis_read
#(parameter
BUF_CFG_AWIDTH = 5,
BUF_AWIDTH = 9,
CONFIG_ID = 1,
CONFIG_ADDR = 23,
CONFIG_DATA = 24,
CONFIG_AWIDTH = 5,
CONFIG_DWIDTH = 32,
CFG_ID = 1,
CFG_ADDR = 23,
CFG_DATA = 24,
CFG_AWIDTH = 5,
CFG_DWIDTH = 32,
AXI_ID_WIDTH = 8,
AXI_LEN_WIDTH = 8,
AXI_ADDR_WIDTH = 32,
AXI_DATA_WIDTH = 32,
@ -38,16 +41,19 @@ module axis_read
(input clk,
input rst,
input [CONFIG_AWIDTH-1:0] cfg_addr,
input [CONFIG_DWIDTH-1:0] cfg_data,
input [CFG_AWIDTH-1:0] cfg_addr,
input [CFG_DWIDTH-1:0] cfg_data,
input cfg_valid,
output cfg_ready,
input axi_arready,
output reg [AXI_ID_WIDTH-1:0] axi_arid,
output [AXI_ADDR_WIDTH-1:0] axi_araddr,
output [AXI_LEN_WIDTH-1:0] axi_arlen,
output axi_arvalid,
input axi_arready,
input [AXI_DATA_WIDTH-1:0] axi_rdata,
input axi_rlast,
input axi_rvalid,
output axi_rready,
@ -61,14 +67,13 @@ module axis_read
*/
localparam WIDTH_RATIO = AXI_DATA_WIDTH/DATA_WIDTH;
localparam CONFIG_NB = 2;
localparam STORE_WIDTH = CONFIG_DWIDTH*CONFIG_NB;
localparam CFG_NB = 2;
localparam STORE_WIDTH = CFG_DWIDTH*CFG_NB;
localparam
C_IDLE = 0,
C_CONFIG = 1,
C_WAIT = 2,
C_ENABLE = 3;
C_STALL = 2;
`ifdef VERBOSE
@ -81,23 +86,19 @@ module axis_read
*/
reg [3:0] c_state;
reg [3:0] c_state_nx;
reg [2:0] c_state;
reg [2:0] c_state_nx;
wire cfg_addr_ready;
wire cfg_data_ready;
reg [CONFIG_AWIDTH-1:0] cfg_addr_r;
reg [CONFIG_DWIDTH-1:0] cfg_data_r;
reg cfg_valid_r;
wire [STORE_WIDTH+CONFIG_DWIDTH-1:0] cfg_store_i;
wire [STORE_WIDTH+CFG_DWIDTH-1:0] cfg_store_i;
reg [STORE_WIDTH-1:0] cfg_store;
reg [7:0] cfg_cnt;
wire cfg_done;
wire [CONFIG_DWIDTH-1:0] start_addr;
reg [CONFIG_DWIDTH-1:0] cfg_address;
wire [CONFIG_DWIDTH-1:0] str_length;
reg [CONFIG_DWIDTH-1:0] cfg_length;
wire [CFG_DWIDTH-1:0] cfg_address;
wire [CFG_DWIDTH-1:0] cfg_length;
reg cfg_enable;
wire id_valid;
wire addressed;
@ -108,30 +109,21 @@ module axis_read
* Implementation
*/
assign cfg_store_i = {cfg_store, cfg_data_r};
assign cfg_store_i = {cfg_store, cfg_data};
assign start_addr = cfg_store[CONFIG_DWIDTH +: CONFIG_DWIDTH];
assign cfg_address = cfg_store[CFG_DWIDTH +: CFG_DWIDTH];
assign str_length = cfg_store[0 +: CONFIG_DWIDTH];
assign cfg_length = cfg_store[0 +: CFG_DWIDTH];
assign id_valid = (CONFIG_ID == cfg_data_r);
assign id_valid = (CFG_ID == cfg_data);
assign addressed = (CONFIG_ADDR == cfg_addr_r) & cfg_valid_r;
assign addressed = (CFG_ADDR == cfg_addr) & cfg_valid;
assign axis_data = (CONFIG_DATA == cfg_addr_r) & cfg_valid_r;
assign axis_data = (CFG_DATA == cfg_addr) & cfg_valid;
assign cfg_ready = ~c_state[C_STALL];
// register for improved timing
always @(posedge clk)
if (rst) cfg_valid_r <= 1'b0;
else cfg_valid_r <= cfg_valid;
// register for improved timing
always @(posedge clk) begin
cfg_addr_r <= cfg_addr;
cfg_data_r <= cfg_data;
end
assign cfg_done = ((CFG_NB-1) == cfg_cnt);
always @(posedge clk)
@ -144,22 +136,25 @@ module axis_read
cfg_cnt <= 'b0;
if (c_state[C_CONFIG]) begin
cfg_cnt <= cfg_cnt + {7'b0, axis_data};
cfg_cnt <= cfg_cnt + {7'd0, axis_data};
end
end
always @(posedge clk)
if (rst) cfg_enable <= 1'b0;
else cfg_enable <= c_state[C_ENABLE];
always @(posedge clk) begin
if (c_state[C_ENABLE]) begin
cfg_address <= start_addr;
cfg_length <= str_length;
if (rst) cfg_enable <= 1'b0;
else if ( ~c_state[C_STALL]) begin
cfg_enable <= c_state[C_CONFIG] & axis_data & cfg_done;
end
always @(posedge clk)
if (rst) begin
axi_arid <= {AXI_ID_WIDTH{1'b0}};
end
else if (axi_arvalid && axi_arready) begin
axi_arid <= axi_arid + {{(AXI_ID_WIDTH-1){1'b0}}, 1'b1};
end
end
always @(posedge clk)
@ -181,19 +176,19 @@ module axis_read
else c_state_nx[C_IDLE] = 1'b1;
end
c_state[C_CONFIG] : begin
if (axis_data & ((CONFIG_NB-1) <= cfg_cnt)) begin
c_state_nx[C_WAIT] = 1'b1;
if (axis_data & cfg_done & cfg_addr_ready & cfg_data_ready) begin
c_state_nx[C_IDLE] = 1'b1;
end
else if (axis_data & cfg_done) begin
c_state_nx[C_STALL] = 1'b1;
end
else c_state_nx[C_CONFIG] = 1'b1;
end
c_state[C_WAIT] : begin
c_state[C_STALL] : begin
if (cfg_addr_ready & cfg_data_ready) begin
c_state_nx[C_ENABLE] = 1'b1;
c_state_nx[C_IDLE] = 1'b1;
end
else c_state_nx[C_WAIT] = 1'b1;
end
c_state[C_ENABLE] : begin
c_state_nx[C_IDLE] = 1'b1;
else c_state_nx[C_STALL] = 1'b1;
end
default : begin
c_state_nx[C_IDLE] = 1'b1;
@ -203,9 +198,11 @@ module axis_read
axis_addr #(
.CONFIG_DWIDTH (CONFIG_DWIDTH),
.BUF_CFG_AWIDTH (BUF_CFG_AWIDTH),
.CFG_DWIDTH (CFG_DWIDTH),
.WIDTH_RATIO (WIDTH_RATIO),
.CONVERT_SHIFT ($clog2(WIDTH_RATIO)),
.AXI_LEN_WIDTH (AXI_LEN_WIDTH),
.AXI_ADDR_WIDTH (AXI_ADDR_WIDTH),
.AXI_DATA_WIDTH (AXI_DATA_WIDTH))
@ -215,8 +212,8 @@ module axis_read
.cfg_address (cfg_address),
.cfg_length (cfg_length),
.cfg_valid (cfg_enable),
.cfg_ready (cfg_addr_ready),
.cfg_val (cfg_enable & ~c_state[C_STALL]),
.cfg_rdy (cfg_addr_ready),
.axi_aready (axi_arready),
.axi_aaddr (axi_araddr),
@ -226,9 +223,10 @@ module axis_read
axis_read_data #(
.BUF_CFG_AWIDTH (BUF_CFG_AWIDTH),
.BUF_AWIDTH (BUF_AWIDTH),
.CONFIG_DWIDTH (CONFIG_DWIDTH),
.WIDTH_RATIO (WIDTH_RATIO),
.CFG_DWIDTH (CFG_DWIDTH),
.AXI_DATA_WIDTH (AXI_DATA_WIDTH),
.DATA_WIDTH (DATA_WIDTH))
axis_read_data_ (
@ -236,10 +234,11 @@ module axis_read
.rst (rst),
.cfg_length (cfg_length),
.cfg_valid (cfg_enable),
.cfg_ready (cfg_data_ready),
.cfg_val (cfg_enable & ~c_state[C_STALL]),
.cfg_rdy (cfg_data_ready),
.axi_rdata (axi_rdata),
.axi_rlast (axi_rlast),
.axi_rvalid (axi_rvalid),
.axi_rready (axi_rready),

View File

@ -14,33 +14,35 @@
* Author:
* Berin Martini (berin.martini@gmail.com)
*/
`ifndef _axis_read_data_ `define _axis_read_data_
`ifndef _axis_read_data_
`define _axis_read_data_
`include "fifo_simple.v"
`include "axis_serializer.v"
`include "axis_gbox.v"
module axis_read_data
#(parameter
BUF_CFG_AWIDTH = 5,
BUF_AWIDTH = 9,
CONFIG_DWIDTH = 32,
WIDTH_RATIO = 2,
CFG_DWIDTH = 32,
AXI_DATA_WIDTH = 64,
DATA_WIDTH = 32)
(input clk,
input rst,
input [CONFIG_DWIDTH-1:0] cfg_length,
input cfg_valid,
output cfg_ready,
input [CFG_DWIDTH-1:0] cfg_length,
input cfg_val,
output cfg_rdy,
input [AXI_DATA_WIDTH-1:0] axi_rdata,
input axi_rlast,
input axi_rvalid,
output axi_rready,
output [DATA_WIDTH-1:0] data,
output reg valid,
output valid,
input ready
);
@ -49,10 +51,10 @@ module axis_read_data
*/
localparam
IDLE = 0,
ACTIVE = 1,
WAIT = 2,
DONE = 3;
RESET = 0,
CONFIG = 1,
SET = 2,
ACTIVE = 3;
`ifdef VERBOSE
@ -67,84 +69,122 @@ module axis_read_data
reg [3:0] state;
reg [3:0] state_nx;
reg [CONFIG_DWIDTH-1:0] str_cnt;
reg [CONFIG_DWIDTH-1:0] str_length;
wire cfg_buf_pop;
wire cfg_buf_full;
wire cfg_buf_empty;
wire [CFG_DWIDTH-1:0] cfg_buf_length;
wire buf_pop;
wire buf_full;
reg [CFG_DWIDTH-1:0] str_cnt;
reg [CFG_DWIDTH-1:0] str_length;
wire buf_afull;
wire buf_empty;
wire [DATA_WIDTH-1:0] buf_data;
wire buf_valid;
wire [AXI_DATA_WIDTH-1:0] buf_data;
wire buf_last;
reg buf_en;
wire buf_pop;
wire buf_rdy;
/**
* Implementation
*/
assign cfg_ready = state[IDLE];
assign buf_pop = ~buf_empty & ready;
assign cfg_rdy = ~cfg_buf_full;
fifo_simple #(
.DATA_WIDTH (CFG_DWIDTH),
.ADDR_WIDTH (BUF_CFG_AWIDTH))
cfg_buffer_ (
.clk (clk),
.rst (rst),
.count (),
.empty (cfg_buf_empty),
.empty_a (),
.full (cfg_buf_full),
.full_a (),
.push_data (cfg_length),
.push (cfg_val),
.pop_data (cfg_buf_length),
.pop (cfg_buf_pop)
);
assign cfg_buf_pop = ~cfg_buf_empty & state[CONFIG];
always @(posedge clk)
if (cfg_valid) begin
str_length <= cfg_length-1;
if (state[SET]) begin
str_length <= cfg_buf_length-1;
end
always @(posedge clk)
if (state[IDLE]) str_cnt <= 'b0;
else if (buf_pop) begin
if (state[SET]) str_cnt <= 'b0;
else if (valid) begin
str_cnt <= str_cnt + 'b1;
end
always @(posedge clk)
if (rst) valid <= 1'b0;
else valid <= buf_pop & state[ACTIVE];
assign axi_rready = ~buf_afull;
fifo_simple #(
.DATA_WIDTH (DATA_WIDTH),
.DATA_WIDTH (1+AXI_DATA_WIDTH),
.ADDR_WIDTH (BUF_AWIDTH))
buffer_ (
.clk (clk),
.rst (state[IDLE]),
.rst (rst),
.count (),
.empty (buf_empty),
.empty_a (),
.full (buf_full),
.full_a (),
.full (),
.full_a (buf_afull),
.push_data (buf_data),
.push (buf_valid),
.push_data ({axi_rlast, axi_rdata}),
.push (axi_rvalid & axi_rready),
.pop_data (data),
.pop_data ({buf_last, buf_data}),
.pop (buf_pop)
);
axis_serializer #(
.DATA_NB (WIDTH_RATIO),
.DATA_WIDTH (DATA_WIDTH))
assign buf_pop = ~buf_en | buf_rdy;
always @(posedge clk)
if (rst) buf_en <= 1'b0;
else if (buf_pop) buf_en <= ~buf_empty;
axis_gbox #(
.DATA_UP_WIDTH (AXI_DATA_WIDTH),
.DATA_DN_WIDTH (DATA_WIDTH))
serializer_ (
.clk (clk),
.rst (state[IDLE]),
.rst (state[RESET]),
.up_data (axi_rdata),
.up_valid (axi_rvalid),
.up_ready (axi_rready),
.up_data (buf_data),
.up_last (buf_last),
.up_val (buf_en),
.up_rdy (buf_rdy),
.down_data (buf_data),
.down_valid (buf_valid),
.down_ready ( ~buf_full)
.dn_data (data),
.dn_last (),
.dn_val (valid),
.dn_rdy (ready & state[ACTIVE])
);
always @(posedge clk)
if (rst) begin
state <= 'b0;
state[IDLE] <= 1'b1;
state <= 'b0;
state[RESET] <= 1'b1;
end
else state <= state_nx;
@ -153,32 +193,36 @@ module axis_read_data
state_nx = 'b0;
case (1'b1)
state[IDLE] : begin
if (cfg_valid) begin
state_nx[ACTIVE] = 1'b1;
state[RESET] : begin
state_nx[CONFIG] = 1'b1;
end
state[CONFIG] : begin
if ( ~cfg_buf_empty) begin
state_nx[SET] = 1'b1;
end
else state_nx[IDLE] = 1'b1;
else state_nx[CONFIG] = 1'b1;
end
state[SET] : begin
state_nx[ACTIVE] = 1'b1;
end
state[ACTIVE] : begin
if (buf_pop & (str_length == str_cnt)) begin
state_nx[WAIT] = 1'b1;
if (valid & (str_length == str_cnt) & ~(buf_en & buf_rdy)) begin
// serializer may contain leftover data
state_nx[RESET] = 1'b1;
end
else if (valid & (str_length == str_cnt) & (buf_en & buf_rdy)) begin
// serializer contains valid data
state_nx[CONFIG] = 1'b1;
end
else state_nx[ACTIVE] = 1'b1;
end
state[WAIT] : begin
state_nx[DONE] = 1'b1;
end
state[DONE] : begin
state_nx[IDLE] = 1'b1;
end
default : begin
state_nx[IDLE] = 1'b1;
state_nx[RESET] = 1'b1;
end
endcase
end
endmodule
`endif // `ifndef _axis_read_data_

View File

@ -53,8 +53,7 @@ module axis_read_data_tb;
localparam STREAM_LENGTH = (256*8*2)-4;
localparam BUF_AWIDTH = 4;
localparam CONFIG_DWIDTH = 32;
localparam WIDTH_RATIO = 8;
localparam CFG_DWIDTH = 32;
localparam AXI_DATA_WIDTH = 256;
localparam DATA_WIDTH = 32;
@ -70,11 +69,12 @@ module axis_read_data_tb;
reg rst;
reg [CONFIG_DWIDTH-1:0] cfg_length;
reg cfg_valid;
wire cfg_ready;
reg [CFG_DWIDTH-1:0] cfg_length;
reg cfg_val;
wire cfg_rdy;
reg [AXI_DATA_WIDTH-1:0] axi_rdata;
reg axi_rlast;
reg axi_rvalid;
wire axi_rready;
@ -89,8 +89,7 @@ module axis_read_data_tb;
axis_read_data #(
.BUF_AWIDTH (BUF_AWIDTH),
.CONFIG_DWIDTH (CONFIG_DWIDTH),
.WIDTH_RATIO (WIDTH_RATIO),
.CFG_DWIDTH (CFG_DWIDTH),
.AXI_DATA_WIDTH (AXI_DATA_WIDTH),
.DATA_WIDTH (DATA_WIDTH))
@ -99,10 +98,11 @@ module axis_read_data_tb;
.rst (rst),
.cfg_length (cfg_length),
.cfg_valid (cfg_valid),
.cfg_ready (cfg_ready),
.cfg_val (cfg_val),
.cfg_rdy (cfg_rdy),
.axi_rdata (axi_rdata),
.axi_rlast (axi_rlast),
.axi_rvalid (axi_rvalid),
.axi_rready (axi_rready),
@ -121,13 +121,14 @@ module axis_read_data_tb;
"%d\t%d",
$time, rst,
"\t%d\t%b",
"\t%d\t%b\t%b",
cfg_length,
cfg_valid,
cfg_ready,
cfg_val,
cfg_rdy,
"\t%x\t%b\t%b",
"\t%x\t%b\t%b\t%b",
axi_rdata,
axi_rlast,
axi_rvalid,
axi_rready,
@ -152,7 +153,8 @@ module axis_read_data_tb;
"\tc_r",
"\t\t\t\t\t\tr_d",
"\t\t\tr_v",
"\t\t\t\tr_l",
"\tr_v",
"\tr_r",
"\t\ts_d",
@ -173,9 +175,10 @@ module axis_read_data_tb;
rst = 0;
cfg_length = 'b0;
cfg_valid = 'b0;
cfg_val = 'b0;
axi_rdata = 'b0;
axi_rlast = 'b0;
axi_rvalid = 'b0;
ready = 'b0;
@ -198,11 +201,11 @@ module axis_read_data_tb;
repeat(5) @(negedge clk);
cfg_length <= 10;
cfg_valid <= 1'b1;
cfg_val <= 1'b1;
@(negedge clk)
cfg_length <= 'b0;
cfg_valid <= 1'b0;
cfg_val <= 1'b0;
repeat(5) @(negedge clk);
@ -217,10 +220,12 @@ module axis_read_data_tb;
axi_rvalid <= 1'b1;
@(negedge clk);
axi_rdata <= {32'd9, 32'd8, 32'd7, 32'd6, 32'd5, 32'd4, 32'd3, 32'd2};
axi_rlast <= 1'b1;
while ( ~axi_rready) @(negedge clk);
axi_rvalid <= 1'b1;
@(negedge clk);
axi_rdata <= 'b0;
axi_rlast <= 1'b0;
axi_rvalid <= 1'b0;
repeat(15) @(negedge clk);

View File

@ -54,11 +54,11 @@ module axis_read_tb;
localparam BUF_AWIDTH = 4;
localparam CONFIG_ID = 1;
localparam CONFIG_ADDR = 23;
localparam CONFIG_DATA = 24;
localparam CONFIG_AWIDTH = 5;
localparam CONFIG_DWIDTH = 32;
localparam CFG_ID = 1;
localparam CFG_ADDR = 23;
localparam CFG_DATA = 24;
localparam CFG_AWIDTH = 5;
localparam CFG_DWIDTH = 32;
localparam AXI_ADDR_WIDTH = 32;
localparam AXI_DATA_WIDTH = 256;
@ -76,8 +76,8 @@ module axis_read_tb;
reg rst;
reg [CONFIG_AWIDTH-1:0] cfg_addr;
reg [CONFIG_DWIDTH-1:0] cfg_data;
reg [CFG_AWIDTH-1:0] cfg_addr;
reg [CFG_DWIDTH-1:0] cfg_data;
reg cfg_valid;
reg axi_arready;
@ -101,11 +101,11 @@ module axis_read_tb;
axis_read #(
.BUF_AWIDTH (BUF_AWIDTH),
.CONFIG_ID (CONFIG_ID),
.CONFIG_ADDR (CONFIG_ADDR),
.CONFIG_DATA (CONFIG_DATA),
.CONFIG_AWIDTH (CONFIG_AWIDTH),
.CONFIG_DWIDTH (CONFIG_DWIDTH),
.CFG_ID (CFG_ID),
.CFG_ADDR (CFG_ADDR),
.CFG_DATA (CFG_DATA),
.CFG_AWIDTH (CFG_AWIDTH),
.CFG_DWIDTH (CFG_DWIDTH),
.AXI_ADDR_WIDTH (AXI_ADDR_WIDTH),
.AXI_DATA_WIDTH (AXI_DATA_WIDTH),
@ -235,8 +235,8 @@ module axis_read_tb;
`endif
repeat(5) @(negedge clk);
cfg_addr <= CONFIG_ADDR;
cfg_data <= CONFIG_ID;
cfg_addr <= CFG_ADDR;
cfg_data <= CFG_ID;
cfg_valid <= 1'b1;
@(negedge clk)
@ -246,7 +246,7 @@ module axis_read_tb;
repeat(5) @(negedge clk);
// memory address
cfg_addr <= CONFIG_DATA;
cfg_addr <= CFG_DATA;
cfg_data <= 4;
cfg_valid <= 1'b1;
@(negedge clk)
@ -257,7 +257,7 @@ module axis_read_tb;
repeat(5) @(negedge clk);
// length of flow stream
cfg_addr <= CONFIG_DATA;
cfg_addr <= CFG_DATA;
cfg_data <= 8;
cfg_valid <= 1'b1;
@(negedge clk)
@ -302,17 +302,17 @@ module axis_read_tb;
`endif
repeat(5) @(negedge clk);
cfg_addr <= CONFIG_ADDR;
cfg_data <= CONFIG_ID;
cfg_addr <= CFG_ADDR;
cfg_data <= CFG_ID;
cfg_valid <= 1'b1;
@(negedge clk)
cfg_addr <= CONFIG_DATA;
cfg_addr <= CFG_DATA;
cfg_data <= 4;
cfg_valid <= 1'b1;
@(negedge clk)
cfg_addr <= CONFIG_DATA;
cfg_addr <= CFG_DATA;
cfg_data <= 20;
cfg_valid <= 1'b1;
@(negedge clk)
@ -370,17 +370,17 @@ module axis_read_tb;
`endif
repeat(5) @(negedge clk);
cfg_addr <= CONFIG_ADDR;
cfg_data <= CONFIG_ID;
cfg_addr <= CFG_ADDR;
cfg_data <= CFG_ID;
cfg_valid <= 1'b1;
@(negedge clk)
cfg_addr <= CONFIG_DATA;
cfg_addr <= CFG_DATA;
cfg_data <= 255;
cfg_valid <= 1'b1;
@(negedge clk)
cfg_addr <= CONFIG_DATA;
cfg_addr <= CFG_DATA;
cfg_data <= STREAM_LENGTH;
cfg_valid <= 1'b1;
@(negedge clk)

View File

@ -1,117 +0,0 @@
/**
* Module:
* axis_serializer
*
* Description:
* Serializes the 'up' flow bus data word into multiple smaller 'down' data
* words. The module will stall when the down_ready flag deasserts.
*
* Testbench:
* axis_serializer_tb.v
*
* Created:
* Fri Nov 7 11:50:04 EST 2014
*
* Authors:
* Berin Martini (berin.martini@gmail.com)
*/
`ifndef _axis_serializer_ `define _axis_serializer_
module axis_serializer
#(parameter
DATA_NB = 2,
DATA_WIDTH = 8)
(input clk,
input rst,
output up_ready,
input up_valid,
input [(DATA_WIDTH*DATA_NB)-1:0] up_data,
input down_ready,
output reg down_valid,
output reg [DATA_WIDTH-1:0] down_data
);
/**
* Local parameters
*/
`ifdef VERBOSE
initial $display("\using 'axis_serializer' with %0d words\n", DATA_NB);
`endif
/**
* Internal signals
*/
wire [2*DATA_NB-1:0] token_nx;
reg [DATA_NB-1:0] token;
reg [DATA_NB:0] serial_valid;
reg [(DATA_WIDTH*DATA_NB)-1:0] serial_data;
wire serial_start;
/**
* Implementation
*/
assign up_ready = down_ready & token[0];
assign serial_start = |(token >> 1);
assign token_nx = {token, token};
always @(posedge clk)
if (rst) token <= 'b1;
else if (down_ready) begin
if (serial_start | (up_ready & up_valid)) begin
token <= token_nx[DATA_NB-1 +: DATA_NB];
end
end
always @(posedge clk)
if (down_ready) begin
serial_data <= serial_data >> DATA_WIDTH;
if (up_ready & up_valid) begin
serial_data <= up_data;
end
end
always @(posedge clk)
if (rst) serial_valid <= 'b0;
else if (down_ready) begin
serial_valid <= {serial_valid[0 +: DATA_NB], 1'b0};
if (up_ready & up_valid) begin
serial_valid <= {serial_valid[0 +: DATA_NB], 1'b1};
end
end
always @(posedge clk)
if (down_ready) begin
down_data <= serial_data[0 +: DATA_WIDTH];
end
always @(posedge clk)
if (rst) down_valid <= 1'b0;
else if (down_ready) begin
down_valid <= |(serial_valid[0 +: DATA_NB]);
end
endmodule
`endif // `ifndef _axis_serializer_

View File

@ -1,243 +0,0 @@
/**
* Testbench for:
* axis_serializer
*
* Created:
* Fri Nov 7 11:49:55 EST 2014
*
* Author:
* Berin Martini (berin.martini@gmail.com)
*/
`timescale 1ns/10ps
`define TB_VERBOSE
//`define VERBOSE
`include "axis_serializer.v"
module axis_serializer_tb;
/**
* Clock and control functions
*/
// Generate a clk
reg clk;
always #1 clk = !clk;
// End of simulation event definition
event end_trigger;
always @(end_trigger) $finish;
`ifdef TB_VERBOSE
// Display header information
initial #1 display_header();
always @(end_trigger) display_header();
// And strobe signals at each clk
always @(posedge clk) display_signals();
`endif
// initial begin
// $dumpfile("result.vcd"); // Waveform file
// $dumpvars;
// end
/**
* Local parameters
*/
localparam DATA_NB = 3;
localparam DATA_WIDTH = 8;
localparam STREAM_LENGTH = 256;
`ifdef TB_VERBOSE
initial begin
$display("Testbench for unit 'axis_serializer' data width: %d, nb: %d",
DATA_WIDTH, DATA_NB);
end
`endif
/**
* signals, registers and wires
*/
reg rst;
reg [DATA_NB*DATA_WIDTH-1:0] up_data;
wire up_valid;
wire up_ready;
wire [DATA_WIDTH-1:0] down_data;
wire down_valid;
reg down_ready;
reg [DATA_WIDTH-1:0] stream [0:STREAM_LENGTH-1];
integer cnt;
/**
* Unit under test
*/
axis_serializer #(
.DATA_NB (DATA_NB),
.DATA_WIDTH (DATA_WIDTH))
uut (
.clk (clk),
.rst (rst),
.up_data (up_data),
.up_valid (up_valid),
.up_ready (up_ready),
.down_data (down_data),
.down_valid (down_valid),
.down_ready (down_ready)
);
/**
* Wave form display
*/
task display_signals;
$display(
"%d\t%d",
$time, rst,
"\tu2: %d\tu1: %d\tu0: %d",
up_data[2*DATA_WIDTH+:DATA_WIDTH],
up_data[1*DATA_WIDTH+:DATA_WIDTH],
up_data[0*DATA_WIDTH+:DATA_WIDTH],
"\tv %b\tr %b",
up_valid,
up_ready,
"\t%d\t%b\t%b",
down_data,
down_valid,
down_ready,
"\t%b",
uut.token,
"\t%x\t%b",
uut.serial_data,
uut.serial_valid,
);
endtask // display_signals
task display_header;
$display(
"\t\ttime\trst",
"\tu2_d",
"\tu1_d",
"\tu0_d",
"\tu_v",
"\tu_r",
"\td_d",
"\td_v",
"\td_r",
);
endtask
/**
* Testbench program
*/
//assign up_valid = up_ready;
assign up_valid = 1'b1;
always @(posedge clk)
if (up_ready & up_valid) begin
cnt <= cnt + 1;
end
always @(posedge clk)
up_data <= {stream[cnt]+4'd2, stream[cnt]+4'd1, stream[cnt]};
initial begin
// init values
clk = 0;
rst = 0;
down_ready = 'b0;
cnt = 0;
repeat (STREAM_LENGTH) begin
stream[cnt] = (DATA_NB*cnt)+1;
cnt = cnt + 1;
end
cnt = 0;
//end init
`ifdef TB_VERBOSE
$display("RESET");
`endif
repeat(6) @(negedge clk);
rst <= 1'b1;
repeat(6) @(negedge clk);
rst <= 1'b0;
repeat(6) @(negedge clk);
`ifdef TB_VERBOSE
$display("test continuous ready");
`endif
@(negedge clk);
down_ready <= 1'b1;
repeat(20) @(negedge clk);
down_ready <= 1'b0;
repeat(10) @(negedge clk);
`ifdef TB_VERBOSE
$display("test non-continuous ready");
`endif
down_ready <= 1'b1;
repeat(20) @(negedge clk);
down_ready <= 1'b0;
@(negedge clk);
down_ready <= 1'b1;
repeat(5) @(negedge clk);
down_ready <= 1'b0;
repeat(5) @(negedge clk);
down_ready <= 1'b1;
repeat(5) @(negedge clk);
down_ready <= 1'b0;
repeat(10) @(negedge clk);
down_ready <= 1'b1;
@(negedge clk);
down_ready <= 1'b0;
@(negedge clk);
down_ready <= 1'b1;
@(negedge clk);
down_ready <= 1'b0;
repeat(10) @(negedge clk);
`ifdef TB_VERBOSE
$display("END");
`endif
-> end_trigger;
end
endmodule

View File

@ -3,7 +3,7 @@
* axis_write
*
* Description:
* The axis_write takes a system stream an translate it to the axi data
* The axis_write takes a system stream and translates it to the axi data
* channel protocol.
*
* Test bench:
@ -15,7 +15,8 @@
* Author:
* Berin Martini (berin.martini@gmail.com)
*/
`ifndef _axis_write_ `define _axis_write_
`ifndef _axis_write_
`define _axis_write_
`include "axis_addr.v"
@ -23,14 +24,16 @@
module axis_write
#(parameter
BUF_CFG_AWIDTH = 5,
BUF_AWIDTH = 9,
CONFIG_ID = 1,
CONFIG_ADDR = 23,
CONFIG_DATA = 24,
CONFIG_AWIDTH = 5,
CONFIG_DWIDTH = 32,
CFG_ID = 1,
CFG_ADDR = 23,
CFG_DATA = 24,
CFG_AWIDTH = 5,
CFG_DWIDTH = 32,
AXI_ID_WIDTH = 8,
AXI_LEN_WIDTH = 8,
AXI_ADDR_WIDTH = 32,
AXI_DATA_WIDTH = 32,
@ -38,17 +41,20 @@ module axis_write
(input clk,
input rst,
input [CONFIG_AWIDTH-1:0] cfg_addr,
input [CONFIG_DWIDTH-1:0] cfg_data,
input [CFG_AWIDTH-1:0] cfg_addr,
input [CFG_DWIDTH-1:0] cfg_data,
input cfg_valid,
output cfg_ready,
input axi_awready,
output reg [AXI_ID_WIDTH-1:0] axi_awid,
output [AXI_ADDR_WIDTH-1:0] axi_awaddr,
output [AXI_LEN_WIDTH-1:0] axi_awlen,
output axi_awvalid,
input axi_awready,
output axi_wlast,
output reg [AXI_ID_WIDTH-1:0] axi_wid,
output [AXI_DATA_WIDTH-1:0] axi_wdata,
output axi_wlast,
output axi_wvalid,
input axi_wready,
@ -62,14 +68,13 @@ module axis_write
*/
localparam WIDTH_RATIO = AXI_DATA_WIDTH/DATA_WIDTH;
localparam CONFIG_NB = 2;
localparam STORE_WIDTH = CONFIG_DWIDTH*CONFIG_NB;
localparam CFG_NB = 2;
localparam STORE_WIDTH = CFG_DWIDTH*CFG_NB;
localparam
C_IDLE = 0,
C_CONFIG = 1,
C_WAIT = 2,
C_ENABLE = 3;
C_STALL = 2;
`ifdef VERBOSE
@ -82,23 +87,19 @@ module axis_write
*/
reg [3:0] c_state;
reg [3:0] c_state_nx;
reg [2:0] c_state;
reg [2:0] c_state_nx;
wire cfg_addr_ready;
wire cfg_data_ready;
reg [CONFIG_AWIDTH-1:0] cfg_addr_r;
reg [CONFIG_DWIDTH-1:0] cfg_data_r;
reg cfg_valid_r;
wire [STORE_WIDTH+CONFIG_DWIDTH-1:0] cfg_store_i;
wire [STORE_WIDTH+CFG_DWIDTH-1:0] cfg_store_i;
reg [STORE_WIDTH-1:0] cfg_store;
reg [7:0] cfg_cnt;
wire cfg_done;
wire [CONFIG_DWIDTH-1:0] start_addr;
reg [CONFIG_DWIDTH-1:0] cfg_address;
wire [CONFIG_DWIDTH-1:0] str_length;
reg [CONFIG_DWIDTH-1:0] cfg_length;
wire [CFG_DWIDTH-1:0] cfg_address;
wire [CFG_DWIDTH-1:0] cfg_length;
reg cfg_enable;
wire id_valid;
wire addressed;
@ -109,30 +110,21 @@ module axis_write
* Implementation
*/
assign cfg_store_i = {cfg_store, cfg_data_r};
assign cfg_store_i = {cfg_store, cfg_data};
assign start_addr = cfg_store[CONFIG_DWIDTH +: CONFIG_DWIDTH];
assign cfg_address = cfg_store[CFG_DWIDTH +: CFG_DWIDTH];
assign str_length = cfg_store[0 +: CONFIG_DWIDTH];
assign cfg_length = cfg_store[0 +: CFG_DWIDTH];
assign id_valid = (CONFIG_ID == cfg_data_r);
assign id_valid = (CFG_ID == cfg_data);
assign addressed = (CONFIG_ADDR == cfg_addr_r) & cfg_valid_r;
assign addressed = (CFG_ADDR == cfg_addr) & cfg_valid;
assign axis_data = (CONFIG_DATA == cfg_addr_r) & cfg_valid_r;
assign axis_data = (CFG_DATA == cfg_addr) & cfg_valid;
assign cfg_ready = ~c_state[C_STALL];
// register for improved timing
always @(posedge clk)
if (rst) cfg_valid_r <= 1'b0;
else cfg_valid_r <= cfg_valid;
// register for improved timing
always @(posedge clk) begin
cfg_addr_r <= cfg_addr;
cfg_data_r <= cfg_data;
end
assign cfg_done = ((CFG_NB-1) == cfg_cnt);
always @(posedge clk)
@ -151,16 +143,28 @@ module axis_write
always @(posedge clk)
if (rst) cfg_enable <= 1'b0;
else cfg_enable <= c_state[C_ENABLE];
always @(posedge clk) begin
if (c_state[C_ENABLE]) begin
cfg_address <= start_addr;
cfg_length <= str_length;
if (rst) cfg_enable <= 1'b0;
else if ( ~c_state[C_STALL]) begin
cfg_enable <= c_state[C_CONFIG] & axis_data & cfg_done;
end
always @(posedge clk)
if (rst) begin
axi_awid <= {AXI_ID_WIDTH{1'b0}};
end
else if (axi_awvalid && axi_awready) begin
axi_awid <= axi_awid + {{(AXI_ID_WIDTH-1){1'b0}}, 1'b1};
end
always @(posedge clk)
if (rst) begin
axi_wid <= {AXI_ID_WIDTH{1'b0}};
end
else if (axi_wvalid & axi_wready & axi_wlast) begin
axi_wid <= axi_wid + {{(AXI_ID_WIDTH-1){1'b0}}, 1'b1};
end
end
always @(posedge clk)
@ -182,19 +186,19 @@ module axis_write
else c_state_nx[C_IDLE] = 1'b1;
end
c_state[C_CONFIG] : begin
if (axis_data & ((CONFIG_NB-1) <= cfg_cnt)) begin
c_state_nx[C_WAIT] = 1'b1;
if (axis_data & cfg_done & cfg_addr_ready & cfg_data_ready) begin
c_state_nx[C_IDLE] = 1'b1;
end
else if (axis_data & cfg_done) begin
c_state_nx[C_STALL] = 1'b1;
end
else c_state_nx[C_CONFIG] = 1'b1;
end
c_state[C_WAIT] : begin
c_state[C_STALL] : begin
if (cfg_addr_ready & cfg_data_ready) begin
c_state_nx[C_ENABLE] = 1'b1;
c_state_nx[C_IDLE] = 1'b1;
end
else c_state_nx[C_WAIT] = 1'b1;
end
c_state[C_ENABLE] : begin
c_state_nx[C_IDLE] = 1'b1;
else c_state_nx[C_STALL] = 1'b1;
end
default : begin
c_state_nx[C_IDLE] = 1'b1;
@ -204,9 +208,11 @@ module axis_write
axis_addr #(
.CONFIG_DWIDTH (CONFIG_DWIDTH),
.BUF_CFG_AWIDTH (BUF_CFG_AWIDTH),
.CFG_DWIDTH (CFG_DWIDTH),
.WIDTH_RATIO (WIDTH_RATIO),
.CONVERT_SHIFT ($clog2(WIDTH_RATIO)),
.AXI_LEN_WIDTH (AXI_LEN_WIDTH),
.AXI_ADDR_WIDTH (AXI_ADDR_WIDTH),
.AXI_DATA_WIDTH (AXI_DATA_WIDTH))
@ -216,8 +222,8 @@ module axis_write
.cfg_address (cfg_address),
.cfg_length (cfg_length),
.cfg_valid (cfg_enable),
.cfg_ready (cfg_addr_ready),
.cfg_val (cfg_enable & ~c_state[C_STALL]),
.cfg_rdy (cfg_addr_ready),
.axi_aready (axi_awready),
.axi_aaddr (axi_awaddr),
@ -227,10 +233,11 @@ module axis_write
axis_write_data #(
.BUF_CFG_AWIDTH (BUF_CFG_AWIDTH),
.BUF_AWIDTH (BUF_AWIDTH),
.CONFIG_DWIDTH (CONFIG_DWIDTH),
.WIDTH_RATIO (WIDTH_RATIO),
.CFG_DWIDTH (CFG_DWIDTH),
.CONVERT_SHIFT ($clog2(WIDTH_RATIO)),
.AXI_LEN_WIDTH (AXI_LEN_WIDTH),
.AXI_DATA_WIDTH (AXI_DATA_WIDTH),
.DATA_WIDTH (DATA_WIDTH))
@ -239,8 +246,8 @@ module axis_write
.rst (rst),
.cfg_length (cfg_length),
.cfg_valid (cfg_enable),
.cfg_ready (cfg_data_ready),
.cfg_val (cfg_enable & ~c_state[C_STALL]),
.cfg_rdy (cfg_data_ready),
.axi_wlast (axi_wlast),
.axi_wdata (axi_wdata),

View File

@ -14,17 +14,18 @@
* Author:
* Berin Martini (berin.martini@gmail.com)
*/
`ifndef _axis_write_data_ `define _axis_write_data_
`ifndef _axis_write_data_
`define _axis_write_data_
`include "fifo_simple.v"
`include "axis_deserializer.v"
`include "axis_gbox.v"
module axis_write_data
#(parameter
BUF_CFG_AWIDTH = 5,
BUF_AWIDTH = 9,
CONFIG_DWIDTH = 32,
WIDTH_RATIO = 2,
CFG_DWIDTH = 32,
CONVERT_SHIFT = 3,
AXI_LEN_WIDTH = 8,
@ -33,9 +34,9 @@ module axis_write_data
(input clk,
input rst,
input [CONFIG_DWIDTH-1:0] cfg_length,
input cfg_valid,
output cfg_ready,
input [CFG_DWIDTH-1:0] cfg_length,
input cfg_val,
output cfg_rdy,
output axi_wlast,
output [AXI_DATA_WIDTH-1:0] axi_wdata,
@ -55,10 +56,10 @@ module axis_write_data
localparam BURST_LAST = (1<<BURST_WIDTH)-1;
localparam
IDLE = 0,
ACTIVE = 1,
WAIT = 2,
DONE = 3;
CONFIG = 0,
SET = 1,
LOAD = 2,
ACTIVE = 3;
`ifdef VERBOSE
@ -73,58 +74,66 @@ module axis_write_data
reg [3:0] state;
reg [3:0] state_nx;
reg [CONFIG_DWIDTH-1:0] str_cnt;
reg [CONFIG_DWIDTH-1:0] str_length;
wire cfg_buf_pop;
wire cfg_buf_full;
wire cfg_buf_empty;
wire [CFG_DWIDTH-1:0] cfg_buf_length;
reg [CFG_DWIDTH-1:0] str_cnt;
reg [CFG_DWIDTH-1:0] str_next;
reg [CFG_DWIDTH-1:0] str_length;
wire [BUF_AWIDTH:0] buf_count;
wire buf_pop;
wire buf_empty;
reg deser_done;
reg deser_last;
wire [DATA_WIDTH-1:0] deser_data;
reg deser_valid;
reg deser_en;
wire deser_rdy;
/**
* Implementation
*/
assign cfg_ready = state[IDLE];
assign buf_pop = ~buf_empty & axi_wready;
assign cfg_rdy = ~cfg_buf_full;
fifo_simple #(
.DATA_WIDTH (CFG_DWIDTH),
.ADDR_WIDTH (BUF_CFG_AWIDTH))
cfg_buffer_ (
.clk (clk),
.rst (rst),
.count (),
.empty (cfg_buf_empty),
.empty_a (),
.full (cfg_buf_full),
.full_a (),
.push_data (cfg_length),
.push (cfg_val),
.pop_data (cfg_buf_length),
.pop (cfg_buf_pop)
);
assign cfg_buf_pop = ~cfg_buf_empty & state[CONFIG];
always @(posedge clk)
if (cfg_valid) begin
str_length <= cfg_length-1;
if (state[SET]) begin
str_length <= cfg_buf_length-'b1;
end
// use axi_wready as a stall signal
always @(posedge clk)
if (state[IDLE]) deser_valid <= 1'b0;
else if (axi_wready) deser_valid <= buf_pop;
// half way mark ready flag
always @(posedge clk)
if (state[IDLE]) ready <= 1'b0;
else ready <= ~|(buf_count[BUF_AWIDTH:BUF_AWIDTH-1]);
always @(posedge clk)
if (state[IDLE]) str_cnt <= 'b0;
else if (axi_wready & buf_pop) begin
str_cnt <= str_cnt + 'd1;
end
always @(posedge clk)
if (state[IDLE]) deser_last <= 1'b0;
else if (axi_wready) begin
// trigger on last word in stream or last word in burst
deser_last <= buf_pop &
((str_length == str_cnt) | (BURST_LAST == str_cnt[0 +: BURST_WIDTH]));
end
if (rst) ready <= 1'b0;
else ready <= ~|(buf_count[BUF_AWIDTH:BUF_AWIDTH-1]);
fifo_simple #(
@ -132,7 +141,7 @@ module axis_write_data
.ADDR_WIDTH (BUF_AWIDTH))
buffer_ (
.clk (clk),
.rst (state[IDLE]),
.rst (rst),
.count (buf_count),
.empty (buf_empty),
@ -148,29 +157,78 @@ module axis_write_data
);
axis_deserializer #(
.DATA_NB (WIDTH_RATIO),
.DATA_WIDTH (DATA_WIDTH))
assign buf_pop = ~deser_en | (deser_rdy & state[ACTIVE]);
always @(posedge clk)
if (rst) deser_en <= 1'b0;
else if (buf_pop) deser_en <= ~buf_empty;
always @(posedge clk)
if (state[LOAD]) begin
deser_done <= str_next[0] & (str_length == {CFG_DWIDTH{1'b0}});
end
else if (buf_pop) begin
// trigger on last word in stream
deser_done <= ~buf_empty & (str_length == str_cnt);
end
always @(posedge clk)
if (state[LOAD]) begin
deser_last <= str_next[0] &
((str_length == {CFG_DWIDTH{1'b0}}) | (BURST_LAST == {BURST_WIDTH{1'b0}}));
end
else if (buf_pop) begin
// trigger on last word in stream or last word in burst
deser_last <= ~buf_empty &
((str_length == str_cnt) | (BURST_LAST == str_cnt[0 +: BURST_WIDTH]));
end
always @(posedge clk)
if (state[LOAD]) begin
str_cnt <= str_next;
end
else if (buf_pop) begin
str_cnt <= str_cnt + {{CFG_DWIDTH-1{1'b0}}, ~buf_empty};
end
always @(posedge clk)
if (rst) str_next <= 'b0;
else if (deser_en & deser_rdy & deser_done & state[ACTIVE]) begin
// if buffer is not empty when one stream is done it means the 1st
// word of the next stream is already in the pipeline
str_next <= {{CFG_DWIDTH-1{1'b0}}, ~buf_empty};
end
axis_gbox #(
.DATA_UP_WIDTH (DATA_WIDTH),
.DATA_DN_WIDTH (AXI_DATA_WIDTH))
deser_ (
.clk (clk),
.rst (state[IDLE]),
.rst (rst),
.up_data (deser_data),
.up_valid (deser_valid),
.up_ready (),
.up_last (deser_last),
.up_val (deser_en & state[ACTIVE]),
.up_rdy (deser_rdy),
.down_data (axi_wdata),
.down_valid (axi_wvalid),
.down_ready (axi_wready),
.down_last (axi_wlast)
.dn_data (axi_wdata),
.dn_last (axi_wlast),
.dn_val (axi_wvalid),
.dn_rdy (axi_wready)
);
always @(posedge clk)
if (rst) begin
state <= 'b0;
state[IDLE] <= 1'b1;
state <= 'b0;
state[CONFIG] <= 1'b1;
end
else state <= state_nx;
@ -179,34 +237,32 @@ module axis_write_data
state_nx = 'b0;
case (1'b1)
state[IDLE] : begin
if (cfg_valid) begin
state_nx[ACTIVE] = 1'b1;
state[CONFIG] : begin
if ( ~cfg_buf_empty) begin
state_nx[SET] = 1'b1;
end
else state_nx[IDLE] = 1'b1;
else state_nx[CONFIG] = 1'b1;
end
state[SET] : begin
state_nx[LOAD] = 1'b1;
end
state[LOAD] : begin
state_nx[ACTIVE] = 1'b1;
end
state[ACTIVE] : begin
if (axi_wready & buf_pop & (str_length == str_cnt)) begin
state_nx[WAIT] = 1'b1;
if (deser_en & deser_rdy & deser_done) begin
state_nx[CONFIG] = 1'b1;
end
else state_nx[ACTIVE] = 1'b1;
end
state[WAIT] : begin
if (axi_wready & axi_wlast) begin
state_nx[DONE] = 1'b1;
end
else state_nx[WAIT] = 1'b1;
end
state[DONE] : begin
state_nx[IDLE] = 1'b1;
end
default : begin
state_nx[IDLE] = 1'b1;
state_nx[CONFIG] = 1'b1;
end
endcase
end
endmodule
`endif // `ifndef _axis_write_data_

View File

@ -53,7 +53,7 @@ module axis_write_data_tb;
localparam STREAM_LENGTH = (256*8*2)-4;
localparam BUF_AWIDTH = 4;
localparam CONFIG_DWIDTH = 32;
localparam CFG_DWIDTH = 32;
localparam AXI_LEN_WIDTH = 4;
localparam AXI_DATA_WIDTH = 64;
@ -73,11 +73,9 @@ module axis_write_data_tb;
reg rst;
wire done;
reg [CONFIG_DWIDTH-1:0] cfg_length;
reg cfg_valid;
wire cfg_ready;
reg [CFG_DWIDTH-1:0] cfg_length;
reg cfg_val;
wire cfg_rdy;
wire axi_wlast;
wire [AXI_DATA_WIDTH-1:0] axi_wdata;
@ -95,8 +93,7 @@ module axis_write_data_tb;
axis_write_data #(
.BUF_AWIDTH (BUF_AWIDTH),
.CONFIG_DWIDTH (CONFIG_DWIDTH),
.WIDTH_RATIO (WIDTH_RATIO),
.CFG_DWIDTH (CFG_DWIDTH),
.CONVERT_SHIFT ($clog2(WIDTH_RATIO)),
.AXI_LEN_WIDTH (AXI_LEN_WIDTH),
@ -107,8 +104,8 @@ module axis_write_data_tb;
.rst (rst),
.cfg_length (cfg_length),
.cfg_valid (cfg_valid),
.cfg_ready (cfg_ready),
.cfg_val (cfg_val),
.cfg_rdy (cfg_rdy),
.axi_wlast (axi_wlast),
.axi_wdata (axi_wdata),
@ -132,8 +129,8 @@ module axis_write_data_tb;
"\t%d\t%b\t%b",
cfg_length,
cfg_valid,
cfg_ready,
cfg_val,
cfg_rdy,
"\t%x\t%b\t%b\t%b",
axi_wdata,
@ -149,6 +146,9 @@ module axis_write_data_tb;
"\t%b",
uut.state,
"\t%d",
uut.str_cnt,
);
endtask // display_signals
@ -184,7 +184,7 @@ module axis_write_data_tb;
rst = 0;
cfg_length = 'b0;
cfg_valid = 'b0;
cfg_val = 'b0;
axi_wready = 'b0;
data = 'b0;
@ -208,11 +208,11 @@ module axis_write_data_tb;
repeat(5) @(negedge clk);
cfg_length <= 8;
cfg_valid <= 1'b1;
cfg_val <= 1'b1;
@(negedge clk)
cfg_length <= 'b0;
cfg_valid <= 1'b0;
cfg_val <= 1'b0;
repeat(5) @(negedge clk);
@ -285,11 +285,11 @@ module axis_write_data_tb;
repeat(5) @(negedge clk);
cfg_length <= 8;
cfg_valid <= 1'b1;
cfg_val <= 1'b1;
@(negedge clk)
cfg_length <= 'b0;
cfg_valid <= 1'b0;
cfg_val <= 1'b0;
repeat(5) @(negedge clk);
@ -337,11 +337,19 @@ module axis_write_data_tb;
repeat(5) @(negedge clk);
cfg_length <= STREAM_LENGTH;
cfg_valid <= 1'b1;
cfg_val <= 1'b1;
@(negedge clk)
cfg_length <= 1;
cfg_val <= 1'b1;
@(negedge clk)
cfg_length <= 1;
cfg_val <= 1'b1;
@(negedge clk)
cfg_length <= 'b0;
cfg_valid <= 1'b0;
cfg_val <= 1'b0;
repeat(5) @(negedge clk);
@ -355,7 +363,7 @@ module axis_write_data_tb;
axi_wready <= 1'b1;
repeat(15) @(negedge clk);
repeat (STREAM_LENGTH) begin
repeat (STREAM_LENGTH+1) begin
data <= data + 1;
valid <= 1'b1;
@(negedge clk);
@ -363,6 +371,11 @@ module axis_write_data_tb;
valid <= 1'b0;
repeat(15) @(negedge clk);
data <= data + 1;
valid <= 1'b1;
@(negedge clk);
valid <= 1'b0;
repeat(15) @(negedge clk);
axi_wready <= 1'b0;

View File

@ -54,11 +54,11 @@ module axis_write_tb;
localparam BUF_AWIDTH = 4;
localparam CONFIG_ID = 1;
localparam CONFIG_ADDR = 23;
localparam CONFIG_DATA = 24;
localparam CONFIG_AWIDTH = 5;
localparam CONFIG_DWIDTH = 32;
localparam CFG_ID = 1;
localparam CFG_ADDR = 23;
localparam CFG_DATA = 24;
localparam CFG_AWIDTH = 5;
localparam CFG_DWIDTH = 32;
localparam AXI_LEN_WIDTH = 2;
localparam AXI_ADDR_WIDTH = 32;
@ -77,8 +77,8 @@ module axis_write_tb;
reg rst;
reg [CONFIG_AWIDTH-1:0] cfg_addr;
reg [CONFIG_DWIDTH-1:0] cfg_data;
reg [CFG_AWIDTH-1:0] cfg_addr;
reg [CFG_DWIDTH-1:0] cfg_data;
reg cfg_valid;
reg axi_awready;
@ -103,11 +103,11 @@ module axis_write_tb;
axis_write #(
.BUF_AWIDTH (BUF_AWIDTH),
.CONFIG_ID (CONFIG_ID),
.CONFIG_ADDR (CONFIG_ADDR),
.CONFIG_DATA (CONFIG_DATA),
.CONFIG_AWIDTH (CONFIG_AWIDTH),
.CONFIG_DWIDTH (CONFIG_DWIDTH),
.CFG_ID (CFG_ID),
.CFG_ADDR (CFG_ADDR),
.CFG_DATA (CFG_DATA),
.CFG_AWIDTH (CFG_AWIDTH),
.CFG_DWIDTH (CFG_DWIDTH),
.AXI_LEN_WIDTH (AXI_LEN_WIDTH),
.AXI_ADDR_WIDTH (AXI_ADDR_WIDTH),
@ -240,8 +240,8 @@ module axis_write_tb;
`endif
repeat(5) @(negedge clk);
cfg_addr <= CONFIG_ADDR;
cfg_data <= CONFIG_ID;
cfg_addr <= CFG_ADDR;
cfg_data <= CFG_ID;
cfg_valid <= 1'b1;
@(negedge clk)
@ -250,7 +250,7 @@ module axis_write_tb;
cfg_valid <= 1'b0;
repeat(5) @(negedge clk);
cfg_addr <= CONFIG_DATA;
cfg_addr <= CFG_DATA;
cfg_data <= 4;
cfg_valid <= 1'b1;
@(negedge clk)
@ -260,7 +260,7 @@ module axis_write_tb;
cfg_valid <= 1'b0;
repeat(5) @(negedge clk);
cfg_addr <= CONFIG_DATA;
cfg_addr <= CFG_DATA;
cfg_data <= 8;
cfg_valid <= 1'b1;
@(negedge clk)
@ -320,17 +320,17 @@ module axis_write_tb;
`endif
repeat(5) @(negedge clk);
cfg_addr <= CONFIG_ADDR;
cfg_data <= CONFIG_ID;
cfg_addr <= CFG_ADDR;
cfg_data <= CFG_ID;
cfg_valid <= 1'b1;
@(negedge clk)
cfg_addr <= CONFIG_DATA;
cfg_addr <= CFG_DATA;
cfg_data <= 4;
cfg_valid <= 1'b1;
@(negedge clk)
cfg_addr <= CONFIG_DATA;
cfg_addr <= CFG_DATA;
cfg_data <= 8;
cfg_valid <= 1'b1;
@(negedge clk)
@ -375,17 +375,17 @@ module axis_write_tb;
`endif
repeat(5) @(negedge clk);
cfg_addr <= CONFIG_ADDR;
cfg_data <= CONFIG_ID;
cfg_addr <= CFG_ADDR;
cfg_data <= CFG_ID;
cfg_valid <= 1'b1;
@(negedge clk)
cfg_addr <= CONFIG_DATA;
cfg_addr <= CFG_DATA;
cfg_data <= 255;
cfg_valid <= 1'b1;
@(negedge clk)
cfg_addr <= CONFIG_DATA;
cfg_addr <= CFG_DATA;
cfg_data <= STREAM_LENGTH;
cfg_valid <= 1'b1;
@(negedge clk)

View File

@ -1,4 +1,5 @@
`ifndef _axi4lite_cfg_ `define _axi4lite_cfg_
`ifndef _axi4lite_cfg_
`define _axi4lite_cfg_
`timescale 1 ns / 1 ps

View File

@ -14,7 +14,8 @@
* Author:
* Berin Martini (berin.martini@gmail.com)
*/
`ifndef _fifo_simple_ `define _fifo_simple_
`ifndef _fifo_simple_
`define _fifo_simple_
module fifo_simple

View File

@ -210,12 +210,12 @@ module axis_loopback #(
axis #(
.BUF_AWIDTH (9),
.CONFIG_ID_RD (1),
.CONFIG_ID_WR (2),
.CONFIG_ADDR (CFG_AXIS_ADDR),
.CONFIG_DATA (CFG_AXIS_DATA),
.CONFIG_AWIDTH (CFG_AWIDTH),
.CONFIG_DWIDTH (CFG_DWIDTH),
.CFG_ID_RD (1),
.CFG_ID_WR (2),
.CFG_ADDR (CFG_AXIS_ADDR),
.CFG_DATA (CFG_AXIS_DATA),
.CFG_AWIDTH (CFG_AWIDTH),
.CFG_DWIDTH (CFG_DWIDTH),
.STREAM_WIDTH (SYS_DWIDTH),
.AXI_ID_WIDTH (C_M00_AXI_ID_WIDTH),
.AXI_LEN_WIDTH (C_M00_AXI_BURST_LEN),

132
hdl/top/axis_loopback_tb.v Normal file
View File

@ -0,0 +1,132 @@
/**
* Testbench:
* axis_loopback
*
* Created:
* Sun Jun 3 14:42:30 PDT 2018
*
* Author:
* Berin Martini (berin.martini@gmail.com)
*/
`timescale 1ns/10ps
`define TB_VERBOSE
//`define VERBOSE
`include "axis_loopback.v"
module axis_loopback_tb;
/**
* Clock and control functions
*/
// Generate a clk
reg clk;
always #1 clk = !clk;
// End of simulation event definition
event end_trigger;
always @(end_trigger) $finish;
`ifdef TB_VERBOSE
// Display header information
initial #1 display_header();
always @(end_trigger) display_header();
// And strobe signals at each clk
always @(posedge clk) display_signals();
`endif
// initial begin
// $dumpfile("result.vcd"); // Waveform file
// $dumpvars;
// end
/**
* Local parameters
*/
`ifdef TB_VERBOSE
initial $display("Testbench for unit 'axis_loopback'");
`endif
/**
* signals, registers and wires
*/
reg rst;
/**
* Unit under test
*/
axis_loopback
uut (
.clk (clk),
.rst_n ( ~rst)
);
/**
* Wave form display
*/
task display_signals;
$display(
"%d\t%d",
$time, rst,
);
endtask // display_signals
task display_header;
$display(
"\t\ttime\trst",
);
endtask
/**
* Testbench program
*/
initial begin
// init values
clk = 0;
rst = 0;
//end init
`ifdef TB_VERBOSE
$display("RESET");
`endif
repeat(6) @(negedge clk);
rst <= 1'b1;
repeat(6) @(negedge clk);
rst <= 1'b0;
@(negedge clk);
`ifdef TB_VERBOSE
$display("wait");
`endif
repeat(10) @(negedge clk);
`ifdef TB_VERBOSE
$display("END");
`endif
-> end_trigger;
end
endmodule