mirror of
https://github.com/bmartini/zynq-axis.git
synced 2024-09-05 19:19:27 +08:00
Add axis and related modules
The axis module instantiates the AXI read and write path modules. It performs a simple stream over the AXI port interface with no error checking. It is configured by first addressing the module and then sending a physical memory address and the number of streaming words to be written. The streaming interface is not exactly like the Xilinx stream interface in that the data is always valid when the valid flag is high, the ready flag being low does not invalidate the data but is used to signal up stream to stop sending data. Down stream has a buffer able to absorb to incoming valid data until such time as up stream stop sending.
This commit is contained in:
parent
3370f1bd32
commit
d9d8540a6c
211
hdl/axis/axis.v
Normal file
211
hdl/axis/axis.v
Normal file
@ -0,0 +1,211 @@
|
||||
/*
|
||||
* Module:
|
||||
* axis
|
||||
*
|
||||
* Description:
|
||||
* The axis module instantiates the AXI read and write path modules.
|
||||
*
|
||||
* Created:
|
||||
* Fri Nov 7 23:07:05 EST 2014
|
||||
*
|
||||
* Author:
|
||||
* Berin Martini (berin.martini@gmail.com)
|
||||
*/
|
||||
`ifndef _axis_ `define _axis_
|
||||
|
||||
|
||||
`include "axis_write.v"
|
||||
`include "axis_read.v"
|
||||
|
||||
module axis #(
|
||||
parameter
|
||||
BUF_AWIDTH = 9,
|
||||
|
||||
CONFIG_ID_WR = 1,
|
||||
CONFIG_ID_RD = 2,
|
||||
CONFIG_ADDR = 23,
|
||||
CONFIG_DATA = 24,
|
||||
CONFIG_AWIDTH = 5,
|
||||
CONFIG_DWIDTH = 32,
|
||||
|
||||
STREAM_WIDTH = 32,
|
||||
|
||||
AXI_ID_WIDTH = 8,
|
||||
AXI_LEN_WIDTH = 8,
|
||||
AXI_ADDR_WIDTH = 32,
|
||||
AXI_DATA_WIDTH = 256)
|
||||
(input clk,
|
||||
input rst,
|
||||
|
||||
// configuation
|
||||
input [CONFIG_AWIDTH-1:0] cfg_addr,
|
||||
input [CONFIG_DWIDTH-1:0] cfg_data,
|
||||
input cfg_valid,
|
||||
|
||||
// stream interface
|
||||
input wr_valid,
|
||||
input [STREAM_WIDTH-1:0] wr_data,
|
||||
output wr_ready,
|
||||
|
||||
output rd_valid,
|
||||
output [STREAM_WIDTH-1:0] rd_data,
|
||||
input rd_ready,
|
||||
|
||||
// AXI write address channel signals
|
||||
input axi_awready,
|
||||
output [AXI_ID_WIDTH-1:0] axi_awid,
|
||||
output [AXI_ADDR_WIDTH-1:0] axi_awaddr,
|
||||
output [AXI_LEN_WIDTH-1:0] axi_awlen,
|
||||
output [2:0] axi_awsize,
|
||||
output [1:0] axi_awburst,
|
||||
output axi_awlock,
|
||||
output [3:0] axi_awcache,
|
||||
output [2:0] axi_awprot,
|
||||
output [3:0] axi_awqos,
|
||||
output axi_awvalid,
|
||||
|
||||
// AXI write data channel signals
|
||||
input axi_wready,
|
||||
output [AXI_DATA_WIDTH-1:0] axi_wdata,
|
||||
output [AXI_DATA_WIDTH/8-1:0] axi_wstrb,
|
||||
output axi_wlast,
|
||||
output axi_wvalid,
|
||||
|
||||
// AXI write response channel signals
|
||||
input [AXI_ID_WIDTH-1:0] axi_bid,
|
||||
input [1:0] axi_bresp,
|
||||
input axi_bvalid,
|
||||
output axi_bready,
|
||||
|
||||
// AXI read address channel signals
|
||||
input axi_arready,
|
||||
output [AXI_ID_WIDTH-1:0] axi_arid,
|
||||
output [AXI_ADDR_WIDTH-1:0] axi_araddr,
|
||||
output [AXI_LEN_WIDTH-1:0] axi_arlen,
|
||||
output [2:0] axi_arsize,
|
||||
output [1:0] axi_arburst,
|
||||
output axi_arlock,
|
||||
output [3:0] axi_arcache,
|
||||
output [2:0] axi_arprot,
|
||||
output axi_arvalid,
|
||||
output [3:0] axi_arqos,
|
||||
|
||||
// AXI read data channel signals
|
||||
input [AXI_ID_WIDTH-1:0] axi_rid,
|
||||
input [1:0] axi_rresp,
|
||||
input axi_rvalid,
|
||||
input [AXI_DATA_WIDTH-1:0] axi_rdata,
|
||||
input axi_rlast,
|
||||
output axi_rready
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* Implementation
|
||||
*/
|
||||
|
||||
// write path static values
|
||||
assign axi_awlock = 1'h0; // NORMAL_ACCESS
|
||||
assign axi_awcache = 4'h0; // NON_CACHE_NON_BUFFER
|
||||
assign axi_awprot = 3'h0; // DATA_SECURE_NORMAL
|
||||
assign axi_awburst = 2'h1; // INCREMENTING
|
||||
assign axi_awqos = 4'h0; // NOT_QOS_PARTICIPANT
|
||||
assign axi_awsize = 3'h5; // THIRTY_TWO_BYTES
|
||||
assign axi_wstrb = {(AXI_DATA_WIDTH/8){1'b1}};
|
||||
|
||||
// read path static values
|
||||
assign axi_arlock = 1'h0; // NORMAL_ACCESS
|
||||
assign axi_arcache = 4'h0; // NON_CACHE_NON_BUFFER
|
||||
assign axi_arprot = 3'h0; // DATA_SECURE_NORMAL
|
||||
assign axi_arburst = 2'h1; // INCREMENTING
|
||||
assign axi_arqos = 4'h0; // NOT_QOS_PARTICIPANT
|
||||
assign axi_arsize = 3'h5; // THIRTY_TWO_BYTES
|
||||
|
||||
|
||||
// assume that all writes are successful and therefore do not need to
|
||||
// check the write response
|
||||
assign axi_bready = 1'b1;
|
||||
|
||||
|
||||
axis_write #(
|
||||
.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),
|
||||
|
||||
.AXI_ID_WIDTH (AXI_ID_WIDTH),
|
||||
.AXI_LEN_WIDTH (AXI_LEN_WIDTH),
|
||||
.AXI_ADDR_WIDTH (AXI_ADDR_WIDTH),
|
||||
.AXI_DATA_WIDTH (AXI_DATA_WIDTH),
|
||||
.DATA_WIDTH (STREAM_WIDTH))
|
||||
axis_write_ (
|
||||
.clk (clk),
|
||||
.rst (rst),
|
||||
|
||||
.cfg_addr (cfg_addr),
|
||||
.cfg_data (cfg_data),
|
||||
.cfg_valid (cfg_valid),
|
||||
|
||||
.axi_awready (axi_awready),
|
||||
.axi_awid (axi_awid),
|
||||
.axi_awaddr (axi_awaddr),
|
||||
.axi_awlen (axi_awlen),
|
||||
.axi_awvalid (axi_awvalid),
|
||||
|
||||
.axi_wlast (axi_wlast),
|
||||
.axi_wdata (axi_wdata),
|
||||
.axi_wvalid (axi_wvalid),
|
||||
.axi_wready (axi_wready),
|
||||
|
||||
.data (wr_data),
|
||||
.valid (wr_valid),
|
||||
.ready (wr_ready)
|
||||
);
|
||||
|
||||
|
||||
axis_read #(
|
||||
.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),
|
||||
|
||||
.AXI_ID_WIDTH (AXI_ID_WIDTH),
|
||||
.AXI_LEN_WIDTH (AXI_LEN_WIDTH),
|
||||
.AXI_ADDR_WIDTH (AXI_ADDR_WIDTH),
|
||||
.AXI_DATA_WIDTH (AXI_DATA_WIDTH),
|
||||
.DATA_WIDTH (STREAM_WIDTH))
|
||||
axis_read_ (
|
||||
.clk (clk),
|
||||
.rst (rst),
|
||||
|
||||
.cfg_addr (cfg_addr),
|
||||
.cfg_data (cfg_data),
|
||||
.cfg_valid (cfg_valid),
|
||||
|
||||
.axi_arready (axi_arready),
|
||||
.axi_arid (axi_arid),
|
||||
.axi_araddr (axi_araddr),
|
||||
.axi_arlen (axi_arlen),
|
||||
.axi_arvalid (axi_arvalid),
|
||||
|
||||
.axi_rresp (axi_rresp),
|
||||
.axi_rlast (axi_rlast),
|
||||
.axi_rdata (axi_rdata),
|
||||
.axi_rvalid (axi_rvalid),
|
||||
.axi_rready (axi_rready),
|
||||
|
||||
.data (rd_data),
|
||||
.valid (rd_valid),
|
||||
.ready (rd_ready)
|
||||
);
|
||||
|
||||
|
||||
endmodule
|
||||
|
||||
`endif // `ifndef _axis_
|
213
hdl/axis/axis_addr.v
Normal file
213
hdl/axis/axis_addr.v
Normal file
@ -0,0 +1,213 @@
|
||||
/**
|
||||
* Module:
|
||||
* axis_addr
|
||||
*
|
||||
* Description:
|
||||
* The axis_addr handles the AXI write address channel.
|
||||
*
|
||||
* Test bench:
|
||||
* axis_addr_tb.v
|
||||
*
|
||||
* Created:
|
||||
* Wed Nov 5 21:15:56 EST 2014
|
||||
*
|
||||
* Author:
|
||||
* Berin Martini (berin.martini@gmail.com)
|
||||
*/
|
||||
`ifndef _axis_addr_ `define _axis_addr_
|
||||
|
||||
|
||||
module axis_addr
|
||||
#(parameter
|
||||
CONFIG_DWIDTH = 32,
|
||||
WIDTH_RATIO = 16,
|
||||
CONVERT_SHIFT = 3,
|
||||
AXI_ID_WIDTH = 8,
|
||||
AXI_LEN_WIDTH = 8,
|
||||
AXI_ADDR_WIDTH = 32)
|
||||
(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 axi_aready,
|
||||
output reg [AXI_ID_WIDTH-1:0] axi_aid,
|
||||
output [AXI_ADDR_WIDTH-1:0] axi_aaddr,
|
||||
output [AXI_LEN_WIDTH-1:0] axi_alen,
|
||||
output axi_avalid
|
||||
);
|
||||
|
||||
/**
|
||||
* Local parameters
|
||||
*/
|
||||
|
||||
localparam BURST_NB_WIDTH = CONFIG_DWIDTH-AXI_LEN_WIDTH;
|
||||
localparam BURST_LENGTH = 1<<AXI_LEN_WIDTH;
|
||||
|
||||
localparam
|
||||
IDLE = 0,
|
||||
SETUP = 1,
|
||||
BURST = 2,
|
||||
LAST = 3,
|
||||
DONE = 4;
|
||||
|
||||
|
||||
|
||||
`ifdef VERBOSE
|
||||
initial $display("\using 'axis_addr'\n");
|
||||
`endif
|
||||
|
||||
|
||||
/**
|
||||
* Internal signals
|
||||
*/
|
||||
|
||||
|
||||
reg [4:0] state;
|
||||
reg [4:0] state_nx;
|
||||
|
||||
reg last_en;
|
||||
reg [AXI_LEN_WIDTH-1:0] last_nb;
|
||||
|
||||
reg burst_en;
|
||||
reg [BURST_NB_WIDTH-1:0] burst_nb;
|
||||
reg [BURST_NB_WIDTH-1:0] burst_cnt;
|
||||
|
||||
reg [CONFIG_DWIDTH-1:0] cfg_length_r;
|
||||
reg cfg_valid_r;
|
||||
reg cfg_done;
|
||||
|
||||
reg [CONFIG_DWIDTH-1:0] axi_address;
|
||||
|
||||
|
||||
/**
|
||||
* Implementation
|
||||
*/
|
||||
|
||||
assign cfg_ready = state[IDLE];
|
||||
|
||||
assign axi_aaddr = axi_address;
|
||||
|
||||
assign axi_alen = state[BURST] ? (BURST_LENGTH-1) : last_nb;
|
||||
|
||||
assign axi_avalid = state[BURST] | state[LAST];
|
||||
|
||||
assign burst_done = (burst_nb == burst_cnt);
|
||||
|
||||
|
||||
always @(posedge clk)
|
||||
if (rst) cfg_valid_r <= 1'b0;
|
||||
else cfg_valid_r <= cfg_valid;
|
||||
|
||||
|
||||
always @(posedge clk)
|
||||
if (cfg_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;
|
||||
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;
|
||||
end
|
||||
else if (axi_aready & state[BURST]) begin
|
||||
// each burst has 256 long words and each long word has 32 bytes
|
||||
axi_address <= axi_address + (BURST_LENGTH * 32);
|
||||
end
|
||||
|
||||
|
||||
always @(posedge clk)
|
||||
if (state[IDLE]) begin
|
||||
burst_cnt <= 'b0;
|
||||
end
|
||||
else if (axi_aready & state[BURST]) begin
|
||||
burst_cnt <= burst_cnt + 1;
|
||||
end
|
||||
|
||||
|
||||
always @(posedge clk)
|
||||
if (rst) begin
|
||||
state <= 'b0;
|
||||
state[IDLE] <= 1'b1;
|
||||
end
|
||||
else state <= state_nx;
|
||||
|
||||
|
||||
always @* begin : ADDR_
|
||||
state_nx <= 'b0;
|
||||
|
||||
case (1'b1)
|
||||
state[IDLE] : begin
|
||||
if (cfg_valid) begin
|
||||
state_nx[SETUP] <= 1'b1;
|
||||
end
|
||||
else state_nx[IDLE] <= 1'b1;
|
||||
end
|
||||
state[SETUP] : begin
|
||||
if (cfg_done & burst_en) begin
|
||||
state_nx[BURST] <= 1'b1;
|
||||
end
|
||||
else if (cfg_done & ~burst_en) begin
|
||||
state_nx[LAST] <= 1'b1;
|
||||
end
|
||||
else state_nx[SETUP] <= 1'b1;
|
||||
end
|
||||
state[BURST] : begin
|
||||
if (axi_aready & burst_done & last_en) begin
|
||||
state_nx[LAST] <= 1'b1;
|
||||
end
|
||||
else if (axi_aready & burst_done & ~last_en) begin
|
||||
state_nx[DONE] <= 1'b1;
|
||||
end
|
||||
else state_nx[BURST] <= 1'b1;
|
||||
end
|
||||
state[LAST] : begin
|
||||
if (axi_aready) begin
|
||||
state_nx[DONE] <= 1'b1;
|
||||
end
|
||||
else state_nx[LAST] <= 1'b1;
|
||||
end
|
||||
state[DONE] : begin
|
||||
state_nx[IDLE] <= 1'b1;
|
||||
end
|
||||
default : begin
|
||||
state_nx[IDLE] <= 1'b1;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
|
||||
always @(posedge clk)
|
||||
if (state[IDLE]) begin
|
||||
axi_aid <= 'b0;
|
||||
end
|
||||
else if (axi_aready & axi_avalid) begin
|
||||
axi_aid <= axi_aid + 1;
|
||||
end
|
||||
|
||||
|
||||
endmodule
|
||||
|
||||
`endif // `ifndef _axis_addr_
|
229
hdl/axis/axis_addr_tb.v
Normal file
229
hdl/axis/axis_addr_tb.v
Normal file
@ -0,0 +1,229 @@
|
||||
/**
|
||||
* Testbench:
|
||||
* axis_addr
|
||||
*
|
||||
* Created:
|
||||
* Wed Nov 5 21:16:08 EST 2014
|
||||
*
|
||||
* Author:
|
||||
* Berin Martini (berin.martini@gmail.com)
|
||||
*/
|
||||
|
||||
`timescale 1ns/10ps
|
||||
|
||||
`define TB_VERBOSE
|
||||
//`define VERBOSE
|
||||
|
||||
|
||||
`include "axis_addr.v"
|
||||
|
||||
module axis_addr_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 CONFIG_DWIDTH = 32;
|
||||
localparam WIDTH_RATIO = 16;
|
||||
localparam AXI_ID_WIDTH = 8;
|
||||
localparam AXI_LEN_WIDTH = 8;
|
||||
localparam AXI_ADDR_WIDTH = 32;
|
||||
|
||||
|
||||
`ifdef TB_VERBOSE
|
||||
initial $display("Testbench for unit 'axis_addr'");
|
||||
`endif
|
||||
|
||||
|
||||
/**
|
||||
* signals, registers and wires
|
||||
*/
|
||||
|
||||
reg rst;
|
||||
|
||||
reg [CONFIG_DWIDTH-1:0] cfg_address;
|
||||
reg [CONFIG_DWIDTH-1:0] cfg_length;
|
||||
reg cfg_valid;
|
||||
wire cfg_ready;
|
||||
|
||||
reg axi_aready;
|
||||
wire [AXI_ID_WIDTH-1:0] axi_aid;
|
||||
wire [AXI_ADDR_WIDTH-1:0] axi_aaddr;
|
||||
wire [AXI_LEN_WIDTH-1:0] axi_alen;
|
||||
wire axi_avalid;
|
||||
|
||||
|
||||
/**
|
||||
* Unit under test
|
||||
*/
|
||||
|
||||
axis_addr #(
|
||||
.CONFIG_DWIDTH (CONFIG_DWIDTH),
|
||||
.WIDTH_RATIO (WIDTH_RATIO),
|
||||
.CONVERT_SHIFT ($clog2(WIDTH_RATIO)),
|
||||
.AXI_ID_WIDTH (AXI_ID_WIDTH),
|
||||
.AXI_LEN_WIDTH (AXI_LEN_WIDTH),
|
||||
.AXI_ADDR_WIDTH (AXI_ADDR_WIDTH))
|
||||
uut (
|
||||
.clk (clk),
|
||||
.rst (rst),
|
||||
|
||||
.cfg_address (cfg_address),
|
||||
.cfg_length (cfg_length),
|
||||
.cfg_valid (cfg_valid),
|
||||
.cfg_ready (cfg_ready),
|
||||
|
||||
.axi_aready (axi_aready),
|
||||
.axi_aid (axi_aid),
|
||||
.axi_aaddr (axi_aaddr),
|
||||
.axi_alen (axi_alen),
|
||||
.axi_avalid (axi_avalid)
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* Wave form display
|
||||
*/
|
||||
|
||||
task display_signals;
|
||||
$display(
|
||||
"%d\t%d",
|
||||
$time, rst,
|
||||
|
||||
"\t%d\t%d\t%b\t%b",
|
||||
cfg_address,
|
||||
cfg_length,
|
||||
cfg_valid,
|
||||
cfg_ready,
|
||||
|
||||
"\t%d\t%d\t%d\t%b\t%b",
|
||||
axi_aid,
|
||||
axi_aaddr,
|
||||
axi_alen,
|
||||
axi_avalid,
|
||||
axi_aready,
|
||||
|
||||
"\tl_en %d\tl_nb %d",
|
||||
uut.last_en,
|
||||
uut.last_nb,
|
||||
|
||||
"\tb_en %d\tb_nb %d",
|
||||
uut.burst_en,
|
||||
uut.burst_nb,
|
||||
|
||||
"\t%b",
|
||||
uut.state,
|
||||
|
||||
);
|
||||
|
||||
endtask // display_signals
|
||||
|
||||
task display_header;
|
||||
$display(
|
||||
"\t\ttime\trst",
|
||||
|
||||
"\t\tc_a",
|
||||
"\t\tc_l",
|
||||
"\tc_v",
|
||||
"\tc_r",
|
||||
|
||||
"\ta_id",
|
||||
"\t\ta_a",
|
||||
"\ta_l",
|
||||
"\ta_v",
|
||||
"\ta_r",
|
||||
|
||||
);
|
||||
endtask
|
||||
|
||||
|
||||
/**
|
||||
* Testbench program
|
||||
*/
|
||||
|
||||
initial begin
|
||||
// init values
|
||||
clk = 0;
|
||||
rst = 0;
|
||||
|
||||
cfg_address = 'b0;
|
||||
cfg_length = 'b0;
|
||||
cfg_valid = 'b0;
|
||||
|
||||
axi_aready = 'b0;
|
||||
//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("send config address and length");
|
||||
`endif
|
||||
|
||||
repeat(5) @(negedge clk);
|
||||
cfg_address <= 255;
|
||||
//cfg_length <= 8;
|
||||
cfg_length <= 256+256+64;
|
||||
cfg_valid <= 1'b1;
|
||||
@(negedge clk);
|
||||
cfg_address <= 'b0;
|
||||
cfg_length <= 'b0;
|
||||
cfg_valid <= 1'b0;
|
||||
repeat(5) @(negedge clk);
|
||||
|
||||
|
||||
`ifdef TB_VERBOSE
|
||||
$display("test write address channel");
|
||||
`endif
|
||||
|
||||
repeat(3) @(negedge clk);
|
||||
axi_aready <= 1'b1;
|
||||
@(negedge clk);
|
||||
axi_aready <= 1'b0;
|
||||
@(negedge clk);
|
||||
axi_aready <= 1'b1;
|
||||
repeat(50) @(negedge clk);
|
||||
|
||||
|
||||
`ifdef TB_VERBOSE
|
||||
$display("END");
|
||||
`endif
|
||||
-> end_trigger;
|
||||
end
|
||||
|
||||
endmodule
|
105
hdl/axis/axis_deserializer.v
Normal file
105
hdl/axis/axis_deserializer.v
Normal file
@ -0,0 +1,105 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
reg [DATA_NB-1:0] token;
|
||||
|
||||
|
||||
/**
|
||||
* Implementation
|
||||
*/
|
||||
|
||||
|
||||
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, token[DATA_NB-1]};
|
||||
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_
|
261
hdl/axis/axis_deserializer_tb.v
Normal file
261
hdl/axis/axis_deserializer_tb.v
Normal file
@ -0,0 +1,261 @@
|
||||
/**
|
||||
* Testbench for:
|
||||
* axis_deserializer
|
||||
*
|
||||
* Created:
|
||||
* Thu Nov 6 17:29:45 EST 2014
|
||||
*
|
||||
* Author:
|
||||
* Berin Martini (berin.martini@gmail.com)
|
||||
*/
|
||||
|
||||
`timescale 1ns/10ps
|
||||
|
||||
`define TB_VERBOSE
|
||||
//`define VERBOSE
|
||||
|
||||
|
||||
`include "axis_deserializer.v"
|
||||
|
||||
module axis_deserializer_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_deserializer' data width: %d, nb: %d",
|
||||
DATA_WIDTH, DATA_NB);
|
||||
end
|
||||
`endif
|
||||
|
||||
|
||||
/**
|
||||
* signals, registers and wires
|
||||
*/
|
||||
|
||||
reg rst;
|
||||
|
||||
reg [DATA_WIDTH-1:0] up_data;
|
||||
reg up_valid;
|
||||
wire up_ready;
|
||||
reg up_last;
|
||||
|
||||
wire [DATA_NB*DATA_WIDTH-1:0] down_data;
|
||||
wire down_valid;
|
||||
reg down_ready;
|
||||
wire down_last;
|
||||
|
||||
reg [DATA_WIDTH-1:0] stream [0:STREAM_LENGTH-1];
|
||||
integer cnt;
|
||||
|
||||
/**
|
||||
* Unit under test
|
||||
*/
|
||||
|
||||
axis_deserializer #(
|
||||
.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),
|
||||
.up_last (up_last),
|
||||
|
||||
.down_data (down_data),
|
||||
.down_valid (down_valid),
|
||||
.down_ready (down_ready),
|
||||
.down_last (down_last)
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* Wave form display
|
||||
*/
|
||||
|
||||
task display_signals;
|
||||
$display(
|
||||
"%d\t%d",
|
||||
$time, rst,
|
||||
|
||||
"\t%x\t%b\t%b\t%b",
|
||||
up_data,
|
||||
up_valid,
|
||||
up_ready,
|
||||
up_last,
|
||||
|
||||
"\t%x\t%b\t%b\t%b",
|
||||
down_data,
|
||||
down_valid,
|
||||
down_ready,
|
||||
down_last,
|
||||
|
||||
);
|
||||
|
||||
endtask // display_signals
|
||||
|
||||
task display_header;
|
||||
$display(
|
||||
"\t\ttime\trst",
|
||||
|
||||
"\tu_d",
|
||||
"\tu_v",
|
||||
"\tu_r",
|
||||
"\tu_l",
|
||||
|
||||
"\td_d",
|
||||
"\td_v",
|
||||
"\td_r",
|
||||
"\td_l",
|
||||
|
||||
);
|
||||
endtask
|
||||
|
||||
|
||||
/**
|
||||
* Testbench program
|
||||
*/
|
||||
|
||||
|
||||
always @(posedge clk)
|
||||
if (up_ready) 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
|
||||
clk = 0;
|
||||
rst = 0;
|
||||
|
||||
up_last = 'b0;
|
||||
|
||||
down_ready = 'b0;
|
||||
|
||||
cnt = 0;
|
||||
repeat (STREAM_LENGTH) begin
|
||||
stream[cnt] = 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
|
||||
|
||||
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;
|
||||
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;
|
||||
@(negedge clk);
|
||||
up_last <= 1'b0;
|
||||
repeat(5) @(negedge clk);
|
||||
down_ready <= 1'b0;
|
||||
repeat(10) @(negedge clk);
|
||||
|
||||
|
||||
|
||||
`ifdef TB_VERBOSE
|
||||
$display("END");
|
||||
`endif
|
||||
-> end_trigger;
|
||||
end
|
||||
|
||||
endmodule
|
255
hdl/axis/axis_read.v
Normal file
255
hdl/axis/axis_read.v
Normal file
@ -0,0 +1,255 @@
|
||||
/**
|
||||
* Module:
|
||||
* axis_read
|
||||
*
|
||||
* Description:
|
||||
* The axis_read is configured to read an area of memory and then converts
|
||||
* the large words that are returned by the AXI into a system stream.
|
||||
*
|
||||
* Test bench:
|
||||
* axis_write_tb.v
|
||||
*
|
||||
* Created:
|
||||
* Fri Nov 7 17:23:00 EST 2014
|
||||
*
|
||||
* Author:
|
||||
* Berin Martini (berin.martini@gmail.com)
|
||||
*/
|
||||
`ifndef _axis_read_ `define _axis_read_
|
||||
|
||||
|
||||
`include "axis_addr.v"
|
||||
`include "axis_read_data.v"
|
||||
|
||||
module axis_read
|
||||
#(parameter
|
||||
BUF_AWIDTH = 9,
|
||||
|
||||
CONFIG_ID = 1,
|
||||
CONFIG_ADDR = 23,
|
||||
CONFIG_DATA = 24,
|
||||
CONFIG_AWIDTH = 5,
|
||||
CONFIG_DWIDTH = 32,
|
||||
|
||||
AXI_ID_WIDTH = 8,
|
||||
AXI_LEN_WIDTH = 8,
|
||||
AXI_ADDR_WIDTH = 32,
|
||||
AXI_DATA_WIDTH = 32,
|
||||
DATA_WIDTH = 32)
|
||||
(input clk,
|
||||
input rst,
|
||||
|
||||
input [CONFIG_AWIDTH-1:0] cfg_addr,
|
||||
input [CONFIG_DWIDTH-1:0] cfg_data,
|
||||
input cfg_valid,
|
||||
|
||||
input axi_arready,
|
||||
output [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_rresp,
|
||||
input axi_rlast,
|
||||
input [AXI_DATA_WIDTH-1:0] axi_rdata,
|
||||
input axi_rvalid,
|
||||
output axi_rready,
|
||||
|
||||
output [DATA_WIDTH-1:0] data,
|
||||
output valid,
|
||||
input ready
|
||||
);
|
||||
|
||||
/**
|
||||
* Local parameters
|
||||
*/
|
||||
|
||||
localparam WIDTH_RATIO = AXI_DATA_WIDTH/DATA_WIDTH;
|
||||
localparam CONFIG_NB = 2;
|
||||
|
||||
localparam
|
||||
C_IDLE = 0,
|
||||
C_CONFIG = 1,
|
||||
C_WAIT = 2,
|
||||
C_ENABLE = 3;
|
||||
|
||||
|
||||
`ifdef VERBOSE
|
||||
initial $display("\using 'axis_read'\n");
|
||||
`endif
|
||||
|
||||
|
||||
/**
|
||||
* Internal signals
|
||||
*/
|
||||
|
||||
|
||||
reg [3:0] c_state;
|
||||
reg [3: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;
|
||||
reg [CONFIG_DWIDTH*CONFIG_NB-1:0] cfg_store;
|
||||
reg [7:0] cfg_cnt;
|
||||
|
||||
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;
|
||||
reg cfg_enable;
|
||||
|
||||
|
||||
/**
|
||||
* Implementation
|
||||
*/
|
||||
|
||||
assign start_addr = cfg_store[CONFIG_DWIDTH +: CONFIG_DWIDTH];
|
||||
|
||||
assign str_length = cfg_store[0 +: CONFIG_DWIDTH];
|
||||
|
||||
assign id_valid = (CONFIG_ID == cfg_data_r);
|
||||
|
||||
assign addressed = (CONFIG_ADDR == cfg_addr_r) & cfg_valid_r;
|
||||
|
||||
assign axis_data = (CONFIG_DATA == cfg_addr_r) & 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
|
||||
|
||||
|
||||
always @(posedge clk)
|
||||
if (c_state[C_CONFIG] & axis_data) begin
|
||||
cfg_store <= {cfg_store, cfg_data_r};
|
||||
end
|
||||
|
||||
|
||||
always @(posedge clk) begin
|
||||
cfg_cnt <= 'b0;
|
||||
|
||||
if (c_state[C_CONFIG]) begin
|
||||
cfg_cnt <= cfg_cnt + 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;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
always @(posedge clk)
|
||||
if (rst) begin
|
||||
c_state <= 'b0;
|
||||
c_state[C_IDLE] <= 1'b1;
|
||||
end
|
||||
else c_state <= c_state_nx;
|
||||
|
||||
|
||||
always @* begin : CONFIG_
|
||||
c_state_nx = 'b0;
|
||||
|
||||
case (1'b1)
|
||||
c_state[C_IDLE] : begin
|
||||
if (addressed & id_valid) begin
|
||||
c_state_nx[C_CONFIG] = 1'b1;
|
||||
end
|
||||
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;
|
||||
end
|
||||
else c_state_nx[C_CONFIG] = 1'b1;
|
||||
end
|
||||
c_state[C_WAIT] : begin
|
||||
if (cfg_addr_ready & cfg_data_ready) begin
|
||||
c_state_nx[C_ENABLE] = 1'b1;
|
||||
end
|
||||
else c_state_nx[C_WAIT] = 1'b1;
|
||||
end
|
||||
c_state[C_ENABLE] : begin
|
||||
c_state_nx[C_IDLE] = 1'b1;
|
||||
end
|
||||
default : begin
|
||||
c_state_nx[C_IDLE] = 1'b1;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
|
||||
axis_addr #(
|
||||
.CONFIG_DWIDTH (CONFIG_DWIDTH),
|
||||
.WIDTH_RATIO (WIDTH_RATIO),
|
||||
.CONVERT_SHIFT ($clog2(WIDTH_RATIO)),
|
||||
.AXI_ID_WIDTH (AXI_ID_WIDTH),
|
||||
.AXI_LEN_WIDTH (AXI_LEN_WIDTH),
|
||||
.AXI_ADDR_WIDTH (AXI_ADDR_WIDTH))
|
||||
axis_addr_ (
|
||||
.clk (clk),
|
||||
.rst (rst),
|
||||
|
||||
.cfg_address (cfg_address),
|
||||
.cfg_length (cfg_length),
|
||||
.cfg_valid (cfg_enable),
|
||||
.cfg_ready (cfg_addr_ready),
|
||||
|
||||
.axi_aready (axi_arready),
|
||||
.axi_aid (axi_arid),
|
||||
.axi_aaddr (axi_araddr),
|
||||
.axi_alen (axi_arlen),
|
||||
.axi_avalid (axi_arvalid)
|
||||
);
|
||||
|
||||
|
||||
axis_read_data #(
|
||||
.BUF_AWIDTH (BUF_AWIDTH),
|
||||
.CONFIG_DWIDTH (CONFIG_DWIDTH),
|
||||
.WIDTH_RATIO (WIDTH_RATIO),
|
||||
.AXI_DATA_WIDTH (AXI_DATA_WIDTH),
|
||||
.DATA_WIDTH (DATA_WIDTH))
|
||||
axis_read_data_ (
|
||||
.clk (clk),
|
||||
.rst (rst),
|
||||
|
||||
.cfg_length (cfg_length),
|
||||
.cfg_valid (cfg_enable),
|
||||
.cfg_ready (cfg_data_ready),
|
||||
|
||||
.axi_rresp (axi_rresp),
|
||||
.axi_rlast (axi_rlast),
|
||||
.axi_rdata (axi_rdata),
|
||||
.axi_rvalid (axi_rvalid),
|
||||
.axi_rready (axi_rready),
|
||||
|
||||
.data (data),
|
||||
.valid (valid),
|
||||
.ready (ready)
|
||||
);
|
||||
|
||||
|
||||
|
||||
endmodule
|
||||
|
||||
`endif // `ifndef _axis_read_
|
184
hdl/axis/axis_read_data.v
Normal file
184
hdl/axis/axis_read_data.v
Normal file
@ -0,0 +1,184 @@
|
||||
/**
|
||||
* Module:
|
||||
* axis_read_data
|
||||
*
|
||||
* Description:
|
||||
* The axis_read_data handles the AXI read data channel.
|
||||
*
|
||||
* Testbench:
|
||||
* axis_read_data_tb.v
|
||||
*
|
||||
* Created:
|
||||
* Tue Nov 4 22:18:14 EST 2014
|
||||
*
|
||||
* Author:
|
||||
* Berin Martini (berin.martini@gmail.com)
|
||||
*/
|
||||
`ifndef _axis_read_data_ `define _axis_read_data_
|
||||
|
||||
|
||||
`include "fifo_simple.v"
|
||||
`include "axis_serializer.v"
|
||||
|
||||
module axis_read_data
|
||||
#(parameter
|
||||
BUF_AWIDTH = 9,
|
||||
CONFIG_DWIDTH = 32,
|
||||
WIDTH_RATIO = 16,
|
||||
|
||||
AXI_DATA_WIDTH = 32,
|
||||
DATA_WIDTH = 32)
|
||||
(input clk,
|
||||
input rst,
|
||||
|
||||
input [CONFIG_DWIDTH-1:0] cfg_length,
|
||||
input cfg_valid,
|
||||
output cfg_ready,
|
||||
|
||||
input axi_rresp,
|
||||
input axi_rlast,
|
||||
input [AXI_DATA_WIDTH-1:0] axi_rdata,
|
||||
input axi_rvalid,
|
||||
output axi_rready,
|
||||
|
||||
output [DATA_WIDTH-1:0] data,
|
||||
output reg valid,
|
||||
input ready
|
||||
);
|
||||
|
||||
/**
|
||||
* Local parameters
|
||||
*/
|
||||
|
||||
localparam
|
||||
IDLE = 0,
|
||||
ACTIVE = 1,
|
||||
WAIT = 2,
|
||||
DONE = 3;
|
||||
|
||||
|
||||
`ifdef VERBOSE
|
||||
initial $display("\using 'axis_read_data'\n");
|
||||
`endif
|
||||
|
||||
|
||||
/**
|
||||
* Internal signals
|
||||
*/
|
||||
|
||||
reg [3:0] state;
|
||||
reg [3:0] state_nx;
|
||||
|
||||
reg [CONFIG_DWIDTH-1:0] str_cnt;
|
||||
reg [CONFIG_DWIDTH-1:0] str_length;
|
||||
|
||||
wire buf_pop;
|
||||
wire buf_full;
|
||||
wire buf_empty;
|
||||
wire [DATA_WIDTH-1:0] buf_data;
|
||||
wire buf_valid;
|
||||
|
||||
/**
|
||||
* Implementation
|
||||
*/
|
||||
|
||||
assign cfg_ready = state[IDLE];
|
||||
|
||||
assign buf_pop = ~buf_empty & ready;
|
||||
|
||||
|
||||
always @(posedge clk)
|
||||
if (cfg_valid) begin
|
||||
str_length <= cfg_length-1;
|
||||
end
|
||||
|
||||
|
||||
always @(posedge clk)
|
||||
if (state[IDLE]) str_cnt <= 'b0;
|
||||
else str_cnt <= str_cnt + buf_pop;
|
||||
|
||||
|
||||
always @(posedge clk)
|
||||
if (rst) valid <= 1'b0;
|
||||
else valid <= buf_pop & state[ACTIVE];
|
||||
|
||||
|
||||
fifo_simple #(
|
||||
.DATA_WIDTH (DATA_WIDTH),
|
||||
.ADDR_WIDTH (BUF_AWIDTH))
|
||||
buffer_ (
|
||||
.clk (clk),
|
||||
.rst (state[IDLE]),
|
||||
|
||||
.count (),
|
||||
.empty (buf_empty),
|
||||
.empty_a (),
|
||||
.full (buf_full),
|
||||
.full_a (),
|
||||
|
||||
.push_data (buf_data),
|
||||
.push (buf_valid),
|
||||
|
||||
.pop_data (data),
|
||||
.pop (buf_pop)
|
||||
);
|
||||
|
||||
|
||||
axis_serializer #(
|
||||
.DATA_NB (WIDTH_RATIO),
|
||||
.DATA_WIDTH (DATA_WIDTH))
|
||||
serializer_ (
|
||||
.clk (clk),
|
||||
.rst (state[IDLE]),
|
||||
|
||||
.up_data (axi_rdata),
|
||||
.up_valid (axi_rvalid),
|
||||
.up_ready (axi_rready),
|
||||
|
||||
.down_data (buf_data),
|
||||
.down_valid (buf_valid),
|
||||
.down_ready ( ~buf_full)
|
||||
);
|
||||
|
||||
|
||||
always @(posedge clk)
|
||||
if (rst) begin
|
||||
state <= 'b0;
|
||||
state[IDLE] <= 1'b1;
|
||||
end
|
||||
else state <= state_nx;
|
||||
|
||||
|
||||
always @* begin : DATA_
|
||||
state_nx <= 'b0;
|
||||
|
||||
case (1'b1)
|
||||
state[IDLE] : begin
|
||||
if (cfg_valid) begin
|
||||
state_nx[ACTIVE] <= 1'b1;
|
||||
end
|
||||
else state_nx[IDLE] <= 1'b1;
|
||||
end
|
||||
state[ACTIVE] : begin
|
||||
if (buf_pop & (str_length == str_cnt)) begin
|
||||
state_nx[WAIT] <= 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;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
|
||||
|
||||
endmodule
|
||||
|
||||
`endif // `ifndef _axis_read_data_
|
240
hdl/axis/axis_read_data_tb.v
Normal file
240
hdl/axis/axis_read_data_tb.v
Normal file
@ -0,0 +1,240 @@
|
||||
/**
|
||||
* Testbench:
|
||||
* axis_read_data
|
||||
*
|
||||
* Created:
|
||||
* Tue Nov 4 22:17:15 EST 2014
|
||||
*
|
||||
* Author:
|
||||
* Berin Martini (berin.martini@gmail.com)
|
||||
*/
|
||||
|
||||
`timescale 1ns/10ps
|
||||
|
||||
`define TB_VERBOSE
|
||||
//`define VERBOSE
|
||||
|
||||
|
||||
`include "axis_read_data.v"
|
||||
|
||||
module axis_read_data_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 STREAM_LENGTH = (256*8*2)-4;
|
||||
|
||||
localparam BUF_AWIDTH = 4;
|
||||
localparam CONFIG_DWIDTH = 32;
|
||||
localparam WIDTH_RATIO = 8;
|
||||
localparam AXI_DATA_WIDTH = 256;
|
||||
localparam DATA_WIDTH = 32;
|
||||
|
||||
|
||||
`ifdef TB_VERBOSE
|
||||
initial $display("Testbench for unit 'axis_read_data'");
|
||||
`endif
|
||||
|
||||
|
||||
/**
|
||||
* signals, registers and wires
|
||||
*/
|
||||
|
||||
reg rst;
|
||||
|
||||
reg [CONFIG_DWIDTH-1:0] cfg_length;
|
||||
reg cfg_valid;
|
||||
wire cfg_ready;
|
||||
|
||||
reg axi_rresp;
|
||||
reg axi_rlast;
|
||||
reg [AXI_DATA_WIDTH-1:0] axi_rdata;
|
||||
reg axi_rvalid;
|
||||
wire axi_rready;
|
||||
|
||||
wire [DATA_WIDTH-1:0] data;
|
||||
wire valid;
|
||||
reg ready;
|
||||
|
||||
|
||||
/**
|
||||
* Unit under test
|
||||
*/
|
||||
|
||||
axis_read_data #(
|
||||
.BUF_AWIDTH (BUF_AWIDTH),
|
||||
.CONFIG_DWIDTH (CONFIG_DWIDTH),
|
||||
.WIDTH_RATIO (WIDTH_RATIO),
|
||||
|
||||
.AXI_DATA_WIDTH (AXI_DATA_WIDTH),
|
||||
.DATA_WIDTH (DATA_WIDTH))
|
||||
uut (
|
||||
.clk (clk),
|
||||
.rst (rst),
|
||||
|
||||
.cfg_length (cfg_length),
|
||||
.cfg_valid (cfg_valid),
|
||||
.cfg_ready (cfg_ready),
|
||||
|
||||
.axi_rresp (axi_rresp),
|
||||
.axi_rlast (axi_rlast),
|
||||
.axi_rdata (axi_rdata),
|
||||
.axi_rvalid (axi_rvalid),
|
||||
.axi_rready (axi_rready),
|
||||
|
||||
.data (data),
|
||||
.valid (valid),
|
||||
.ready (ready)
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* Wave form display
|
||||
*/
|
||||
|
||||
task display_signals;
|
||||
$display(
|
||||
"%d\t%d",
|
||||
$time, rst,
|
||||
|
||||
"\t%d\t%b",
|
||||
cfg_length,
|
||||
cfg_valid,
|
||||
cfg_ready,
|
||||
|
||||
"\t%x\t%b\t%b",
|
||||
axi_rdata,
|
||||
axi_rvalid,
|
||||
axi_rready,
|
||||
|
||||
"\t%x\t%b\t%b",
|
||||
data,
|
||||
valid,
|
||||
ready,
|
||||
|
||||
"\t%b",
|
||||
uut.state,
|
||||
|
||||
);
|
||||
|
||||
endtask // display_signals
|
||||
|
||||
task display_header;
|
||||
$display(
|
||||
"\t\ttime\trst",
|
||||
|
||||
"\t\tc_l",
|
||||
"\tc_v",
|
||||
"\tc_r",
|
||||
|
||||
"\t\t\t\t\t\tr_d",
|
||||
"\t\t\tr_v",
|
||||
"\tr_r",
|
||||
|
||||
"\t\ts_d",
|
||||
"\ts_v",
|
||||
"\ts_r",
|
||||
|
||||
);
|
||||
endtask
|
||||
|
||||
|
||||
/**
|
||||
* Testbench program
|
||||
*/
|
||||
|
||||
initial begin
|
||||
// init values
|
||||
clk = 0;
|
||||
rst = 0;
|
||||
|
||||
cfg_length = 'b0;
|
||||
cfg_valid = 'b0;
|
||||
|
||||
axi_rresp = 'b0;
|
||||
axi_rlast = 'b0;
|
||||
axi_rdata = 'b0;
|
||||
axi_rvalid = 'b0;
|
||||
|
||||
ready = 'b0;
|
||||
//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("send config id, start address and length");
|
||||
`endif
|
||||
|
||||
repeat(5) @(negedge clk);
|
||||
cfg_length <= 10;
|
||||
cfg_valid <= 1'b1;
|
||||
@(negedge clk)
|
||||
|
||||
cfg_length <= 'b0;
|
||||
cfg_valid <= 1'b0;
|
||||
repeat(5) @(negedge clk);
|
||||
|
||||
|
||||
`ifdef TB_VERBOSE
|
||||
$display("test read");
|
||||
`endif
|
||||
|
||||
ready <= 1'b1;
|
||||
repeat(5) @(negedge clk);
|
||||
|
||||
axi_rdata <= {32'd8, 32'd7, 32'd6, 32'd5, 32'd4, 32'd3, 32'd2, 32'd1};
|
||||
axi_rvalid <= 1'b1;
|
||||
@(negedge clk);
|
||||
axi_rdata <= {32'd9, 32'd8, 32'd7, 32'd6, 32'd5, 32'd4, 32'd3, 32'd2};
|
||||
while ( ~axi_rready) @(negedge clk);
|
||||
axi_rvalid <= 1'b1;
|
||||
@(negedge clk);
|
||||
axi_rdata <= 'b0;
|
||||
axi_rvalid <= 1'b0;
|
||||
|
||||
repeat(15) @(negedge clk);
|
||||
|
||||
`ifdef TB_VERBOSE
|
||||
$display("END");
|
||||
`endif
|
||||
-> end_trigger;
|
||||
end
|
||||
|
||||
endmodule
|
439
hdl/axis/axis_read_tb.v
Normal file
439
hdl/axis/axis_read_tb.v
Normal file
@ -0,0 +1,439 @@
|
||||
/**
|
||||
* Testbench:
|
||||
* axis_read
|
||||
*
|
||||
* Created:
|
||||
* Fri Nov 7 17:22:50 EST 2014
|
||||
*
|
||||
* Author:
|
||||
* Berin Martini (berin.martini@gmail.com)
|
||||
*/
|
||||
|
||||
`timescale 1ns/10ps
|
||||
|
||||
`define TB_VERBOSE
|
||||
//`define VERBOSE
|
||||
|
||||
|
||||
`include "axis_read.v"
|
||||
|
||||
module axis_read_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 STREAM_LENGTH = (256*8*2)-4;
|
||||
|
||||
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 AXI_ID_WIDTH = 8;
|
||||
localparam AXI_ADDR_WIDTH = 32;
|
||||
localparam AXI_DATA_WIDTH = 256;
|
||||
localparam DATA_WIDTH = 32;
|
||||
|
||||
|
||||
`ifdef TB_VERBOSE
|
||||
initial $display("Testbench for unit 'axis_read'");
|
||||
`endif
|
||||
|
||||
|
||||
/**
|
||||
* signals, registers and wires
|
||||
*/
|
||||
|
||||
reg rst;
|
||||
|
||||
reg [CONFIG_AWIDTH-1:0] cfg_addr;
|
||||
reg [CONFIG_DWIDTH-1:0] cfg_data;
|
||||
reg cfg_valid;
|
||||
|
||||
reg axi_arready;
|
||||
wire [AXI_ID_WIDTH-1:0] axi_arid;
|
||||
wire [AXI_ADDR_WIDTH-1:0] axi_araddr;
|
||||
wire [7:0] axi_arlen;
|
||||
wire axi_arvalid;
|
||||
|
||||
reg [AXI_DATA_WIDTH-1:0] axi_rdata;
|
||||
reg axi_rvalid;
|
||||
wire axi_rready;
|
||||
|
||||
wire [DATA_WIDTH-1:0] data;
|
||||
wire valid;
|
||||
reg ready;
|
||||
|
||||
|
||||
/**
|
||||
* Unit under test
|
||||
*/
|
||||
|
||||
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),
|
||||
|
||||
.AXI_ID_WIDTH (AXI_ID_WIDTH),
|
||||
.AXI_ADDR_WIDTH (AXI_ADDR_WIDTH),
|
||||
.AXI_DATA_WIDTH (AXI_DATA_WIDTH),
|
||||
.DATA_WIDTH (DATA_WIDTH))
|
||||
uut (
|
||||
.clk (clk),
|
||||
.rst (rst),
|
||||
|
||||
.cfg_addr (cfg_addr),
|
||||
.cfg_data (cfg_data),
|
||||
.cfg_valid (cfg_valid),
|
||||
|
||||
.axi_arready (axi_arready),
|
||||
.axi_arid (axi_arid),
|
||||
.axi_araddr (axi_araddr),
|
||||
.axi_arlen (axi_arlen),
|
||||
.axi_arvalid (axi_arvalid),
|
||||
|
||||
.axi_rresp (),
|
||||
.axi_rlast (),
|
||||
.axi_rdata (axi_rdata),
|
||||
.axi_rvalid (axi_rvalid),
|
||||
.axi_rready (axi_rready),
|
||||
|
||||
.data (data),
|
||||
.valid (valid),
|
||||
.ready (ready)
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* Wave form display
|
||||
*/
|
||||
|
||||
task display_signals;
|
||||
$display(
|
||||
"%d\t%d",
|
||||
$time, rst,
|
||||
|
||||
"\t%d\t%d\t%b",
|
||||
cfg_addr,
|
||||
cfg_data,
|
||||
cfg_valid,
|
||||
|
||||
"\t%d\t%d\t%d\t%b\t%b",
|
||||
axi_arid,
|
||||
axi_araddr,
|
||||
axi_arlen,
|
||||
axi_arvalid,
|
||||
axi_arready,
|
||||
|
||||
"\t%x\t%b\t%b",
|
||||
axi_rdata,
|
||||
axi_rvalid,
|
||||
axi_rready,
|
||||
|
||||
"\t%d\t%b\t%b",
|
||||
data,
|
||||
valid,
|
||||
ready,
|
||||
|
||||
"\t%b",
|
||||
uut.c_state,
|
||||
|
||||
"\t%b",
|
||||
uut.axis_addr_.state,
|
||||
|
||||
);
|
||||
|
||||
endtask // display_signals
|
||||
|
||||
task display_header;
|
||||
$display(
|
||||
"\t\ttime\trst",
|
||||
|
||||
"\tc_a",
|
||||
"\t\tc_d",
|
||||
"\tc_v",
|
||||
|
||||
"\tar_id",
|
||||
"\t\tar_a",
|
||||
"\tar_l",
|
||||
"\tar_v",
|
||||
"\tar_r",
|
||||
|
||||
"\t\t\t\t\t\tr_d",
|
||||
"\t\t\t\tr_v",
|
||||
"\tr_r",
|
||||
|
||||
"\t\ts_d",
|
||||
"\ts_v",
|
||||
"\tm_r",
|
||||
|
||||
);
|
||||
endtask
|
||||
|
||||
|
||||
/**
|
||||
* Testbench program
|
||||
*/
|
||||
|
||||
initial begin
|
||||
// init values
|
||||
clk = 0;
|
||||
rst = 0;
|
||||
|
||||
cfg_addr = 'b0;
|
||||
cfg_data = 'b0;
|
||||
cfg_valid = 'b0;
|
||||
|
||||
axi_arready = 'b0;
|
||||
|
||||
axi_rdata = 'b0;
|
||||
axi_rvalid = 'b0;
|
||||
|
||||
ready = 'b0;
|
||||
//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("send config id, start address and length");
|
||||
`endif
|
||||
|
||||
repeat(5) @(negedge clk);
|
||||
cfg_addr <= CONFIG_ADDR;
|
||||
cfg_data <= CONFIG_ID;
|
||||
cfg_valid <= 1'b1;
|
||||
@(negedge clk)
|
||||
|
||||
cfg_addr <= 'b0;
|
||||
cfg_data <= 'b0;
|
||||
cfg_valid <= 1'b0;
|
||||
repeat(5) @(negedge clk);
|
||||
|
||||
// memory address
|
||||
cfg_addr <= CONFIG_DATA;
|
||||
cfg_data <= 4;
|
||||
cfg_valid <= 1'b1;
|
||||
@(negedge clk)
|
||||
|
||||
cfg_addr <= 'b0;
|
||||
cfg_data <= 'b0;
|
||||
cfg_valid <= 1'b0;
|
||||
repeat(5) @(negedge clk);
|
||||
|
||||
// length of flow stream
|
||||
cfg_addr <= CONFIG_DATA;
|
||||
cfg_data <= 8;
|
||||
cfg_valid <= 1'b1;
|
||||
@(negedge clk)
|
||||
|
||||
cfg_addr <= 'b0;
|
||||
cfg_data <= 'b0;
|
||||
cfg_valid <= 1'b0;
|
||||
repeat(5) @(negedge clk);
|
||||
|
||||
|
||||
`ifdef TB_VERBOSE
|
||||
$display("test read address channel");
|
||||
`endif
|
||||
|
||||
repeat(3) @(negedge clk);
|
||||
axi_arready <= 1'b1;
|
||||
repeat(5) @(negedge clk);
|
||||
axi_arready <= 1'b0;
|
||||
|
||||
|
||||
`ifdef TB_VERBOSE
|
||||
$display("test read data channel");
|
||||
`endif
|
||||
|
||||
@(negedge clk);
|
||||
|
||||
ready <= 1'b1;
|
||||
axi_rdata <= 'b0;
|
||||
axi_rvalid <= 1'b0;
|
||||
repeat(5) @(negedge clk);
|
||||
|
||||
axi_rdata <= {32'd8, 32'd7, 32'd6, 32'd5, 32'd4, 32'd3, 32'd2, 32'd1};
|
||||
axi_rvalid <= 1'b1;
|
||||
@(negedge clk);
|
||||
|
||||
axi_rvalid <= 1'b0;
|
||||
repeat(15) @(negedge clk);
|
||||
|
||||
|
||||
`ifdef TB_VERBOSE
|
||||
$display("send config id, start address and length");
|
||||
`endif
|
||||
|
||||
repeat(5) @(negedge clk);
|
||||
cfg_addr <= CONFIG_ADDR;
|
||||
cfg_data <= CONFIG_ID;
|
||||
cfg_valid <= 1'b1;
|
||||
@(negedge clk)
|
||||
|
||||
cfg_addr <= CONFIG_DATA;
|
||||
cfg_data <= 4;
|
||||
cfg_valid <= 1'b1;
|
||||
@(negedge clk)
|
||||
|
||||
cfg_addr <= CONFIG_DATA;
|
||||
cfg_data <= 20;
|
||||
cfg_valid <= 1'b1;
|
||||
@(negedge clk)
|
||||
|
||||
cfg_addr <= 'b0;
|
||||
cfg_data <= 'b0;
|
||||
cfg_valid <= 1'b0;
|
||||
repeat(5) @(negedge clk);
|
||||
|
||||
|
||||
`ifdef TB_VERBOSE
|
||||
$display("test read address channel");
|
||||
`endif
|
||||
|
||||
repeat(3) @(negedge clk);
|
||||
axi_arready <= 1'b1;
|
||||
repeat(5) @(negedge clk);
|
||||
|
||||
|
||||
`ifdef TB_VERBOSE
|
||||
$display("test read data channel");
|
||||
`endif
|
||||
|
||||
|
||||
@(negedge clk);
|
||||
|
||||
ready <= 1'b1;
|
||||
axi_rdata <= 'b0;
|
||||
axi_rvalid <= 1'b0;
|
||||
repeat(5) @(negedge clk);
|
||||
|
||||
axi_rdata <= {32'd8, 32'd7, 32'd6, 32'd5, 32'd4, 32'd3, 32'd2, 32'd1};
|
||||
axi_rvalid <= 1'b1;
|
||||
@(negedge clk);
|
||||
axi_rdata <= {32'd16, 32'd15, 32'd14, 32'd13, 32'd12, 32'd11, 32'd10, 32'd9};
|
||||
while ( ~axi_rready) @(negedge clk);
|
||||
axi_rvalid <= 1'b1;
|
||||
@(negedge clk);
|
||||
axi_rdata <= {32'd24, 32'd23, 32'd22, 32'd21, 32'd20, 32'd19, 32'd18, 32'd17};
|
||||
while ( ~axi_rready) @(negedge clk);
|
||||
axi_rvalid <= 1'b1;
|
||||
@(negedge clk);
|
||||
axi_rdata <= 'b0;
|
||||
axi_rvalid <= 1'b0;
|
||||
|
||||
axi_rvalid <= 1'b0;
|
||||
repeat(15) @(negedge clk);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
||||
`ifdef TB_VERBOSE
|
||||
$display("send config id, start address and length");
|
||||
`endif
|
||||
|
||||
repeat(5) @(negedge clk);
|
||||
cfg_addr <= CONFIG_ADDR;
|
||||
cfg_data <= CONFIG_ID;
|
||||
cfg_valid <= 1'b1;
|
||||
@(negedge clk)
|
||||
|
||||
cfg_addr <= CONFIG_DATA;
|
||||
cfg_data <= 255;
|
||||
cfg_valid <= 1'b1;
|
||||
@(negedge clk)
|
||||
|
||||
cfg_addr <= CONFIG_DATA;
|
||||
cfg_data <= STREAM_LENGTH;
|
||||
cfg_valid <= 1'b1;
|
||||
@(negedge clk)
|
||||
|
||||
cfg_addr <= 'b0;
|
||||
cfg_data <= 'b0;
|
||||
cfg_valid <= 1'b0;
|
||||
repeat(5) @(negedge clk);
|
||||
|
||||
|
||||
`ifdef TB_VERBOSE
|
||||
$display("test long read");
|
||||
`endif
|
||||
|
||||
repeat(3) @(negedge clk);
|
||||
// ready to recive address
|
||||
axi_arready <= 1'b1;
|
||||
repeat(5) @(negedge clk);
|
||||
|
||||
|
||||
// ready to recive data
|
||||
axi_rready <= 1'b1;
|
||||
data <= 'b0;
|
||||
valid <= 1'b0;
|
||||
repeat(5) @(negedge clk);
|
||||
|
||||
|
||||
repeat (STREAM_LENGTH) begin
|
||||
// stream data into axis
|
||||
data <= data + 1;
|
||||
valid <= 1'b1;
|
||||
@(negedge clk);
|
||||
end
|
||||
|
||||
valid <= 1'b0;
|
||||
repeat(15) @(negedge clk);
|
||||
axi_rready <= 1'b0;
|
||||
repeat(15) @(negedge clk);
|
||||
*/
|
||||
|
||||
|
||||
`ifdef TB_VERBOSE
|
||||
$display("END");
|
||||
`endif
|
||||
-> end_trigger;
|
||||
end
|
||||
|
||||
endmodule
|
117
hdl/axis/axis_serializer.v
Normal file
117
hdl/axis/axis_serializer.v
Normal file
@ -0,0 +1,117 @@
|
||||
/**
|
||||
* 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-1: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], 1'b0};
|
||||
if (up_ready & up_valid) begin
|
||||
serial_valid <= {serial_valid[0 +: DATA_NB-1], 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);
|
||||
end
|
||||
|
||||
|
||||
|
||||
endmodule
|
||||
|
||||
`endif // `ifndef _axis_serializer_
|
243
hdl/axis/axis_serializer_tb.v
Normal file
243
hdl/axis/axis_serializer_tb.v
Normal file
@ -0,0 +1,243 @@
|
||||
/**
|
||||
* 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
|
255
hdl/axis/axis_write.v
Normal file
255
hdl/axis/axis_write.v
Normal file
@ -0,0 +1,255 @@
|
||||
/**
|
||||
* Module:
|
||||
* axis_write
|
||||
*
|
||||
* Description:
|
||||
* The axis_write takes a system stream an translate it to the axi data
|
||||
* channel protocol.
|
||||
*
|
||||
* Test bench:
|
||||
* axis_write_tb.v
|
||||
*
|
||||
* Created:
|
||||
* Tue Nov 4 22:18:14 EST 2014
|
||||
*
|
||||
* Author:
|
||||
* Berin Martini (berin.martini@gmail.com)
|
||||
*/
|
||||
`ifndef _axis_write_ `define _axis_write_
|
||||
|
||||
|
||||
`include "axis_addr.v"
|
||||
`include "axis_write_data.v"
|
||||
|
||||
module axis_write
|
||||
#(parameter
|
||||
BUF_AWIDTH = 9,
|
||||
|
||||
CONFIG_ID = 1,
|
||||
CONFIG_ADDR = 23,
|
||||
CONFIG_DATA = 24,
|
||||
CONFIG_AWIDTH = 5,
|
||||
CONFIG_DWIDTH = 32,
|
||||
|
||||
AXI_ID_WIDTH = 8,
|
||||
AXI_LEN_WIDTH = 8,
|
||||
AXI_ADDR_WIDTH = 32,
|
||||
AXI_DATA_WIDTH = 32,
|
||||
DATA_WIDTH = 32)
|
||||
(input clk,
|
||||
input rst,
|
||||
|
||||
input [CONFIG_AWIDTH-1:0] cfg_addr,
|
||||
input [CONFIG_DWIDTH-1:0] cfg_data,
|
||||
input cfg_valid,
|
||||
|
||||
input axi_awready,
|
||||
output [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,
|
||||
|
||||
output axi_wlast,
|
||||
output [AXI_DATA_WIDTH-1:0] axi_wdata,
|
||||
output axi_wvalid,
|
||||
input axi_wready,
|
||||
|
||||
input [DATA_WIDTH-1:0] data,
|
||||
input valid,
|
||||
output ready
|
||||
);
|
||||
|
||||
/**
|
||||
* Local parameters
|
||||
*/
|
||||
|
||||
localparam WIDTH_RATIO = AXI_DATA_WIDTH/DATA_WIDTH;
|
||||
localparam CONFIG_NB = 2;
|
||||
|
||||
localparam
|
||||
C_IDLE = 0,
|
||||
C_CONFIG = 1,
|
||||
C_WAIT = 2,
|
||||
C_ENABLE = 3;
|
||||
|
||||
|
||||
`ifdef VERBOSE
|
||||
initial $display("\using 'axis_write'\n");
|
||||
`endif
|
||||
|
||||
|
||||
/**
|
||||
* Internal signals
|
||||
*/
|
||||
|
||||
|
||||
reg [3:0] c_state;
|
||||
reg [3: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;
|
||||
reg [CONFIG_DWIDTH*CONFIG_NB-1:0] cfg_store;
|
||||
reg [7:0] cfg_cnt;
|
||||
|
||||
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;
|
||||
reg cfg_enable;
|
||||
|
||||
|
||||
/**
|
||||
* Implementation
|
||||
*/
|
||||
|
||||
assign start_addr = cfg_store[CONFIG_DWIDTH +: CONFIG_DWIDTH];
|
||||
|
||||
assign str_length = cfg_store[0 +: CONFIG_DWIDTH];
|
||||
|
||||
assign id_valid = (CONFIG_ID == cfg_data_r);
|
||||
|
||||
assign addressed = (CONFIG_ADDR == cfg_addr_r) & cfg_valid_r;
|
||||
|
||||
assign axis_data = (CONFIG_DATA == cfg_addr_r) & 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
|
||||
|
||||
|
||||
always @(posedge clk)
|
||||
if (c_state[C_CONFIG] & axis_data) begin
|
||||
cfg_store <= {cfg_store, cfg_data_r};
|
||||
end
|
||||
|
||||
|
||||
always @(posedge clk) begin
|
||||
cfg_cnt <= 'b0;
|
||||
|
||||
if (c_state[C_CONFIG]) begin
|
||||
cfg_cnt <= cfg_cnt + 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;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
always @(posedge clk)
|
||||
if (rst) begin
|
||||
c_state <= 'b0;
|
||||
c_state[C_IDLE] <= 1'b1;
|
||||
end
|
||||
else c_state <= c_state_nx;
|
||||
|
||||
|
||||
always @* begin : CONFIG_
|
||||
c_state_nx = 'b0;
|
||||
|
||||
case (1'b1)
|
||||
c_state[C_IDLE] : begin
|
||||
if (addressed & id_valid) begin
|
||||
c_state_nx[C_CONFIG] = 1'b1;
|
||||
end
|
||||
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;
|
||||
end
|
||||
else c_state_nx[C_CONFIG] = 1'b1;
|
||||
end
|
||||
c_state[C_WAIT] : begin
|
||||
if (cfg_addr_ready & cfg_data_ready) begin
|
||||
c_state_nx[C_ENABLE] = 1'b1;
|
||||
end
|
||||
else c_state_nx[C_WAIT] = 1'b1;
|
||||
end
|
||||
c_state[C_ENABLE] : begin
|
||||
c_state_nx[C_IDLE] = 1'b1;
|
||||
end
|
||||
default : begin
|
||||
c_state_nx[C_IDLE] = 1'b1;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
|
||||
axis_addr #(
|
||||
.CONFIG_DWIDTH (CONFIG_DWIDTH),
|
||||
.WIDTH_RATIO (WIDTH_RATIO),
|
||||
.CONVERT_SHIFT ($clog2(WIDTH_RATIO)),
|
||||
.AXI_ID_WIDTH (AXI_ID_WIDTH),
|
||||
.AXI_LEN_WIDTH (AXI_LEN_WIDTH),
|
||||
.AXI_ADDR_WIDTH (AXI_ADDR_WIDTH))
|
||||
axis_addr_ (
|
||||
.clk (clk),
|
||||
.rst (rst),
|
||||
|
||||
.cfg_address (cfg_address),
|
||||
.cfg_length (cfg_length),
|
||||
.cfg_valid (cfg_enable),
|
||||
.cfg_ready (cfg_addr_ready),
|
||||
|
||||
.axi_aready (axi_awready),
|
||||
.axi_aid (axi_awid),
|
||||
.axi_aaddr (axi_awaddr),
|
||||
.axi_alen (axi_awlen),
|
||||
.axi_avalid (axi_awvalid)
|
||||
);
|
||||
|
||||
|
||||
axis_write_data #(
|
||||
.BUF_AWIDTH (BUF_AWIDTH),
|
||||
.CONFIG_DWIDTH (CONFIG_DWIDTH),
|
||||
.WIDTH_RATIO (WIDTH_RATIO),
|
||||
.CONVERT_SHIFT ($clog2(WIDTH_RATIO)),
|
||||
.AXI_LEN_WIDTH (AXI_LEN_WIDTH),
|
||||
.AXI_DATA_WIDTH (AXI_DATA_WIDTH),
|
||||
.DATA_WIDTH (DATA_WIDTH))
|
||||
axis_write_data_ (
|
||||
.clk (clk),
|
||||
.rst (rst),
|
||||
|
||||
.cfg_length (cfg_length),
|
||||
.cfg_valid (cfg_enable),
|
||||
.cfg_ready (cfg_data_ready),
|
||||
|
||||
.axi_wlast (axi_wlast),
|
||||
.axi_wdata (axi_wdata),
|
||||
.axi_wvalid (axi_wvalid),
|
||||
.axi_wready (axi_wready),
|
||||
|
||||
.data (data),
|
||||
.valid (valid),
|
||||
.ready (ready)
|
||||
);
|
||||
|
||||
|
||||
|
||||
endmodule
|
||||
|
||||
`endif // `ifndef _axis_write_
|
210
hdl/axis/axis_write_data.v
Normal file
210
hdl/axis/axis_write_data.v
Normal file
@ -0,0 +1,210 @@
|
||||
/**
|
||||
* Module:
|
||||
* axis_write_data
|
||||
*
|
||||
* Description:
|
||||
* The axis_write_data handles the AXI write data channel.
|
||||
*
|
||||
* Test bench:
|
||||
* axis_write_tb.v
|
||||
*
|
||||
* Created:
|
||||
* Tue Nov 4 22:18:14 EST 2014
|
||||
*
|
||||
* Author:
|
||||
* Berin Martini (berin.martini@gmail.com)
|
||||
*/
|
||||
`ifndef _axis_write_data_ `define _axis_write_data_
|
||||
|
||||
|
||||
`include "fifo_simple.v"
|
||||
`include "axis_deserializer.v"
|
||||
|
||||
module axis_write_data
|
||||
#(parameter
|
||||
BUF_AWIDTH = 9,
|
||||
CONFIG_DWIDTH = 32,
|
||||
WIDTH_RATIO = 16,
|
||||
CONVERT_SHIFT = 3,
|
||||
|
||||
AXI_LEN_WIDTH = 8,
|
||||
AXI_DATA_WIDTH = 32,
|
||||
DATA_WIDTH = 32)
|
||||
(input clk,
|
||||
input rst,
|
||||
|
||||
input [CONFIG_DWIDTH-1:0] cfg_length,
|
||||
input cfg_valid,
|
||||
output cfg_ready,
|
||||
|
||||
output axi_wlast,
|
||||
output [AXI_DATA_WIDTH-1:0] axi_wdata,
|
||||
output axi_wvalid,
|
||||
input axi_wready,
|
||||
|
||||
input [DATA_WIDTH-1:0] data,
|
||||
input valid,
|
||||
output reg ready
|
||||
);
|
||||
|
||||
/**
|
||||
* Local parameters
|
||||
*/
|
||||
|
||||
localparam BURST_WIDTH = AXI_LEN_WIDTH+CONVERT_SHIFT;
|
||||
localparam BURST_LAST = (1<<BURST_WIDTH)-1;
|
||||
|
||||
localparam
|
||||
IDLE = 0,
|
||||
ACTIVE = 1,
|
||||
WAIT = 2,
|
||||
DONE = 3;
|
||||
|
||||
|
||||
`ifdef VERBOSE
|
||||
initial $display("\using 'axis_write_data'\n");
|
||||
`endif
|
||||
|
||||
|
||||
/**
|
||||
* Internal signals
|
||||
*/
|
||||
|
||||
reg [3:0] state;
|
||||
reg [3:0] state_nx;
|
||||
|
||||
reg [CONFIG_DWIDTH-1:0] str_cnt;
|
||||
reg [CONFIG_DWIDTH-1:0] str_length;
|
||||
|
||||
wire [BUF_AWIDTH:0] buf_count;
|
||||
wire buf_pop;
|
||||
wire buf_empty;
|
||||
|
||||
reg deser_last;
|
||||
wire [DATA_WIDTH-1:0] deser_data;
|
||||
reg deser_valid;
|
||||
|
||||
/**
|
||||
* Implementation
|
||||
*/
|
||||
|
||||
assign cfg_ready = state[IDLE];
|
||||
|
||||
assign buf_pop = ~buf_empty & axi_wready;
|
||||
|
||||
|
||||
always @(posedge clk)
|
||||
if (cfg_valid) begin
|
||||
str_length <= cfg_length-1;
|
||||
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) str_cnt <= str_cnt + buf_pop;
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
fifo_simple #(
|
||||
.DATA_WIDTH (DATA_WIDTH),
|
||||
.ADDR_WIDTH (BUF_AWIDTH))
|
||||
buffer_ (
|
||||
.clk (clk),
|
||||
.rst (state[IDLE]),
|
||||
|
||||
.count (buf_count),
|
||||
.empty (buf_empty),
|
||||
.empty_a (),
|
||||
.full (),
|
||||
.full_a (),
|
||||
|
||||
.push_data (data),
|
||||
.push (valid),
|
||||
|
||||
.pop_data (deser_data),
|
||||
.pop (buf_pop)
|
||||
);
|
||||
|
||||
|
||||
axis_deserializer #(
|
||||
.DATA_NB (WIDTH_RATIO),
|
||||
.DATA_WIDTH (DATA_WIDTH))
|
||||
deser_ (
|
||||
.clk (clk),
|
||||
.rst (state[IDLE]),
|
||||
|
||||
.up_data (deser_data),
|
||||
.up_valid (deser_valid),
|
||||
.up_ready (),
|
||||
.up_last (deser_last),
|
||||
|
||||
.down_data (axi_wdata),
|
||||
.down_valid (axi_wvalid),
|
||||
.down_ready (axi_wready),
|
||||
.down_last (axi_wlast)
|
||||
);
|
||||
|
||||
|
||||
always @(posedge clk)
|
||||
if (rst) begin
|
||||
state <= 'b0;
|
||||
state[IDLE] <= 1'b1;
|
||||
end
|
||||
else state <= state_nx;
|
||||
|
||||
|
||||
always @* begin : DATA_
|
||||
state_nx <= 'b0;
|
||||
|
||||
case (1'b1)
|
||||
state[IDLE] : begin
|
||||
if (cfg_valid) begin
|
||||
state_nx[ACTIVE] <= 1'b1;
|
||||
end
|
||||
else state_nx[IDLE] <= 1'b1;
|
||||
end
|
||||
state[ACTIVE] : begin
|
||||
if (axi_wready & buf_pop & (str_length == str_cnt)) begin
|
||||
state_nx[WAIT] <= 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;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
|
||||
endmodule
|
||||
|
||||
`endif // `ifndef _axis_write_data_
|
375
hdl/axis/axis_write_data_tb.v
Normal file
375
hdl/axis/axis_write_data_tb.v
Normal file
@ -0,0 +1,375 @@
|
||||
/**
|
||||
* Testbench:
|
||||
* axis_write_data
|
||||
*
|
||||
* Created:
|
||||
* Tue Nov 4 22:17:15 EST 2014
|
||||
*
|
||||
* Author:
|
||||
* Berin Martini (berin.martini@gmail.com)
|
||||
*/
|
||||
|
||||
`timescale 1ns/10ps
|
||||
|
||||
`define TB_VERBOSE
|
||||
//`define VERBOSE
|
||||
|
||||
|
||||
`include "axis_write_data.v"
|
||||
|
||||
module axis_write_data_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 STREAM_LENGTH = (256*8*2)-4;
|
||||
|
||||
localparam BUF_AWIDTH = 4;
|
||||
localparam CONFIG_DWIDTH = 32;
|
||||
localparam WIDTH_RATIO = 8;
|
||||
localparam AXI_DATA_WIDTH = 256;
|
||||
localparam DATA_WIDTH = 32;
|
||||
|
||||
|
||||
`ifdef TB_VERBOSE
|
||||
initial $display("Testbench for unit 'axis_write_data'");
|
||||
`endif
|
||||
|
||||
|
||||
/**
|
||||
* signals, registers and wires
|
||||
*/
|
||||
|
||||
reg rst;
|
||||
|
||||
wire done;
|
||||
|
||||
reg [CONFIG_DWIDTH-1:0] cfg_length;
|
||||
reg cfg_valid;
|
||||
|
||||
wire axi_wlast;
|
||||
wire [AXI_DATA_WIDTH-1:0] axi_wdata;
|
||||
wire axi_wvalid;
|
||||
reg axi_wready;
|
||||
|
||||
reg [DATA_WIDTH-1:0] data;
|
||||
reg valid;
|
||||
wire ready;
|
||||
|
||||
|
||||
/**
|
||||
* Unit under test
|
||||
*/
|
||||
|
||||
axis_write_data #(
|
||||
.BUF_AWIDTH (BUF_AWIDTH),
|
||||
.CONFIG_DWIDTH (CONFIG_DWIDTH),
|
||||
.WIDTH_RATIO (WIDTH_RATIO),
|
||||
|
||||
.AXI_DATA_WIDTH (AXI_DATA_WIDTH),
|
||||
.DATA_WIDTH (DATA_WIDTH))
|
||||
uut (
|
||||
.clk (clk),
|
||||
.rst (rst),
|
||||
|
||||
.done (done),
|
||||
|
||||
.cfg_length (cfg_length),
|
||||
.cfg_valid (cfg_valid),
|
||||
|
||||
.axi_wlast (axi_wlast),
|
||||
.axi_wdata (axi_wdata),
|
||||
.axi_wvalid (axi_wvalid),
|
||||
.axi_wready (axi_wready),
|
||||
|
||||
.data (data),
|
||||
.valid (valid),
|
||||
.ready (ready)
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* Wave form display
|
||||
*/
|
||||
|
||||
task display_signals;
|
||||
$display(
|
||||
"%d\t%d",
|
||||
$time, rst,
|
||||
|
||||
"\t%d\t%b",
|
||||
cfg_length,
|
||||
cfg_valid,
|
||||
|
||||
"\t%x\t%b\t%b\t%b",
|
||||
axi_wdata,
|
||||
axi_wvalid,
|
||||
axi_wready,
|
||||
axi_wlast,
|
||||
|
||||
"\t%x\t%b\t%b",
|
||||
data,
|
||||
valid,
|
||||
ready,
|
||||
|
||||
"\t%b",
|
||||
done,
|
||||
|
||||
"\t%b",
|
||||
uut.state,
|
||||
|
||||
);
|
||||
|
||||
endtask // display_signals
|
||||
|
||||
task display_header;
|
||||
$display(
|
||||
"\t\ttime\trst",
|
||||
|
||||
"\t\tc_l",
|
||||
"\tc_v",
|
||||
|
||||
"\t\t\t\t\t\tw_d",
|
||||
"\t\t\t\tw_v",
|
||||
"\tw_r",
|
||||
"\tw_l",
|
||||
|
||||
"\t\ts_d",
|
||||
"\ts_v",
|
||||
"\ts_r",
|
||||
|
||||
"\tdone",
|
||||
|
||||
);
|
||||
endtask
|
||||
|
||||
|
||||
/**
|
||||
* Testbench program
|
||||
*/
|
||||
|
||||
initial begin
|
||||
// init values
|
||||
clk = 0;
|
||||
rst = 0;
|
||||
|
||||
cfg_length = 'b0;
|
||||
cfg_valid = 'b0;
|
||||
|
||||
axi_wready = 'b0;
|
||||
data = 'b0;
|
||||
valid = 'b0;
|
||||
//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("send config id, start address and length");
|
||||
`endif
|
||||
|
||||
repeat(5) @(negedge clk);
|
||||
cfg_length <= 8;
|
||||
cfg_valid <= 1'b1;
|
||||
@(negedge clk)
|
||||
|
||||
cfg_length <= 'b0;
|
||||
cfg_valid <= 1'b0;
|
||||
repeat(5) @(negedge clk);
|
||||
|
||||
|
||||
`ifdef TB_VERBOSE
|
||||
$display("test write");
|
||||
`endif
|
||||
|
||||
axi_wready <= 1'b1;
|
||||
data <= 'b0;
|
||||
valid <= 1'b0;
|
||||
repeat(5) @(negedge clk);
|
||||
|
||||
repeat (5) begin
|
||||
data <= data + 1;
|
||||
valid <= 1'b1;
|
||||
@(negedge clk);
|
||||
end
|
||||
|
||||
axi_wready <= 1'b0;
|
||||
//data <= 'b0;
|
||||
valid <= 1'b0;
|
||||
repeat(5) @(negedge clk);
|
||||
|
||||
repeat (3) begin
|
||||
data <= data + 1;
|
||||
valid <= 1'b1;
|
||||
@(negedge clk);
|
||||
end
|
||||
|
||||
axi_wready <= 1'b1;
|
||||
//data <= 'b0;
|
||||
valid <= 1'b0;
|
||||
repeat(4) @(negedge clk);
|
||||
axi_wready <= 1'b1;
|
||||
@(negedge clk);
|
||||
axi_wready <= 1'b0;
|
||||
@(negedge clk);
|
||||
axi_wready <= 1'b1;
|
||||
@(negedge clk);
|
||||
axi_wready <= 1'b0;
|
||||
@(negedge clk);
|
||||
axi_wready <= 1'b1;
|
||||
@(negedge clk);
|
||||
axi_wready <= 1'b0;
|
||||
@(negedge clk);
|
||||
axi_wready <= 1'b1;
|
||||
@(negedge clk);
|
||||
axi_wready <= 1'b0;
|
||||
@(negedge clk);
|
||||
axi_wready <= 1'b0;
|
||||
@(negedge clk);
|
||||
axi_wready <= 1'b1;
|
||||
repeat(15) @(negedge clk);
|
||||
|
||||
|
||||
`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("send config id, start address and length");
|
||||
`endif
|
||||
|
||||
repeat(5) @(negedge clk);
|
||||
cfg_length <= 8;
|
||||
cfg_valid <= 1'b1;
|
||||
@(negedge clk)
|
||||
|
||||
cfg_length <= 'b0;
|
||||
cfg_valid <= 1'b0;
|
||||
repeat(5) @(negedge clk);
|
||||
|
||||
|
||||
`ifdef TB_VERBOSE
|
||||
$display("test write address channel");
|
||||
`endif
|
||||
|
||||
repeat(5) @(negedge clk);
|
||||
axi_wready <= 1'b1;
|
||||
//data <= 'b0;
|
||||
valid <= 1'b0;
|
||||
repeat(5) @(negedge clk);
|
||||
|
||||
|
||||
repeat (8) begin
|
||||
data <= data + 1;
|
||||
valid <= 1'b1;
|
||||
@(negedge clk);
|
||||
valid <= 1'b0;
|
||||
repeat(5) @(negedge clk);
|
||||
end
|
||||
valid <= 1'b0;
|
||||
|
||||
|
||||
repeat(15) @(negedge clk);
|
||||
axi_wready <= 1'b0;
|
||||
|
||||
repeat(15) @(negedge clk);
|
||||
|
||||
|
||||
`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("send config id, start address and length");
|
||||
`endif
|
||||
|
||||
repeat(5) @(negedge clk);
|
||||
cfg_length <= STREAM_LENGTH;
|
||||
cfg_valid <= 1'b1;
|
||||
@(negedge clk)
|
||||
|
||||
cfg_length <= 'b0;
|
||||
cfg_valid <= 1'b0;
|
||||
repeat(5) @(negedge clk);
|
||||
|
||||
|
||||
`ifdef TB_VERBOSE
|
||||
$display("test write address channel");
|
||||
`endif
|
||||
|
||||
repeat(5) @(negedge clk);
|
||||
data <= 'b0;
|
||||
valid <= 1'b0;
|
||||
axi_wready <= 1'b1;
|
||||
repeat(15) @(negedge clk);
|
||||
|
||||
repeat (STREAM_LENGTH) begin
|
||||
data <= data + 1;
|
||||
valid <= 1'b1;
|
||||
@(negedge clk);
|
||||
end
|
||||
valid <= 1'b0;
|
||||
|
||||
|
||||
repeat(15) @(negedge clk);
|
||||
axi_wready <= 1'b0;
|
||||
|
||||
repeat(15) @(negedge clk);
|
||||
|
||||
`ifdef TB_VERBOSE
|
||||
$display("END");
|
||||
`endif
|
||||
-> end_trigger;
|
||||
end
|
||||
|
||||
endmodule
|
443
hdl/axis/axis_write_tb.v
Normal file
443
hdl/axis/axis_write_tb.v
Normal file
@ -0,0 +1,443 @@
|
||||
/**
|
||||
* Testbench:
|
||||
* axis_write
|
||||
*
|
||||
* Created:
|
||||
* Tue Nov 4 22:17:15 EST 2014
|
||||
*
|
||||
* Author:
|
||||
* Berin Martini (berin.martini@gmail.com)
|
||||
*/
|
||||
|
||||
`timescale 1ns/10ps
|
||||
|
||||
`define TB_VERBOSE
|
||||
//`define VERBOSE
|
||||
|
||||
|
||||
`include "axis_write.v"
|
||||
|
||||
module axis_write_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 STREAM_LENGTH = (256*8*2)-4;
|
||||
|
||||
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 AXI_ID_WIDTH = 8;
|
||||
localparam AXI_LEN_WIDTH = 2;
|
||||
localparam AXI_ADDR_WIDTH = 32;
|
||||
localparam AXI_DATA_WIDTH = 256;
|
||||
localparam DATA_WIDTH = 32;
|
||||
|
||||
|
||||
`ifdef TB_VERBOSE
|
||||
initial $display("Testbench for unit 'axis_write'");
|
||||
`endif
|
||||
|
||||
|
||||
/**
|
||||
* signals, registers and wires
|
||||
*/
|
||||
|
||||
reg rst;
|
||||
|
||||
reg [CONFIG_AWIDTH-1:0] cfg_addr;
|
||||
reg [CONFIG_DWIDTH-1:0] cfg_data;
|
||||
reg cfg_valid;
|
||||
|
||||
reg axi_awready;
|
||||
wire [AXI_ID_WIDTH-1:0] axi_awid;
|
||||
wire [AXI_ADDR_WIDTH-1:0] axi_awaddr;
|
||||
//wire [7:0] axi_awlen;
|
||||
wire [AXI_LEN_WIDTH-1:0] axi_awlen;
|
||||
wire axi_awvalid;
|
||||
|
||||
wire axi_wlast;
|
||||
wire [AXI_DATA_WIDTH-1:0] axi_wdata;
|
||||
wire axi_wvalid;
|
||||
reg axi_wready;
|
||||
|
||||
reg [DATA_WIDTH-1:0] data;
|
||||
reg valid;
|
||||
wire ready;
|
||||
|
||||
|
||||
/**
|
||||
* Unit under test
|
||||
*/
|
||||
|
||||
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),
|
||||
|
||||
.AXI_ID_WIDTH (AXI_ID_WIDTH),
|
||||
.AXI_LEN_WIDTH (AXI_LEN_WIDTH),
|
||||
.AXI_ADDR_WIDTH (AXI_ADDR_WIDTH),
|
||||
.AXI_DATA_WIDTH (AXI_DATA_WIDTH),
|
||||
.DATA_WIDTH (DATA_WIDTH))
|
||||
uut (
|
||||
.clk (clk),
|
||||
.rst (rst),
|
||||
|
||||
.cfg_addr (cfg_addr),
|
||||
.cfg_data (cfg_data),
|
||||
.cfg_valid (cfg_valid),
|
||||
|
||||
.axi_awready (axi_awready),
|
||||
.axi_awid (axi_awid),
|
||||
.axi_awaddr (axi_awaddr),
|
||||
.axi_awlen (axi_awlen[0 +: AXI_LEN_WIDTH]),
|
||||
.axi_awvalid (axi_awvalid),
|
||||
|
||||
.axi_wlast (axi_wlast),
|
||||
.axi_wdata (axi_wdata),
|
||||
.axi_wvalid (axi_wvalid),
|
||||
.axi_wready (axi_wready),
|
||||
|
||||
.data (data),
|
||||
.valid (valid),
|
||||
.ready (ready)
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* Wave form display
|
||||
*/
|
||||
|
||||
task display_signals;
|
||||
$display(
|
||||
"%d\t%d",
|
||||
$time, rst,
|
||||
|
||||
"\t%d\t%d\t%b",
|
||||
cfg_addr,
|
||||
cfg_data,
|
||||
cfg_valid,
|
||||
|
||||
"\t%d\t%d\t%d\t%b\t%b",
|
||||
axi_awid,
|
||||
axi_awaddr,
|
||||
axi_awlen,
|
||||
axi_awvalid,
|
||||
axi_awready,
|
||||
|
||||
"\t%x\t%b\t%b\t%b",
|
||||
axi_wdata,
|
||||
axi_wvalid,
|
||||
axi_wready,
|
||||
axi_wlast,
|
||||
|
||||
"\t%d\t%b\t%b",
|
||||
data,
|
||||
valid,
|
||||
ready,
|
||||
|
||||
"\t%b",
|
||||
uut.c_state,
|
||||
|
||||
"\t%b",
|
||||
uut.axis_addr_.state,
|
||||
|
||||
);
|
||||
|
||||
endtask // display_signals
|
||||
|
||||
task display_header;
|
||||
$display(
|
||||
"\t\ttime\trst",
|
||||
|
||||
"\tc_a",
|
||||
"\t\tc_d",
|
||||
"\tc_v",
|
||||
|
||||
"\taw_id",
|
||||
"\t\taw_a",
|
||||
"\taw_l",
|
||||
"\taw_v",
|
||||
"\taw_r",
|
||||
|
||||
"\t\t\t\t\t\tw_d",
|
||||
"\t\t\t\tw_v",
|
||||
"\tw_r",
|
||||
"\tw_l",
|
||||
|
||||
"\t\ts_d",
|
||||
"\ts_v",
|
||||
"\tm_r",
|
||||
|
||||
);
|
||||
endtask
|
||||
|
||||
|
||||
/**
|
||||
* Testbench program
|
||||
*/
|
||||
|
||||
initial begin
|
||||
// init values
|
||||
clk = 0;
|
||||
rst = 0;
|
||||
|
||||
cfg_addr = 'b0;
|
||||
cfg_data = 'b0;
|
||||
cfg_valid = 'b0;
|
||||
|
||||
axi_awready = 'b0;
|
||||
|
||||
axi_wready = 'b0;
|
||||
data = 'b0;
|
||||
valid = 'b0;
|
||||
//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("send config id, start address and length");
|
||||
`endif
|
||||
|
||||
repeat(5) @(negedge clk);
|
||||
cfg_addr <= CONFIG_ADDR;
|
||||
cfg_data <= CONFIG_ID;
|
||||
cfg_valid <= 1'b1;
|
||||
@(negedge clk)
|
||||
|
||||
cfg_addr <= 'b0;
|
||||
cfg_data <= 'b0;
|
||||
cfg_valid <= 1'b0;
|
||||
repeat(5) @(negedge clk);
|
||||
|
||||
cfg_addr <= CONFIG_DATA;
|
||||
cfg_data <= 4;
|
||||
cfg_valid <= 1'b1;
|
||||
@(negedge clk)
|
||||
|
||||
cfg_addr <= 'b0;
|
||||
cfg_data <= 'b0;
|
||||
cfg_valid <= 1'b0;
|
||||
repeat(5) @(negedge clk);
|
||||
|
||||
cfg_addr <= CONFIG_DATA;
|
||||
cfg_data <= 8;
|
||||
cfg_valid <= 1'b1;
|
||||
@(negedge clk)
|
||||
|
||||
cfg_addr <= 'b0;
|
||||
cfg_data <= 'b0;
|
||||
cfg_valid <= 1'b0;
|
||||
repeat(5) @(negedge clk);
|
||||
|
||||
|
||||
`ifdef TB_VERBOSE
|
||||
$display("test write address channel");
|
||||
`endif
|
||||
|
||||
repeat(3) @(negedge clk);
|
||||
axi_awready <= 1'b1;
|
||||
repeat(5) @(negedge clk);
|
||||
|
||||
|
||||
axi_wready <= 1'b1;
|
||||
data <= 'b0;
|
||||
valid <= 1'b0;
|
||||
repeat(5) @(negedge clk);
|
||||
|
||||
repeat (5) begin
|
||||
data <= data + 1;
|
||||
valid <= 1'b1;
|
||||
@(negedge clk);
|
||||
end
|
||||
|
||||
axi_wready <= 1'b0;
|
||||
//data <= 'b0;
|
||||
valid <= 1'b0;
|
||||
repeat(5) @(negedge clk);
|
||||
|
||||
repeat (3) begin
|
||||
data <= data + 1;
|
||||
valid <= 1'b1;
|
||||
@(negedge clk);
|
||||
end
|
||||
|
||||
axi_wready <= 1'b1;
|
||||
data <= 'b0;
|
||||
valid <= 1'b0;
|
||||
//repeat(4) @(negedge clk);
|
||||
repeat(5) @(negedge clk);
|
||||
//repeat(6) @(negedge clk);
|
||||
axi_wready <= 1'b0;
|
||||
@(negedge clk);
|
||||
axi_wready <= 1'b1;
|
||||
repeat(15) @(negedge clk);
|
||||
|
||||
|
||||
|
||||
`ifdef TB_VERBOSE
|
||||
$display("send config id, start address and length");
|
||||
`endif
|
||||
|
||||
repeat(5) @(negedge clk);
|
||||
cfg_addr <= CONFIG_ADDR;
|
||||
cfg_data <= CONFIG_ID;
|
||||
cfg_valid <= 1'b1;
|
||||
@(negedge clk)
|
||||
|
||||
cfg_addr <= CONFIG_DATA;
|
||||
cfg_data <= 4;
|
||||
cfg_valid <= 1'b1;
|
||||
@(negedge clk)
|
||||
|
||||
cfg_addr <= CONFIG_DATA;
|
||||
cfg_data <= 8;
|
||||
cfg_valid <= 1'b1;
|
||||
@(negedge clk)
|
||||
|
||||
cfg_addr <= 'b0;
|
||||
cfg_data <= 'b0;
|
||||
cfg_valid <= 1'b0;
|
||||
repeat(5) @(negedge clk);
|
||||
|
||||
|
||||
`ifdef TB_VERBOSE
|
||||
$display("test write address channel");
|
||||
`endif
|
||||
|
||||
repeat(3) @(negedge clk);
|
||||
axi_awready <= 1'b1;
|
||||
repeat(5) @(negedge clk);
|
||||
|
||||
|
||||
axi_wready <= 1'b1;
|
||||
data <= 'b0;
|
||||
valid <= 1'b0;
|
||||
repeat(5) @(negedge clk);
|
||||
|
||||
|
||||
repeat (8) begin
|
||||
data <= data + 1;
|
||||
valid <= 1'b1;
|
||||
@(negedge clk);
|
||||
valid <= 1'b0;
|
||||
repeat(5) @(negedge clk);
|
||||
end
|
||||
|
||||
axi_awready <= 1'b0;
|
||||
axi_wready <= 1'b0;
|
||||
repeat(15) @(negedge clk);
|
||||
|
||||
|
||||
|
||||
`ifdef TB_VERBOSE
|
||||
$display("send config id, start address and length");
|
||||
`endif
|
||||
|
||||
repeat(5) @(negedge clk);
|
||||
cfg_addr <= CONFIG_ADDR;
|
||||
cfg_data <= CONFIG_ID;
|
||||
cfg_valid <= 1'b1;
|
||||
@(negedge clk)
|
||||
|
||||
cfg_addr <= CONFIG_DATA;
|
||||
cfg_data <= 255;
|
||||
cfg_valid <= 1'b1;
|
||||
@(negedge clk)
|
||||
|
||||
cfg_addr <= CONFIG_DATA;
|
||||
cfg_data <= STREAM_LENGTH;
|
||||
cfg_valid <= 1'b1;
|
||||
@(negedge clk)
|
||||
|
||||
cfg_addr <= 'b0;
|
||||
cfg_data <= 'b0;
|
||||
cfg_valid <= 1'b0;
|
||||
repeat(5) @(negedge clk);
|
||||
|
||||
|
||||
`ifdef TB_VERBOSE
|
||||
$display("test long write");
|
||||
`endif
|
||||
|
||||
repeat(3) @(negedge clk);
|
||||
// ready to recive address
|
||||
axi_awready <= 1'b1;
|
||||
repeat(5) @(negedge clk);
|
||||
|
||||
|
||||
// ready to recive data
|
||||
axi_wready <= 1'b1;
|
||||
data <= 'b0;
|
||||
valid <= 1'b0;
|
||||
repeat(5) @(negedge clk);
|
||||
|
||||
|
||||
repeat (STREAM_LENGTH) begin
|
||||
// stream data into axis
|
||||
data <= data + 1;
|
||||
valid <= 1'b1;
|
||||
@(negedge clk);
|
||||
end
|
||||
|
||||
valid <= 1'b0;
|
||||
repeat(15) @(negedge clk);
|
||||
axi_wready <= 1'b0;
|
||||
repeat(15) @(negedge clk);
|
||||
|
||||
|
||||
|
||||
`ifdef TB_VERBOSE
|
||||
$display("END");
|
||||
`endif
|
||||
-> end_trigger;
|
||||
end
|
||||
|
||||
endmodule
|
Loading…
x
Reference in New Issue
Block a user