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

Merge branch 'connect-axis-to-hp0'

Add a High Performance port (HP0) to the zedboard_axis project and
connect a AXIS module that can read and write to the main memory using
HP0. Add two small applications that test writing and reading from
memory.
This commit is contained in:
Berin Martini 2015-01-08 14:52:39 -05:00
commit 80d401db54
24 changed files with 4714 additions and 2 deletions

View File

@ -4,6 +4,8 @@ CFLAGS := -c -Wall -Werror
INCLUDES := -I.
EXECUTABLE = \
write-memory \
read-memory \
test-cfg
@ -15,6 +17,14 @@ all : $(EXECUTABLE)
$(CC) $(INCLUDES) $(CFLAGS) $< -o $@
write-memory : write-memory.o
$(CC) $< -o $@ $(LDFLAGS)
read-memory : read-memory.o
$(CC) $< -o $@ $(LDFLAGS)
test-cfg : test-cfg.o
$(CC) $< -o $@ $(LDFLAGS)

57
app/read-memory.c Normal file
View File

@ -0,0 +1,57 @@
#include <interface.h>
#include <stdio.h>
#include <stdlib.h>
enum cfg_regsiters {
CFG_AXIS_ADDR,
CFG_AXIS_DATA,
CFG_HP0_DST_CNT,
CFG_HP0_SRC_CNT,
CFG_HP0_DST_DATA,
CFG_HP0_SRC_DATA,
CFG_EMPTY,
};
int main(int argc, char *argv[])
{
int i = 0;
if (axis_init("/dev/axis") != 0) {
return -1;
}
if (argc < 2) {
printf("Usage: %s <length>\n", argv[0]);
return 0;
}
off_t offset = 0x1b900000;
size_t len = atoi(argv[1]);
printf("phys_addr: %ld, %02x, length: %ld\n", (long int)offset,
(unsigned int)offset, (long int)len);
// configure axis to write to memory
printf("config start\n");
cfg_write(CFG_AXIS_ADDR, 1);
cfg_write(CFG_AXIS_DATA, offset);
cfg_write(CFG_AXIS_DATA, len);
printf("config done\n");
// send data to be written over cfg bus
printf("read start\n");
cfg_read(CFG_HP0_SRC_DATA); // prime cfg register
for (i = 0; i < len; ++i) {
printf("%d ", cfg_read(CFG_HP0_SRC_DATA));
}
printf("\nhp0 src cnt: %d\n", cfg_read(CFG_HP0_SRC_CNT));
if (axis_exit() != 0) {
return -1;
}
printf("\ndone\n");
return 0;
}

82
app/write-memory.c Normal file
View File

@ -0,0 +1,82 @@
#include <interface.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
enum cfg_regsiters {
CFG_AXIS_ADDR,
CFG_AXIS_DATA,
CFG_HP0_DST_CNT,
CFG_HP0_SRC_CNT,
CFG_HP0_DST_DATA,
CFG_HP0_SRC_DATA,
CFG_EMPTY,
};
int main(int argc, char *argv[])
{
int i = 0;
if (axis_init("/dev/axis") != 0) {
return -1;
}
if (argc < 2) {
printf("Usage: %s <length>\n", argv[0]);
return 0;
}
off_t offset = 0x1b900000;
size_t len = atoi(argv[1]);
printf("phys_addr: %ld, %02x, length: %ld\n", (long int)offset,
(unsigned int)offset, (long int)len);
int fd = open("/dev/mem", O_SYNC);
unsigned int *mem =
(unsigned int *)mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE,
fd, offset);
if (mem == NULL) {
printf("Can't map memory\n");
return -2;
}
// configure axis to write to memory
printf("config start\n");
cfg_write(CFG_AXIS_ADDR, 2);
cfg_write(CFG_AXIS_DATA, offset);
cfg_write(CFG_AXIS_DATA, len);
printf("config done\n");
// send data to be written over cfg bus
printf("write start\n");
for (i = 0; i < len; ++i) {
cfg_write(CFG_HP0_DST_DATA, i + 1);
//cfg_write(CFG_HP0_DST_DATA, 0);
}
printf("hp0 dst cnt: %d\n", cfg_read(CFG_HP0_DST_CNT));
printf("write done\n");
// check memory for data
for (i = 0; i < len; ++i) {
printf("%6d, %10ld, %02x, hex: %x,\tbinary: %d\n", i + 1,
(offset + (sizeof(mem[0]) * i)),
(unsigned int)(offset + (sizeof(mem[0]) * i)),
(int)mem[i], (int)mem[i]);
}
if (munmap(mem, len) < 0) {
printf("Can't unmap memory\n");
return -3;
}
if (axis_exit() != 0) {
return -1;
}
printf("\ndone\n");
return 0;
}

