Pushing the bulk of UHD-3.7.0 code.

Original-commit: ff1546f8137f7f92bb250f685561b0c34cc0e053
This commit is contained in:
Ben Hilburn
2014-02-14 12:05:07 -08:00
parent 29086f9001
commit fbbc991a7d
2194 changed files with 1489297 additions and 1084 deletions
+1
View File
@@ -0,0 +1 @@
/build
File diff suppressed because one or more lines are too long
+81
View File
@@ -0,0 +1,81 @@
/*
-------------------------------------------------------------------------------
--
-- File: LvFpga_Chinch_Interface.vhd
-- Author: Ashish Chaudhari
-- Original Project: EttusUsrpB250Top
-- Date: 1 Oct 2013
--
-------------------------------------------------------------------------------
-- (c) 2013 Copyright National Instruments Corporation
-- All Rights Reserved
-- National Instruments Internal Information
-------------------------------------------------------------------------------
*/
`include "LvFpga_Chinch_Interface.vh"
module LvFpga_Chinch_Interface
(
input aIoResetIn_n,
output bBusReset,
input BusClk,
input Rio40Clk,
input IDelayRefClk,
input aRioClkPllLocked,
output aRioClkPllReset,
output aIoReadyOut,
input aIoReadyIn,
output aIoPort2Restart,
input IoRxClock,
input IoRxClock_n,
input [`LVFPGA_IFACE_LINK_WIDTH-1:0] irIoRxData,
input [`LVFPGA_IFACE_LINK_WIDTH-1:0] irIoRxData_n,
input irIoRxHeader,
input irIoRxHeader_n,
output IoTxClock,
output IoTxClock_n,
output [`LVFPGA_IFACE_LINK_WIDTH-1:0] itIoTxData,
output [`LVFPGA_IFACE_LINK_WIDTH-1:0] itIoTxData_n,
output itIoTxHeader,
output itIoTxHeader_n,
input [(`LVFPGA_IFACE_NUM_RX_DMA_CNT*`LVFPGA_IFACE_DMA_CHAN_WIDTH)-1:0] bDmaRxData,
input [`LVFPGA_IFACE_NUM_RX_DMA_CNT-1:0] bDmaRxValid,
output [`LVFPGA_IFACE_NUM_RX_DMA_CNT-1:0] bDmaRxReady,
output [`LVFPGA_IFACE_NUM_RX_DMA_CNT-1:0] bDmaRxEnabled,
output [(`LVFPGA_IFACE_NUM_RX_DMA_CNT*`LVFPGA_IFACE_DMA_SIZE_WIDTH)-1:0] bDmaRxFifoFreeCnt,
output [(`LVFPGA_IFACE_NUM_TX_DMA_CNT*`LVFPGA_IFACE_DMA_CHAN_WIDTH)-1:0] bDmaTxData,
output [`LVFPGA_IFACE_NUM_TX_DMA_CNT-1:0] bDmaTxValid,
input [`LVFPGA_IFACE_NUM_TX_DMA_CNT-1:0] bDmaTxReady,
output [`LVFPGA_IFACE_NUM_TX_DMA_CNT-1:0] bDmaTxEnabled,
output [(`LVFPGA_IFACE_NUM_TX_DMA_CNT*`LVFPGA_IFACE_DMA_SIZE_WIDTH)-1:0] bDmaTxFifoFullCnt,
output bUserRegPortInWt,
output bUserRegPortInRd,
output [`LVFPGA_IFACE_UREG_ADDR_WIDTH-1:0] bUserRegPortInAddr,
output [`LVFPGA_IFACE_UREG_DATA_WIDTH-1:0] bUserRegPortInData,
output [`LVFPGA_IFACE_UREG_SIZE_WIDTH-1:0] bUserRegPortInSize,
input [`LVFPGA_IFACE_UREG_DATA_WIDTH-1:0] bUserRegPortOutData,
input bUserRegPortOutDataValid,
input bUserRegPortOutReady,
input bChinchRegPortOutWt,
input bChinchRegPortOutRd,
input [`LVFPGA_IFACE_CREG_ADDR_WIDTH-1:0] bChinchRegPortOutAddr,
input [`LVFPGA_IFACE_CREG_DATA_WIDTH-1:0] bChinchRegPortOutData,
input [`LVFPGA_IFACE_CREG_SIZE_WIDTH-1:0] bChinchRegPortOutSize,
output [`LVFPGA_IFACE_CREG_DATA_WIDTH-1:0] bChinchRegPortInData,
output bChinchRegPortInDataValid,
output bChinchRegPortInReady,
output aIrq
) /* synthesis syn_black_box syn_noprune=1 */;
// This module serves as an API wrapper for LvFpga_Chinch_Interface.ngc and we don't want
// the tool to accidentally prune out it contents. Hence the syn_black_box syn_noprune=1 directives.
endmodule
+35
View File
@@ -0,0 +1,35 @@
/*
-------------------------------------------------------------------------------
--
-- File: LvFpga_Chinch_Interface.vh
-- Author: Ashish Chaudhari
-- Original Project: EttusUsrpB250Top
-- Date: 1 Oct 2013
--
-------------------------------------------------------------------------------
-- (c) 2013 Copyright National Instruments Corporation
-- All Rights Reserved
-- National Instruments Internal Information
-------------------------------------------------------------------------------
*/
//Physical link width for the IoPort2 interface to the STC3
`define LVFPGA_IFACE_LINK_WIDTH 16
//DMA Related Constants
`define LVFPGA_IFACE_DMA_CHAN_WIDTH 64 //DMA data bus width
`define LVFPGA_IFACE_DMA_SIZE_WIDTH 11 //DMA FIFO fullness count width
`define LVFPGA_IFACE_NUM_RX_DMA_CNT 6 //Number of RX DMA channels
`define LVFPGA_IFACE_NUM_TX_DMA_CNT 6 //Number of TX DMA channels
`define LVFPGA_IFACE_RX_DMA_INDEX 0 //Index for the first RX DMA channel
`define LVFPGA_IFACE_TX_DMA_INDEX 6 //Index for the first TX DMA channel
//User register port constants
`define LVFPGA_IFACE_UREG_ADDR_WIDTH 20 //Address width
`define LVFPGA_IFACE_UREG_DATA_WIDTH 32 //Payload width
`define LVFPGA_IFACE_UREG_SIZE_WIDTH 2 //Transaction size width
//Chinch register port constants
`define LVFPGA_IFACE_CREG_ADDR_WIDTH 32 //Address width
`define LVFPGA_IFACE_CREG_DATA_WIDTH 64 //Payload width
`define LVFPGA_IFACE_CREG_SIZE_WIDTH 2 //Transaction size width
+19
View File
@@ -0,0 +1,19 @@
#
# Copyright 2012-2013 Ettus Research LLC
#
##################################################
# io_port2
##################################################
IOPORT2_SRCS = $(abspath $(addprefix $(BASE_DIR)/../lib/io_port2/, \
./LvFpga_Chinch_Interface.v \
./LvFpga_Chinch_Interface.ngc \
./ioport2_msg_codec.v \
./pcie_pkt_route_specifier.v \
./pcie_axi_wb_conv.v \
./pcie_wb_reg_core.v \
./pcie_iop2_msg_arbiter.v \
./pcie_basic_regs.v \
./pcie_dma_ctrl.v \
./data_swapper_64.v \
))
+76
View File
@@ -0,0 +1,76 @@
#!/usr/bin/python
from xml.etree import ElementTree
from collections import namedtuple
import optparse
import base64
import md5
import os
import sys
# Parse options
parser = optparse.OptionParser()
parser.add_option("--device", type="string", dest="device_type", help="Device Type. (Has to match the LVFPGA target plugin)", default=None)
parser.add_option("--input-bin", type="string", dest="input_bin", help="Path to bin file that needs to be merged with the LVBITX before exporting", default=None)
parser.add_option("--output-bin", type="string", dest="output_bin", help="Create a binary configuration bitstream", default=None)
parser.add_option("--output-lvbitx", type="string", dest="output_lvbitx_path", help="Output path for autogenerated LVBITX file", default=None)
parser.add_option("--output-src-path", type="string", dest="output_src_path", help="Output path for autogenerated src file", default=None)
(options, args) = parser.parse_args()
# Args
if (len(args) < 1):
print 'ERROR: Please specify the input LVBITX file name'
parser.print_help()
sys.exit(1)
lvbitx_filename = args[0]
input_filename = os.path.abspath(lvbitx_filename)
if (not os.path.isfile(input_filename)):
print 'ERROR: LVBITX File ' + input_filename + ' could not be accessed or is not a file.'
parser.print_help()
sys.exit(1)
if (options.input_bin is not None and not os.path.isfile(os.path.abspath(options.input_bin))):
print 'ERROR: FPGA Bin File ' + options.input_bin + ' could not be accessed or is not a file.'
parser.print_help()
sys.exit(1)
if (options.output_lvbitx_path is not None and input_filename == options.output_lvbitx_path):
print 'ERROR: Input and output LVBITX files were the same. Choose a difference input or output file.'
parser.print_help()
sys.exit(1)
# Get XML Tree Node
tree = ElementTree.parse(input_filename)
root = tree.getroot()
# Update device type
if (options.device_type is not None):
root.find('Project').find('TargetClass').text += '; ' + options.device_type
# Merge bitstream into LVBITX
if (options.input_bin is not None):
with open(os.path.abspath(options.input_bin), 'rb') as bin_file:
bitstream = bin_file.read()
bitstream_md5 = md5.new(bitstream).hexdigest()
bitstream_b64 = base64.b64encode(bitstream)
bitstream_b64_lb = ''
for i in range(0, len(bitstream_b64), 76):
bitstream_b64_lb += bitstream_b64[i:i+76] + '\n'
root.find('Bitstream').text = bitstream_b64_lb
root.find('BitstreamMD5').text = bitstream_md5
# Write BIN file
bitstream = base64.b64decode(root.find('Bitstream').text)
if (options.output_lvbitx_path is not None and md5.new(bitstream).hexdigest() != root.find('BitstreamMD5').text):
print 'ERROR: The MD5 sum for the output LVBITX was incorrect. Make sure that the bitstream in the input LVBITX or BIN file is valid.'
sys.exit(1)
if (options.output_bin is not None):
fpga_bin_file = open(options.output_bin, 'w')
fpga_bin_file.write(bitstream)
fpga_bin_file.close()
# Save LVBITX
if (options.output_lvbitx_path is not None):
tree.write(options.output_lvbitx_path, encoding="utf-8", xml_declaration=True, default_namespace=None, method="xml")
+22
View File
@@ -0,0 +1,22 @@
//
// Copyright 2013 Ettus Research LLC
//
module data_swapper_64 (
input [2:0] swap_lanes,
input [63:0] i_tdata,
output [63:0] o_tdata
);
localparam SWAP_32B = 3'b100;
localparam SWAP_16B = 3'b010;
localparam SWAP_8B = 3'b001;
wire [63:0] data_p1, data_p2;
assign data_p1 = (|(swap_lanes & SWAP_32B)) ? { i_tdata[31:0], i_tdata[63:32] } : i_tdata;
assign data_p2 = (|(swap_lanes & SWAP_16B)) ? { data_p1[47:32], data_p1[63:48], data_p1[15:0], data_p1[31:16] } : data_p1;
assign o_tdata = (|(swap_lanes & SWAP_8B)) ? { data_p2[55:48], data_p2[63:56], data_p2[39:32], data_p2[47:40],
data_p2[23:16], data_p2[31:24], data_p2[7:0], data_p2[15:8] } : data_p2;
endmodule // data_swapper_64
+49
View File
@@ -0,0 +1,49 @@
//
// Copyright 2013 Ettus Research LLC
//
//Message format:
// msg[63]: Completion {1 -> Read Completion, 0 -> Transaction Request}
// msg[62]: Write request*
// msg[61]: Read request*
// msg[60]: Half word {1 -> 16-bit transaction, 0 -> 32-bit transaction}*
// msg[59:52]: Reserved
// msg[51:32]: Address*
// msg[31:0]: Data
//
// * Field only valid when the word is a transaction request.
module ioport2_msg_decode(
input [63:0] message,
output rd_response,
output wr_request,
output rd_request,
output half_word,
output [19:0] address,
output [31:0] data,
output [31:0] control
);
assign rd_response = message[63];
assign wr_request = message[62];
assign rd_request = message[61];
assign half_word = message[60];
assign address = message[51:32];
assign data = message[31:0];
assign control = message[63:32];
endmodule
module ioport2_msg_encode(
input rd_response,
input wr_request,
input rd_request,
input half_word,
input [19:0] address,
input [31:0] data,
output [31:0] control,
output [63:0] message
);
assign control = rd_response ? {rd_response, 31'h0} : {rd_response, wr_request, rd_request, half_word, 8'h00, address};
assign message = {control, data};
endmodule
+196
View File
@@ -0,0 +1,196 @@
//
// Copyright 2013 Ettus Research LLC
//
module pcie_axi_wb_conv #(
parameter WB_ADDRW = 16,
parameter WB_DATAW = 32
)(
input clk,
input rst,
input wb_stb_i,
input wb_we_i,
input [WB_ADDRW-1:0] wb_adr_i,
input [WB_DATAW-1:0] wb_dat_i,
output wb_ack_o,
output [WB_DATAW-1:0] wb_dat_o,
input [63:0] msgi_tdata,
input msgi_tvalid,
output msgi_tready,
output [63:0] msgo_tdata,
output msgo_tvalid,
input msgo_tready,
output wb_monitor_active,
output reg wb_req_pending,
output reg wb_resp_pending,
output reg pcie_resp_pending
);
localparam SB_ADDRW = 4;
localparam SB_DATAW = 32;
localparam MONITOR_TIMEOUTW = 20; //20bits@175MHz ~ 6ms
localparam SR_PCIE_DATA_REG = 4'd0;
localparam SR_PCIE_CTRL_REG = 4'd1;
localparam RB_PCIE_DATA_REG = 4'd0;
localparam RB_PCIE_CTRL_REG = 4'd1;
localparam RB_PCIE_RESP_DATA_REG = 4'd2;
localparam RB_PCIE_STATUS_REG = 4'd3;
//------------------------------------------
// Settings and readback bus
//
wire [SB_DATAW-1:0] set_data, rb_data;
wire [SB_ADDRW-1:0] set_addr, rb_addr;
wire set_stb, rb_stb;
settings_bus #(.AWIDTH(WB_ADDRW), .DWIDTH(WB_DATAW)) settings_bus (
.wb_clk(clk), .wb_rst(rst),
.wb_adr_i(wb_adr_i), .wb_dat_i(wb_dat_i),
.wb_stb_i(wb_stb_i), .wb_we_i(wb_we_i), .wb_ack_o(wb_ack_o),
.strobe(set_stb), .addr(set_addr), .data(set_data)
);
settings_readback #(.AWIDTH(WB_ADDRW), .DWIDTH(WB_DATAW), .RB_ADDRW(SB_ADDRW)) settings_readback (
.wb_clk(clk), .wb_rst(rst),
.wb_adr_i(wb_adr_i), .wb_stb_i(wb_stb_i), .wb_we_i(wb_we_i),
.rb_data(rb_data), .rb_addr(rb_addr), .rb_rd_stb(rb_stb),
.wb_dat_o(wb_dat_o)
);
//------------------------------------------
//------------------------------------------
// Settings/Readback Registers
//
wire [31:0] axi_out_data, axi_out_ctrl;
wire axi_out_stb;
setting_reg #(.my_addr(SR_PCIE_DATA_REG), .awidth(SB_ADDRW), .width(SB_DATAW)) set_pcie_out_data_reg (
.clk(clk), .rst(rst),
.strobe(set_stb), .addr(set_addr), .in(set_data),
.out(axi_out_data)
);
setting_reg #(.my_addr(SR_PCIE_CTRL_REG), .awidth(SB_ADDRW), .width(SB_DATAW)) set_pcie_out_ctrl_reg (
.clk(clk), .rst(rst),
.strobe(set_stb), .addr(set_addr), .in(set_data),
.out(axi_out_ctrl), .changed(axi_out_stb)
);
reg [31:0] axi_in_data_reg, axi_in_ctrl_reg, axi_in_resp_reg;
wire msgo_fifo_tready;
// Readback MUX
assign rb_data = (
(rb_addr == RB_PCIE_STATUS_REG) ? {27'h0, ~msgo_fifo_tready, 1'b0, wb_resp_pending, wb_req_pending, pcie_resp_pending} : (
(rb_addr == RB_PCIE_RESP_DATA_REG) ? axi_in_resp_reg : (
(rb_addr == RB_PCIE_DATA_REG) ? axi_in_data_reg : (
(rb_addr == RB_PCIE_CTRL_REG) ? axi_in_ctrl_reg : 32'h0))));
//------------------------------------------
//------------------------------------------
// Output message handler
//
wire [63:0] msgo_fifo_tdata;
wire axi_out_rd, axi_out_wr, axi_out_rr;
assign msgo_fifo_tdata = {axi_out_ctrl, axi_out_data};
axi_fifo_short #(.WIDTH(64)) wb_out_msg_fifo (
.clk(clk), .reset(rst), .clear(1'b0),
.i_tdata(msgo_fifo_tdata), .i_tvalid(axi_out_stb), .i_tready(msgo_fifo_tready),
.o_tdata(msgo_tdata), .o_tvalid(msgo_tvalid), .o_tready(msgo_tready),
.space(), .occupied());
ioport2_msg_decode axi_out_decoder (
.message(msgo_fifo_tdata),
.rd_response(axi_out_rr), .wr_request(axi_out_wr), .rd_request(axi_out_rd)
);
//------------------------------------------
//------------------------------------------
// Input message handler
//
wire [63:0] msgi_fifo_tdata;
wire axi_in_valid, axi_in_stb;
wire [31:0] axi_in_data, axi_in_ctrl;
wire axi_in_rd, axi_in_wr, axi_in_rr;
axi_fifo_short #(.WIDTH(64)) wb_in_msg_fifo (
.clk(clk), .reset(rst), .clear(1'b0),
.i_tdata(msgi_tdata), .i_tvalid(msgi_tvalid), .i_tready(msgi_tready),
.o_tdata(msgi_fifo_tdata), .o_tvalid(axi_in_valid), .o_tready(axi_in_stb),
.space(), .occupied());
ioport2_msg_decode axi_in_decoder (
.message(msgi_fifo_tdata),
.rd_response(axi_in_rr), .wr_request(axi_in_wr), .rd_request(axi_in_rd),
.data(axi_in_data), .control(axi_in_ctrl)
);
assign axi_in_stb = axi_in_valid & (axi_in_rr | ((axi_in_wr | axi_in_rd) & ~(wb_req_pending | wb_resp_pending)));
always @(posedge clk) begin
if (rst) begin
axi_in_data_reg <= 32'h0;
axi_in_ctrl_reg <= 32'h0;
axi_in_resp_reg <= 32'h0;
end else begin
if (axi_in_stb & axi_in_rr) begin
axi_in_resp_reg <= axi_in_data;
end else if (axi_in_stb & (axi_in_wr | axi_in_rd)) begin
axi_in_data_reg <= axi_in_data;
axi_in_ctrl_reg <= axi_in_ctrl;
end
end
end
//------------------------------------------
//------------------------------------------
// State handler
//
//wb_monitor_active
reg [MONITOR_TIMEOUTW-1:0] wb_monitor_timeout;
assign wb_monitor_active = (wb_monitor_timeout != {(MONITOR_TIMEOUTW){1'b0}});
always @(posedge clk) begin
if (rst)
wb_monitor_timeout <= {(MONITOR_TIMEOUTW){1'b0}}; //Monitor disabled on rst
else if (rb_stb && (rb_addr == RB_PCIE_STATUS_REG))
wb_monitor_timeout <= {(MONITOR_TIMEOUTW){1'b1}}; //Reset counter when the ZPU queries the status reg
else if (wb_monitor_active)
wb_monitor_timeout <= wb_monitor_timeout - 1; //Decrement counter when idle
end
//wb_req_pending
always @(posedge clk) begin
if (rst || (rb_stb && (rb_addr == RB_PCIE_CTRL_REG)))
wb_req_pending <= 1'b0;
else if (axi_in_stb & (axi_in_rd | axi_in_wr))
wb_req_pending <= 1'b1;
end
//wb_resp_pending
always @(posedge clk) begin
if (rst | (axi_out_stb & msgo_fifo_tready & axi_out_rr))
wb_resp_pending <= 1'b0;
else if (axi_in_stb & axi_in_rd)
wb_resp_pending <= 1'b1;
end
//pcie_resp_pending
always @(posedge clk) begin
if (rst | (axi_in_stb & axi_in_rr))
pcie_resp_pending <= 1'b0;
else if (axi_out_stb & msgo_fifo_tready & axi_out_rd)
pcie_resp_pending <= 1'b1;
end
//------------------------------------------
endmodule
+103
View File
@@ -0,0 +1,103 @@
//
// Copyright 2013 Ettus Research LLC
//
module pcie_basic_regs (
input clk,
input reset,
input [63:0] regi_tdata,
input regi_tvalid,
output regi_tready,
output [63:0] rego_tdata,
output rego_tvalid,
input rego_tready,
input [31:0] misc_status
);
localparam PCIE_FPGA_SIG_VAL = 32'h58333030; //X300 (ASCII)
localparam PCIE_FPGA_COUNTER_FREQ = 32'h0A6E49C0; //175MHz
localparam PCIE_REG_ADDR_MASK = 20'h001FF;
localparam PCIE_FPGA_SIG_REG_ADDR = 20'h00000; //32-bit
localparam PCIE_FPGA_COUNTER_LO_REG_ADDR = 20'h00004; //32-bit
localparam PCIE_FPGA_COUNTER_HI_REG_ADDR = 20'h00008; //32-bit
localparam PCIE_FPGA_COUNTER_FREQ_ADDR = 20'h0000C; //32-bit
localparam PCIE_FPGA_SCRATCH0_ADDR = 20'h00010; //32-bit
localparam PCIE_FPGA_SCRATCH1_ADDR = 20'h00014; //32-bit
localparam PCIE_FPGA_MISC_STATUS_ADDR = 20'h00020; //32-bit
localparam PCIE_FPGA_USR_SIG_REG_ADDR = 20'h00030; //128-bit
wire regi_wr, regi_rd;
wire [19:0] regi_addr, regi_addr_local;
wire [31:0] regi_payload;
reg [31:0] rego_payload;
ioport2_msg_decode regi_decoder (
.message(regi_tdata), .wr_request(regi_wr), .rd_request(regi_rd),
.address(regi_addr), .data(regi_payload)
);
ioport2_msg_encode rego_encoder (
.rd_response(1'b1), .data(rego_payload), .message(rego_tdata)
);
assign regi_tready = (regi_tvalid & regi_wr) | rego_tready;
assign rego_tvalid = regi_tvalid & regi_rd;
assign regi_addr_local = regi_addr & PCIE_REG_ADDR_MASK;
//Counter counting bus_clk cycles
reg [63:0] bus_counter;
always @(posedge clk) begin
if (reset) bus_counter <= 64'h0;
else bus_counter <= bus_counter + 1;
end
//Scratch registers
reg [63:0] scratch;
always @(posedge clk) begin
if (reset)
scratch <= 64'h0;
else if (regi_tvalid & regi_tready & regi_wr)
if (regi_addr_local == PCIE_FPGA_SCRATCH0_ADDR)
scratch[31:0] <= regi_payload;
else if (regi_addr_local == PCIE_FPGA_SCRATCH1_ADDR)
scratch[63:32] <= regi_payload;
end
//User signature register
reg [127:0] usr_signature;
always @(posedge clk) begin
if (reset)
usr_signature <= 128'h0;
else if (regi_tvalid & regi_tready & regi_wr)
if (regi_addr_local == (PCIE_FPGA_USR_SIG_REG_ADDR + 20'h00000))
usr_signature[31:0] <= regi_payload;
else if (regi_addr_local == (PCIE_FPGA_USR_SIG_REG_ADDR + 20'h00004))
usr_signature[63:32] <= regi_payload;
else if (regi_addr_local == (PCIE_FPGA_USR_SIG_REG_ADDR + 20'h00008))
usr_signature[95:64] <= regi_payload;
else if (regi_addr_local == (PCIE_FPGA_USR_SIG_REG_ADDR + 20'h0000C))
usr_signature[127:96] <= regi_payload;
end
always @(*) begin
case (regi_addr_local)
PCIE_FPGA_SIG_REG_ADDR: rego_payload = PCIE_FPGA_SIG_VAL;
PCIE_FPGA_COUNTER_LO_REG_ADDR: rego_payload = bus_counter[31:0];
PCIE_FPGA_COUNTER_HI_REG_ADDR: rego_payload = bus_counter[63:32];
PCIE_FPGA_COUNTER_FREQ_ADDR: rego_payload = PCIE_FPGA_COUNTER_FREQ;
PCIE_FPGA_SCRATCH0_ADDR: rego_payload = scratch[31:0];
PCIE_FPGA_SCRATCH1_ADDR: rego_payload = scratch[63:32];
PCIE_FPGA_MISC_STATUS_ADDR: rego_payload = misc_status;
PCIE_FPGA_USR_SIG_REG_ADDR + 20'h00000: rego_payload = usr_signature[31:0];
PCIE_FPGA_USR_SIG_REG_ADDR + 20'h00004: rego_payload = usr_signature[63:32];
PCIE_FPGA_USR_SIG_REG_ADDR + 20'h00008: rego_payload = usr_signature[95:64];
PCIE_FPGA_USR_SIG_REG_ADDR + 20'h0000C: rego_payload = usr_signature[127:96];
default: rego_payload = 32'hFFFFFFFF;
endcase
end
endmodule
+156
View File
@@ -0,0 +1,156 @@
//
// Copyright 2013 Ettus Research LLC
//
`define BIT_WIDTH(N) (\
N <= 2 ? 1 : \
N <= 4 ? 2 : \
N <= 8 ? 3 : \
N <= 16 ? 4 : \
N <= 32 ? 5 : \
N <= 64 ? 6 : \
N <= 128 ? 7 : \
N <= 256 ? 8 : \
N <= 512 ? 9 : \
10)
`define GET_REG_OFFSET(reg_addr, chan_idx) (((chan_idx * (1<<DMA_REG_GRP_W)) + reg_addr) + REG_BASE_ADDR)
`define EXTRACT_CHAN_NUM(reg_addr) regi_addr[`BIT_WIDTH(NUM_STREAMS)+DMA_REG_GRP_W-1:DMA_REG_GRP_W]
module pcie_dma_ctrl #(
parameter NUM_STREAMS = 4,
parameter FRAME_SIZE_W = 16,
parameter REG_BASE_ADDR = 20'h00000,
parameter ENABLE_ROUTER = 0,
parameter ROUTER_SID_W = 8,
parameter ROUTER_DST_W = 2
) (
input clk,
input reset,
input [63:0] regi_tdata,
input regi_tvalid,
output regi_tready,
output [63:0] rego_tdata,
output rego_tvalid,
input rego_tready,
output reg [NUM_STREAMS-1:0] set_clear,
output [(NUM_STREAMS*FRAME_SIZE_W)-1:0] set_frame_size,
output [(NUM_STREAMS*3)-1:0] swap_lanes,
input [NUM_STREAMS-1:0] packet_stb,
input [NUM_STREAMS-1:0] sample_stb,
input [NUM_STREAMS-1:0] stream_err,
input [ROUTER_SID_W-1:0] rtr_sid,
output [ROUTER_DST_W-1:0] rtr_dst
);
localparam DMA_REG_GRP_W = 4;
localparam DMA_CTRL_STATUS_REG = 4'h0; //[RW] R: Stream Error, W: Reset stream
localparam DMA_FSIZE_REG = 4'h4; //[RW] R: Frame Size, W: Frame Size
localparam DMA_SAMP_CNT_REG = 4'h8; //[RW] R: Sample Count, W: Reset Count to 0
localparam DMA_PKT_CNT_REG = 4'hC; //[RW] R: Packet Count, W: Reset Count to 0
localparam DEFAULT_FSIZE = 32;
//NOTE: Although this module supports these, the 8 and 16 bit modes will be disabled for efficiency
localparam DMA_CTRL_BUF_SIZE_8 = 2'b00; // 8-bit wide SW buffer
localparam DMA_CTRL_BUF_SIZE_16 = 2'b01; //16-bit wide SW buffer
localparam DMA_CTRL_BUF_SIZE_32 = 2'b10; //32-bit wide SW buffer
localparam DMA_CTRL_BUF_SIZE_64 = 2'b11; //64-bit wide SW buffer
wire regi_wr, regi_rd;
wire [19:0] regi_addr;
wire [31:0] regi_payload;
wire [31:0] rego_payload;
ioport2_msg_decode regi_decoder (
.message(regi_tdata), .wr_request(regi_wr), .rd_request(regi_rd),
.address(regi_addr), .data(regi_payload)
);
ioport2_msg_encode rego_encoder (
.rd_response(1'b1), .data(rego_payload), .message(rego_tdata)
);
reg [31:0] pkt_count_mem[0:NUM_STREAMS-1];
reg [31:0] samp_count_mem[0:NUM_STREAMS-1];
reg [FRAME_SIZE_W-1:0] frame_size_mem[0:NUM_STREAMS-1];
reg [NUM_STREAMS-1:0] sw_buf_width_mem;
genvar i;
generate
for (i=0; i<NUM_STREAMS; i=i+1) begin: dma_ctrl_logic_generator
//Memory -> output translations
assign set_frame_size[(FRAME_SIZE_W*(i+1))-1:(FRAME_SIZE_W*i)] = frame_size_mem[i];
assign swap_lanes[(3*(i+1))-1:(3*i)] = { ~(sw_buf_width_mem[i]), 2'b00 }; //Optimized for only 2 modes
//Setting registers
always @(posedge clk) begin
if (reset) begin
frame_size_mem[i] <= DEFAULT_FSIZE;
set_clear[i] <= 0;
sw_buf_width_mem[i] <= 1;
end else if (regi_tready & regi_tvalid & regi_wr) begin
if (regi_addr == `GET_REG_OFFSET(DMA_CTRL_STATUS_REG, i)) begin
set_clear[i] <= regi_payload[0]; //DMA_CTRL_STATUS_REG[0] == Clear DMA queues
sw_buf_width_mem[i] <= regi_payload[4]; //DMA_CTRL_STATUS_REG[5:4] == SW Buffer Size (See note above)
end else if (regi_addr == `GET_REG_OFFSET(DMA_FSIZE_REG, i)) begin
frame_size_mem[i] <= regi_payload[FRAME_SIZE_W-1:0]; //DMA_FSIZE_REG[14:0] == DMA Frame size
set_clear[i] <= 1;
end
end else begin
set_clear[i] <= 0; //set_clear should be "self-clearing"
end
end
//Packet counter
always @(posedge clk) begin
if (reset | (regi_tvalid && regi_wr && (regi_addr == `GET_REG_OFFSET(DMA_PKT_CNT_REG, i)))) begin
pkt_count_mem[i] <= 0;
end else if (packet_stb[i]) begin
pkt_count_mem[i] <= pkt_count_mem[i] + 1;
end
end
//Sample counter
always @(posedge clk) begin
if (reset | (regi_tvalid && regi_wr && (regi_addr == `GET_REG_OFFSET(DMA_SAMP_CNT_REG, i)))) begin
samp_count_mem[i] <= 0;
end else if (sample_stb[i]) begin
samp_count_mem[i] <= samp_count_mem[i] + 1;
end
end
end
endgenerate
//Readback
assign rego_payload =
(regi_addr[DMA_REG_GRP_W-1:0] == DMA_PKT_CNT_REG) ? pkt_count_mem[`EXTRACT_CHAN_NUM(regi_addr)] : (
(regi_addr[DMA_REG_GRP_W-1:0] == DMA_SAMP_CNT_REG) ? samp_count_mem[`EXTRACT_CHAN_NUM(regi_addr)] : (
(regi_addr[DMA_REG_GRP_W-1:0] == DMA_FSIZE_REG) ? frame_size_mem[`EXTRACT_CHAN_NUM(regi_addr)] : (
(regi_addr[DMA_REG_GRP_W-1:0] == DMA_CTRL_STATUS_REG) ? {31'h0, stream_err[`EXTRACT_CHAN_NUM(regi_addr)]} : (
32'hFFFFFFFF))));
assign rego_tvalid = regi_tvalid && regi_rd;
assign regi_tready = rego_tready || (regi_tvalid && regi_wr);
//Optional router
if (ENABLE_ROUTER == 1) begin
pcie_pkt_route_specifier #(
.BASE_ADDR((1<<ROUTER_SID_W) + REG_BASE_ADDR), .ADDR_MASK(20'hFFFFF^((1<<ROUTER_SID_W)-1)),
.SID_WIDTH(ROUTER_SID_W), .DST_WIDTH(ROUTER_DST_W)
) route_specifier (
.clk(clk), .reset(reset),
.regi_tdata(regi_tdata), .regi_tvalid(regi_tvalid), .regi_tready(),
.local_sid(rtr_sid), .fifo_dst(rtr_dst)
);
end
endmodule
`undef EXTRACT_CHAN_NUM
`undef GET_REG_OFFSET
`undef BIT_WIDTH
+89
View File
@@ -0,0 +1,89 @@
//
// Copyright 2013 Ettus Research LLC
//
`timescale 500ps/1ps
module pcie_dma_ctrl_tb();
reg clk = 0;
reg reset = 1;
always #10 clk = ~clk;
initial begin
#100 reset = 0;
#200000;
$finish;
end
function [63:0] iop2_msg_write;
input [19:0] address;
input [31:0] data;
input half_wd;
begin
// {rd_response, wr_request, rd_request, half_word, 8'h00, address, data};
iop2_msg_write = {1'b0, 1'b1, 1'b0, half_wd, 8'h00, address, data};
end
endfunction // iop2_msg_write
function [63:0] iop2_msg_read;
input [19:0] address;
input half_wd;
begin
// {rd_response, wr_request, rd_request, half_word, 8'h00, address, data};
iop2_msg_read = {1'b0, 1'b0, 1'b1, half_wd, 8'h00, address, 32'h0};
end
endfunction // iop2_msg_read
wire [3:0] clear;
wire [63:0] frame_size;
reg [3:0] pkt_stb = 0;
reg [3:0] samp_stb = 0;
reg [3:0] error = 0;
reg [7:0] rtr_sid = 4;
wire [3:0] rtr_dst;
reg [63:0] regi_tdata;
reg regi_tvalid;
wire regi_tready;
wire [63:0] rego_tdata;
wire rego_tvalid;
reg rego_tready;
reg [31:0] rego_payload;
always @(posedge clk)
if (rego_tdata[63] & rego_tvalid & rego_tready)
rego_payload <= rego_tdata[31:0];
initial begin
regi_tvalid <= 0;
rego_tready <= 0;
while (reset) @(posedge clk);
rego_tready <= 1;
@(posedge clk);
regi_tdata <= iop2_msg_write(20'h304, 32'hA, 0);
regi_tvalid <= 1;
@(posedge clk);
while (~regi_tready) @(posedge clk);
regi_tvalid <= 0;
@(posedge clk);
end // initial begin
pcie_dma_ctrl #(
.NUM_STREAMS(4), .FRAME_SIZE_W(16),
.REG_BASE_ADDR(20'h00200), .ENABLE_ROUTER(1),
.ROUTER_SID_W(8), .ROUTER_DST_W(4)
) dut (
.clk(clk), .reset(reset),
.regi_tdata(regi_tdata), .regi_tvalid(regi_tvalid), .regi_tready(regi_tready),
.rego_tdata(rego_tdata), .rego_tvalid(rego_tvalid), .rego_tready(rego_tready),
.set_clear(clear), .set_frame_size(frame_size), .sample_stb(samp_stb), .packet_stb(pkt_stb),
.stream_err(error), .rtr_sid(rtr_sid), .rtr_dst(rtr_dst)
);
endmodule
+131
View File
@@ -0,0 +1,131 @@
//
// Copyright 2013 Ettus Research LLC
//
module pcie_iop2_msg_arbiter #(
parameter E0_ADDR = 20'h0,
parameter E0_MASK = 20'h0,
parameter E1_ADDR = 20'h0,
parameter E1_MASK = 20'h0,
parameter E2_ADDR = 20'h0,
parameter E2_MASK = 20'h0,
parameter E3_ADDR = 20'h0,
parameter E3_MASK = 20'h0
) (
//Clocks and resets
input clk,
input reset,
input [63:0] regi_tdata,
input regi_tvalid,
output regi_tready,
output [63:0] rego_tdata,
output rego_tvalid,
input rego_tready,
output [63:0] e0_regi_tdata,
output e0_regi_tvalid,
input e0_regi_tready,
input [63:0] e0_rego_tdata,
input e0_rego_tvalid,
output e0_rego_tready,
output [63:0] e1_regi_tdata,
output e1_regi_tvalid,
input e1_regi_tready,
input [63:0] e1_rego_tdata,
input e1_rego_tvalid,
output e1_rego_tready,
output [63:0] e2_regi_tdata,
output e2_regi_tvalid,
input e2_regi_tready,
input [63:0] e2_rego_tdata,
input e2_rego_tvalid,
output e2_rego_tready,
output [63:0] e3_regi_tdata,
output e3_regi_tvalid,
input e3_regi_tready,
input [63:0] e3_rego_tdata,
input e3_rego_tvalid,
output e3_rego_tready
);
//*******************************************************************************
// PCIe output message arbiter
//
axi_mux4 #(.PRIO(0), .WIDTH(64), .BUFFER(0)) rego_arbiter_mux (
.clk(clk), .reset(reset), .clear(1'b0),
.i0_tdata(e0_rego_tdata), .i0_tlast(e0_rego_tvalid), .i0_tvalid(e0_rego_tvalid), .i0_tready(e0_rego_tready),
.i1_tdata(e1_rego_tdata), .i1_tlast(e1_rego_tvalid), .i1_tvalid(e1_rego_tvalid), .i1_tready(e1_rego_tready),
.i2_tdata(e2_rego_tdata), .i2_tlast(e2_rego_tvalid), .i2_tvalid(e2_rego_tvalid), .i2_tready(e2_rego_tready),
.i3_tdata(e3_rego_tdata), .i3_tlast(e3_rego_tvalid), .i3_tvalid(e3_rego_tvalid), .i3_tready(e3_rego_tready),
.o_tdata(rego_tdata), .o_tlast(), .o_tvalid(rego_tvalid), .o_tready(rego_tready)
);
//
//*******************************************************************************
//*******************************************************************************
// PCIe input message arbiter
//
wire [63:0] regi_msg;
wire regi_rc;
wire [19:0] regi_addr;
wire e0_rego_rd, e1_rego_rd, e2_rego_rd, e3_rego_rd;
ioport2_msg_decode e0_rego_decoder (.message(e0_rego_tdata), .rd_request(e0_rego_rd));
ioport2_msg_decode e1_rego_decoder (.message(e1_rego_tdata), .rd_request(e1_rego_rd));
ioport2_msg_decode e2_rego_decoder (.message(e2_rego_tdata), .rd_request(e2_rego_rd));
ioport2_msg_decode e3_rego_decoder (.message(e3_rego_tdata), .rd_request(e3_rego_rd));
localparam DEST_E0 = 2'd0;
localparam DEST_E1 = 2'd1;
localparam DEST_E2 = 2'd2;
localparam DEST_E3 = 2'd3;
reg [1:0] regi_resp_dest;
wire [1:0] regi_req_dest, regi_dest;
assign regi_req_dest =
((regi_addr & E0_MASK) == E0_ADDR) ? DEST_E0 : (
((regi_addr & E1_MASK) == E1_ADDR) ? DEST_E1 : (
((regi_addr & E2_MASK) == E2_ADDR) ? DEST_E2 : (
((regi_addr & E3_MASK) == E3_ADDR) ? DEST_E3 : (
DEST_E0))));
//A response must be routed to the port with the last read request
always @(posedge clk) begin
if (reset)
regi_resp_dest <= DEST_E0; //Default 0
else if (e0_rego_tvalid & e0_rego_tready & e0_rego_rd)
regi_resp_dest <= DEST_E0;
else if (e1_rego_tvalid & e1_rego_tready & e1_rego_rd)
regi_resp_dest <= DEST_E1;
else if (e2_rego_tvalid & e2_rego_tready & e2_rego_rd)
regi_resp_dest <= DEST_E2;
else if (e3_rego_tvalid & e3_rego_tready & e3_rego_rd)
regi_resp_dest <= DEST_E3;
end
ioport2_msg_decode regi_decoder (
.message(regi_msg), .rd_response(regi_rc), .address(regi_addr));
//If request, get destination from msg.
//If response, get destination from last read location.
assign regi_dest = regi_rc ? regi_resp_dest : regi_req_dest;
axi_demux4 #(.ACTIVE_CHAN(4'b1111), .WIDTH(64), .BUFFER(0)) regi_arbiter_demux (
.clk(clk), .reset(reset), .clear(1'b0),
.header(regi_msg), .dest(regi_dest),
.i_tdata(regi_tdata), .i_tlast(regi_tvalid), .i_tvalid(regi_tvalid), .i_tready(regi_tready),
.o0_tdata(e0_regi_tdata), .o0_tlast(), .o0_tvalid(e0_regi_tvalid), .o0_tready(e0_regi_tready),
.o1_tdata(e1_regi_tdata), .o1_tlast(), .o1_tvalid(e1_regi_tvalid), .o1_tready(e1_regi_tready),
.o2_tdata(e2_regi_tdata), .o2_tlast(), .o2_tvalid(e2_regi_tvalid), .o2_tready(e2_regi_tready),
.o3_tdata(e3_regi_tdata), .o3_tlast(), .o3_tvalid(e3_regi_tvalid), .o3_tready(e3_regi_tready)
);
//
//*******************************************************************************
endmodule
+107
View File
@@ -0,0 +1,107 @@
//
// Copyright 2013 Ettus Research LLC
//
`timescale 500ps/1ps
module pcie_iop2_msg_arbiter_tb();
reg clk = 0;
reg reset = 1;
always #10 clk = ~clk;
initial begin
#100 reset = 0;
#200000;
$finish;
end
function [63:0] iop2_msg_write;
input [19:0] address;
input [31:0] data;
input half_wd;
begin
// {rd_response, wr_request, rd_request, half_word, 8'h00, address, data};
iop2_msg_write = {1'b0, 1'b1, 1'b0, half_wd, 8'h00, address, data};
end
endfunction // iop2_msg_write
function [63:0] iop2_msg_read;
input [19:0] address;
input half_wd;
begin
// {rd_response, wr_request, rd_request, half_word, 8'h00, address, data};
iop2_msg_read = {1'b0, 1'b0, 1'b1, half_wd, 8'h00, address, 32'h0};
end
endfunction // iop2_msg_read
reg [63:0] msgi_tdata;
wire [63:0] msgo_tdata;
wire msgo_tvalid, msgi_tready;
reg msgo_tready, msgi_tvalid;
wire [63:0] basic_regi_tdata, zpu_regi_tdata;
wire basic_regi_tvalid, zpu_regi_tvalid;
reg basic_regi_tready, zpu_regi_tready;
reg [63:0] basic_rego_tdata, zpu_rego_tdata;
reg basic_rego_tvalid, zpu_rego_tvalid;
wire basic_rego_tready, zpu_rego_tready;
initial begin
//@TODO: Make this a self-checking TB
while (reset) @(posedge clk);
msgo_tready <= 1;
basic_regi_tready <= 1;
@(posedge clk);
msgi_tdata <= iop2_msg_write(20'h0, 32'hDEAD, 0);
msgi_tvalid <= 1;
while (~msgi_tready) @(posedge clk);
msgi_tvalid <= 0;
@(posedge clk);
msgi_tdata <= iop2_msg_read(20'h00000, 0);
msgi_tvalid <= 1;
while (~msgi_tready) @(posedge clk);
msgi_tvalid <= 0;
@(posedge clk);
zpu_rego_tdata <= {1, 31'h0, 32'h12345678};
zpu_rego_tvalid <= 1;
while (~zpu_rego_tready) @(posedge clk);
zpu_rego_tvalid <= 0;
end // initial begin
pcie_iop2_msg_arbiter #(
.E0_ADDR(20'h00000), .E0_MASK(20'hFFF00), //0x00000 - 0x000FF: Basic PCIe registers
.E1_ADDR(20'h00100), .E1_MASK(20'hFFF00), //0x00100 - 0x001FF: PCIe router registers
.E2_ADDR(20'h00200), .E2_MASK(20'hFFE00), //0x00200 - 0x003FF: DMA stream registers
.E3_ADDR(20'h40000), .E3_MASK(20'hC0000) //0x40000 - 0x7FFFF: Client address space
) iop2_msg_arbiter (
.clk(clk), .reset(reset),
//Master
.regi_tdata(msgi_tdata), .regi_tvalid(msgi_tvalid), .regi_tready(msgi_tready),
.rego_tdata(msgo_tdata), .rego_tvalid(msgo_tvalid), .rego_tready(msgo_tready),
//Endpoint 0
.e0_regi_tdata(basic_regi_tdata), .e0_regi_tvalid(basic_regi_tvalid), .e0_regi_tready(basic_regi_tready),
.e0_rego_tdata(basic_rego_tdata), .e0_rego_tvalid(basic_rego_tvalid), .e0_rego_tready(basic_rego_tready),
//Endpoint 1
.e1_regi_tdata(), .e1_regi_tvalid(), .e1_regi_tready(1'b1),
.e1_rego_tdata(64'h0), .e1_rego_tvalid(1'b0), .e1_rego_tready(),
//Endpoint 2
.e2_regi_tdata(), .e2_regi_tvalid(), .e2_regi_tready(1'b1),
.e2_rego_tdata(64'h0), .e2_rego_tvalid(1'b0), .e2_rego_tready(),
//Endpoint 3
.e3_regi_tdata(zpu_regi_tdata), .e3_regi_tvalid(zpu_regi_tvalid), .e3_regi_tready(zpu_regi_tready),
.e3_rego_tdata(zpu_rego_tdata), .e3_rego_tvalid(zpu_rego_tvalid), .e3_rego_tready(zpu_rego_tready)
);
endmodule
+43
View File
@@ -0,0 +1,43 @@
//
// Copyright 2013 Ettus Research LLC
//
module pcie_pkt_route_specifier #(
parameter BASE_ADDR = 20'h0,
parameter ADDR_MASK = 20'hFFF00,
parameter SID_WIDTH = 8,
parameter DST_WIDTH = 4
) (
input clk,
input reset,
input [63:0] regi_tdata,
input regi_tvalid,
output regi_tready,
input [SID_WIDTH-1:0] local_sid,
output [DST_WIDTH-1:0] fifo_dst
);
// Routing table
reg [DST_WIDTH-1:0] routing_table[0:(1<<SID_WIDTH)-1];
assign fifo_dst = routing_table[local_sid];
wire reg_wr;
wire [19:0] reg_addr;
wire [31:0] reg_data;
// Routing table configuration
ioport2_msg_decode config_message_decoder (
.message(regi_tdata), .wr_request(reg_wr), .rd_request(reg_rd), .address(reg_addr), .data(reg_data)
);
always @(posedge clk) begin
if (regi_tvalid && regi_tready && reg_wr && ((reg_addr & ADDR_MASK) == BASE_ADDR)) begin
routing_table[reg_data[SID_WIDTH+15:16]] <= reg_data[DST_WIDTH-1:0];
end
end
assign regi_tready = 1;
endmodule
+126
View File
@@ -0,0 +1,126 @@
//
// Copyright 2013 Ettus Research LLC
//
module pcie_wb_reg_core #(
parameter WB_ADDRW = 16,
parameter WB_DATAW = 32
)(
input clk,
input rst,
input wb_stb_i,
input wb_we_i,
input [WB_ADDRW-1:0] wb_adr_i,
input [WB_DATAW-1:0] wb_dat_i,
output wb_ack_o,
output [WB_DATAW-1:0] wb_dat_o,
input [63:0] msgi_tdata,
input msgi_tvalid,
output msgi_tready,
output [63:0] msgo_tdata,
output msgo_tvalid,
input msgo_tready,
output [31:0] debug
);
// Parameters
localparam PCIE_REGPORT_ADDR_MASK = 20'h0FFFF;
localparam PCIE_REGPORT_DATA_ADDR = 20'h70000;
localparam PCIE_REGPORT_READ_ADDR = 20'h60000;
localparam PCIE_REGPORT_STATUS_ADDR = 20'h60000;
//------------------------------------------
// WB AXI interface
//
wire [63:0] wb_msgi_tdata, wb_msgo_tdata;
wire wb_msgi_tvalid, wb_msgi_tready, wb_msgo_tvalid, wb_msgo_tready;
wire wb_monitor_active, wb_req_pending, wb_resp_pending;
pcie_axi_wb_conv #( .WB_ADDRW(WB_ADDRW), .WB_DATAW(WB_DATAW) ) axi_wb_translator (
.clk(clk), .rst(rst),
.wb_stb_i(wb_stb_i), .wb_we_i(wb_we_i), .wb_adr_i(wb_adr_i),
.wb_dat_i(wb_dat_i), .wb_ack_o(wb_ack_o), .wb_dat_o(wb_dat_o),
.msgi_tdata(wb_msgo_tdata), .msgi_tvalid(wb_msgo_tvalid), .msgi_tready(wb_msgo_tready),
.msgo_tdata(wb_msgi_tdata), .msgo_tvalid(wb_msgi_tvalid), .msgo_tready(wb_msgi_tready),
.wb_monitor_active(wb_monitor_active), .wb_req_pending(wb_req_pending), .wb_resp_pending(wb_resp_pending)
);
//------------------------------------------
//------------------------------------------
// PCIe In -> WB Out
//
wire pcie_in_wr, pcie_in_rd, wb_out_wr, wb_out_rd;
wire pcie2wb_rr, pcie2wb_hword;
wire pcie_in_status_read, pcie_in_data_read;
wire [19:0] pcie_in_addr;
wire [31:0] pcie2wb_payload;
ioport2_msg_decode pcie_in_decoder (
.message(msgi_tdata),
.rd_response(pcie2wb_rr), .wr_request(pcie_in_wr), .rd_request(pcie_in_rd),
.half_word(pcie2wb_hword), .address(pcie_in_addr), .data(pcie2wb_payload)
);
ioport2_msg_encode wb_out_decoder (
.rd_response(pcie2wb_rr), .wr_request(wb_out_wr), .rd_request(wb_out_rd),
.half_word(pcie2wb_hword), .address(pcie_in_addr & PCIE_REGPORT_ADDR_MASK), .data(pcie2wb_payload),
.message(wb_msgo_tdata)
);
assign wb_out_wr = pcie_in_wr && ((pcie_in_addr & ~PCIE_REGPORT_ADDR_MASK) == PCIE_REGPORT_DATA_ADDR);
assign wb_out_rd = pcie_in_wr && ((pcie_in_addr & ~PCIE_REGPORT_ADDR_MASK) == PCIE_REGPORT_READ_ADDR);
assign wb_msgo_tvalid = msgi_tvalid & (wb_out_wr | wb_out_rd | pcie2wb_rr);
assign msgi_tready = pcie_out_auto_resp_valid ? pcie_out_auto_resp_ready : wb_msgo_tready;
//------------------------------------------
//------------------------------------------
// WB In -> PCIe Out
//
assign pcie_in_status_read = pcie_in_rd && ((pcie_in_addr & ~PCIE_REGPORT_ADDR_MASK) == PCIE_REGPORT_STATUS_ADDR);
assign pcie_in_data_read = pcie_in_rd && ((pcie_in_addr & ~PCIE_REGPORT_ADDR_MASK) == PCIE_REGPORT_DATA_ADDR);
reg [31:0] wb_in_resp_payload_reg;
wire wb_in_rr, wb_msgi_tready_int;
wire [63:0] pcie_out_auto_resp_data;
wire pcie_out_auto_resp_valid, pcie_out_auto_resp_ready;
wire [31:0] wb_in_resp_payload;
ioport2_msg_decode wb_in_decoder (
.message(wb_msgi_tdata), .rd_response(wb_in_rr), .data(wb_in_resp_payload)
);
assign pcie_out_auto_resp_valid = (msgi_tvalid & (pcie_in_status_read | pcie_in_data_read));
ioport2_msg_encode auto_response_encoder (
.rd_response(1'b1),
.data(pcie_in_data_read ? wb_in_resp_payload_reg : {~wb_monitor_active, 30'h0, (wb_req_pending | wb_resp_pending)}),
.message(pcie_out_auto_resp_data)
);
always @(posedge clk) begin
if (rst)
wb_in_resp_payload_reg <= 32'h0;
else if (wb_msgi_tvalid & wb_msgi_tready & wb_in_rr)
wb_in_resp_payload_reg <= wb_in_resp_payload;
end
axi_mux4 #(.PRIO(0), .WIDTH(64), .BUFFER(1)) msgo_arbiter_mux (
.clk(clk), .reset(rst), .clear(1'b0),
.i0_tdata(wb_msgi_tdata), .i0_tlast(1'b1), .i0_tvalid(wb_msgi_tvalid & ~wb_in_rr), .i0_tready(wb_msgi_tready_int),
.i1_tdata(pcie_out_auto_resp_data), .i1_tlast(1'b1), .i1_tvalid(pcie_out_auto_resp_valid), .i1_tready(pcie_out_auto_resp_ready),
.i2_tdata(0), .i2_tlast(1'b0), .i2_tvalid(1'b0), .i2_tready(),
.i3_tdata(0), .i3_tlast(1'b0), .i3_tvalid(1'b0), .i3_tready(),
.o_tdata(msgo_tdata), .o_tlast(), .o_tvalid(msgo_tvalid), .o_tready(msgo_tready)
);
assign wb_msgi_tready = wb_msgi_tready_int | (wb_msgi_tvalid & wb_in_rr);
//------------------------------------------
endmodule
+240
View File
@@ -0,0 +1,240 @@
//
// Copyright 2013 Ettus Research LLC
//
`timescale 500ps/1ps
`define CHECK_VALUE(val, expected, report) \
if (val == expected) \
$display("%s...Passed",report); \
else \
$display("%s...FAILED!!! (Val=0x%x, Exp=0x%x)",report,val,expected); \
module pcie_wb_reg_core_tb();
reg clk = 0, reset = 1;
reg wb_stb_i = 0;
reg wb_we_i = 0;
reg [15:0] wb_adr_i = 0;
reg [31:0] wb_dat_i = 0;
wire wb_ack_o;
wire [31:0] wb_dat_o;
wire [63:0] msgo_data;
wire msgo_valid;
reg msgo_ready = 0;
reg [63:0] msgi_data = 0;
reg msgi_valid = 0;
wire msgi_ready;
reg [31:0] msgo_payload = 32'h0;
reg [31:0] msgo_ctrl = 32'h0;
reg [31:0] it;
always #10 clk = ~clk;
initial begin
#100 reset = 0;
#200000;
$finish;
end
localparam READ = 3'b001;
localparam WRITE = 3'b010;
localparam RESPONSE = 3'b100;
task pcie_send;
input [2:0] op;
input [19:0] address;
input [31:0] data;
begin
//{rd_resp, wr_request, rd_request, half_word, 8'h00, address, data};
msgi_data <= {op, 1'b0, 8'h00, address, data};
msgi_valid <= 1'b1;
@(posedge clk);
while (~msgi_ready) @(posedge clk);
msgi_valid <= 1'b0;
@(posedge clk);
end
endtask // pcie_send
task pcie_recv;
input [2:0] op;
input [19:0] address;
input [31:0] data;
begin
while (~msgo_valid) @(posedge clk);
msgo_ready <= 1'b1;
@(posedge clk);
if (msgo_data[63] == op[2] || (msgo_data[62:61] == op[1:0] && msgo_data[51:32] == address))
msgo_payload <= msgo_data[31:0];
msgo_ctrl <= msgo_data[63:32];
msgo_ready <= 1'b0;
@(posedge clk);
end
endtask // pcie_recv
task wb_send;
input [2:0] op;
input [15:0] address;
input [31:0] data;
begin
wb_adr_i <= address;
wb_dat_i <= data;
wb_we_i <= op[1];
wb_stb_i <= 1'b1;
@(posedge clk);
while (~wb_ack_o) @(posedge clk);
wb_stb_i <= 1'b0;
end
endtask // pcie_send
initial begin
msgo_ready <= 1'b0;
msgi_valid <= 1'b0;
while (reset) @(posedge clk);
@(posedge clk);
$display("\n[TEST] ZPU Read from PCIe");
pcie_send(WRITE, 20'h6a000, 32'h0);
`CHECK_VALUE(msgo_payload, 32'h0, "Verify PCIe readback before initiating read request");
pcie_send(READ, 20'h6a000, 32'h0);
pcie_recv(RESPONSE, 20'h0, 20'h0);
`CHECK_VALUE(msgo_payload, 32'h1, "Verify PCIe status after initiating read");
pcie_send(READ, 20'h6a000, 32'h0);
pcie_recv(RESPONSE, 20'h0, 20'h0);
`CHECK_VALUE(msgo_payload, 32'h1, "Verify PCIe status after initiating second read");
wb_send(READ, 16'hC, 32'h0);
`CHECK_VALUE(wb_dat_o, 32'h6, "Verify WB status after PCIe read request");
wb_send(READ, 16'h4, 32'h0);
`CHECK_VALUE(wb_dat_o, 32'h2000a000, "Verify WB control value after PCIe read request");
wb_send(READ, 16'hC, 32'h0);
`CHECK_VALUE(wb_dat_o, 32'h4, "Verify WB status value after consuming PCIe read request");
pcie_send(READ, 20'h6a000, 32'h0);
pcie_recv(RESPONSE, 20'h0, 20'h0);
`CHECK_VALUE(msgo_payload, 32'h1, "Verify PCIe status after WB consumes request only");
wb_send(WRITE, 16'h0, 32'hDEADBEEF);
wb_send(WRITE, 16'h4, 32'h80000000);
wb_send(READ, 16'hC, 32'h0);
`CHECK_VALUE(wb_dat_o, 32'h0, "Verify WB status value after responding to PCIe read request");
pcie_send(READ, 20'h6a000, 32'h0);
pcie_recv(RESPONSE, 20'h0, 20'h0);
`CHECK_VALUE(msgo_payload, 32'h0, "Verify PCIe status after WB responds to read request");
pcie_send(READ, 20'h7a000, 32'h0);
pcie_recv(RESPONSE, 20'h0, 20'h0);
`CHECK_VALUE(msgo_payload, 32'hdeadbeef, "Verify PCIe read data");
$display("\n[TEST] ZPU Write from PCIe");
pcie_send(WRITE, 20'h7b000, 32'h12345678);
pcie_send(READ, 20'h7a000, 32'h0);
pcie_recv(RESPONSE, 20'h0, 20'h0);
`CHECK_VALUE(msgo_payload, 32'hdeadbeef, "Verify that PCIe read data is still intact after write");
wb_send(READ, 16'hC, 32'h0);
`CHECK_VALUE(wb_dat_o, 32'h2, "Verify WB status value after PCIe write request");
wb_send(READ, 16'h0, 32'h0);
`CHECK_VALUE(wb_dat_o, 32'h12345678, "Verify WB data value after PCIe read request");
wb_send(READ, 16'h4, 32'h0);
`CHECK_VALUE(wb_dat_o, 32'h4000b000, "Verify WB control value after PCIe read request");
wb_send(READ, 16'hC, 32'h0);
`CHECK_VALUE(wb_dat_o, 32'h0, "Verify WB status value after consuming PCIe write request");
pcie_send(READ, 20'h6a000, 32'h0);
pcie_recv(RESPONSE, 20'h0, 20'h0);
`CHECK_VALUE(msgo_payload, 32'h0, "Verify PCIe status after WB consumes request");
$display("\n[TEST] Chinch Write from ZPU");
wb_send(READ, 16'hC, 32'h0);
`CHECK_VALUE(wb_dat_o, 32'h0, "Verify WB status value before initiating write request");
wb_send(WRITE, 16'h0, 32'h00beef00);
wb_send(READ, 16'hC, 32'h0);
`CHECK_VALUE(wb_dat_o, 32'h0, "Verify WB status value after writing just the data reg");
wb_send(WRITE, 16'h4, 32'h40000200);
wb_send(READ, 16'hC, 32'h0);
`CHECK_VALUE(wb_dat_o, 32'h0, "Verify WB status value after initiating write");
pcie_recv(WRITE, 20'h200, 20'h0);
`CHECK_VALUE(msgo_payload, 32'h00beef00, "Verify received PCIe data");
`CHECK_VALUE(msgo_ctrl, 32'h40000200, "Verify received PCIe control");
wb_send(WRITE, 16'h0, 32'h00feeb00);
wb_send(WRITE, 16'h4, 32'h400002fc);
pcie_recv(WRITE, 20'h200, 20'h0);
`CHECK_VALUE(msgo_payload, 32'h00feeb00, "Verify second received PCIe data");
`CHECK_VALUE(msgo_ctrl, 32'h400002fc, "Verify second received PCIe control");
$display("\n[TEST] Chinch Read from ZPU");
wb_send(READ, 16'hC, 32'h0);
`CHECK_VALUE(wb_dat_o, 32'h0, "Verify WB status value before initiating read request");
wb_send(WRITE, 16'h0, 32'hffffffff);
wb_send(READ, 16'hC, 32'h0);
`CHECK_VALUE(wb_dat_o, 32'h0, "Verify WB status value after writing just the data reg");
wb_send(WRITE, 16'h4, 32'h20000400);
wb_send(READ, 16'hC, 32'h0);
`CHECK_VALUE(wb_dat_o, 32'h1, "Verify WB status value after initiating read request");
pcie_recv(READ, 20'h400, 20'h0);
`CHECK_VALUE(msgo_payload, 32'hffffffff, "Verify received PCIe data");
`CHECK_VALUE(msgo_ctrl, 32'h20000400, "Verify received PCIe control");
wb_send(READ, 16'hC, 32'h0);
wb_send(READ, 16'hC, 32'h0);
`CHECK_VALUE(wb_dat_o, 32'h1, "Verify WB status value before PCIe responds");
pcie_send(RESPONSE, 20'h000, 32'hace06666);
wb_send(READ, 16'hC, 32'h0);
`CHECK_VALUE(wb_dat_o, 32'h0, "Verify WB status value after PCIe responds");
wb_send(READ, 16'h8, 32'h0);
`CHECK_VALUE(wb_dat_o, 32'hace06666, "Verify WB read value after PCIe responds");
$display("\n[TEST] WB Outbound flood");
wb_send(READ, 16'hC, 32'h0);
`CHECK_VALUE(wb_dat_o, 32'h0, "Verify WB status before request flood");
for (it = 0; it < 64; it = it + 1) begin
wb_send(WRITE, 16'h4, 32'h20000400);
end
wb_send(READ, 16'hC, 32'h0);
`CHECK_VALUE(wb_dat_o, 32'h11, "Verify WB status after request flood");
for (it = 0; it < 64; it = it + 1) begin
pcie_recv(READ, 20'h400, 20'h0);
end
wb_send(READ, 16'hC, 32'h0);
`CHECK_VALUE(wb_dat_o, 32'h1, "Verify WB status after consuming requests");
$display("\n[TEST] PCIe Transaction Status");
pcie_send(READ, 20'h6a000, 32'h0);
pcie_recv(RESPONSE, 20'h0, 20'h0);
`CHECK_VALUE(msgo_payload, 32'h0, "Verify PCIe status before multiple reads");
pcie_send(WRITE, 20'h6a000, 32'h0);
pcie_send(WRITE, 20'h6a000, 32'h0);
pcie_send(WRITE, 20'h6a000, 32'h0);
pcie_send(READ, 20'h6a000, 32'h0);
pcie_recv(RESPONSE, 20'h0, 20'h0);
pcie_send(READ, 20'h6a000, 32'h0);
pcie_recv(RESPONSE, 20'h0, 20'h0);
pcie_send(READ, 20'h6a000, 32'h0);
pcie_recv(RESPONSE, 20'h0, 20'h0);
`CHECK_VALUE(msgo_payload, 32'h1, "Verify PCIe status before multiple read requests and status queries");
wb_send(READ, 16'h4, 32'h0);
wb_send(WRITE, 16'h0, 32'hDEADBEEF);
wb_send(WRITE, 16'h4, 32'h80000000);
pcie_send(READ, 20'h6a000, 32'h0);
pcie_recv(RESPONSE, 20'h0, 20'h0);
`CHECK_VALUE(msgo_payload, 32'h0, "Verify PCIe status after response");
$display("\n[DONE]");
end // initial begin
pcie_wb_reg_core #(.WB_ADDRW(16), .WB_DATAW(32)) dut (
.clk(clk), .rst(reset),
.wb_stb_i(wb_stb_i), .wb_we_i(wb_we_i), .wb_adr_i(wb_adr_i),
.wb_dat_i(wb_dat_i), .wb_ack_o(wb_ack_o), .wb_dat_o(wb_dat_o),
.msgi_tdata(msgi_data), .msgi_tvalid(msgi_valid), .msgi_tready(msgi_ready),
.msgo_tdata(msgo_data), .msgo_tvalid(msgo_valid), .msgo_tready(msgo_ready),
.debug());
endmodule