mirror of
https://github.com/corundum/corundum.git
synced 2025-01-30 08:32:52 +08:00
Add TDMA BERT modules and testbenches
This commit is contained in:
parent
905651d5f8
commit
4c3f2412df
447
fpga/common/rtl/tdma_ber.v
Normal file
447
fpga/common/rtl/tdma_ber.v
Normal file
@ -0,0 +1,447 @@
|
||||
/*
|
||||
|
||||
Copyright 2019, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
/*
|
||||
* TDMA BER module
|
||||
*/
|
||||
module tdma_ber #
|
||||
(
|
||||
parameter COUNT = 1,
|
||||
parameter INDEX_WIDTH = 6,
|
||||
parameter SLICE_WIDTH = 5,
|
||||
parameter AXIL_DATA_WIDTH = 32,
|
||||
parameter AXIL_ADDR_WIDTH = INDEX_WIDTH+4+1+$clog2(COUNT),
|
||||
parameter AXIL_STRB_WIDTH = (AXIL_DATA_WIDTH/8),
|
||||
parameter SCHEDULE_START_S = 48'h0,
|
||||
parameter SCHEDULE_START_NS = 30'h0,
|
||||
parameter SCHEDULE_PERIOD_S = 48'd0,
|
||||
parameter SCHEDULE_PERIOD_NS = 30'd1000000,
|
||||
parameter TIMESLOT_PERIOD_S = 48'd0,
|
||||
parameter TIMESLOT_PERIOD_NS = 30'd100000,
|
||||
parameter ACTIVE_PERIOD_S = 48'd0,
|
||||
parameter ACTIVE_PERIOD_NS = 30'd100000
|
||||
)
|
||||
(
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
|
||||
/*
|
||||
* PHY connections
|
||||
*/
|
||||
input wire [COUNT-1:0] phy_tx_clk,
|
||||
input wire [COUNT-1:0] phy_rx_clk,
|
||||
input wire [COUNT*7-1:0] phy_rx_error_count,
|
||||
output wire [COUNT-1:0] phy_tx_prbs31_enable,
|
||||
output wire [COUNT-1:0] phy_rx_prbs31_enable,
|
||||
|
||||
/*
|
||||
* AXI-Lite slave interface
|
||||
*/
|
||||
input wire [AXIL_ADDR_WIDTH-1:0] s_axil_awaddr,
|
||||
input wire [2:0] s_axil_awprot,
|
||||
input wire s_axil_awvalid,
|
||||
output wire s_axil_awready,
|
||||
input wire [AXIL_DATA_WIDTH-1:0] s_axil_wdata,
|
||||
input wire [AXIL_STRB_WIDTH-1:0] s_axil_wstrb,
|
||||
input wire s_axil_wvalid,
|
||||
output wire s_axil_wready,
|
||||
output wire [1:0] s_axil_bresp,
|
||||
output wire s_axil_bvalid,
|
||||
input wire s_axil_bready,
|
||||
input wire [AXIL_ADDR_WIDTH-1:0] s_axil_araddr,
|
||||
input wire [2:0] s_axil_arprot,
|
||||
input wire s_axil_arvalid,
|
||||
output wire s_axil_arready,
|
||||
output wire [AXIL_DATA_WIDTH-1:0] s_axil_rdata,
|
||||
output wire [1:0] s_axil_rresp,
|
||||
output wire s_axil_rvalid,
|
||||
input wire s_axil_rready,
|
||||
|
||||
/*
|
||||
* PTP clock
|
||||
*/
|
||||
input wire [95:0] ptp_ts_96,
|
||||
input wire ptp_ts_step
|
||||
);
|
||||
|
||||
// check configuration
|
||||
initial begin
|
||||
if (AXIL_ADDR_WIDTH < INDEX_WIDTH+4+1+$clog2(COUNT)) begin
|
||||
$error("Error: AXI address width too narrow");
|
||||
$finish;
|
||||
end
|
||||
|
||||
if (AXIL_DATA_WIDTH != 32) begin
|
||||
$error("Error: AXI data width must be 32");
|
||||
$finish;
|
||||
end
|
||||
|
||||
if (AXIL_STRB_WIDTH * 8 != AXIL_DATA_WIDTH) begin
|
||||
$error("Error: Interface requires byte (8-bit) granularity");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
wire [AXIL_ADDR_WIDTH-1:0] axil_csr_awaddr;
|
||||
wire [2:0] axil_csr_awprot;
|
||||
wire axil_csr_awvalid;
|
||||
wire axil_csr_awready;
|
||||
wire [AXIL_DATA_WIDTH-1:0] axil_csr_wdata;
|
||||
wire [AXIL_STRB_WIDTH-1:0] axil_csr_wstrb;
|
||||
wire axil_csr_wvalid;
|
||||
wire axil_csr_wready;
|
||||
wire [1:0] axil_csr_bresp;
|
||||
wire axil_csr_bvalid;
|
||||
wire axil_csr_bready;
|
||||
wire [AXIL_ADDR_WIDTH-1:0] axil_csr_araddr;
|
||||
wire [2:0] axil_csr_arprot;
|
||||
wire axil_csr_arvalid;
|
||||
wire axil_csr_arready;
|
||||
wire [AXIL_DATA_WIDTH-1:0] axil_csr_rdata;
|
||||
wire [1:0] axil_csr_rresp;
|
||||
wire axil_csr_rvalid;
|
||||
wire axil_csr_rready;
|
||||
|
||||
// control registers
|
||||
reg axil_csr_awready_reg = 1'b0;
|
||||
reg axil_csr_wready_reg = 1'b0;
|
||||
reg axil_csr_bvalid_reg = 1'b0;
|
||||
reg axil_csr_arready_reg = 1'b0;
|
||||
reg [AXIL_DATA_WIDTH-1:0] axil_csr_rdata_reg = {AXIL_DATA_WIDTH{1'b0}};
|
||||
reg axil_csr_rvalid_reg = 1'b0;
|
||||
|
||||
reg tdma_enable_reg = 1'b0;
|
||||
wire tdma_locked;
|
||||
wire tdma_error;
|
||||
|
||||
reg [79:0] set_tdma_schedule_start_reg = 0;
|
||||
reg set_tdma_schedule_start_valid_reg = 0;
|
||||
reg [79:0] set_tdma_schedule_period_reg = 0;
|
||||
reg set_tdma_schedule_period_valid_reg = 0;
|
||||
reg [79:0] set_tdma_timeslot_period_reg = 0;
|
||||
reg set_tdma_timeslot_period_valid_reg = 0;
|
||||
reg [79:0] set_tdma_active_period_reg = 0;
|
||||
reg set_tdma_active_period_valid_reg = 0;
|
||||
|
||||
wire tdma_schedule_start;
|
||||
wire [INDEX_WIDTH-1:0] tdma_timeslot_index;
|
||||
wire tdma_timeslot_start;
|
||||
wire tdma_timeslot_end;
|
||||
wire tdma_timeslot_active;
|
||||
|
||||
assign axil_csr_awready = axil_csr_awready_reg;
|
||||
assign axil_csr_wready = axil_csr_wready_reg;
|
||||
assign axil_csr_bresp = 2'b00;
|
||||
assign axil_csr_bvalid = axil_csr_bvalid_reg;
|
||||
assign axil_csr_arready = axil_csr_arready_reg;
|
||||
assign axil_csr_rdata = axil_csr_rdata_reg;
|
||||
assign axil_csr_rresp = 2'b00;
|
||||
assign axil_csr_rvalid = axil_csr_rvalid_reg;
|
||||
|
||||
always @(posedge clk) begin
|
||||
axil_csr_awready_reg <= 1'b0;
|
||||
axil_csr_wready_reg <= 1'b0;
|
||||
axil_csr_bvalid_reg <= axil_csr_bvalid_reg && !axil_csr_bready;
|
||||
axil_csr_arready_reg <= 1'b0;
|
||||
axil_csr_rvalid_reg <= axil_csr_rvalid_reg && !axil_csr_rready;
|
||||
|
||||
set_tdma_schedule_start_valid_reg <= 1'b0;
|
||||
set_tdma_schedule_period_valid_reg <= 1'b0;
|
||||
set_tdma_timeslot_period_valid_reg <= 1'b0;
|
||||
set_tdma_active_period_valid_reg <= 1'b0;
|
||||
|
||||
if (axil_csr_awvalid && axil_csr_wvalid && !axil_csr_bvalid) begin
|
||||
// write operation
|
||||
axil_csr_awready_reg <= 1'b1;
|
||||
axil_csr_wready_reg <= 1'b1;
|
||||
axil_csr_bvalid_reg <= 1'b1;
|
||||
|
||||
case (axil_csr_awaddr & ({AXIL_ADDR_WIDTH{1'b1}} << 2))
|
||||
16'h0100: begin
|
||||
// TDMA control
|
||||
tdma_enable_reg <= axil_csr_wdata[0];
|
||||
end
|
||||
16'h0114: set_tdma_schedule_start_reg[29:0] <= axil_csr_wdata; // TDMA schedule start ns
|
||||
16'h0118: set_tdma_schedule_start_reg[63:32] <= axil_csr_wdata; // TDMA schedule start sec l
|
||||
16'h011C: begin
|
||||
// TDMA schedule start sec h
|
||||
set_tdma_schedule_start_reg[79:64] <= axil_csr_wdata;
|
||||
set_tdma_schedule_start_valid_reg <= 1'b1;
|
||||
end
|
||||
16'h0124: set_tdma_schedule_period_reg[29:0] <= axil_csr_wdata; // TDMA schedule period ns
|
||||
16'h0128: set_tdma_schedule_period_reg[63:32] <= axil_csr_wdata; // TDMA schedule period sec l
|
||||
16'h012C: begin
|
||||
// TDMA schedule period sec h
|
||||
set_tdma_schedule_period_reg[79:64] <= axil_csr_wdata;
|
||||
set_tdma_schedule_period_valid_reg <= 1'b1;
|
||||
end
|
||||
16'h0134: set_tdma_timeslot_period_reg[29:0] <= axil_csr_wdata; // TDMA timeslot period ns
|
||||
16'h0138: set_tdma_timeslot_period_reg[63:32] <= axil_csr_wdata; // TDMA timeslot period sec l
|
||||
16'h013C: begin
|
||||
// TDMA timeslot period sec h
|
||||
set_tdma_timeslot_period_reg[79:64] <= axil_csr_wdata;
|
||||
set_tdma_timeslot_period_valid_reg <= 1'b1;
|
||||
end
|
||||
16'h0144: set_tdma_active_period_reg[29:0] <= axil_csr_wdata; // TDMA active period ns
|
||||
16'h0148: set_tdma_active_period_reg[63:32] <= axil_csr_wdata; // TDMA active period sec l
|
||||
16'h014C: begin
|
||||
// TDMA active period sec h
|
||||
set_tdma_active_period_reg[79:64] <= axil_csr_wdata;
|
||||
set_tdma_active_period_valid_reg <= 1'b1;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
if (axil_csr_arvalid && !axil_csr_rvalid) begin
|
||||
// read operation
|
||||
axil_csr_arready_reg <= 1'b1;
|
||||
axil_csr_rvalid_reg <= 1'b1;
|
||||
axil_csr_rdata_reg <= {AXIL_DATA_WIDTH{1'b0}};
|
||||
|
||||
case (axil_csr_araddr & ({AXIL_ADDR_WIDTH{1'b1}} << 2))
|
||||
16'h0000: axil_csr_rdata_reg <= 0;
|
||||
16'h0010: axil_csr_rdata_reg <= COUNT;
|
||||
16'h0014: axil_csr_rdata_reg <= INDEX_WIDTH;
|
||||
16'h0018: axil_csr_rdata_reg <= SLICE_WIDTH;
|
||||
16'h0100: begin
|
||||
// TDMA control
|
||||
axil_csr_rdata_reg[0] <= tdma_enable_reg;
|
||||
end
|
||||
16'h0104: begin
|
||||
// TDMA status
|
||||
axil_csr_rdata_reg[0] <= tdma_locked;
|
||||
axil_csr_rdata_reg[1] <= tdma_error;
|
||||
end
|
||||
16'h0114: axil_csr_rdata_reg <= set_tdma_schedule_start_reg[29:0]; // TDMA schedule start ns
|
||||
16'h0118: axil_csr_rdata_reg <= set_tdma_schedule_start_reg[63:32]; // TDMA schedule start sec l
|
||||
16'h011C: axil_csr_rdata_reg <= set_tdma_schedule_start_reg[79:64]; // TDMA schedule start sec h
|
||||
16'h0124: axil_csr_rdata_reg <= set_tdma_schedule_period_reg[29:0]; // TDMA schedule period ns
|
||||
16'h0128: axil_csr_rdata_reg <= set_tdma_schedule_period_reg[63:32]; // TDMA schedule period sec l
|
||||
16'h012C: axil_csr_rdata_reg <= set_tdma_schedule_period_reg[79:64]; // TDMA schedule period sec h
|
||||
16'h0134: axil_csr_rdata_reg <= set_tdma_timeslot_period_reg[29:0]; // TDMA timeslot period ns
|
||||
16'h0138: axil_csr_rdata_reg <= set_tdma_timeslot_period_reg[63:32]; // TDMA timeslot period sec l
|
||||
16'h013C: axil_csr_rdata_reg <= set_tdma_timeslot_period_reg[79:64]; // TDMA timeslot period sec h
|
||||
16'h0144: axil_csr_rdata_reg <= set_tdma_active_period_reg[29:0]; // TDMA active period ns
|
||||
16'h0148: axil_csr_rdata_reg <= set_tdma_active_period_reg[63:32]; // TDMA active period sec l
|
||||
16'h014C: axil_csr_rdata_reg <= set_tdma_active_period_reg[79:64]; // TDMA active period sec h
|
||||
endcase
|
||||
end
|
||||
|
||||
if (rst) begin
|
||||
axil_csr_awready_reg <= 1'b0;
|
||||
axil_csr_wready_reg <= 1'b0;
|
||||
axil_csr_bvalid_reg <= 1'b0;
|
||||
axil_csr_arready_reg <= 1'b0;
|
||||
axil_csr_rvalid_reg <= 1'b0;
|
||||
|
||||
tdma_enable_reg <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
tdma_scheduler #(
|
||||
.INDEX_WIDTH(INDEX_WIDTH),
|
||||
.SCHEDULE_START_S(SCHEDULE_START_S),
|
||||
.SCHEDULE_START_NS(SCHEDULE_START_NS),
|
||||
.SCHEDULE_PERIOD_S(SCHEDULE_PERIOD_S),
|
||||
.SCHEDULE_PERIOD_NS(SCHEDULE_PERIOD_NS),
|
||||
.TIMESLOT_PERIOD_S(TIMESLOT_PERIOD_S),
|
||||
.TIMESLOT_PERIOD_NS(TIMESLOT_PERIOD_NS),
|
||||
.ACTIVE_PERIOD_S(ACTIVE_PERIOD_S),
|
||||
.ACTIVE_PERIOD_NS(ACTIVE_PERIOD_NS)
|
||||
)
|
||||
tdma_scheduler_inst (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
.input_ts_96(ptp_ts_96),
|
||||
.input_ts_step(ptp_ts_step),
|
||||
.enable(tdma_enable_reg),
|
||||
.input_schedule_start(set_tdma_schedule_start_reg),
|
||||
.input_schedule_start_valid(set_tdma_schedule_start_valid_reg),
|
||||
.input_schedule_period(set_tdma_schedule_period_reg),
|
||||
.input_schedule_period_valid(set_tdma_schedule_period_valid_reg),
|
||||
.input_timeslot_period(set_tdma_timeslot_period_reg),
|
||||
.input_timeslot_period_valid(set_tdma_timeslot_period_valid_reg),
|
||||
.input_active_period(set_tdma_active_period_reg),
|
||||
.input_active_period_valid(set_tdma_active_period_valid_reg),
|
||||
.locked(tdma_locked),
|
||||
.error(tdma_error),
|
||||
.schedule_start(tdma_schedule_start),
|
||||
.timeslot_index(tdma_timeslot_index),
|
||||
.timeslot_start(tdma_timeslot_start),
|
||||
.timeslot_end(tdma_timeslot_end),
|
||||
.timeslot_active(tdma_timeslot_active)
|
||||
);
|
||||
|
||||
wire [COUNT*AXIL_ADDR_WIDTH-1:0] axil_ch_awaddr;
|
||||
wire [COUNT*3-1:0] axil_ch_awprot;
|
||||
wire [COUNT-1:0] axil_ch_awvalid;
|
||||
wire [COUNT-1:0] axil_ch_awready;
|
||||
wire [COUNT*AXIL_DATA_WIDTH-1:0] axil_ch_wdata;
|
||||
wire [COUNT*AXIL_STRB_WIDTH-1:0] axil_ch_wstrb;
|
||||
wire [COUNT-1:0] axil_ch_wvalid;
|
||||
wire [COUNT-1:0] axil_ch_wready;
|
||||
wire [COUNT*2-1:0] axil_ch_bresp;
|
||||
wire [COUNT-1:0] axil_ch_bvalid;
|
||||
wire [COUNT-1:0] axil_ch_bready;
|
||||
wire [COUNT*AXIL_ADDR_WIDTH-1:0] axil_ch_araddr;
|
||||
wire [COUNT*3-1:0] axil_ch_arprot;
|
||||
wire [COUNT-1:0] axil_ch_arvalid;
|
||||
wire [COUNT-1:0] axil_ch_arready;
|
||||
wire [COUNT*AXIL_DATA_WIDTH-1:0] axil_ch_rdata;
|
||||
wire [COUNT*2-1:0] axil_ch_rresp;
|
||||
wire [COUNT-1:0] axil_ch_rvalid;
|
||||
wire [COUNT-1:0] axil_ch_rready;
|
||||
|
||||
parameter CH_ADDR_WIDTH = INDEX_WIDTH+4;
|
||||
parameter CH_BASE_ADDR_WIDTH = (COUNT+1)*AXIL_ADDR_WIDTH;
|
||||
parameter CH_BASE_ADDR = calcBaseAddrs(CH_ADDR_WIDTH);
|
||||
|
||||
function [CH_BASE_ADDR_WIDTH-1:0] calcBaseAddrs(input [31:0] width);
|
||||
integer i;
|
||||
begin
|
||||
calcBaseAddrs = {CH_BASE_ADDR_WIDTH{1'b0}};
|
||||
for (i = 0; i < COUNT+1; i = i + 1) begin
|
||||
calcBaseAddrs[i * AXIL_ADDR_WIDTH +: AXIL_ADDR_WIDTH] = i * (2**width);
|
||||
end
|
||||
end
|
||||
endfunction
|
||||
|
||||
function [31:0] w_32(input [31:0] val);
|
||||
w_32 = val;
|
||||
endfunction
|
||||
|
||||
axil_interconnect #(
|
||||
.DATA_WIDTH(AXIL_DATA_WIDTH),
|
||||
.ADDR_WIDTH(AXIL_ADDR_WIDTH),
|
||||
.S_COUNT(1),
|
||||
.M_COUNT(COUNT+1),
|
||||
.M_BASE_ADDR(CH_BASE_ADDR),
|
||||
.M_ADDR_WIDTH({COUNT+1{w_32(CH_ADDR_WIDTH)}}),
|
||||
.M_CONNECT_READ({COUNT+1{1'b1}}),
|
||||
.M_CONNECT_WRITE({COUNT+1{1'b1}})
|
||||
)
|
||||
axil_csr_interconnect_inst (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
.s_axil_awaddr(s_axil_awaddr),
|
||||
.s_axil_awprot(s_axil_awprot),
|
||||
.s_axil_awvalid(s_axil_awvalid),
|
||||
.s_axil_awready(s_axil_awready),
|
||||
.s_axil_wdata(s_axil_wdata),
|
||||
.s_axil_wstrb(s_axil_wstrb),
|
||||
.s_axil_wvalid(s_axil_wvalid),
|
||||
.s_axil_wready(s_axil_wready),
|
||||
.s_axil_bresp(s_axil_bresp),
|
||||
.s_axil_bvalid(s_axil_bvalid),
|
||||
.s_axil_bready(s_axil_bready),
|
||||
.s_axil_araddr(s_axil_araddr),
|
||||
.s_axil_arprot(s_axil_arprot),
|
||||
.s_axil_arvalid(s_axil_arvalid),
|
||||
.s_axil_arready(s_axil_arready),
|
||||
.s_axil_rdata(s_axil_rdata),
|
||||
.s_axil_rresp(s_axil_rresp),
|
||||
.s_axil_rvalid(s_axil_rvalid),
|
||||
.s_axil_rready(s_axil_rready),
|
||||
.m_axil_awaddr( {axil_ch_awaddr, axil_csr_awaddr}),
|
||||
.m_axil_awprot( {axil_ch_awprot, axil_csr_awprot}),
|
||||
.m_axil_awvalid( {axil_ch_awvalid, axil_csr_awvalid}),
|
||||
.m_axil_awready( {axil_ch_awready, axil_csr_awready}),
|
||||
.m_axil_wdata( {axil_ch_wdata, axil_csr_wdata}),
|
||||
.m_axil_wstrb( {axil_ch_wstrb, axil_csr_wstrb}),
|
||||
.m_axil_wvalid( {axil_ch_wvalid, axil_csr_wvalid}),
|
||||
.m_axil_wready( {axil_ch_wready, axil_csr_wready}),
|
||||
.m_axil_bresp( {axil_ch_bresp, axil_csr_bresp}),
|
||||
.m_axil_bvalid( {axil_ch_bvalid, axil_csr_bvalid}),
|
||||
.m_axil_bready( {axil_ch_bready, axil_csr_bready}),
|
||||
.m_axil_araddr( {axil_ch_araddr, axil_csr_araddr}),
|
||||
.m_axil_arprot( {axil_ch_arprot, axil_csr_arprot}),
|
||||
.m_axil_arvalid( {axil_ch_arvalid, axil_csr_arvalid}),
|
||||
.m_axil_arready( {axil_ch_arready, axil_csr_arready}),
|
||||
.m_axil_rdata( {axil_ch_rdata, axil_csr_rdata}),
|
||||
.m_axil_rresp( {axil_ch_rresp, axil_csr_rresp}),
|
||||
.m_axil_rvalid( {axil_ch_rvalid, axil_csr_rvalid}),
|
||||
.m_axil_rready( {axil_ch_rready, axil_csr_rready})
|
||||
);
|
||||
|
||||
generate
|
||||
genvar n;
|
||||
|
||||
for (n = 0; n < COUNT; n = n + 1) begin
|
||||
|
||||
tdma_ber_ch #(
|
||||
.INDEX_WIDTH(INDEX_WIDTH),
|
||||
.SLICE_WIDTH(SLICE_WIDTH),
|
||||
.AXIL_DATA_WIDTH(AXIL_DATA_WIDTH),
|
||||
.AXIL_ADDR_WIDTH(CH_ADDR_WIDTH),
|
||||
.AXIL_STRB_WIDTH(AXIL_STRB_WIDTH)
|
||||
)
|
||||
tdma_ber_ch_inst (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
.phy_tx_clk(phy_tx_clk[n]),
|
||||
.phy_rx_clk(phy_rx_clk[n]),
|
||||
.phy_rx_error_count(phy_rx_error_count[n*7 +: 7]),
|
||||
.phy_tx_prbs31_enable(phy_tx_prbs31_enable[n]),
|
||||
.phy_rx_prbs31_enable(phy_rx_prbs31_enable[n]),
|
||||
.s_axil_awaddr(axil_ch_awaddr[n*AXIL_ADDR_WIDTH +: AXIL_ADDR_WIDTH]),
|
||||
.s_axil_awprot(axil_ch_awprot[n*3 +: 3]),
|
||||
.s_axil_awvalid(axil_ch_awvalid[n]),
|
||||
.s_axil_awready(axil_ch_awready[n]),
|
||||
.s_axil_wdata(axil_ch_wdata[n*AXIL_DATA_WIDTH +: AXIL_DATA_WIDTH]),
|
||||
.s_axil_wstrb(axil_ch_wstrb[n*AXIL_STRB_WIDTH +: AXIL_STRB_WIDTH]),
|
||||
.s_axil_wvalid(axil_ch_wvalid[n]),
|
||||
.s_axil_wready(axil_ch_wready[n]),
|
||||
.s_axil_bresp(axil_ch_bresp[n*2 +: 2]),
|
||||
.s_axil_bvalid(axil_ch_bvalid[n]),
|
||||
.s_axil_bready(axil_ch_bready[n]),
|
||||
.s_axil_araddr(axil_ch_araddr[n*AXIL_ADDR_WIDTH +: AXIL_ADDR_WIDTH]),
|
||||
.s_axil_arprot(axil_ch_arprot[n*3 +: 3]),
|
||||
.s_axil_arvalid(axil_ch_arvalid[n]),
|
||||
.s_axil_arready(axil_ch_arready[n]),
|
||||
.s_axil_rdata(axil_ch_rdata[n*AXIL_DATA_WIDTH +: AXIL_DATA_WIDTH]),
|
||||
.s_axil_rresp(axil_ch_rresp[n*2 +: 2]),
|
||||
.s_axil_rvalid(axil_ch_rvalid[n]),
|
||||
.s_axil_rready(axil_ch_rready[n]),
|
||||
.tdma_timeslot_index(tdma_timeslot_index),
|
||||
.tdma_timeslot_start(tdma_timeslot_start),
|
||||
.tdma_timeslot_active(tdma_timeslot_active)
|
||||
);
|
||||
|
||||
end
|
||||
endgenerate
|
||||
|
||||
endmodule
|
585
fpga/common/rtl/tdma_ber_ch.v
Normal file
585
fpga/common/rtl/tdma_ber_ch.v
Normal file
@ -0,0 +1,585 @@
|
||||
/*
|
||||
|
||||
Copyright 2019, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
/*
|
||||
* TDMA BER module
|
||||
*/
|
||||
module tdma_ber_ch #
|
||||
(
|
||||
parameter INDEX_WIDTH = 6,
|
||||
parameter SLICE_WIDTH = 5,
|
||||
parameter AXIL_DATA_WIDTH = 32,
|
||||
parameter AXIL_ADDR_WIDTH = INDEX_WIDTH+4,
|
||||
parameter AXIL_STRB_WIDTH = (AXIL_DATA_WIDTH/8)
|
||||
)
|
||||
(
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
|
||||
/*
|
||||
* PHY connections
|
||||
*/
|
||||
input wire phy_tx_clk,
|
||||
input wire phy_rx_clk,
|
||||
input wire [6:0] phy_rx_error_count,
|
||||
output wire phy_tx_prbs31_enable,
|
||||
output wire phy_rx_prbs31_enable,
|
||||
|
||||
/*
|
||||
* AXI-Lite slave interface
|
||||
*/
|
||||
input wire [AXIL_ADDR_WIDTH-1:0] s_axil_awaddr,
|
||||
input wire [2:0] s_axil_awprot,
|
||||
input wire s_axil_awvalid,
|
||||
output wire s_axil_awready,
|
||||
input wire [AXIL_DATA_WIDTH-1:0] s_axil_wdata,
|
||||
input wire [AXIL_STRB_WIDTH-1:0] s_axil_wstrb,
|
||||
input wire s_axil_wvalid,
|
||||
output wire s_axil_wready,
|
||||
output wire [1:0] s_axil_bresp,
|
||||
output wire s_axil_bvalid,
|
||||
input wire s_axil_bready,
|
||||
input wire [AXIL_ADDR_WIDTH-1:0] s_axil_araddr,
|
||||
input wire [2:0] s_axil_arprot,
|
||||
input wire s_axil_arvalid,
|
||||
output wire s_axil_arready,
|
||||
output wire [AXIL_DATA_WIDTH-1:0] s_axil_rdata,
|
||||
output wire [1:0] s_axil_rresp,
|
||||
output wire s_axil_rvalid,
|
||||
input wire s_axil_rready,
|
||||
|
||||
/*
|
||||
* TDMA schedule
|
||||
*/
|
||||
input wire [INDEX_WIDTH-1:0] tdma_timeslot_index,
|
||||
input wire tdma_timeslot_start,
|
||||
input wire tdma_timeslot_active
|
||||
);
|
||||
|
||||
parameter VALID_ADDR_WIDTH = AXIL_ADDR_WIDTH - $clog2(AXIL_STRB_WIDTH);
|
||||
parameter WORD_WIDTH = AXIL_STRB_WIDTH;
|
||||
parameter WORD_SIZE = AXIL_DATA_WIDTH/WORD_WIDTH;
|
||||
|
||||
// check configuration
|
||||
initial begin
|
||||
if (AXIL_ADDR_WIDTH < INDEX_WIDTH+4) begin
|
||||
$error("Error: AXI address width too narrow");
|
||||
$finish;
|
||||
end
|
||||
|
||||
if (AXIL_DATA_WIDTH != 32) begin
|
||||
$error("Error: AXI data width must be 32");
|
||||
$finish;
|
||||
end
|
||||
|
||||
if (AXIL_STRB_WIDTH * 8 != AXIL_DATA_WIDTH) begin
|
||||
$error("Error: Interface requires byte (8-bit) granularity");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
reg tx_prbs31_enable_reg = 1'b0, tx_prbs31_enable_next;
|
||||
reg rx_prbs31_enable_reg = 1'b0, rx_prbs31_enable_next;
|
||||
|
||||
// PHY TX BER interface
|
||||
reg phy_tx_prbs31_enable_reg = 1'b0;
|
||||
|
||||
always @(posedge phy_tx_clk) begin
|
||||
phy_tx_prbs31_enable_reg <= tx_prbs31_enable_reg;
|
||||
end
|
||||
|
||||
assign phy_tx_prbs31_enable = phy_tx_prbs31_enable_reg;
|
||||
|
||||
// PHY RX BER interface
|
||||
reg phy_rx_prbs31_enable_reg = 1'b0;
|
||||
|
||||
// accumulate errors, dump every 16 cycles
|
||||
reg [10:0] phy_rx_error_count_reg = 0;
|
||||
reg [10:0] phy_rx_error_count_acc_reg = 0;
|
||||
reg [3:0] phy_rx_count_reg = 4'd0;
|
||||
reg phy_rx_flag_reg = 1'b0;
|
||||
|
||||
always @(posedge phy_rx_clk) begin
|
||||
phy_rx_prbs31_enable_reg <= rx_prbs31_enable_reg;
|
||||
|
||||
phy_rx_count_reg <= phy_rx_count_reg + 1;
|
||||
|
||||
if (phy_rx_count_reg == 0) begin
|
||||
phy_rx_error_count_reg <= phy_rx_error_count_acc_reg;
|
||||
phy_rx_error_count_acc_reg <= phy_rx_error_count;
|
||||
phy_rx_flag_reg <= !phy_rx_flag_reg;
|
||||
end else begin
|
||||
phy_rx_error_count_acc_reg <= phy_rx_error_count_acc_reg + phy_rx_error_count;
|
||||
end
|
||||
end
|
||||
|
||||
assign phy_rx_prbs31_enable = phy_rx_prbs31_enable_reg;
|
||||
|
||||
// synchronize dumped counts to control clock domain
|
||||
reg rx_flag_sync_reg_1 = 1'b0;
|
||||
reg rx_flag_sync_reg_2 = 1'b0;
|
||||
reg rx_flag_sync_reg_3 = 1'b0;
|
||||
|
||||
always @(posedge clk) begin
|
||||
rx_flag_sync_reg_1 <= phy_rx_flag_reg;
|
||||
rx_flag_sync_reg_2 <= rx_flag_sync_reg_1;
|
||||
rx_flag_sync_reg_3 <= rx_flag_sync_reg_2;
|
||||
end
|
||||
|
||||
reg [31:0] cycle_count_reg = 32'd0, cycle_count_next;
|
||||
reg [31:0] update_count_reg = 32'd0, update_count_next;
|
||||
reg [31:0] rx_error_count_reg = 32'd0, rx_error_count_next;
|
||||
|
||||
reg [31:0] atomic_cycle_count_reg = 32'd0, atomic_cycle_count_next;
|
||||
reg [31:0] atomic_update_count_reg = 32'd0, atomic_update_count_next;
|
||||
reg [31:0] atomic_rx_error_count_reg = 32'd0, atomic_rx_error_count_next;
|
||||
|
||||
reg accumulate_enable_reg = 1'b0, accumulate_enable_next;
|
||||
reg slice_enable_reg = 1'b0, slice_enable_next;
|
||||
|
||||
reg [31:0] slice_time_reg = 0, slice_time_next;
|
||||
reg [31:0] slice_offset_reg = 0, slice_offset_next;
|
||||
|
||||
reg [SLICE_WIDTH-1:0] slice_select_reg = 0, slice_select_next;
|
||||
|
||||
reg error_count_mem_read_reg = 0;
|
||||
reg [31:0] error_count_mem_read_data_reg = 0;
|
||||
reg update_count_mem_read_reg = 0;
|
||||
reg [31:0] update_count_mem_read_data_reg = 0;
|
||||
|
||||
reg [31:0] error_count_mem[(2**(INDEX_WIDTH+SLICE_WIDTH))-1:0];
|
||||
reg [31:0] update_count_mem[(2**(INDEX_WIDTH+SLICE_WIDTH))-1:0];
|
||||
|
||||
integer i;
|
||||
|
||||
initial begin
|
||||
for (i = 0; i < 2**(INDEX_WIDTH+SLICE_WIDTH); i = i + 1) begin
|
||||
error_count_mem[i] = 0;
|
||||
update_count_mem[i] = 0;
|
||||
end
|
||||
end
|
||||
|
||||
reg [10:0] phy_rx_error_count_sync_reg = 0;
|
||||
reg phy_rx_error_count_sync_valid_reg = 1'b0;
|
||||
|
||||
always @(posedge clk) begin
|
||||
phy_rx_error_count_sync_valid_reg <= 1'b0;
|
||||
if (rx_flag_sync_reg_2 ^ rx_flag_sync_reg_3) begin
|
||||
phy_rx_error_count_sync_reg <= phy_rx_error_count_reg;
|
||||
phy_rx_error_count_sync_valid_reg <= 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
reg slice_running_reg = 1'b0;
|
||||
reg slice_active_reg = 1'b0;
|
||||
reg [31:0] slice_count_reg = 0;
|
||||
reg [SLICE_WIDTH-1:0] cur_slice_reg = 0;
|
||||
|
||||
reg [1:0] accumulate_state_reg = 0;
|
||||
reg [31:0] rx_ts_update_count_read_reg = 0;
|
||||
reg [31:0] rx_ts_error_count_read_reg = 0;
|
||||
reg [31:0] rx_ts_update_count_reg = 0;
|
||||
reg [31:0] rx_ts_error_count_reg = 0;
|
||||
reg [INDEX_WIDTH+SLICE_WIDTH-1:0] index_reg = 0;
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (tdma_timeslot_start) begin
|
||||
slice_running_reg <= 1'b1;
|
||||
if (slice_offset_reg) begin
|
||||
slice_active_reg <= 1'b0;
|
||||
slice_count_reg <= slice_offset_reg;
|
||||
end else begin
|
||||
slice_active_reg <= 1'b1;
|
||||
slice_count_reg <= slice_time_reg;
|
||||
end
|
||||
cur_slice_reg <= 0;
|
||||
end else if (slice_count_reg > 0) begin
|
||||
slice_count_reg <= slice_count_reg - 1;
|
||||
end else begin
|
||||
slice_count_reg <= slice_time_reg;
|
||||
slice_active_reg <= slice_running_reg;
|
||||
if (slice_active_reg && slice_running_reg) begin
|
||||
cur_slice_reg <= cur_slice_reg + 1;
|
||||
slice_running_reg <= cur_slice_reg < {SLICE_WIDTH{1'b1}};
|
||||
slice_active_reg <= cur_slice_reg < {SLICE_WIDTH{1'b1}};
|
||||
end
|
||||
end
|
||||
|
||||
case (accumulate_state_reg)
|
||||
2'd0: begin
|
||||
if (accumulate_enable_reg && tdma_timeslot_active && phy_rx_error_count_sync_valid_reg) begin
|
||||
if (slice_enable_reg) begin
|
||||
index_reg <= (tdma_timeslot_index << SLICE_WIDTH) + cur_slice_reg;
|
||||
if (slice_active_reg) begin
|
||||
accumulate_state_reg <= 2'd1;
|
||||
end
|
||||
end else begin
|
||||
index_reg <= (tdma_timeslot_index << SLICE_WIDTH);
|
||||
accumulate_state_reg <= 2'd1;
|
||||
end
|
||||
end
|
||||
end
|
||||
2'd1: begin
|
||||
rx_ts_update_count_read_reg <= update_count_mem[index_reg];
|
||||
rx_ts_error_count_read_reg <= error_count_mem[index_reg];
|
||||
|
||||
accumulate_state_reg <= 2'd2;
|
||||
end
|
||||
2'd2: begin
|
||||
rx_ts_error_count_reg <= rx_ts_error_count_read_reg + phy_rx_error_count_sync_reg;
|
||||
rx_ts_update_count_reg <= rx_ts_update_count_read_reg + 1;
|
||||
|
||||
// if ((rx_ts_error_count_reg + inc_reg) >> 32) begin
|
||||
// rx_ts_error_count_reg <= 32'hffffffff;
|
||||
// end else begin
|
||||
// rx_ts_error_count_reg <= rx_ts_error_count_reg + inc_reg;
|
||||
// end
|
||||
|
||||
// if ((rx_ts_update_count_reg + 1) >> 32) begin
|
||||
// rx_ts_update_count_reg <= 32'hffffffff;
|
||||
// end else begin
|
||||
// rx_ts_update_count_reg <= rx_ts_update_count_reg + 1;
|
||||
// end
|
||||
|
||||
accumulate_state_reg <= 2'd3;
|
||||
end
|
||||
2'd3: begin
|
||||
update_count_mem[index_reg] <= rx_ts_update_count_reg;
|
||||
error_count_mem[index_reg] <= rx_ts_error_count_reg;
|
||||
|
||||
accumulate_state_reg <= 2'd0;
|
||||
end
|
||||
default: begin
|
||||
accumulate_state_reg <= 2'd0;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
// control registers
|
||||
reg read_eligible;
|
||||
reg write_eligible;
|
||||
|
||||
reg mem_wr_en;
|
||||
reg mem_rd_en;
|
||||
|
||||
reg last_read_reg = 1'b0, last_read_next;
|
||||
|
||||
reg s_axil_awready_reg = 1'b0, s_axil_awready_next;
|
||||
reg s_axil_wready_reg = 1'b0, s_axil_wready_next;
|
||||
reg s_axil_bvalid_reg = 1'b0, s_axil_bvalid_next;
|
||||
reg s_axil_arready_reg = 1'b0, s_axil_arready_next;
|
||||
reg [AXIL_DATA_WIDTH-1:0] s_axil_rdata_reg = {AXIL_DATA_WIDTH{1'b0}}, s_axil_rdata_next;
|
||||
reg s_axil_rvalid_reg = 1'b0, s_axil_rvalid_next;
|
||||
|
||||
assign s_axil_awready = s_axil_awready_reg;
|
||||
assign s_axil_wready = s_axil_wready_reg;
|
||||
assign s_axil_bresp = 2'b00;
|
||||
assign s_axil_bvalid = s_axil_bvalid_reg;
|
||||
assign s_axil_arready = s_axil_arready_reg;
|
||||
assign s_axil_rdata = error_count_mem_read_reg ? error_count_mem_read_data_reg : (update_count_mem_read_reg ? update_count_mem_read_data_reg : s_axil_rdata_reg);
|
||||
assign s_axil_rresp = 2'b00;
|
||||
assign s_axil_rvalid = s_axil_rvalid_reg;
|
||||
|
||||
wire [INDEX_WIDTH+SLICE_WIDTH-1:0] axil_ram_addr = ((mem_rd_en ? s_axil_araddr[INDEX_WIDTH+1+2-1:1+2] : s_axil_awaddr[INDEX_WIDTH+1+2-1:1+2]) << SLICE_WIDTH) | slice_select_reg;
|
||||
|
||||
always @* begin
|
||||
mem_wr_en = 1'b0;
|
||||
mem_rd_en = 1'b0;
|
||||
|
||||
last_read_next = last_read_reg;
|
||||
|
||||
s_axil_awready_next = 1'b0;
|
||||
s_axil_wready_next = 1'b0;
|
||||
s_axil_bvalid_next = s_axil_bvalid_reg && !s_axil_bready;
|
||||
|
||||
s_axil_arready_next = 1'b0;
|
||||
s_axil_rdata_next = s_axil_rdata_reg;
|
||||
s_axil_rvalid_next = s_axil_rvalid_reg && !s_axil_rready;
|
||||
|
||||
cycle_count_next = cycle_count_reg + 1;
|
||||
|
||||
update_count_next = update_count_reg;
|
||||
rx_error_count_next = rx_error_count_reg;
|
||||
if (phy_rx_error_count_sync_valid_reg) begin
|
||||
update_count_next = update_count_reg + 1;
|
||||
rx_error_count_next = phy_rx_error_count_sync_reg + rx_error_count_reg;
|
||||
end
|
||||
|
||||
atomic_cycle_count_next = atomic_cycle_count_reg + 1;
|
||||
if (atomic_cycle_count_reg[31] && ~atomic_cycle_count_next[31]) begin
|
||||
atomic_cycle_count_next = 32'hffffffff;
|
||||
end
|
||||
|
||||
atomic_update_count_next = atomic_update_count_reg;
|
||||
atomic_rx_error_count_next = atomic_rx_error_count_reg;
|
||||
if (phy_rx_error_count_sync_valid_reg) begin
|
||||
atomic_update_count_next = atomic_update_count_reg + 1;
|
||||
atomic_rx_error_count_next = phy_rx_error_count_sync_reg + atomic_rx_error_count_reg;
|
||||
|
||||
// saturate
|
||||
if (atomic_update_count_reg[31] && ~atomic_update_count_next[31]) begin
|
||||
atomic_update_count_next = 32'hffffffff;
|
||||
end
|
||||
if (atomic_rx_error_count_reg[31] && ~atomic_rx_error_count_next[31]) begin
|
||||
atomic_rx_error_count_next = 32'hffffffff;
|
||||
end
|
||||
end
|
||||
|
||||
accumulate_enable_next = accumulate_enable_reg;
|
||||
slice_enable_next = slice_enable_reg;
|
||||
|
||||
slice_time_next = slice_time_reg;
|
||||
slice_offset_next = slice_offset_reg;
|
||||
|
||||
slice_select_next = slice_select_reg;
|
||||
|
||||
tx_prbs31_enable_next = tx_prbs31_enable_reg;
|
||||
rx_prbs31_enable_next = rx_prbs31_enable_reg;
|
||||
|
||||
write_eligible = s_axil_awvalid && s_axil_wvalid && (!s_axil_bvalid || s_axil_bready) && (!s_axil_awready && !s_axil_wready);
|
||||
read_eligible = s_axil_arvalid && (!s_axil_rvalid || s_axil_rready) && (!s_axil_arready);
|
||||
|
||||
if (write_eligible && (!read_eligible || last_read_reg)) begin
|
||||
last_read_next = 1'b0;
|
||||
|
||||
s_axil_awready_next = 1'b1;
|
||||
s_axil_wready_next = 1'b1;
|
||||
s_axil_bvalid_next = 1'b1;
|
||||
|
||||
if (s_axil_awaddr[INDEX_WIDTH+2+1+1-1]) begin
|
||||
mem_wr_en = 1'b1;
|
||||
end else begin
|
||||
case (s_axil_awaddr & ({AXIL_ADDR_WIDTH{1'b1}} << 2))
|
||||
16'h0000: begin
|
||||
// control
|
||||
tx_prbs31_enable_next = s_axil_wdata[0];
|
||||
rx_prbs31_enable_next = s_axil_wdata[1];
|
||||
end
|
||||
16'h0004: begin
|
||||
// cycle count
|
||||
cycle_count_next = 1;
|
||||
end
|
||||
16'h0008: begin
|
||||
// update count
|
||||
update_count_next = 0;
|
||||
end
|
||||
16'h000C: begin
|
||||
// error count
|
||||
rx_error_count_next = 0;
|
||||
end
|
||||
16'h0014: begin
|
||||
// cycle count
|
||||
atomic_cycle_count_next = 1;
|
||||
end
|
||||
16'h0018: begin
|
||||
// update count
|
||||
atomic_update_count_next = 0;
|
||||
end
|
||||
16'h001C: begin
|
||||
// error count
|
||||
atomic_rx_error_count_next = 0;
|
||||
end
|
||||
16'h0020: begin
|
||||
// control
|
||||
accumulate_enable_next = s_axil_wdata[0];
|
||||
slice_enable_next = s_axil_wdata[1];
|
||||
end
|
||||
16'h0024: begin
|
||||
// slice time
|
||||
slice_time_next = s_axil_wdata;
|
||||
end
|
||||
16'h0028: begin
|
||||
// slice offset
|
||||
slice_offset_next = s_axil_wdata;
|
||||
end
|
||||
16'h0030: begin
|
||||
// slice select
|
||||
slice_select_next = s_axil_wdata;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end else if (read_eligible) begin
|
||||
last_read_next = 1'b1;
|
||||
|
||||
s_axil_arready_next = 1'b1;
|
||||
s_axil_rvalid_next = 1'b1;
|
||||
s_axil_rdata_next = {AXIL_DATA_WIDTH{1'b0}};
|
||||
|
||||
if (s_axil_araddr[INDEX_WIDTH+2+1+1-1]) begin
|
||||
mem_rd_en = 1'b1;
|
||||
end else begin
|
||||
case (s_axil_araddr & ({AXIL_ADDR_WIDTH{1'b1}} << 2))
|
||||
16'h0000: begin
|
||||
// control
|
||||
s_axil_rdata_next[0] = tx_prbs31_enable_reg;
|
||||
s_axil_rdata_next[1] = rx_prbs31_enable_reg;
|
||||
end
|
||||
16'h0004: begin
|
||||
// cycle count
|
||||
s_axil_rdata_next = cycle_count_reg;
|
||||
end
|
||||
16'h0008: begin
|
||||
// update count
|
||||
s_axil_rdata_next = update_count_reg;
|
||||
end
|
||||
16'h000C: begin
|
||||
// error count
|
||||
s_axil_rdata_next = rx_error_count_reg;
|
||||
end
|
||||
16'h0014: begin
|
||||
// cycle count
|
||||
s_axil_rdata_next = atomic_cycle_count_reg;
|
||||
atomic_cycle_count_next = 1;
|
||||
end
|
||||
16'h0018: begin
|
||||
// update count
|
||||
s_axil_rdata_next = atomic_update_count_reg;
|
||||
atomic_update_count_next = 0;
|
||||
end
|
||||
16'h001C: begin
|
||||
// error count
|
||||
s_axil_rdata_next = atomic_rx_error_count_reg;
|
||||
atomic_rx_error_count_next = 0;
|
||||
end
|
||||
16'h0020: begin
|
||||
// control
|
||||
s_axil_rdata_next[0] = accumulate_enable_reg;
|
||||
s_axil_rdata_next[1] = slice_enable_reg;
|
||||
end
|
||||
16'h0024: begin
|
||||
// slice time
|
||||
s_axil_rdata_next = slice_time_reg;
|
||||
end
|
||||
16'h0028: begin
|
||||
// slice offset
|
||||
s_axil_rdata_next = slice_offset_reg;
|
||||
end
|
||||
16'h0030: begin
|
||||
// slice select
|
||||
s_axil_rdata_next = slice_select_reg;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (rst) begin
|
||||
last_read_reg <= 1'b0;
|
||||
|
||||
s_axil_awready_reg <= 1'b0;
|
||||
s_axil_wready_reg <= 1'b0;
|
||||
s_axil_bvalid_reg <= 1'b0;
|
||||
|
||||
s_axil_arready_reg <= 1'b0;
|
||||
s_axil_rvalid_reg <= 1'b0;
|
||||
|
||||
cycle_count_reg <= 32'd0;
|
||||
update_count_reg <= 32'd0;
|
||||
rx_error_count_reg <= 32'd0;
|
||||
|
||||
atomic_cycle_count_reg <= 32'd0;
|
||||
atomic_update_count_reg <= 32'd0;
|
||||
atomic_rx_error_count_reg <= 32'd0;
|
||||
|
||||
accumulate_enable_reg <= 1'b0;
|
||||
slice_enable_reg <= 1'b0;
|
||||
|
||||
slice_time_reg <= 32'd0;
|
||||
slice_offset_reg <= 32'd0;
|
||||
|
||||
slice_select_reg <= 0;
|
||||
|
||||
tx_prbs31_enable_reg <= 1'b0;
|
||||
rx_prbs31_enable_reg <= 1'b0;
|
||||
end else begin
|
||||
last_read_reg <= last_read_next;
|
||||
|
||||
s_axil_awready_reg <= s_axil_awready_next;
|
||||
s_axil_wready_reg <= s_axil_wready_next;
|
||||
s_axil_bvalid_reg <= s_axil_bvalid_next;
|
||||
|
||||
s_axil_arready_reg <= s_axil_arready_next;
|
||||
s_axil_rvalid_reg <= s_axil_rvalid_next;
|
||||
|
||||
cycle_count_reg <= cycle_count_next;
|
||||
update_count_reg <= update_count_next;
|
||||
rx_error_count_reg <= rx_error_count_next;
|
||||
|
||||
atomic_cycle_count_reg <= atomic_cycle_count_next;
|
||||
atomic_update_count_reg <= atomic_update_count_next;
|
||||
atomic_rx_error_count_reg <= atomic_rx_error_count_next;
|
||||
|
||||
accumulate_enable_reg <= accumulate_enable_next;
|
||||
slice_enable_reg <= slice_enable_next;
|
||||
|
||||
slice_time_reg <= slice_time_next;
|
||||
slice_offset_reg <= slice_offset_next;
|
||||
|
||||
slice_select_reg <= slice_select_next;
|
||||
|
||||
tx_prbs31_enable_reg <= tx_prbs31_enable_next;
|
||||
rx_prbs31_enable_reg <= rx_prbs31_enable_next;
|
||||
end
|
||||
|
||||
s_axil_rdata_reg <= s_axil_rdata_next;
|
||||
|
||||
error_count_mem_read_reg <= 1'b0;
|
||||
update_count_mem_read_reg <= 1'b0;
|
||||
|
||||
if (mem_rd_en) begin
|
||||
if (s_axil_araddr[2]) begin
|
||||
error_count_mem_read_data_reg <= error_count_mem[axil_ram_addr];
|
||||
error_count_mem_read_reg <= 1'b1;
|
||||
end else begin
|
||||
update_count_mem_read_data_reg <= update_count_mem[axil_ram_addr];
|
||||
update_count_mem_read_reg <= 1'b1;
|
||||
end
|
||||
end else begin
|
||||
for (i = 0; i < WORD_WIDTH; i = i + 1) begin
|
||||
if (mem_wr_en && s_axil_wstrb[i]) begin
|
||||
if (s_axil_awaddr[2]) begin
|
||||
error_count_mem[axil_ram_addr][WORD_SIZE*i +: WORD_SIZE] <= s_axil_wdata[WORD_SIZE*i +: WORD_SIZE];
|
||||
end else begin
|
||||
update_count_mem[axil_ram_addr][WORD_SIZE*i +: WORD_SIZE] <= s_axil_wdata[WORD_SIZE*i +: WORD_SIZE];
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
59
fpga/common/syn/tdma_ber_ch.tcl
Normal file
59
fpga/common/syn/tdma_ber_ch.tcl
Normal file
@ -0,0 +1,59 @@
|
||||
# Copyright 2019, The Regents of the University of California.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
# OF SUCH DAMAGE.
|
||||
#
|
||||
# The views and conclusions contained in the software and documentation are those
|
||||
# of the authors and should not be interpreted as representing official policies,
|
||||
# either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
# TDMA BER channel module
|
||||
|
||||
foreach inst [get_cells -hier -filter {(ORIG_REF_NAME == tdma_ber_ch || REF_NAME == tdma_ber_ch)}] {
|
||||
puts "Inserting timing constraints for tdma_ber_ch instance $inst"
|
||||
|
||||
# get clock periods
|
||||
set clk [get_clocks -of_objects [get_pins $inst/tx_prbs31_enable_reg_reg/C]]
|
||||
set tx_clk [get_clocks -of_objects [get_pins $inst/phy_tx_prbs31_enable_reg_reg/C]]
|
||||
set rx_clk [get_clocks -of_objects [get_pins $inst/phy_rx_prbs31_enable_reg_reg/C]]
|
||||
|
||||
set clk_period [get_property -min PERIOD $clk]
|
||||
set tx_clk_period [get_property -min PERIOD $tx_clk]
|
||||
set rx_clk_period [get_property -min PERIOD $rx_clk]
|
||||
|
||||
set min_clk_period [expr $tx_clk_period < $write_clk_period ? $tx_clk_period : $write_clk_period]
|
||||
|
||||
# control synchronization
|
||||
set_property ASYNC_REG TRUE [get_cells -hier -regexp ".*/phy_(rx|tx)_prbs31_enable_reg_reg" -filter "PARENT == $inst"]
|
||||
|
||||
set_max_delay -from [get_cells "$inst/tx_prbs31_enable_reg_reg"] -to [get_cells "$inst/phy_tx_prbs31_enable_reg_reg"] -datapath_only $clk_period
|
||||
set_max_delay -from [get_cells "$inst/rx_prbs31_enable_reg_reg"] -to [get_cells "$inst/phy_rx_prbs31_enable_reg_reg"] -datapath_only $clk_period
|
||||
|
||||
# data synchronization
|
||||
set_property ASYNC_REG TRUE [get_cells -hier -regexp ".*/rx_flag_sync_reg_\[123\]_reg" -filter "PARENT == $inst"]
|
||||
|
||||
set_max_delay -from [get_cells "$inst/phy_rx_flag_reg_reg"] -to [get_cells $inst/rx_flag_sync_reg_1_reg] -datapath_only $rx_clk_period
|
||||
|
||||
set_max_delay -from [get_cells "$inst/phy_rx_error_count_reg_reg[*]"] -to [get_cells $inst/phy_rx_error_count_sync_reg_reg[*]] -datapath_only $rx_clk_period
|
||||
set_bus_skew -from [get_cells "$inst/phy_rx_error_count_reg_reg[*]"] -to [get_cells $inst/phy_rx_error_count_sync_reg_reg[*]] $clk_period
|
||||
}
|
233
fpga/common/tb/test_tdma_ber.py
Executable file
233
fpga/common/tb/test_tdma_ber.py
Executable file
@ -0,0 +1,233 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
|
||||
Copyright 2019, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
"""
|
||||
|
||||
from myhdl import *
|
||||
import os
|
||||
import struct
|
||||
|
||||
import axil
|
||||
import ptp
|
||||
|
||||
module = 'tdma_ber'
|
||||
testbench = 'test_%s' % module
|
||||
|
||||
srcs = []
|
||||
|
||||
srcs.append("../rtl/%s.v" % module)
|
||||
srcs.append("../rtl/tdma_ber_ch.v")
|
||||
srcs.append("../rtl/tdma_scheduler.v")
|
||||
srcs.append("../lib/axi/rtl/axil_interconnect.v")
|
||||
srcs.append("../lib/axi/rtl/arbiter.v")
|
||||
srcs.append("../lib/axi/rtl/priority_encoder.v")
|
||||
srcs.append("%s.v" % testbench)
|
||||
|
||||
src = ' '.join(srcs)
|
||||
|
||||
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
|
||||
|
||||
def bench():
|
||||
|
||||
# Parameters
|
||||
COUNT = 2
|
||||
INDEX_WIDTH = 6
|
||||
SLICE_WIDTH = 5
|
||||
AXIL_DATA_WIDTH = 32
|
||||
AXIL_ADDR_WIDTH = INDEX_WIDTH+4+1+(COUNT-1).bit_length()
|
||||
AXIL_STRB_WIDTH = (AXIL_DATA_WIDTH/8)
|
||||
SCHEDULE_START_S = 0x0
|
||||
SCHEDULE_START_NS = 0x0
|
||||
SCHEDULE_PERIOD_S = 0
|
||||
SCHEDULE_PERIOD_NS = 1000000
|
||||
TIMESLOT_PERIOD_S = 0
|
||||
TIMESLOT_PERIOD_NS = 100000
|
||||
ACTIVE_PERIOD_S = 0
|
||||
ACTIVE_PERIOD_NS = 100000
|
||||
|
||||
# Inputs
|
||||
clk = Signal(bool(0))
|
||||
rst = Signal(bool(0))
|
||||
current_test = Signal(intbv(0)[8:])
|
||||
|
||||
phy_tx_clk = Signal(intbv(0)[COUNT:])
|
||||
phy_rx_clk = Signal(intbv(0)[COUNT:])
|
||||
phy_rx_error_count = Signal(intbv(0)[COUNT*7:])
|
||||
s_axil_awaddr = Signal(intbv(0)[AXIL_ADDR_WIDTH:])
|
||||
s_axil_awprot = Signal(intbv(0)[3:])
|
||||
s_axil_awvalid = Signal(bool(0))
|
||||
s_axil_wdata = Signal(intbv(0)[AXIL_DATA_WIDTH:])
|
||||
s_axil_wstrb = Signal(intbv(0)[AXIL_STRB_WIDTH:])
|
||||
s_axil_wvalid = Signal(bool(0))
|
||||
s_axil_bready = Signal(bool(0))
|
||||
s_axil_araddr = Signal(intbv(0)[AXIL_ADDR_WIDTH:])
|
||||
s_axil_arprot = Signal(intbv(0)[3:])
|
||||
s_axil_arvalid = Signal(bool(0))
|
||||
s_axil_rready = Signal(bool(0))
|
||||
ptp_ts_96 = Signal(intbv(0)[96:])
|
||||
ptp_ts_step = Signal(bool(0))
|
||||
|
||||
# Outputs
|
||||
phy_tx_prbs31_enable = Signal(intbv(0)[COUNT:])
|
||||
phy_rx_prbs31_enable = Signal(intbv(0)[COUNT:])
|
||||
s_axil_awready = Signal(bool(0))
|
||||
s_axil_wready = Signal(bool(0))
|
||||
s_axil_bresp = Signal(intbv(0)[2:])
|
||||
s_axil_bvalid = Signal(bool(0))
|
||||
s_axil_arready = Signal(bool(0))
|
||||
s_axil_rdata = Signal(intbv(0)[AXIL_DATA_WIDTH:])
|
||||
s_axil_rresp = Signal(intbv(0)[2:])
|
||||
s_axil_rvalid = Signal(bool(0))
|
||||
|
||||
# AXI4-Lite master
|
||||
axil_master_inst = axil.AXILiteMaster()
|
||||
axil_master_pause = Signal(bool(False))
|
||||
|
||||
axil_master_logic = axil_master_inst.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
m_axil_awaddr=s_axil_awaddr,
|
||||
m_axil_awprot=s_axil_awprot,
|
||||
m_axil_awvalid=s_axil_awvalid,
|
||||
m_axil_awready=s_axil_awready,
|
||||
m_axil_wdata=s_axil_wdata,
|
||||
m_axil_wstrb=s_axil_wstrb,
|
||||
m_axil_wvalid=s_axil_wvalid,
|
||||
m_axil_wready=s_axil_wready,
|
||||
m_axil_bresp=s_axil_bresp,
|
||||
m_axil_bvalid=s_axil_bvalid,
|
||||
m_axil_bready=s_axil_bready,
|
||||
m_axil_araddr=s_axil_araddr,
|
||||
m_axil_arprot=s_axil_arprot,
|
||||
m_axil_arvalid=s_axil_arvalid,
|
||||
m_axil_arready=s_axil_arready,
|
||||
m_axil_rdata=s_axil_rdata,
|
||||
m_axil_rresp=s_axil_rresp,
|
||||
m_axil_rvalid=s_axil_rvalid,
|
||||
m_axil_rready=s_axil_rready,
|
||||
pause=axil_master_pause,
|
||||
name='master'
|
||||
)
|
||||
|
||||
# PTP clock
|
||||
ptp_clock = ptp.PtpClock()
|
||||
|
||||
ptp_logic = ptp_clock.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
ts_96=ptp_ts_96
|
||||
)
|
||||
|
||||
# DUT
|
||||
if os.system(build_cmd):
|
||||
raise Exception("Error running build command")
|
||||
|
||||
dut = Cosimulation(
|
||||
"vvp -m myhdl %s.vvp -lxt2" % testbench,
|
||||
clk=clk,
|
||||
rst=rst,
|
||||
current_test=current_test,
|
||||
phy_tx_clk=phy_tx_clk,
|
||||
phy_rx_clk=phy_rx_clk,
|
||||
phy_rx_error_count=phy_rx_error_count,
|
||||
phy_tx_prbs31_enable=phy_tx_prbs31_enable,
|
||||
phy_rx_prbs31_enable=phy_rx_prbs31_enable,
|
||||
s_axil_awaddr=s_axil_awaddr,
|
||||
s_axil_awprot=s_axil_awprot,
|
||||
s_axil_awvalid=s_axil_awvalid,
|
||||
s_axil_awready=s_axil_awready,
|
||||
s_axil_wdata=s_axil_wdata,
|
||||
s_axil_wstrb=s_axil_wstrb,
|
||||
s_axil_wvalid=s_axil_wvalid,
|
||||
s_axil_wready=s_axil_wready,
|
||||
s_axil_bresp=s_axil_bresp,
|
||||
s_axil_bvalid=s_axil_bvalid,
|
||||
s_axil_bready=s_axil_bready,
|
||||
s_axil_araddr=s_axil_araddr,
|
||||
s_axil_arprot=s_axil_arprot,
|
||||
s_axil_arvalid=s_axil_arvalid,
|
||||
s_axil_arready=s_axil_arready,
|
||||
s_axil_rdata=s_axil_rdata,
|
||||
s_axil_rresp=s_axil_rresp,
|
||||
s_axil_rvalid=s_axil_rvalid,
|
||||
s_axil_rready=s_axil_rready,
|
||||
ptp_ts_96=ptp_ts_96,
|
||||
ptp_ts_step=ptp_ts_step
|
||||
)
|
||||
|
||||
@always(delay(4))
|
||||
def clkgen():
|
||||
clk.next = not clk
|
||||
|
||||
@always(delay(3))
|
||||
def clkgen2():
|
||||
phy_tx_clk.next = ~phy_tx_clk
|
||||
phy_rx_clk.next = ~phy_rx_clk
|
||||
|
||||
@instance
|
||||
def check():
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
rst.next = 1
|
||||
yield clk.posedge
|
||||
rst.next = 0
|
||||
yield clk.posedge
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
|
||||
# testbench stimulus
|
||||
|
||||
yield clk.posedge
|
||||
print("test 1: Test pulse out")
|
||||
current_test.next = 1
|
||||
|
||||
axil_master_inst.init_write(0x0110, struct.pack('<LLLL', 0, 500, 0, 0))
|
||||
axil_master_inst.init_write(0x0120, struct.pack('<LLLL', 0, 2000, 0, 0))
|
||||
axil_master_inst.init_write(0x0130, struct.pack('<LLLL', 0, 400, 0, 0))
|
||||
axil_master_inst.init_write(0x0140, struct.pack('<LLLL', 0, 300, 0, 0))
|
||||
axil_master_inst.init_write(0x0100, struct.pack('<L', 0x00000001))
|
||||
|
||||
yield delay(10000)
|
||||
|
||||
yield delay(100)
|
||||
|
||||
raise StopSimulation
|
||||
|
||||
return instances()
|
||||
|
||||
def test_bench():
|
||||
sim = Simulation(bench())
|
||||
sim.run()
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("Running test...")
|
||||
test_bench()
|
181
fpga/common/tb/test_tdma_ber.v
Normal file
181
fpga/common/tb/test_tdma_ber.v
Normal file
@ -0,0 +1,181 @@
|
||||
/*
|
||||
|
||||
Copyright 2019, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
/*
|
||||
* Testbench for tdma_ber
|
||||
*/
|
||||
module test_tdma_ber;
|
||||
|
||||
// Parameters
|
||||
parameter COUNT = 2;
|
||||
parameter INDEX_WIDTH = 6;
|
||||
parameter SLICE_WIDTH = 5;
|
||||
parameter AXIL_DATA_WIDTH = 32;
|
||||
parameter AXIL_ADDR_WIDTH = INDEX_WIDTH+4+1+$clog2(COUNT);
|
||||
parameter AXIL_STRB_WIDTH = (AXIL_DATA_WIDTH/8);
|
||||
parameter SCHEDULE_START_S = 48'h0;
|
||||
parameter SCHEDULE_START_NS = 30'h0;
|
||||
parameter SCHEDULE_PERIOD_S = 48'd0;
|
||||
parameter SCHEDULE_PERIOD_NS = 30'd1000000;
|
||||
parameter TIMESLOT_PERIOD_S = 48'd0;
|
||||
parameter TIMESLOT_PERIOD_NS = 30'd100000;
|
||||
parameter ACTIVE_PERIOD_S = 48'd0;
|
||||
parameter ACTIVE_PERIOD_NS = 30'd100000;
|
||||
|
||||
// Inputs
|
||||
reg clk = 0;
|
||||
reg rst = 0;
|
||||
reg [7:0] current_test = 0;
|
||||
|
||||
reg [COUNT-1:0] phy_tx_clk = 0;
|
||||
reg [COUNT-1:0] phy_rx_clk = 0;
|
||||
reg [COUNT*7-1:0] phy_rx_error_count = 0;
|
||||
reg [AXIL_ADDR_WIDTH-1:0] s_axil_awaddr = 0;
|
||||
reg [2:0] s_axil_awprot = 0;
|
||||
reg s_axil_awvalid = 0;
|
||||
reg [AXIL_DATA_WIDTH-1:0] s_axil_wdata = 0;
|
||||
reg [AXIL_STRB_WIDTH-1:0] s_axil_wstrb = 0;
|
||||
reg s_axil_wvalid = 0;
|
||||
reg s_axil_bready = 0;
|
||||
reg [AXIL_ADDR_WIDTH-1:0] s_axil_araddr = 0;
|
||||
reg [2:0] s_axil_arprot = 0;
|
||||
reg s_axil_arvalid = 0;
|
||||
reg s_axil_rready = 0;
|
||||
reg [95:0] ptp_ts_96 = 0;
|
||||
reg ptp_ts_step = 0;
|
||||
|
||||
// Outputs
|
||||
wire [COUNT-1:0] phy_tx_prbs31_enable;
|
||||
wire [COUNT-1:0] phy_rx_prbs31_enable;
|
||||
wire s_axil_awready;
|
||||
wire s_axil_wready;
|
||||
wire [1:0] s_axil_bresp;
|
||||
wire s_axil_bvalid;
|
||||
wire s_axil_arready;
|
||||
wire [AXIL_DATA_WIDTH-1:0] s_axil_rdata;
|
||||
wire [1:0] s_axil_rresp;
|
||||
wire s_axil_rvalid;
|
||||
|
||||
initial begin
|
||||
// myhdl integration
|
||||
$from_myhdl(
|
||||
clk,
|
||||
rst,
|
||||
current_test,
|
||||
phy_tx_clk,
|
||||
phy_rx_clk,
|
||||
phy_rx_error_count,
|
||||
s_axil_awaddr,
|
||||
s_axil_awprot,
|
||||
s_axil_awvalid,
|
||||
s_axil_wdata,
|
||||
s_axil_wstrb,
|
||||
s_axil_wvalid,
|
||||
s_axil_bready,
|
||||
s_axil_araddr,
|
||||
s_axil_arprot,
|
||||
s_axil_arvalid,
|
||||
s_axil_rready,
|
||||
ptp_ts_96,
|
||||
ptp_ts_step
|
||||
);
|
||||
$to_myhdl(
|
||||
phy_tx_prbs31_enable,
|
||||
phy_rx_prbs31_enable,
|
||||
s_axil_awready,
|
||||
s_axil_wready,
|
||||
s_axil_bresp,
|
||||
s_axil_bvalid,
|
||||
s_axil_arready,
|
||||
s_axil_rdata,
|
||||
s_axil_rresp,
|
||||
s_axil_rvalid
|
||||
);
|
||||
|
||||
// dump file
|
||||
$dumpfile("test_tdma_ber.lxt");
|
||||
$dumpvars(0, test_tdma_ber);
|
||||
end
|
||||
|
||||
tdma_ber #(
|
||||
.COUNT(COUNT),
|
||||
.INDEX_WIDTH(INDEX_WIDTH),
|
||||
.SLICE_WIDTH(SLICE_WIDTH),
|
||||
.AXIL_DATA_WIDTH(AXIL_DATA_WIDTH),
|
||||
.AXIL_ADDR_WIDTH(AXIL_ADDR_WIDTH),
|
||||
.AXIL_STRB_WIDTH(AXIL_STRB_WIDTH),
|
||||
.SCHEDULE_START_S(SCHEDULE_START_S),
|
||||
.SCHEDULE_START_NS(SCHEDULE_START_NS),
|
||||
.SCHEDULE_PERIOD_S(SCHEDULE_PERIOD_S),
|
||||
.SCHEDULE_PERIOD_NS(SCHEDULE_PERIOD_NS),
|
||||
.TIMESLOT_PERIOD_S(TIMESLOT_PERIOD_S),
|
||||
.TIMESLOT_PERIOD_NS(TIMESLOT_PERIOD_NS),
|
||||
.ACTIVE_PERIOD_S(ACTIVE_PERIOD_S),
|
||||
.ACTIVE_PERIOD_NS(ACTIVE_PERIOD_NS)
|
||||
)
|
||||
UUT (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
.phy_tx_clk(phy_tx_clk),
|
||||
.phy_rx_clk(phy_rx_clk),
|
||||
.phy_rx_error_count(phy_rx_error_count),
|
||||
.phy_tx_prbs31_enable(phy_tx_prbs31_enable),
|
||||
.phy_rx_prbs31_enable(phy_rx_prbs31_enable),
|
||||
.s_axil_awaddr(s_axil_awaddr),
|
||||
.s_axil_awprot(s_axil_awprot),
|
||||
.s_axil_awvalid(s_axil_awvalid),
|
||||
.s_axil_awready(s_axil_awready),
|
||||
.s_axil_wdata(s_axil_wdata),
|
||||
.s_axil_wstrb(s_axil_wstrb),
|
||||
.s_axil_wvalid(s_axil_wvalid),
|
||||
.s_axil_wready(s_axil_wready),
|
||||
.s_axil_bresp(s_axil_bresp),
|
||||
.s_axil_bvalid(s_axil_bvalid),
|
||||
.s_axil_bready(s_axil_bready),
|
||||
.s_axil_araddr(s_axil_araddr),
|
||||
.s_axil_arprot(s_axil_arprot),
|
||||
.s_axil_arvalid(s_axil_arvalid),
|
||||
.s_axil_arready(s_axil_arready),
|
||||
.s_axil_rdata(s_axil_rdata),
|
||||
.s_axil_rresp(s_axil_rresp),
|
||||
.s_axil_rvalid(s_axil_rvalid),
|
||||
.s_axil_rready(s_axil_rready),
|
||||
.ptp_ts_96(ptp_ts_96),
|
||||
.ptp_ts_step(ptp_ts_step)
|
||||
);
|
||||
|
||||
endmodule
|
535
fpga/common/tb/test_tdma_ber_ch.py
Executable file
535
fpga/common/tb/test_tdma_ber_ch.py
Executable file
@ -0,0 +1,535 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
|
||||
Copyright 2019, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
"""
|
||||
|
||||
from myhdl import *
|
||||
import os
|
||||
import struct
|
||||
|
||||
import axil
|
||||
|
||||
module = 'tdma_ber_ch'
|
||||
testbench = 'test_%s' % module
|
||||
|
||||
srcs = []
|
||||
|
||||
srcs.append("../rtl/%s.v" % module)
|
||||
srcs.append("%s.v" % testbench)
|
||||
|
||||
src = ' '.join(srcs)
|
||||
|
||||
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
|
||||
|
||||
def bench():
|
||||
|
||||
# Parameters
|
||||
INDEX_WIDTH = 6
|
||||
SLICE_WIDTH = 5
|
||||
AXIL_DATA_WIDTH = 32
|
||||
AXIL_ADDR_WIDTH = INDEX_WIDTH+4
|
||||
AXIL_STRB_WIDTH = (AXIL_DATA_WIDTH/8)
|
||||
|
||||
# Inputs
|
||||
clk = Signal(bool(0))
|
||||
rst = Signal(bool(0))
|
||||
current_test = Signal(intbv(0)[8:])
|
||||
|
||||
phy_tx_clk = Signal(bool(0))
|
||||
phy_rx_clk = Signal(bool(0))
|
||||
phy_rx_error_count = Signal(intbv(0)[7:])
|
||||
s_axil_awaddr = Signal(intbv(0)[AXIL_ADDR_WIDTH:])
|
||||
s_axil_awprot = Signal(intbv(0)[3:])
|
||||
s_axil_awvalid = Signal(bool(0))
|
||||
s_axil_wdata = Signal(intbv(0)[AXIL_DATA_WIDTH:])
|
||||
s_axil_wstrb = Signal(intbv(0)[AXIL_STRB_WIDTH:])
|
||||
s_axil_wvalid = Signal(bool(0))
|
||||
s_axil_bready = Signal(bool(0))
|
||||
s_axil_araddr = Signal(intbv(0)[AXIL_ADDR_WIDTH:])
|
||||
s_axil_arprot = Signal(intbv(0)[3:])
|
||||
s_axil_arvalid = Signal(bool(0))
|
||||
s_axil_rready = Signal(bool(0))
|
||||
tdma_timeslot_index = Signal(intbv(0)[INDEX_WIDTH:])
|
||||
tdma_timeslot_start = Signal(bool(0))
|
||||
tdma_timeslot_active = Signal(bool(0))
|
||||
|
||||
# Outputs
|
||||
phy_tx_prbs31_enable = Signal(bool(0))
|
||||
phy_rx_prbs31_enable = Signal(bool(0))
|
||||
s_axil_awready = Signal(bool(0))
|
||||
s_axil_wready = Signal(bool(0))
|
||||
s_axil_bresp = Signal(intbv(0)[2:])
|
||||
s_axil_bvalid = Signal(bool(0))
|
||||
s_axil_arready = Signal(bool(0))
|
||||
s_axil_rdata = Signal(intbv(0)[AXIL_DATA_WIDTH:])
|
||||
s_axil_rresp = Signal(intbv(0)[2:])
|
||||
s_axil_rvalid = Signal(bool(0))
|
||||
|
||||
# AXI4-Lite master
|
||||
axil_master_inst = axil.AXILiteMaster()
|
||||
axil_master_pause = Signal(bool(False))
|
||||
|
||||
axil_master_logic = axil_master_inst.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
m_axil_awaddr=s_axil_awaddr,
|
||||
m_axil_awprot=s_axil_awprot,
|
||||
m_axil_awvalid=s_axil_awvalid,
|
||||
m_axil_awready=s_axil_awready,
|
||||
m_axil_wdata=s_axil_wdata,
|
||||
m_axil_wstrb=s_axil_wstrb,
|
||||
m_axil_wvalid=s_axil_wvalid,
|
||||
m_axil_wready=s_axil_wready,
|
||||
m_axil_bresp=s_axil_bresp,
|
||||
m_axil_bvalid=s_axil_bvalid,
|
||||
m_axil_bready=s_axil_bready,
|
||||
m_axil_araddr=s_axil_araddr,
|
||||
m_axil_arprot=s_axil_arprot,
|
||||
m_axil_arvalid=s_axil_arvalid,
|
||||
m_axil_arready=s_axil_arready,
|
||||
m_axil_rdata=s_axil_rdata,
|
||||
m_axil_rresp=s_axil_rresp,
|
||||
m_axil_rvalid=s_axil_rvalid,
|
||||
m_axil_rready=s_axil_rready,
|
||||
pause=axil_master_pause,
|
||||
name='master'
|
||||
)
|
||||
|
||||
# DUT
|
||||
if os.system(build_cmd):
|
||||
raise Exception("Error running build command")
|
||||
|
||||
dut = Cosimulation(
|
||||
"vvp -m myhdl %s.vvp -lxt2" % testbench,
|
||||
clk=clk,
|
||||
rst=rst,
|
||||
current_test=current_test,
|
||||
phy_tx_clk=phy_tx_clk,
|
||||
phy_rx_clk=phy_rx_clk,
|
||||
phy_rx_error_count=phy_rx_error_count,
|
||||
phy_tx_prbs31_enable=phy_tx_prbs31_enable,
|
||||
phy_rx_prbs31_enable=phy_rx_prbs31_enable,
|
||||
s_axil_awaddr=s_axil_awaddr,
|
||||
s_axil_awprot=s_axil_awprot,
|
||||
s_axil_awvalid=s_axil_awvalid,
|
||||
s_axil_awready=s_axil_awready,
|
||||
s_axil_wdata=s_axil_wdata,
|
||||
s_axil_wstrb=s_axil_wstrb,
|
||||
s_axil_wvalid=s_axil_wvalid,
|
||||
s_axil_wready=s_axil_wready,
|
||||
s_axil_bresp=s_axil_bresp,
|
||||
s_axil_bvalid=s_axil_bvalid,
|
||||
s_axil_bready=s_axil_bready,
|
||||
s_axil_araddr=s_axil_araddr,
|
||||
s_axil_arprot=s_axil_arprot,
|
||||
s_axil_arvalid=s_axil_arvalid,
|
||||
s_axil_arready=s_axil_arready,
|
||||
s_axil_rdata=s_axil_rdata,
|
||||
s_axil_rresp=s_axil_rresp,
|
||||
s_axil_rvalid=s_axil_rvalid,
|
||||
s_axil_rready=s_axil_rready,
|
||||
tdma_timeslot_index=tdma_timeslot_index,
|
||||
tdma_timeslot_start=tdma_timeslot_start,
|
||||
tdma_timeslot_active=tdma_timeslot_active
|
||||
)
|
||||
|
||||
@always(delay(4))
|
||||
def clkgen():
|
||||
clk.next = not clk
|
||||
|
||||
@always(delay(3))
|
||||
def clkgen2():
|
||||
phy_tx_clk.next = not phy_tx_clk
|
||||
phy_rx_clk.next = not phy_rx_clk
|
||||
|
||||
@instance
|
||||
def check():
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
rst.next = 1
|
||||
yield clk.posedge
|
||||
rst.next = 0
|
||||
yield clk.posedge
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
|
||||
# testbench stimulus
|
||||
|
||||
yield clk.posedge
|
||||
print("test 1: test error counts")
|
||||
current_test.next = 1
|
||||
|
||||
axil_master_inst.init_write(0x0000, struct.pack('<L', 0x00000003))
|
||||
axil_master_inst.init_write(0x0020, struct.pack('<L', 0x00000001))
|
||||
|
||||
axil_master_inst.init_read(0x0014, 12)
|
||||
axil_master_inst.init_read(0x0200, 32)
|
||||
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
axil_master_inst.init_write(0x0200, b'\x00'*32)
|
||||
|
||||
data = axil_master_inst.get_read_data()
|
||||
data = struct.unpack('<LLL', data[1])
|
||||
print(data)
|
||||
|
||||
data2 = axil_master_inst.get_read_data()
|
||||
data2 = struct.unpack('<8L', data2[1])
|
||||
print(data2)
|
||||
|
||||
yield clk.posedge
|
||||
for l in range(5):
|
||||
for k in range(4):
|
||||
tdma_timeslot_index.next = k
|
||||
tdma_timeslot_start.next = 1
|
||||
tdma_timeslot_active.next = 1
|
||||
yield clk.posedge
|
||||
tdma_timeslot_start.next = 0
|
||||
for k in range(49):
|
||||
yield clk.posedge
|
||||
tdma_timeslot_active.next = 0
|
||||
|
||||
axil_master_inst.init_read(0x0014, 12)
|
||||
axil_master_inst.init_read(0x0200, 32)
|
||||
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
axil_master_inst.init_write(0x0200, b'\x00'*32)
|
||||
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
data = axil_master_inst.get_read_data()
|
||||
data = struct.unpack('<LLL', data[1])
|
||||
print(data)
|
||||
|
||||
data2 = axil_master_inst.get_read_data()
|
||||
data2 = struct.unpack('<8L', data2[1])
|
||||
print(data2)
|
||||
|
||||
phy_rx_error_count.next = 1
|
||||
|
||||
yield clk.posedge
|
||||
for l in range(5):
|
||||
for k in range(4):
|
||||
tdma_timeslot_index.next = k
|
||||
tdma_timeslot_start.next = 1
|
||||
tdma_timeslot_active.next = 1
|
||||
yield clk.posedge
|
||||
tdma_timeslot_start.next = 0
|
||||
for k in range(49):
|
||||
yield clk.posedge
|
||||
tdma_timeslot_active.next = 0
|
||||
|
||||
phy_rx_error_count.next = 0
|
||||
|
||||
axil_master_inst.init_read(0x0014, 12)
|
||||
axil_master_inst.init_read(0x0200, 32)
|
||||
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
axil_master_inst.init_write(0x0200, b'\x00'*32)
|
||||
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
data = axil_master_inst.get_read_data()
|
||||
data = struct.unpack('<LLL', data[1])
|
||||
print(data)
|
||||
|
||||
data2 = axil_master_inst.get_read_data()
|
||||
data2 = struct.unpack('<8L', data2[1])
|
||||
print(data2)
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 2: change duty cycle")
|
||||
current_test.next = 2
|
||||
|
||||
axil_master_inst.init_write(0x0000, struct.pack('<L', 0x00000003))
|
||||
axil_master_inst.init_write(0x0020, struct.pack('<L', 0x00000001))
|
||||
|
||||
axil_master_inst.init_read(0x0014, 12)
|
||||
axil_master_inst.init_read(0x0200, 32)
|
||||
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
axil_master_inst.init_write(0x0200, b'\x00'*32)
|
||||
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
data = axil_master_inst.get_read_data()
|
||||
data = struct.unpack('<LLL', data[1])
|
||||
print(data)
|
||||
|
||||
data2 = axil_master_inst.get_read_data()
|
||||
data2 = struct.unpack('<8L', data2[1])
|
||||
print(data2)
|
||||
|
||||
yield clk.posedge
|
||||
for l in range(5):
|
||||
for k in range(4):
|
||||
tdma_timeslot_index.next = k
|
||||
tdma_timeslot_start.next = 1
|
||||
tdma_timeslot_active.next = 1
|
||||
yield clk.posedge
|
||||
tdma_timeslot_start.next = 0
|
||||
for k in range(39):
|
||||
yield clk.posedge
|
||||
tdma_timeslot_active.next = 0
|
||||
for k in range(10):
|
||||
yield clk.posedge
|
||||
|
||||
axil_master_inst.init_read(0x0014, 12)
|
||||
axil_master_inst.init_read(0x0200, 32)
|
||||
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
axil_master_inst.init_write(0x0200, b'\x00'*32)
|
||||
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
data = axil_master_inst.get_read_data()
|
||||
data = struct.unpack('<LLL', data[1])
|
||||
print(data)
|
||||
|
||||
data2 = axil_master_inst.get_read_data()
|
||||
data2 = struct.unpack('<8L', data2[1])
|
||||
print(data2)
|
||||
|
||||
phy_rx_error_count.next = 1
|
||||
|
||||
yield clk.posedge
|
||||
for l in range(5):
|
||||
for k in range(4):
|
||||
tdma_timeslot_index.next = k
|
||||
tdma_timeslot_start.next = 1
|
||||
tdma_timeslot_active.next = 1
|
||||
yield clk.posedge
|
||||
tdma_timeslot_start.next = 0
|
||||
for k in range(39):
|
||||
yield clk.posedge
|
||||
tdma_timeslot_active.next = 0
|
||||
for k in range(10):
|
||||
yield clk.posedge
|
||||
|
||||
phy_rx_error_count.next = 0
|
||||
|
||||
axil_master_inst.init_read(0x0014, 12)
|
||||
axil_master_inst.init_read(0x0200, 32)
|
||||
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
axil_master_inst.init_write(0x0200, b'\x00'*32)
|
||||
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
data = axil_master_inst.get_read_data()
|
||||
data = struct.unpack('<LLL', data[1])
|
||||
print(data)
|
||||
|
||||
data2 = axil_master_inst.get_read_data()
|
||||
data2 = struct.unpack('<8L', data2[1])
|
||||
print(data2)
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 3: test slices")
|
||||
current_test.next = 3
|
||||
|
||||
axil_master_inst.init_write(0x0000, struct.pack('<L', 0x00000003))
|
||||
axil_master_inst.init_write(0x0020, struct.pack('<L', 0x00000003))
|
||||
axil_master_inst.init_write(0x0024, struct.pack('<L', 0x00000010))
|
||||
axil_master_inst.init_write(0x0028, struct.pack('<L', 0x00000020))
|
||||
|
||||
axil_master_inst.init_read(0x0014, 12)
|
||||
|
||||
axil_master_inst.init_write(0x0030, struct.pack('<L', 0x00000000))
|
||||
yield axil_master_inst.wait()
|
||||
axil_master_inst.init_read(0x0200, 32)
|
||||
yield axil_master_inst.wait()
|
||||
axil_master_inst.init_write(0x0200, b'\x00'*32)
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
axil_master_inst.init_write(0x0030, struct.pack('<L', 0x00000001))
|
||||
yield axil_master_inst.wait()
|
||||
axil_master_inst.init_read(0x0200, 32)
|
||||
yield axil_master_inst.wait()
|
||||
axil_master_inst.init_write(0x0200, b'\x00'*32)
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
axil_master_inst.init_write(0x0030, struct.pack('<L', 0x00000002))
|
||||
yield axil_master_inst.wait()
|
||||
axil_master_inst.init_read(0x0200, 32)
|
||||
yield axil_master_inst.wait()
|
||||
axil_master_inst.init_write(0x0200, b'\x00'*32)
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
data = axil_master_inst.get_read_data()
|
||||
data = struct.unpack('<LLL', data[1])
|
||||
print(data)
|
||||
|
||||
data2 = axil_master_inst.get_read_data()
|
||||
data2 = struct.unpack('<8L', data2[1])
|
||||
print(data2)
|
||||
|
||||
data2 = axil_master_inst.get_read_data()
|
||||
data2 = struct.unpack('<8L', data2[1])
|
||||
print(data2)
|
||||
|
||||
data2 = axil_master_inst.get_read_data()
|
||||
data2 = struct.unpack('<8L', data2[1])
|
||||
print(data2)
|
||||
|
||||
yield clk.posedge
|
||||
for l in range(5):
|
||||
for k in range(4):
|
||||
tdma_timeslot_index.next = k
|
||||
tdma_timeslot_start.next = 1
|
||||
tdma_timeslot_active.next = 1
|
||||
yield clk.posedge
|
||||
tdma_timeslot_start.next = 0
|
||||
for k in range(399):
|
||||
yield clk.posedge
|
||||
tdma_timeslot_active.next = 0
|
||||
for k in range(100):
|
||||
yield clk.posedge
|
||||
|
||||
axil_master_inst.init_read(0x0014, 12)
|
||||
|
||||
axil_master_inst.init_write(0x0030, struct.pack('<L', 0x00000000))
|
||||
yield axil_master_inst.wait()
|
||||
axil_master_inst.init_read(0x0200, 32)
|
||||
yield axil_master_inst.wait()
|
||||
axil_master_inst.init_write(0x0200, b'\x00'*32)
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
axil_master_inst.init_write(0x0030, struct.pack('<L', 0x00000001))
|
||||
yield axil_master_inst.wait()
|
||||
axil_master_inst.init_read(0x0200, 32)
|
||||
yield axil_master_inst.wait()
|
||||
axil_master_inst.init_write(0x0200, b'\x00'*32)
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
axil_master_inst.init_write(0x0030, struct.pack('<L', 0x00000002))
|
||||
yield axil_master_inst.wait()
|
||||
axil_master_inst.init_read(0x0200, 32)
|
||||
yield axil_master_inst.wait()
|
||||
axil_master_inst.init_write(0x0200, b'\x00'*32)
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
data = axil_master_inst.get_read_data()
|
||||
data = struct.unpack('<LLL', data[1])
|
||||
print(data)
|
||||
|
||||
data2 = axil_master_inst.get_read_data()
|
||||
data2 = struct.unpack('<8L', data2[1])
|
||||
print(data2)
|
||||
|
||||
data2 = axil_master_inst.get_read_data()
|
||||
data2 = struct.unpack('<8L', data2[1])
|
||||
print(data2)
|
||||
|
||||
data2 = axil_master_inst.get_read_data()
|
||||
data2 = struct.unpack('<8L', data2[1])
|
||||
print(data2)
|
||||
|
||||
phy_rx_error_count.next = 1
|
||||
|
||||
yield clk.posedge
|
||||
for l in range(5):
|
||||
for k in range(4):
|
||||
tdma_timeslot_index.next = k
|
||||
tdma_timeslot_start.next = 1
|
||||
tdma_timeslot_active.next = 1
|
||||
yield clk.posedge
|
||||
tdma_timeslot_start.next = 0
|
||||
for k in range(399):
|
||||
yield clk.posedge
|
||||
tdma_timeslot_active.next = 0
|
||||
for k in range(100):
|
||||
yield clk.posedge
|
||||
|
||||
phy_rx_error_count.next = 0
|
||||
|
||||
axil_master_inst.init_read(0x0014, 12)
|
||||
|
||||
axil_master_inst.init_write(0x0030, struct.pack('<L', 0x00000000))
|
||||
yield axil_master_inst.wait()
|
||||
axil_master_inst.init_read(0x0200, 32)
|
||||
yield axil_master_inst.wait()
|
||||
axil_master_inst.init_write(0x0200, b'\x00'*32)
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
axil_master_inst.init_write(0x0030, struct.pack('<L', 0x00000001))
|
||||
yield axil_master_inst.wait()
|
||||
axil_master_inst.init_read(0x0200, 32)
|
||||
yield axil_master_inst.wait()
|
||||
axil_master_inst.init_write(0x0200, b'\x00'*32)
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
axil_master_inst.init_write(0x0030, struct.pack('<L', 0x00000002))
|
||||
yield axil_master_inst.wait()
|
||||
axil_master_inst.init_read(0x0200, 32)
|
||||
yield axil_master_inst.wait()
|
||||
axil_master_inst.init_write(0x0200, b'\x00'*32)
|
||||
yield axil_master_inst.wait()
|
||||
|
||||
data = axil_master_inst.get_read_data()
|
||||
data = struct.unpack('<LLL', data[1])
|
||||
print(data)
|
||||
|
||||
data2 = axil_master_inst.get_read_data()
|
||||
data2 = struct.unpack('<8L', data2[1])
|
||||
print(data2)
|
||||
|
||||
data2 = axil_master_inst.get_read_data()
|
||||
data2 = struct.unpack('<8L', data2[1])
|
||||
print(data2)
|
||||
|
||||
data2 = axil_master_inst.get_read_data()
|
||||
data2 = struct.unpack('<8L', data2[1])
|
||||
print(data2)
|
||||
|
||||
yield delay(100)
|
||||
|
||||
raise StopSimulation
|
||||
|
||||
return instances()
|
||||
|
||||
def test_bench():
|
||||
sim = Simulation(bench())
|
||||
sim.run()
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("Running test...")
|
||||
test_bench()
|
166
fpga/common/tb/test_tdma_ber_ch.v
Normal file
166
fpga/common/tb/test_tdma_ber_ch.v
Normal file
@ -0,0 +1,166 @@
|
||||
/*
|
||||
|
||||
Copyright 2019, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
/*
|
||||
* Testbench for tdma_ber_ch
|
||||
*/
|
||||
module test_tdma_ber_ch;
|
||||
|
||||
// Parameters
|
||||
parameter INDEX_WIDTH = 6;
|
||||
parameter SLICE_WIDTH = 5;
|
||||
parameter AXIL_DATA_WIDTH = 32;
|
||||
parameter AXIL_ADDR_WIDTH = INDEX_WIDTH+4;
|
||||
parameter AXIL_STRB_WIDTH = (AXIL_DATA_WIDTH/8);
|
||||
|
||||
// Inputs
|
||||
reg clk = 0;
|
||||
reg rst = 0;
|
||||
reg [7:0] current_test = 0;
|
||||
|
||||
reg phy_tx_clk = 0;
|
||||
reg phy_rx_clk = 0;
|
||||
reg [6:0] phy_rx_error_count = 0;
|
||||
reg [AXIL_ADDR_WIDTH-1:0] s_axil_awaddr = 0;
|
||||
reg [2:0] s_axil_awprot = 0;
|
||||
reg s_axil_awvalid = 0;
|
||||
reg [AXIL_DATA_WIDTH-1:0] s_axil_wdata = 0;
|
||||
reg [AXIL_STRB_WIDTH-1:0] s_axil_wstrb = 0;
|
||||
reg s_axil_wvalid = 0;
|
||||
reg s_axil_bready = 0;
|
||||
reg [AXIL_ADDR_WIDTH-1:0] s_axil_araddr = 0;
|
||||
reg [2:0] s_axil_arprot = 0;
|
||||
reg s_axil_arvalid = 0;
|
||||
reg s_axil_rready = 0;
|
||||
reg [INDEX_WIDTH-1:0] tdma_timeslot_index = 0;
|
||||
reg tdma_timeslot_start = 0;
|
||||
reg tdma_timeslot_active = 0;
|
||||
|
||||
// Outputs
|
||||
wire phy_tx_prbs31_enable;
|
||||
wire phy_rx_prbs31_enable;
|
||||
wire s_axil_awready;
|
||||
wire s_axil_wready;
|
||||
wire [1:0] s_axil_bresp;
|
||||
wire s_axil_bvalid;
|
||||
wire s_axil_arready;
|
||||
wire [AXIL_DATA_WIDTH-1:0] s_axil_rdata;
|
||||
wire [1:0] s_axil_rresp;
|
||||
wire s_axil_rvalid;
|
||||
|
||||
initial begin
|
||||
// myhdl integration
|
||||
$from_myhdl(
|
||||
clk,
|
||||
rst,
|
||||
current_test,
|
||||
phy_tx_clk,
|
||||
phy_rx_clk,
|
||||
phy_rx_error_count,
|
||||
s_axil_awaddr,
|
||||
s_axil_awprot,
|
||||
s_axil_awvalid,
|
||||
s_axil_wdata,
|
||||
s_axil_wstrb,
|
||||
s_axil_wvalid,
|
||||
s_axil_bready,
|
||||
s_axil_araddr,
|
||||
s_axil_arprot,
|
||||
s_axil_arvalid,
|
||||
s_axil_rready,
|
||||
tdma_timeslot_index,
|
||||
tdma_timeslot_start,
|
||||
tdma_timeslot_active
|
||||
);
|
||||
$to_myhdl(
|
||||
phy_tx_prbs31_enable,
|
||||
phy_rx_prbs31_enable,
|
||||
s_axil_awready,
|
||||
s_axil_wready,
|
||||
s_axil_bresp,
|
||||
s_axil_bvalid,
|
||||
s_axil_arready,
|
||||
s_axil_rdata,
|
||||
s_axil_rresp,
|
||||
s_axil_rvalid
|
||||
);
|
||||
|
||||
// dump file
|
||||
$dumpfile("test_tdma_ber_ch.lxt");
|
||||
$dumpvars(0, test_tdma_ber_ch);
|
||||
end
|
||||
|
||||
tdma_ber_ch #(
|
||||
.INDEX_WIDTH(INDEX_WIDTH),
|
||||
.SLICE_WIDTH(SLICE_WIDTH),
|
||||
.AXIL_DATA_WIDTH(AXIL_DATA_WIDTH),
|
||||
.AXIL_ADDR_WIDTH(AXIL_ADDR_WIDTH),
|
||||
.AXIL_STRB_WIDTH(AXIL_STRB_WIDTH)
|
||||
)
|
||||
UUT (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
.phy_tx_clk(phy_tx_clk),
|
||||
.phy_rx_clk(phy_rx_clk),
|
||||
.phy_rx_error_count(phy_rx_error_count),
|
||||
.phy_tx_prbs31_enable(phy_tx_prbs31_enable),
|
||||
.phy_rx_prbs31_enable(phy_rx_prbs31_enable),
|
||||
.s_axil_awaddr(s_axil_awaddr),
|
||||
.s_axil_awprot(s_axil_awprot),
|
||||
.s_axil_awvalid(s_axil_awvalid),
|
||||
.s_axil_awready(s_axil_awready),
|
||||
.s_axil_wdata(s_axil_wdata),
|
||||
.s_axil_wstrb(s_axil_wstrb),
|
||||
.s_axil_wvalid(s_axil_wvalid),
|
||||
.s_axil_wready(s_axil_wready),
|
||||
.s_axil_bresp(s_axil_bresp),
|
||||
.s_axil_bvalid(s_axil_bvalid),
|
||||
.s_axil_bready(s_axil_bready),
|
||||
.s_axil_araddr(s_axil_araddr),
|
||||
.s_axil_arprot(s_axil_arprot),
|
||||
.s_axil_arvalid(s_axil_arvalid),
|
||||
.s_axil_arready(s_axil_arready),
|
||||
.s_axil_rdata(s_axil_rdata),
|
||||
.s_axil_rresp(s_axil_rresp),
|
||||
.s_axil_rvalid(s_axil_rvalid),
|
||||
.s_axil_rready(s_axil_rready),
|
||||
.tdma_timeslot_index(tdma_timeslot_index),
|
||||
.tdma_timeslot_start(tdma_timeslot_start),
|
||||
.tdma_timeslot_active(tdma_timeslot_active)
|
||||
);
|
||||
|
||||
endmodule
|
Loading…
x
Reference in New Issue
Block a user