225
hdl/axis/axis.v Normal file
View File

@ -0,0 +1,225 @@
/*
* 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_ID_WIDTH-1:0] axi_wid,
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 [1:0] 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
);
/**
* Local parameters
*/
localparam BURST_SIZE =
( 1 == (AXI_DATA_WIDTH/8)) ? 3'h0 :
( 2 == (AXI_DATA_WIDTH/8)) ? 3'h1 :
( 4 == (AXI_DATA_WIDTH/8)) ? 3'h2 :
( 8 == (AXI_DATA_WIDTH/8)) ? 3'h3 :
(16 == (AXI_DATA_WIDTH/8)) ? 3'h4 :
(32 == (AXI_DATA_WIDTH/8)) ? 3'h5 :
(64 == (AXI_DATA_WIDTH/8)) ? 3'h6 : 3'h7;
/**
* 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 = 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
assign axi_arlock = 2'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 = BURST_SIZE;
assign axi_arid = {AXI_ID_WIDTH{1'b0}};
// 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_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_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_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_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_

203
hdl/axis/axis_addr.v Normal file
View File

@ -0,0 +1,203 @@
/**
* 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_LEN_WIDTH = 8,
AXI_ADDR_WIDTH = 32,
AXI_DATA_WIDTH = 256)
(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 [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
// e.g. each burst has 256 long words & each long word has 32 bytes
axi_address <= axi_address + (BURST_LENGTH * (AXI_DATA_WIDTH/8));
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
endmodule
`endif // `ifndef _axis_addr_

229
hdl/axis/axis_addr_tb.v Normal file
View 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

View 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_

View 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

252
hdl/axis/axis_read.v Normal file
View File

@ -0,0 +1,252 @@
/**
* 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_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_ADDR_WIDTH-1:0] axi_araddr,
output [AXI_LEN_WIDTH-1:0] axi_arlen,
output axi_arvalid,
input [1:0] 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_LEN_WIDTH (AXI_LEN_WIDTH),
.AXI_ADDR_WIDTH (AXI_ADDR_WIDTH),
.AXI_DATA_WIDTH (AXI_DATA_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_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
View 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 [1:0] 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_

View 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
View 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
View 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_

View 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

252
hdl/axis/axis_write.v Normal file
View File

@ -0,0 +1,252 @@
/**
* 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_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_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_LEN_WIDTH (AXI_LEN_WIDTH),
.AXI_ADDR_WIDTH (AXI_ADDR_WIDTH),
.AXI_DATA_WIDTH (AXI_DATA_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_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
View 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_

View File

@ -0,0 +1,377 @@
/**
* 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 AXI_LEN_WIDTH = 4;
localparam AXI_DATA_WIDTH = 64;
localparam DATA_WIDTH = 32;
localparam WIDTH_RATIO = AXI_DATA_WIDTH/DATA_WIDTH;
`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 cfg_ready;
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),
.CONVERT_SHIFT ($clog2(WIDTH_RATIO)),
.AXI_LEN_WIDTH (AXI_LEN_WIDTH),
.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_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\t%b",
cfg_length,
cfg_valid,
cfg_ready,
"\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",
uut.state,
);
endtask // display_signals
task display_header;
$display(
"\t\ttime\trst",
"\t\tc_l",
"\tc_v",
"\tc_r",
"\tw_d",
"\t\t\tw_v",
"\tw_r",
"\tw_l",
"\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_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
View 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

187
hdl/fifo/fifo_simple.v Normal file
View File

@ -0,0 +1,187 @@
/**
* Module:
* fifo_simple
*
* Description:
* A simple FIFO, with synchronous clock for both the pop and push ports.
*
* Testbench:
* fifo_simple_tb.v
*
* Created:
* Sun Nov 30 13:39:40 EST 2014
*
* Author:
* Berin Martini (berin.martini@gmail.com)
*/
`ifndef _fifo_simple_ `define _fifo_simple_
module fifo_simple
#(parameter
DATA_WIDTH = 16,
ADDR_WIDTH = 16)
(input clk,
input rst,
output reg [ADDR_WIDTH:0] count,
output reg full,
output reg full_a,
output reg empty,
output reg empty_a,
input push,
input [DATA_WIDTH-1:0] push_data,
input pop,
output reg [DATA_WIDTH-1:0] pop_data
);
/**
* Local parameters
*/
localparam DEPTH = 1<<ADDR_WIDTH;
`ifdef VERBOSE
initial $display("fifo sync with depth: %d", DEPTH);
`endif
/**
* Internal signals
*/
reg [DATA_WIDTH-1:0] mem [0:DEPTH-1];
reg [ADDR_WIDTH:0] push_ptr;
wire [ADDR_WIDTH:0] push_ptr_nx;
reg [ADDR_WIDTH:0] pop_ptr;
wire [ADDR_WIDTH:0] pop_ptr_nx;
wire [ADDR_WIDTH-1:0] push_addr;
wire [ADDR_WIDTH-1:0] push_addr_nx;
wire [ADDR_WIDTH-1:0] pop_addr;
wire [ADDR_WIDTH-1:0] pop_addr_nx;
wire full_nx;
wire empty_nx;
wire full_a_nx;
wire [ADDR_WIDTH-1:0] push_addr_a_nx;
wire [ADDR_WIDTH:0] push_ptr_a_nx;
wire empty_a_nx;
wire [ADDR_WIDTH-1:0] pop_addr_a_nx;
wire [ADDR_WIDTH:0] pop_ptr_a_nx;
/**
* Implementation
*/
assign push_addr = push_ptr [ADDR_WIDTH-1:0];
assign push_addr_nx = push_ptr_nx [ADDR_WIDTH-1:0];
assign pop_addr = pop_ptr [ADDR_WIDTH-1:0];
assign pop_addr_nx = pop_ptr_nx [ADDR_WIDTH-1:0];
// full next
assign full_nx = (push_addr_nx == pop_addr) & (push_ptr_nx[ADDR_WIDTH] != pop_ptr[ADDR_WIDTH]);
// almost full next
assign push_ptr_a_nx = push_ptr_nx + 1;
assign push_addr_a_nx = push_ptr_a_nx[0 +: ADDR_WIDTH];
assign full_a_nx =
(push_addr_a_nx == pop_addr) & (push_ptr_a_nx[ADDR_WIDTH] != pop_ptr[ADDR_WIDTH]);
// empty next
assign empty_nx = (push_addr == pop_addr_nx) & (push_ptr[ADDR_WIDTH] == pop_ptr_nx[ADDR_WIDTH]);
// almost empty next
assign pop_ptr_a_nx = pop_ptr_nx + 1;
assign pop_addr_a_nx = pop_ptr_a_nx[0 +: ADDR_WIDTH];
assign empty_a_nx =
(push_addr == pop_addr_a_nx) & (push_ptr[ADDR_WIDTH] == pop_ptr_a_nx[ADDR_WIDTH]);
// pop next
assign pop_ptr_nx = pop_ptr + (pop & ~empty);
// push next
assign push_ptr_nx = push_ptr + (push & ~full);
// registered population count.
always @(posedge clk)
if (rst) begin
count <= 'b0;
end
else begin
if (push_ptr[ADDR_WIDTH] == pop_ptr_nx[ADDR_WIDTH]) begin
count <= (push_addr - pop_addr_nx);
end
else begin
count <= DEPTH - pop_addr_nx + push_addr;
end
end
// registered full flag
always @(posedge clk)
if (rst) full <= 1'b0;
else full <= full_nx;
// almost full flag
always @(posedge clk)
if (rst) full_a <= 1'b0;
else full_a <= full_a_nx | full_nx;
// registered empty flag
always @(posedge clk)
if (rst) empty <= 1'b1;
else empty <= empty_nx;
// almost empty flag
always @(posedge clk)
if (rst) empty_a <= 1'b1;
else empty_a <= empty_a_nx | empty_nx;
// memory read-address pointer
always @(posedge clk)
if (rst) pop_ptr <= 0;
else pop_ptr <= pop_ptr_nx;
// read from memory
always @(posedge clk)
if (pop & ~empty) pop_data <= mem[pop_addr];
// memory write-address pointer
always @(posedge clk)
if (rst) push_ptr <= 0;
else push_ptr <= push_ptr_nx;
// write to memory
always @(posedge clk)
if (push & ~full) mem[push_addr] <= push_data;
endmodule
`endif // `ifndef _fifo_simple_

