mirror of
https://github.com/parallella/parallella-hw.git
synced 2024-11-24 03:34:40 +00:00
455 lines
12 KiB
Verilog
455 lines
12 KiB
Verilog
|
|
`timescale 1 ns / 1 ps
|
|
|
|
`define NULL 0
|
|
`define EOF 32'hFFFF_FFFF
|
|
`define MAX_LINE_LENGTH 200
|
|
|
|
module elink2stream_tb;
|
|
|
|
reg aclk;
|
|
reg aresetn;
|
|
reg start;
|
|
wire reset = ~aresetn;
|
|
wire done0;
|
|
wire error0;
|
|
|
|
wire rx_cclk_n;
|
|
wire rx_cclk_p;
|
|
|
|
wire [11:0] param_coreid = 12'h810;
|
|
wire TX_rd_wait_n = 1'b1;
|
|
wire TX_rd_wait_p = 1'b0;
|
|
wire TX_wr_wait_n = 1'b1;
|
|
wire TX_wr_wait_p = 1'b0;
|
|
|
|
wire [31:0]M00_AXI_araddr;
|
|
wire [1:0]M00_AXI_arburst;
|
|
wire [3:0]M00_AXI_arcache;
|
|
wire [0:0]M00_AXI_arid;
|
|
wire [7:0]M00_AXI_arlen;
|
|
wire M00_AXI_arlock;
|
|
wire [2:0]M00_AXI_arprot;
|
|
wire [3:0]M00_AXI_arqos;
|
|
wire M00_AXI_arready = 1'b1;
|
|
wire [2:0]M00_AXI_arsize;
|
|
wire M00_AXI_arvalid;
|
|
|
|
wire [31:0]M00_AXI_awaddr;
|
|
wire [1:0]M00_AXI_awburst;
|
|
wire [3:0]M00_AXI_awcache;
|
|
wire [0:0]M00_AXI_awid;
|
|
wire [7:0]M00_AXI_awlen;
|
|
wire M00_AXI_awlock;
|
|
wire [2:0]M00_AXI_awprot;
|
|
wire [3:0]M00_AXI_awqos;
|
|
wire M00_AXI_awready = 1'b1;
|
|
wire [2:0]M00_AXI_awsize;
|
|
wire M00_AXI_awvalid;
|
|
|
|
wire [0:0]M00_AXI_bid = 1'b0;
|
|
wire M00_AXI_bready;
|
|
wire [1:0]M00_AXI_bresp = 2'b00;
|
|
reg M00_AXI_bvalid;
|
|
|
|
reg [63:0]M00_AXI_rdata;
|
|
reg [0:0]M00_AXI_rid = 1'b0;
|
|
reg M00_AXI_rlast;
|
|
wire M00_AXI_rready;
|
|
wire [1:0]M00_AXI_rresp = 2'b00;
|
|
reg M00_AXI_rvalid;
|
|
|
|
wire [63:0]M00_AXI_wdata;
|
|
wire M00_AXI_wlast;
|
|
wire M00_AXI_wready = 1'b1;
|
|
wire [7:0]M00_AXI_wstrb;
|
|
wire M00_AXI_wvalid;
|
|
|
|
wire [7:0]TX_data_n;
|
|
wire [7:0]TX_data_p;
|
|
wire TX_frame_n;
|
|
wire TX_frame_p;
|
|
wire TX_lclk_n;
|
|
wire TX_lclk_p;
|
|
|
|
reg [7:0]RX_data_p;
|
|
wire [7:0]RX_data_n = ~RX_data_p;
|
|
reg RX_frame_p;
|
|
wire RX_frame_n = ~RX_frame_p;
|
|
wire RX_lclk_n = TX_lclk_n;
|
|
wire RX_lclk_p = TX_lclk_p;
|
|
wire RX_rd_wait_n;
|
|
wire RX_rd_wait_p;
|
|
wire RX_wr_wait_n;
|
|
wire RX_wr_wait_p;
|
|
|
|
// Transaction parameters
|
|
reg [31:0] src, dst, data;
|
|
reg [3:0] ctrlmode;
|
|
reg [1:0] datamode;
|
|
reg write;
|
|
reg access;
|
|
reg stream;
|
|
reg [31:0] delay;
|
|
reg done;
|
|
wire all_done;
|
|
assign #5000 all_done = done;
|
|
|
|
// Transmitter state machine
|
|
reg [15:0] pc;
|
|
reg [4:0] txstate;
|
|
reg [15:0] delaycnt;
|
|
reg isstream;
|
|
integer writecount;
|
|
integer readcount;
|
|
|
|
integer fileid;
|
|
integer fscanret;
|
|
reg [8*`MAX_LINE_LENGTH:0] line;
|
|
|
|
task getnext;
|
|
begin // delay src dst data cmode dmode write access stream done
|
|
if($feof(fileid)) begin
|
|
$display("Unexpected EOF");
|
|
$finish;
|
|
end
|
|
fscanret = $fgets(line, fileid);
|
|
fscanret = $sscanf(line, "%d %h %h %h %h %d %d %d %d %d",
|
|
delay, src, dst, data, ctrlmode, datamode,
|
|
write, access, stream, done);
|
|
if(fscanret == 1) begin
|
|
src <= 32'd0;
|
|
dst <= 32'd0;
|
|
data <= 32'd0;
|
|
ctrlmode <= 4'd0;
|
|
datamode <= 2'd0;
|
|
write <= 1'b0;
|
|
access <= 1'b0;
|
|
stream <= 1'b0;
|
|
done <= 1'b0;
|
|
end else if(fscanret != 10) begin
|
|
$display("ERROR: Wrong number of entries in file: (position %d) %s",
|
|
$ftell(fileid), line);
|
|
$finish;
|
|
end
|
|
end
|
|
endtask // getnext
|
|
|
|
initial begin
|
|
fileid = $fopen("../../test_prog.dat", "r");
|
|
if(fileid == 0) begin
|
|
$display("Unable to open file!");
|
|
$finish;
|
|
end
|
|
getnext();
|
|
end
|
|
|
|
wire lclk_delay;
|
|
assign #0.8333 lclk_delay = TX_lclk_p;
|
|
|
|
// Test transmitter
|
|
always @ (lclk_delay) begin
|
|
if(~done0) begin
|
|
|
|
pc <= 16'd1;
|
|
txstate <= 5'd0;
|
|
delaycnt <= 16'd0;
|
|
RX_data_p <= 8'd0;
|
|
RX_frame_p <= 1'b0;
|
|
isstream <= 1'b0;
|
|
writecount <= 0;
|
|
readcount <= 0;
|
|
|
|
end else begin
|
|
|
|
// default is to advance to next state
|
|
txstate <= txstate + 1;
|
|
|
|
case(txstate)
|
|
|
|
5'd0: begin // Start new transaction or delay
|
|
RX_frame_p <= 1'b0;
|
|
delaycnt <= delay - 16'd2;
|
|
isstream <= 1'b0;
|
|
|
|
if(done) begin
|
|
txstate <= 5'd31;
|
|
$display("<-- Transmission complete!");
|
|
end else if(delay == 16'd1) begin
|
|
txstate <= 5'd0;
|
|
pc <= pc + 16'd1;
|
|
getnext();
|
|
$display("<-- Waiting 1 cycle");
|
|
end else if(|delay) begin
|
|
txstate <= 5'd16;
|
|
$display("<-- Waiting %d cycles", delay);
|
|
end else if(RX_wr_wait_p | RX_rd_wait_p) begin
|
|
txstate <= 5'd0;
|
|
end else begin
|
|
if(write) begin
|
|
$write("<-- %d Writing ", writecount);
|
|
writecount <= writecount + 1;
|
|
end else begin
|
|
$write("<-- %d Reading ", readcount);
|
|
readcount <= readcount + 1;
|
|
end
|
|
|
|
case(datamode)
|
|
2'd0: $write("BYTE ");
|
|
2'd1: $write("HWORD ");
|
|
2'd2: $write("WORD ");
|
|
2'd3: $write("DWORD ");
|
|
endcase // case (datamode)
|
|
|
|
if(write && datamode == 3'd3)
|
|
$display("0x%H:0x%H to address 0x%H", src, data, dst);
|
|
else if(write)
|
|
$display("0x%H to address 0x%H", data, dst);
|
|
else
|
|
$display("from address 0x%H, return to 0x%H", dst, src);
|
|
end
|
|
end
|
|
|
|
5'd1: begin // TRAN byte
|
|
RX_data_p <= {~write, 7'd0};
|
|
RX_frame_p <= 1'b1;
|
|
end
|
|
|
|
5'd2:
|
|
RX_data_p <= {ctrlmode, dst[31:28]};
|
|
|
|
5'd3:
|
|
RX_data_p <= dst[27:20];
|
|
|
|
5'd4:
|
|
RX_data_p <= dst[19:12];
|
|
|
|
5'd5:
|
|
RX_data_p <= dst[11:4];
|
|
|
|
5'd6:
|
|
RX_data_p <= {dst[3:0], datamode, write, access};
|
|
|
|
5'd7: begin
|
|
if(isstream) begin
|
|
$display("<-- %d Streaming data 0x%H:0x%H",
|
|
writecount, src, data);
|
|
writecount <= writecount + 1;
|
|
end
|
|
RX_data_p <= data[31:24];
|
|
end
|
|
|
|
5'd8:
|
|
RX_data_p <= data[23:16];
|
|
|
|
5'd9:
|
|
RX_data_p <= data[15:8];
|
|
|
|
5'd10:
|
|
RX_data_p <= data[7:0];
|
|
|
|
5'd11:
|
|
RX_data_p <= src[31:24];
|
|
|
|
5'd12:
|
|
RX_data_p <= src[23:16];
|
|
|
|
5'd13:
|
|
RX_data_p <= src[15:8];
|
|
|
|
5'd14: begin
|
|
RX_data_p <= src[7:0];
|
|
pc <= pc + 1;
|
|
getnext();
|
|
isstream <= stream;
|
|
if(stream)
|
|
txstate <= 5'd7; // next 'data'
|
|
else
|
|
txstate <= 5'd0;
|
|
end
|
|
|
|
5'd16: begin // delay, hold eLink idle
|
|
delaycnt <= delaycnt - 1;
|
|
if(~|delaycnt) begin
|
|
pc <= pc + 1;
|
|
getnext();
|
|
txstate <= 5'd0;
|
|
end else begin
|
|
txstate <= txstate; // override default
|
|
end
|
|
end
|
|
|
|
5'd31: txstate <= txstate; // All done
|
|
|
|
endcase // case (txstate)
|
|
|
|
end // else: !if(reset)
|
|
end // always @ (TX_lclk_p)
|
|
|
|
integer awcount, wcount, arcount;
|
|
|
|
initial begin
|
|
awcount = 0;
|
|
wcount = 0;
|
|
arcount = 0;
|
|
end
|
|
|
|
always @ (posedge aclk) begin
|
|
if(M00_AXI_awvalid & M00_AXI_awready) begin
|
|
$display("--> %d Write address: 0x%H, size: %d, len: %d",
|
|
awcount, M00_AXI_awaddr, M00_AXI_awsize, M00_AXI_awlen);
|
|
awcount <= awcount + 1;
|
|
end
|
|
end
|
|
|
|
// Respond to write requests
|
|
always @ (posedge aclk) begin
|
|
if(reset) begin
|
|
M00_AXI_bvalid <= 1'b0;
|
|
end else begin
|
|
|
|
if(M00_AXI_awvalid & M00_AXI_awready) begin
|
|
$display("--> %d Write data: 0x%H", wcount, M00_AXI_wdata);
|
|
M00_AXI_bvalid <= 1'b1;
|
|
wcount <= wcount + 1;
|
|
end else if(M00_AXI_bready) begin
|
|
M00_AXI_bvalid <= 1'b0;
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
// Respond to read requests
|
|
always @ (posedge aclk) begin
|
|
if(reset) begin
|
|
M00_AXI_rdata <= 64'd0;
|
|
M00_AXI_rlast <= 1'b0;
|
|
M00_AXI_rvalid <= 1'b0;
|
|
end else begin
|
|
|
|
if(M00_AXI_arvalid & M00_AXI_arready) begin
|
|
$display("--> %d Read request: <TBD>", arcount);
|
|
arcount <= arcount + 1;
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
|
|
// Reset Generator
|
|
initial begin
|
|
aresetn = 1'b0;
|
|
#500;
|
|
// Release the reset on the posedge of the clk.
|
|
@(posedge aclk);
|
|
aresetn = 1'b1;
|
|
end
|
|
|
|
// Clock Generator
|
|
initial aclk = 1'b0;
|
|
always #5 aclk = ~aclk;
|
|
|
|
// Drive the BFM
|
|
initial begin
|
|
|
|
start = 1'b0;
|
|
|
|
// Wait for end of reset
|
|
wait(aresetn === 0) @(posedge aclk);
|
|
wait(aresetn === 1) @(posedge aclk);
|
|
|
|
#500 start = 1'b1;
|
|
@(posedge aclk);
|
|
|
|
$display("=== TB Started");
|
|
|
|
wait( all_done == 1'b1);
|
|
$display("=== TEST_FINISHED");
|
|
if ( wcount != writecount || arcount != readcount ) begin
|
|
$display("=== TEST: FAILED!\n %d writes sent, %d writes rcvd\n %d reads sent, %d reads rcvd",
|
|
writecount, wcount, readcount, arcount);
|
|
end else begin
|
|
$display("=== TEST: PASSED!");
|
|
end
|
|
|
|
end
|
|
|
|
always @ (posedge done0)
|
|
$display("=== INIT Complete");
|
|
|
|
always @ (posedge error0)
|
|
if( done0 == 1'b0)
|
|
$display("=== ERROR FLAG INIT @ %T", $time);
|
|
|
|
// Create an instance of the example
|
|
elink2_stream dut
|
|
(.M00_AXI_araddr(M00_AXI_araddr),
|
|
.M00_AXI_arburst(M00_AXI_arburst),
|
|
.M00_AXI_arcache(M00_AXI_arcache),
|
|
.M00_AXI_arid(M00_AXI_arid),
|
|
.M00_AXI_arlen(M00_AXI_arlen),
|
|
.M00_AXI_arlock(M00_AXI_arlock),
|
|
.M00_AXI_arprot(M00_AXI_arprot),
|
|
.M00_AXI_arqos(M00_AXI_arqos),
|
|
.M00_AXI_arready(M00_AXI_arready),
|
|
.M00_AXI_arsize(M00_AXI_arsize),
|
|
.M00_AXI_arvalid(M00_AXI_arvalid),
|
|
.M00_AXI_awaddr(M00_AXI_awaddr),
|
|
.M00_AXI_awburst(M00_AXI_awburst),
|
|
.M00_AXI_awcache(M00_AXI_awcache),
|
|
.M00_AXI_awid(M00_AXI_awid),
|
|
.M00_AXI_awlen(M00_AXI_awlen),
|
|
.M00_AXI_awlock(M00_AXI_awlock),
|
|
.M00_AXI_awprot(M00_AXI_awprot),
|
|
.M00_AXI_awqos(M00_AXI_awqos),
|
|
.M00_AXI_awready(M00_AXI_awready),
|
|
.M00_AXI_awsize(M00_AXI_awsize),
|
|
.M00_AXI_awvalid(M00_AXI_awvalid),
|
|
.M00_AXI_bid(M00_AXI_bid),
|
|
.M00_AXI_bready(M00_AXI_bready),
|
|
.M00_AXI_bresp(M00_AXI_bresp),
|
|
.M00_AXI_bvalid(M00_AXI_bvalid),
|
|
.M00_AXI_rdata(M00_AXI_rdata),
|
|
.M00_AXI_rid(M00_AXI_rid),
|
|
.M00_AXI_rlast(M00_AXI_rlast),
|
|
.M00_AXI_rready(M00_AXI_rready),
|
|
.M00_AXI_rresp(M00_AXI_rresp),
|
|
.M00_AXI_rvalid(M00_AXI_rvalid),
|
|
.M00_AXI_wdata(M00_AXI_wdata),
|
|
.M00_AXI_wlast(M00_AXI_wlast),
|
|
.M00_AXI_wready(M00_AXI_wready),
|
|
.M00_AXI_wstrb(M00_AXI_wstrb),
|
|
.M00_AXI_wvalid(M00_AXI_wvalid),
|
|
.RX_data_n(RX_data_n),
|
|
.RX_data_p(RX_data_p),
|
|
.RX_frame_n(RX_frame_n),
|
|
.RX_frame_p(RX_frame_p),
|
|
.RX_lclk_n(RX_lclk_n),
|
|
.RX_lclk_p(RX_lclk_p),
|
|
.RX_rd_wait_n(RX_rd_wait_n),
|
|
.RX_rd_wait_p(RX_rd_wait_p),
|
|
.RX_wr_wait_n(RX_wr_wait_n),
|
|
.RX_wr_wait_p(RX_wr_wait_p),
|
|
.TX_data_n(TX_data_n),
|
|
.TX_data_p(TX_data_p),
|
|
.TX_frame_n(TX_frame_n),
|
|
.TX_frame_p(TX_frame_p),
|
|
.TX_lclk_n(TX_lclk_n),
|
|
.TX_lclk_p(TX_lclk_p),
|
|
.TX_rd_wait_n(TX_rd_wait_n),
|
|
.TX_rd_wait_p(TX_rd_wait_p),
|
|
.TX_wr_wait_n(TX_wr_wait_n),
|
|
.TX_wr_wait_p(TX_wr_wait_p),
|
|
.aclk(aclk),
|
|
.aresetn(aresetn),
|
|
.done0(done0),
|
|
.error0(error0),
|
|
.param_coreid(param_coreid),
|
|
.reset(reset),
|
|
.rx_cclk_n(rx_cclk_n),
|
|
.rx_cclk_p(rx_cclk_p),
|
|
.start(start));
|
|
|
|
|
|
endmodule
|