228
hdl/fifo/fifo_simple_tb.v Normal file
View File

@ -0,0 +1,228 @@
/**
* Testbench:
* fifo_simple
*
* Created:
* Sun Nov 30 13:44:07 EST 2014
*
* Author:
* Berin Martini (berin.martini@gmail.com)
*/
`timescale 1ns/10ps
`define TB_VERBOSE
//`define VERBOSE
`include "fifo_simple.v"
module fifo_simple_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_WIDTH = 6;
localparam ADDR_WIDTH = 4;
/**
* signals, registers and wires
*/
reg rst;
reg pop;
reg push;
reg [DATA_WIDTH-1:0] push_data;
wire [DATA_WIDTH-1:0] pop_data;
wire empty;
wire full;
wire empty_a;
wire full_a;
wire [ADDR_WIDTH:0] count;
/**
* Unit under test
*/
fifo_simple #(
.DATA_WIDTH (DATA_WIDTH),
.ADDR_WIDTH (ADDR_WIDTH))
uut (
.clk (clk),
.rst (rst),
.count (count),
.full (full),
.full_a (full_a),
.empty (empty),
.empty_a (empty_a),
.push (push),
.push_data (push_data),
.pop (pop),
.pop_data (pop_data)
);
/**
* Wave form display
*/
task display_signals;
$display("%d\t%b\t%b\t%d\t%b\t%b\t%b\t%d\t%b\t%b\t%d\t%d",
$time, rst,
push,
push_data,
full,
full_a,
pop,
pop_data,
empty,
empty_a,
count,
|(count[ADDR_WIDTH:ADDR_WIDTH-1]),
);
endtask // display_signals
task display_header;
$display(
"\t\ttime\trst",
"\tpush",
"\tdat",
"\tfull",
"\tfull_a",
"\tpop",
"\tdat",
"\tempty",
"\tempty_a",
"\tcount",
);
endtask
/**
* Testbench program
*/
initial begin
// init values
clk = 0;
rst = 0;
push = 0;
push_data = 0;
pop = 0;
`ifdef TB_VERBOSE
$display("RESET");
`endif
@(negedge clk);
rst <= 1'b1;
repeat(6) @(negedge clk);
rst <= 1'b0;
repeat(6) @(negedge clk);
$display("TEST write to fifo");
repeat (20) @(negedge clk) begin
push <= 1'b1;
push_data <= $random;
end
push <= 1'b0;
push_data <= 0;
$display("TEST read from fifo");
#1
repeat (16) @(negedge clk) begin
pop <= 1'b1;
end
pop <= 1'b0;
$display("TEST write 5 data points to fifo");
repeat (5) @(negedge clk) begin
push <= 1'b1;
push_data <= $random;
end
push <= 1'b0;
push_data <= 0;
#5
$display("TEST read two data points from fifo");
repeat (2) @(negedge clk) begin
pop <= 1'b1;
end
pop <= 1'b0;
#5
$display("TEST write 15 data points to fifo");
repeat (15) @(negedge clk) begin
push <= 1'b1;
push_data <= $random;
end
push <= 1'b0;
push_data <= 0;
#5
$display("TEST read two data points from fifo");
#1
repeat (8) @(negedge clk) begin
pop <= 1'b1;
end
pop <= 1'b0;
$display("TEST simultaneous read/write 15 data points to fifo");
repeat (15) @(negedge clk) begin
pop <= 1'b1;
push <= 1'b1;
push_data <= $random;
end
repeat (15) @(negedge clk) begin
pop <= 1'b1;
end
$display("OTHER TESTS");
push <= 1'b0;
`ifdef TB_VERBOSE
$display("END");
`endif
-> end_trigger;
end
endmodule

View File

@ -1,5 +1,6 @@
`include "axi4lite_cfg.v"
`include "axis.v"
module zedboard_axis
(inout [14:0] DDR_addr,
@ -25,6 +26,24 @@ module zedboard_axis
inout FIXED_IO_ps_srstb
);
localparam CFG_AWIDTH = 5;
localparam CFG_DWIDTH = 32;
localparam AXI_ID_WIDTH = 6;
localparam AXI_LEN_WIDTH = 4;
localparam AXI_ADDR_WIDTH = 32;
localparam AXI_DATA_WIDTH = 64;
localparam
CFG_AXIS_ADDR = 0,
CFG_AXIS_DATA = 1,
CFG_HP0_DST_CNT = 2,
CFG_HP0_SRC_CNT = 3,
CFG_HP0_DST_DATA = 4,
CFG_HP0_SRC_DATA = 5,
CFG_EMPTY = 6;
genvar i;
wire axi_clk;
@ -50,6 +69,45 @@ module zedboard_axis
wire [3:0] axi_wstrb;
wire axi_wvalid;
wire [31:0] axi_hp0_araddr;
wire [1:0] axi_hp0_arburst;
wire [3:0] axi_hp0_arcache;
wire [5:0] axi_hp0_arid;
wire [3:0] axi_hp0_arlen;
wire [1:0] axi_hp0_arlock;
wire [2:0] axi_hp0_arprot;
wire [3:0] axi_hp0_arqos;
wire axi_hp0_arready;
wire [2:0] axi_hp0_arsize;
wire axi_hp0_arvalid;
wire [31:0] axi_hp0_awaddr;
wire [1:0] axi_hp0_awburst;
wire [3:0] axi_hp0_awcache;
wire [5:0] axi_hp0_awid;
wire [3:0] axi_hp0_awlen;
wire [1:0] axi_hp0_awlock;
wire [2:0] axi_hp0_awprot;
wire [3:0] axi_hp0_awqos;
wire axi_hp0_awready;
wire [2:0] axi_hp0_awsize;
wire axi_hp0_awvalid;
wire [5:0] axi_hp0_bid;
wire axi_hp0_bready;
wire [1:0] axi_hp0_bresp;
wire axi_hp0_bvalid;
wire [63:0] axi_hp0_rdata;
wire [5:0] axi_hp0_rid;
wire axi_hp0_rlast;
wire axi_hp0_rready;
wire [1:0] axi_hp0_rresp;
wire axi_hp0_rvalid;
wire [63:0] axi_hp0_wdata;
wire [5:0] axi_hp0_wid;
wire axi_hp0_wlast;
wire axi_hp0_wready;
wire [7:0] axi_hp0_wstrb;
wire axi_hp0_wvalid;
wire [31:0] cfg_wr_data;
wire [4:0] cfg_wr_addr;
wire cfg_wr_en;
@ -61,6 +119,18 @@ module zedboard_axis
reg [31:0] cfg_hold [0:31];
reg [0:31] cfg_hold_en;
wire [31:0] sys_hp0_dst_data;
wire sys_hp0_dst_valid;
wire sys_hp0_dst_ready;
wire [31:0] sys_hp0_src_data;
wire sys_hp0_src_valid;
wire sys_hp0_src_ready;
reg [CFG_DWIDTH-1:0] axis_hp0_dst_cnt;
reg [CFG_DWIDTH-1:0] axis_hp0_src_cnt;
system
system_i (
.DDR_addr (DDR_addr),
@ -106,7 +176,50 @@ module zedboard_axis
.M00_AXI_wdata (axi_wdata),
.M00_AXI_wready (axi_wready),
.M00_AXI_wstrb (axi_wstrb),
.M00_AXI_wvalid (axi_wvalid)
.M00_AXI_wvalid (axi_wvalid),
.S_AXI_HP0_araddr (axi_hp0_araddr),
.S_AXI_HP0_arburst (axi_hp0_arburst),
.S_AXI_HP0_arcache (axi_hp0_arcache),
.S_AXI_HP0_arid (axi_hp0_arid),
.S_AXI_HP0_arlen (axi_hp0_arlen),
.S_AXI_HP0_arlock (axi_hp0_arlock),
.S_AXI_HP0_arprot (axi_hp0_arprot),
.S_AXI_HP0_arqos (axi_hp0_arqos),
.S_AXI_HP0_arready (axi_hp0_arready),
.S_AXI_HP0_arsize (axi_hp0_arsize),
.S_AXI_HP0_arvalid (axi_hp0_arvalid),
.S_AXI_HP0_awaddr (axi_hp0_awaddr),
.S_AXI_HP0_awburst (axi_hp0_awburst),
.S_AXI_HP0_awcache (axi_hp0_awcache),
.S_AXI_HP0_awid (axi_hp0_awid),
.S_AXI_HP0_awlen (axi_hp0_awlen),
.S_AXI_HP0_awlock (axi_hp0_awlock),
.S_AXI_HP0_awprot (axi_hp0_awprot),
.S_AXI_HP0_awqos (axi_hp0_awqos),
.S_AXI_HP0_awready (axi_hp0_awready),
.S_AXI_HP0_awsize (axi_hp0_awsize),
.S_AXI_HP0_awvalid (axi_hp0_awvalid),
.S_AXI_HP0_bid (axi_hp0_bid),
.S_AXI_HP0_bready (axi_hp0_bready),
.S_AXI_HP0_bresp (axi_hp0_bresp),
.S_AXI_HP0_bvalid (axi_hp0_bvalid),
.S_AXI_HP0_rdata (axi_hp0_rdata),
.S_AXI_HP0_rid (axi_hp0_rid),
.S_AXI_HP0_rlast (axi_hp0_rlast),
.S_AXI_HP0_rready (axi_hp0_rready),
.S_AXI_HP0_rresp (axi_hp0_rresp),
.S_AXI_HP0_rvalid (axi_hp0_rvalid),
.S_AXI_HP0_wdata (axi_hp0_wdata),
.S_AXI_HP0_wid (axi_hp0_wid),
.S_AXI_HP0_wlast (axi_hp0_wlast),
.S_AXI_HP0_wready (axi_hp0_wready),
.S_AXI_HP0_wstrb (axi_hp0_wstrb),
.S_AXI_HP0_wvalid (axi_hp0_wvalid)
);
@ -179,6 +292,9 @@ module zedboard_axis
if (cfg_rd_en) begin
case (cfg_rd_addr)
CFG_HP0_DST_CNT : cfg_rd_data <= axis_hp0_dst_cnt;
CFG_HP0_SRC_CNT : cfg_rd_data <= axis_hp0_src_cnt;
CFG_HP0_SRC_DATA : cfg_rd_data <= sys_hp0_src_data;
default : cfg_rd_data <= cfg_hold[cfg_rd_addr];
endcase
@ -186,4 +302,97 @@ module zedboard_axis
end
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),
.STREAM_WIDTH (32),
.AXI_ID_WIDTH (AXI_ID_WIDTH),
.AXI_LEN_WIDTH (AXI_LEN_WIDTH),
.AXI_ADDR_WIDTH (AXI_ADDR_WIDTH),
.AXI_DATA_WIDTH (AXI_DATA_WIDTH))
axis_hp0_ (
.clk (axi_clk),
.rst ( ~axi_rst_n),
.cfg_addr (cfg_wr_addr),
.cfg_data (cfg_wr_data),
.cfg_valid (cfg_wr_en),
.wr_data (sys_hp0_dst_data),
.wr_valid (sys_hp0_dst_valid),
.wr_ready (sys_hp0_dst_ready),
.rd_data (sys_hp0_src_data),
.rd_valid (sys_hp0_src_valid),
.rd_ready (sys_hp0_src_ready),
.axi_awready (axi_hp0_awready),
.axi_awid (axi_hp0_awid),
.axi_awaddr (axi_hp0_awaddr),
.axi_awlen (axi_hp0_awlen),
.axi_awsize (axi_hp0_awsize),
.axi_awburst (axi_hp0_awburst),
.axi_awlock (axi_hp0_awlock),
.axi_awcache (axi_hp0_awcache),
.axi_awprot (axi_hp0_awprot),
.axi_awqos (axi_hp0_awqos),
.axi_awvalid (axi_hp0_awvalid),
.axi_wready (axi_hp0_wready),
.axi_wid (axi_hp0_wid),
.axi_wdata (axi_hp0_wdata),
.axi_wstrb (axi_hp0_wstrb),
.axi_wlast (axi_hp0_wlast),
.axi_wvalid (axi_hp0_wvalid),
.axi_bid (axi_hp0_bid),
.axi_bresp (axi_hp0_bresp),
.axi_bvalid (axi_hp0_bvalid),
.axi_bready (axi_hp0_bready),
.axi_arready (axi_hp0_arready),
.axi_arid (axi_hp0_arid),
.axi_araddr (axi_hp0_araddr),
.axi_arlen (axi_hp0_arlen),
.axi_arsize (axi_hp0_arsize),
.axi_arburst (axi_hp0_arburst),
.axi_arlock (axi_hp0_arlock),
.axi_arcache (axi_hp0_arcache),
.axi_arprot (axi_hp0_arprot),
.axi_arvalid (axi_hp0_arvalid),
.axi_arqos (axi_hp0_arqos),
.axi_rid (axi_hp0_rid),
.axi_rresp (axi_hp0_rresp),
.axi_rvalid (axi_hp0_rvalid),
.axi_rdata (axi_hp0_rdata),
.axi_rlast (axi_hp0_rlast),
.axi_rready (axi_hp0_rready)
);
assign sys_hp0_dst_data = cfg_hold[CFG_HP0_DST_DATA];
assign sys_hp0_dst_valid = cfg_hold_en[CFG_HP0_DST_DATA];
assign sys_hp0_src_ready = cfg_rd_en & (CFG_HP0_SRC_DATA == cfg_rd_addr);
// counts number of system data sent from AXIS port
always @(posedge axi_clk)
if ( ~axi_rst_n) axis_hp0_dst_cnt <= 'b0;
else if (sys_hp0_dst_valid) begin
axis_hp0_dst_cnt <= axis_hp0_dst_cnt + 1;
end
always @(posedge axi_clk)
if ( ~axi_rst_n) axis_hp0_src_cnt <= 'b0;
else if (sys_hp0_src_valid) begin
axis_hp0_src_cnt <= axis_hp0_src_cnt + 1;
end
endmodule

67
sim-module Executable file
View File

@ -0,0 +1,67 @@
#!/bin/bash
set -o errexit
# Should give an arg
if [ $# == 0 ]
then
echo "? executes the testbench for the module"
echo "syntax:"
echo " ./sim-module <module-name>"
exit
fi
# create sim scratch work directory
test -d sim/scratch && rm -rf sim/scratch
mkdir -p sim/scratch/src
# copy verilog code files from hdl directory into sim work dir
for FILE in $(find ./hdl/* -name "*.v" -type f -print)
do
cp -n $FILE ./sim/scratch/src/ || { echo "ERROR duplicate filename ${FILE}" ; exit 1; }
done
# copy verilog header files from hdl directory into sim work dir
for FILE in $(find ./hdl/*/ -name "*.vh" -type f -print)
do
cp -n $FILE ./sim/scratch/src/ || { echo "ERROR duplicate filename ${FILE}" ; exit 1; }
done
# copy SystemVerilog code files from hdl directory into sim work dir
for FILE in $(find ./hdl/*/ -name "*.sv" -type f -print)
do
cp -n $FILE ./sim/scratch/src/ || { echo "ERROR duplicate filename ${FILE}" ; exit 1; }
done
# cd into the working dir
cd sim/scratch/src
# UUT should contain the name of the unit under test
if [ -f $1_tb.v ]
then
UUT=$1
else
echo "syntax:"
echo " ./sim-module <module-name>"
echo ""
echo "Where <module-name>_tb.v should exist"
exit
fi
# compile current unit
echo "UUT = $UUT"
iverilog -o ../$UUT ${UUT}_tb.v
cd ..
# run current simul/testbench
if [ -f $UUT ]
then
./$UUT
else
echo "iverilog failed"
exit
fi
echo "test for unit ${UUT} done"

View File

@ -251,7 +251,7 @@
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PCW_USE_S_AXI_GP0">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PCW_USE_S_AXI_GP1">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PCW_USE_S_AXI_ACP">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PCW_USE_S_AXI_HP0">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PCW_USE_S_AXI_HP0">1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PCW_USE_S_AXI_HP1">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PCW_USE_S_AXI_HP2">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PCW_USE_S_AXI_HP3">0</spirit:configurableElementValue>

View File

@ -45,6 +45,78 @@
</spirit:parameter>
</spirit:parameters>
</spirit:busInterface>
<spirit:busInterface>
<spirit:name>S_AXI_HP0</spirit:name>
<spirit:slave/>
<spirit:busType spirit:library="interface" spirit:name="aximm" spirit:vendor="xilinx.com" spirit:version="1.0"/>
<spirit:abstractionType spirit:library="interface" spirit:name="aximm_rtl" spirit:vendor="xilinx.com" spirit:version="1.0"/>
<spirit:parameters>
<spirit:parameter>
<spirit:name>DATA_WIDTH</spirit:name>
<spirit:value>64</spirit:value>
</spirit:parameter>
<spirit:parameter>
<spirit:name>PROTOCOL</spirit:name>
<spirit:value>AXI3</spirit:value>
</spirit:parameter>
<spirit:parameter>
<spirit:name>FREQ_HZ</spirit:name>
<spirit:value>100000000</spirit:value>
</spirit:parameter>
<spirit:parameter>
<spirit:name>ID_WIDTH</spirit:name>
<spirit:value>6</spirit:value>
</spirit:parameter>
<spirit:parameter>
<spirit:name>ADDR_WIDTH</spirit:name>
<spirit:value>32</spirit:value>
</spirit:parameter>
<spirit:parameter>
<spirit:name>AWUSER_WIDTH</spirit:name>
<spirit:value>0</spirit:value>
</spirit:parameter>
<spirit:parameter>
<spirit:name>ARUSER_WIDTH</spirit:name>
<spirit:value>0</spirit:value>
</spirit:parameter>
<spirit:parameter>
<spirit:name>WUSER_WIDTH</spirit:name>
<spirit:value>0</spirit:value>
</spirit:parameter>
<spirit:parameter>
<spirit:name>RUSER_WIDTH</spirit:name>
<spirit:value>0</spirit:value>
</spirit:parameter>
<spirit:parameter>
<spirit:name>BUSER_WIDTH</spirit:name>
<spirit:value>0</spirit:value>
</spirit:parameter>
<spirit:parameter>
<spirit:name>READ_WRITE_MODE</spirit:name>
<spirit:value>READ_WRITE</spirit:value>
</spirit:parameter>
<spirit:parameter>
<spirit:name>SUPPORTS_NARROW_BURST</spirit:name>
<spirit:value>1</spirit:value>
</spirit:parameter>
<spirit:parameter>
<spirit:name>NUM_READ_OUTSTANDING</spirit:name>
<spirit:value>1</spirit:value>
</spirit:parameter>
<spirit:parameter>
<spirit:name>NUM_WRITE_OUTSTANDING</spirit:name>
<spirit:value>1</spirit:value>
</spirit:parameter>
<spirit:parameter>
<spirit:name>MAX_BURST_LENGTH</spirit:name>
<spirit:value>16</spirit:value>
</spirit:parameter>
<spirit:parameter>
<spirit:name>PHASE</spirit:name>
<spirit:value>0.000</spirit:value>
</spirit:parameter>
</spirit:parameters>
</spirit:busInterface>
<spirit:busInterface>
<spirit:name>CLK.AXI_CLK</spirit:name>
<spirit:displayName>Clk</spirit:displayName>
@ -107,6 +179,21 @@
</spirit:port>
</spirit:ports>
</spirit:model>
<spirit:addressSpaces>
<spirit:addressSpace>
<spirit:name>S_AXI_HP0</spirit:name>
<spirit:range>4G</spirit:range>
<spirit:width>32</spirit:width>
<spirit:segments>
<spirit:segment>
<spirit:name>SEG_ps7_HP0_DDR_LOWOCM</spirit:name>
<spirit:displayName>/ps7/S_AXI_HP0/HP0_DDR_LOWOCM</spirit:displayName>
<spirit:addressOffset>0x00000000</spirit:addressOffset>
<spirit:range>512M</spirit:range>
</spirit:segment>
</spirit:segments>
</spirit:addressSpace>
</spirit:addressSpaces>
<spirit:memoryMaps>
<spirit:memoryMap>
<spirit:name>M00_AXI</spirit:name>
@ -131,6 +218,7 @@
<spirit:componentRef spirit:library="ip" spirit:name="processing_system7" spirit:vendor="xilinx.com" spirit:version="5.4"/>
<spirit:configurableElementValues>
<spirit:configurableElementValue spirit:referenceId="bd:xciName">system_ps7_0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PCW_USE_S_AXI_HP0">1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="preset">*</spirit:configurableElementValue>
</spirit:configurableElementValues>
</spirit:componentInstance>
@ -160,6 +248,7 @@
<spirit:internalPortReference spirit:componentRef="axi_interconnect_0" spirit:portRef="M00_ACLK"/>
<spirit:internalPortReference spirit:componentRef="axi_interconnect_0" spirit:portRef="S00_ACLK"/>
<spirit:internalPortReference spirit:componentRef="axi_interconnect_0" spirit:portRef="ACLK"/>
<spirit:internalPortReference spirit:componentRef="ps7" spirit:portRef="S_AXI_HP0_ACLK"/>
</spirit:adHocConnection>
<spirit:adHocConnection>
<spirit:name>ps7_FCLK_RESET0_N</spirit:name>
@ -180,6 +269,9 @@
<spirit:hierConnection spirit:interfaceRef="M00_AXI/axi_interconnect_0_M00_AXI">
<spirit:activeInterface spirit:busRef="M00_AXI" spirit:componentRef="axi_interconnect_0"/>
</spirit:hierConnection>
<spirit:hierConnection spirit:interfaceRef="S_AXI_HP0/S_AXI_HP0_1">
<spirit:activeInterface spirit:busRef="S_AXI_HP0" spirit:componentRef="ps7"/>
</spirit:hierConnection>
</spirit:hierConnections>
</spirit:design>