fpga: x400: Add support for X410 motherboard FPGA

Co-authored-by: Andrew Moch <Andrew.Moch@ni.com>
Co-authored-by: Daniel Jepson <daniel.jepson@ni.com>
Co-authored-by: Javier Valenzuela <javier.valenzuela@ni.com>
Co-authored-by: Joerg Hofrichter <joerg.hofrichter@ni.com>
Co-authored-by: Kumaran Subramoniam <kumaran.subramoniam@ni.com>
Co-authored-by: Max Köhler <max.koehler@ni.com>
Co-authored-by: Michael Auchter <michael.auchter@ni.com>
Co-authored-by: Paul Butler <paul.butler@ni.com>
Co-authored-by: Wade Fife <wade.fife@ettus.com>
Co-authored-by: Hector Rubio <hrubio@ni.com>


Original-commit: 6d3765605262016a80f71e36357f749ea35cbe5a
This commit is contained in:
Wade Fife
2021-06-10 11:56:58 -05:00
committed by Aaron Rossetto
co-authored by Andrew Moch Daniel Jepson Javier Valenzuela Joerg Hofrichter Kumaran Subramoniam Max Köhler Michael Auchter Paul Butler Hector Rubio
parent bfef20ea45
commit 61782b02d7
205 changed files with 299634 additions and 0 deletions
@@ -0,0 +1,186 @@
//
// Copyright 2021 Ettus Research, a National Instruments Brand
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: ctrlport_byte_deserializer
//
// Description:
// Slave interface of CtrlPort interface serialized as byte stream.
// See description in ctrlport_byte_serializer module for more details.
//
`default_nettype none
module ctrlport_byte_deserializer (
input wire ctrlport_clk,
input wire ctrlport_rst,
// Request
output wire m_ctrlport_req_wr,
output wire m_ctrlport_req_rd,
output wire [19:0] m_ctrlport_req_addr,
output wire [31:0] m_ctrlport_req_data,
// Response
input wire m_ctrlport_resp_ack,
input wire [ 1:0] m_ctrlport_resp_status,
input wire [31:0] m_ctrlport_resp_data,
// byte interface
input wire [ 7:0] bytestream_data_in,
input wire bytestream_valid_in,
input wire bytestream_direction,
output reg [ 7:0] bytestream_data_out = 8'b0,
output reg bytestream_valid_out = 1'b0,
output reg bytestream_output_enable = 1'b0
);
`include "../../../lib/rfnoc/core/ctrlport.vh"
//---------------------------------------------------------------
// transfer constants
//---------------------------------------------------------------
// derived from transaction specification
localparam NUM_BYTES_RX_READ = 2;
localparam NUM_BYTES_TX_READ = 5;
localparam NUM_BYTES_RX_WRITE = 6;
localparam NUM_BYTES_TX_WRITE = 1;
localparam SPI_TRANSFER_ADDRESS_WIDTH = 15;
//----------------------------------------------------------
// handle transfer
//----------------------------------------------------------
localparam INIT_RX = 2'd0;
localparam RECEIVE = 2'd1;
localparam WAIT_RESPONSE = 2'd2;
localparam SENDING = 2'd3;
// internal registers
reg [ 1:0] state = INIT_RX;
reg [NUM_BYTES_RX_WRITE*8-1:0] request_cache = {NUM_BYTES_RX_WRITE*8 {1'b0}};
reg [ NUM_BYTES_TX_READ*8-1:0] response_cache = {NUM_BYTES_TX_READ*8 {1'b0}};
reg [ 2:0] byte_counter = 3'b0;
reg transfer_complete = 1'b0;
reg write_transfer = 1'b0;
// input registers to relax input timing
reg [7:0] bytestream_data_in_reg = 8'b0;
reg bytestream_valid_in_reg = 1'b0;
reg bytestream_direction_reg = 1'b0;
always @ (posedge ctrlport_clk) begin
bytestream_data_in_reg <= bytestream_data_in;
bytestream_valid_in_reg <= bytestream_valid_in;
bytestream_direction_reg <= bytestream_direction;
end
// state machine
always @ (posedge ctrlport_clk) begin
if (ctrlport_rst) begin
state <= INIT_RX;
byte_counter <= 3'b0;
transfer_complete <= 1'b0;
bytestream_output_enable <= 1'b0;
end else begin
// default assignments
transfer_complete <= 1'b0;
// direction defined by master
bytestream_output_enable <= bytestream_direction;
bytestream_valid_out <= 1'b0;
case (state)
// additional cycle for switching to make sure valid signal is driven
// from master when being in RECEIVE state
INIT_RX: begin
byte_counter <= 3'b0;
if (bytestream_direction_reg == 0) begin
state <= RECEIVE;
end
end
// wait for reception of request from master
RECEIVE: begin
if (bytestream_valid_in_reg) begin
byte_counter <= byte_counter + 1'b1;
request_cache <= {request_cache[NUM_BYTES_RX_WRITE*8-9:0], bytestream_data_in_reg};
// capture write or read
if (byte_counter == 0) begin
write_transfer <= bytestream_data_in_reg[7];
end
// wait until request completes
if ((write_transfer && byte_counter == NUM_BYTES_RX_WRITE-1) ||
(~write_transfer && byte_counter == NUM_BYTES_RX_READ-1)) begin
transfer_complete <= 1'b1;
state <= WAIT_RESPONSE;
end
end
// Workaround for missing pull down resistor:
// Use pull up and schmitt trigger to detect FPGA reload by line going high unexpectedly
if (bytestream_direction_reg == 1) begin
state <= INIT_RX;
end
end
WAIT_RESPONSE: begin
byte_counter <= 3'b0;
if (m_ctrlport_resp_ack) begin
state <= SENDING;
if (write_transfer) begin
response_cache <= {5'b0, 1'b1, m_ctrlport_resp_status, 32'b0};
end else begin
response_cache <= {m_ctrlport_resp_data, 5'b0, 1'b1, m_ctrlport_resp_status};
end
end
//abort by host
if (bytestream_direction_reg == 0) begin
state <= INIT_RX;
end
end
SENDING: begin
bytestream_valid_out <= 1'b1;
bytestream_data_out <= response_cache[NUM_BYTES_TX_READ*8-8+:8];
response_cache <= {response_cache[NUM_BYTES_TX_READ*8-9:0], 8'b0};
byte_counter <= byte_counter + 1'b1;
// wait until request completes
if ((write_transfer && byte_counter == NUM_BYTES_TX_WRITE-1) ||
(~write_transfer && byte_counter == NUM_BYTES_TX_READ-1)) begin
state <= INIT_RX;
end
//abort by host
if (bytestream_direction_reg == 0) begin
state <= INIT_RX;
end
end
default: begin
state <= INIT_RX;
end
endcase
end
end
//----------------------------------------------------------
// assign request to ctrlport
//----------------------------------------------------------
assign m_ctrlport_req_wr = write_transfer & transfer_complete;
assign m_ctrlport_req_rd = ~write_transfer & transfer_complete;
assign m_ctrlport_req_data = request_cache[0+:CTRLPORT_DATA_W];
assign m_ctrlport_req_addr = (write_transfer) ?
// Skipping data in LSBs to get to the address for writes.
{5'b0, request_cache[CTRLPORT_DATA_W+:SPI_TRANSFER_ADDRESS_WIDTH]} :
// Full request = address of 2 bytes in LSBs.
{5'b0, request_cache[0+:SPI_TRANSFER_ADDRESS_WIDTH]};
endmodule
`default_nettype wire
+228
View File
@@ -0,0 +1,228 @@
//
// Copyright 2021 Ettus Research, a National Instruments Brand
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: ctrlport_byte_serializer
//
// Description:
// Serializes CtrlPort requests into a byte stream.
//
// The serialized data is similar to an AXI4-Streaming interface with one byte
// per clock cycle and a valid signal. Direction controls the current transmission
// direction. 0 = Master to Slave, 1 = Slave to Master, where this module is the
// master. Direction is always present in direction master to slave where the
// other signals valid and data can be shared on a tri-state bus.
//
// The transmission is defined as described below. The bytes are transmitted MSB
// first.
// Write request:
// 1'b1 = write, 15 bit address, 32 bit data (MOSI) = 6 bytes request
// 5 bit padding, 1 bit ack, 2 bit status = 1 byte response
// Read request:
// 1'b0 = read, 15 bit address = 2 bytes request
// 32 bit data, 5 bit padding, 1 bit ack, 2 bit status = 5 bytes response
//
// When sharing valid and data signal lines between master and slave the
// timing is defined as:
//
// clk __/--\__/--\__/--\__/--\__/--\__/--\__/--\__/--\__/--\__/--\__/--\__
// direction _______________________/-----------------\____________
// master output enable _____/-----------------\______________________________
// slave output enable _____________________________/-----------------\______
// valid & data zzzzz| Master driven | zzz | Slave driven | zzzzz
// transaction <--- Request ---><--- Response --->
//
// The slave should use the direction signal to derive it's own output enable
// leaving the master the option to terminate the transaction.
// On switch from slave to master the direction has to be changed at least
// one clock cycle before enabling the master output enable to avoid driving the
// bus from two sources.
//
`default_nettype none
module ctrlport_byte_serializer (
// Clock and Reset
input wire ctrlport_clk,
input wire ctrlport_rst,
// Request
input wire s_ctrlport_req_wr,
input wire s_ctrlport_req_rd,
input wire [19:0] s_ctrlport_req_addr,
input wire [31:0] s_ctrlport_req_data,
// Response
output reg s_ctrlport_resp_ack = 1'b0,
output reg [ 1:0] s_ctrlport_resp_status = 2'b0,
output reg [31:0] s_ctrlport_resp_data = 32'b0,
// GPIO interface
input wire [ 7:0] bytestream_data_in,
input wire bytestream_valid_in,
output reg [ 7:0] bytestream_data_out = 8'b0,
output reg bytestream_valid_out = 1'b0,
output reg bytestream_direction = 1'b0,
output reg bytestream_output_enable = 1'b1
);
`include "../../../lib/rfnoc/core/ctrlport.vh"
//---------------------------------------------------------------
// transfer constants
//---------------------------------------------------------------
// derived from the transaction format (see description above)
localparam NUM_BYTES_TX_READ = 2;
localparam NUM_BYTES_RX_READ = 5;
localparam NUM_BYTES_TX_WRITE = 6;
localparam NUM_BYTES_RX_WRITE = 1;
localparam TIMEOUT_COUNTER_WIDTH = 6;
//----------------------------------------------------------
// FSM to handle transfers
//----------------------------------------------------------
localparam IDLE = 3'd0;
localparam SENDING = 3'd1;
localparam INIT_RX = 3'd2;
localparam DIR_SWITCH = 3'd3;
localparam DIR_SWITCH_DLY = 3'd4;
localparam RECEIVING = 3'd5;
localparam ACK = 3'd6;
localparam TIMEOUT = 3'd7;
// input registers to relax input timing
reg [7:0] bytestream_data_in_reg = 8'b0;
reg bytestream_valid_in_reg = 1'b0;
always @ (posedge ctrlport_clk) begin
bytestream_data_in_reg <= bytestream_data_in;
bytestream_valid_in_reg <= bytestream_valid_in;
end
// internal registers
reg [ 2:0] state = IDLE;
reg [NUM_BYTES_TX_WRITE*8-1:0] request_cache = {NUM_BYTES_TX_WRITE*8{1'b0}};
reg [ NUM_BYTES_RX_READ*8-1:0] response_cache = {NUM_BYTES_RX_READ*8{1'b0}};
reg [ 2:0] byte_counter = 3'b0;
reg write_transfer = 1'b0;
reg [TIMEOUT_COUNTER_WIDTH-1:0] timeout_counter = {TIMEOUT_COUNTER_WIDTH {1'b0}};
always @ (posedge ctrlport_clk) begin
if (ctrlport_rst) begin
state <= IDLE;
bytestream_valid_out <= 1'b0;
byte_counter <= 3'b0;
bytestream_direction <= 1'b0;
bytestream_output_enable <= 1'b1;
s_ctrlport_resp_ack <= 1'b0;
end else begin
case (state)
IDLE: begin
// reset values from previous states
s_ctrlport_resp_ack <= 1'b0;
bytestream_valid_out <= 1'b0;
bytestream_output_enable <= 1'b1;
byte_counter <= 3'b0;
timeout_counter <= {TIMEOUT_COUNTER_WIDTH {1'b0}};
// start transmission on read or write
if (s_ctrlport_req_rd || s_ctrlport_req_wr) begin
state <= SENDING;
request_cache <= {s_ctrlport_req_wr, s_ctrlport_req_addr[14:0], s_ctrlport_req_data};
write_transfer <= s_ctrlport_req_wr;
end
end
// send as many bytes as required for read / write
SENDING: begin
bytestream_data_out <= request_cache[NUM_BYTES_TX_WRITE*8-8+:8];
request_cache <= {request_cache[NUM_BYTES_TX_WRITE*8-9:0], 8'b0};
bytestream_valid_out <= 1'b1;
byte_counter <= byte_counter + 1'b1;
if ((write_transfer && byte_counter == NUM_BYTES_TX_WRITE-1) ||
(~write_transfer && byte_counter == NUM_BYTES_TX_READ-1)) begin
state <= INIT_RX;
end
end
// first cycle for switching to make sure valid signal is driven
// from slave when being in RECEIVING state
INIT_RX: begin
state <= DIR_SWITCH;
bytestream_direction <= 1'b1;
bytestream_output_enable <= 1'b0;
bytestream_valid_out <= 1'b0;
byte_counter <= 3'b0;
end
// second switching cycle to let CPLD load the lines based on direction
DIR_SWITCH: begin
state <= DIR_SWITCH_DLY;
end
// third switching cycle to compensate data input register
DIR_SWITCH_DLY: begin
state <= RECEIVING;
end
// wait for response to be received
// immediately change direction after successful reception to have one
// clock cycle of pause to avoid double driving the bus
RECEIVING: begin
timeout_counter <= timeout_counter + 1;
if (bytestream_valid_in_reg) begin
byte_counter <= byte_counter + 1'b1;
response_cache = {response_cache[NUM_BYTES_RX_READ*8-9:0], bytestream_data_in_reg};
if ((write_transfer && byte_counter == NUM_BYTES_RX_WRITE-1) ||
(~write_transfer && byte_counter == NUM_BYTES_RX_READ-1)) begin
state <= ACK;
bytestream_direction <= 1'b0;
end
end
if (timeout_counter == {TIMEOUT_COUNTER_WIDTH {1'b1}}) begin
state <= TIMEOUT;
bytestream_direction <= 1'b0;
end
end
// issue ctrlport response
ACK: begin
state <= IDLE;
s_ctrlport_resp_ack <= 1'b1;
// status based on received ack
s_ctrlport_resp_status <= response_cache[2] ? response_cache[1:0] : CTRL_STS_CMDERR;
if (write_transfer) begin
s_ctrlport_resp_data <= 32'b0;
end else begin
s_ctrlport_resp_data <= response_cache[39:8];
end
end
TIMEOUT: begin
state <= IDLE;
s_ctrlport_resp_ack <= 1'b1;
s_ctrlport_resp_status <= CTRL_STS_CMDERR;
s_ctrlport_resp_data <= 32'b0;
end
default: begin
state <= IDLE;
end
endcase
end
end
endmodule
`default_nettype wire
+323
View File
@@ -0,0 +1,323 @@
//
// Copyright 2021 Ettus Research, a National Instruments Brand
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: db_gpio_interface
//
// Description:
// Interface for GPIO interface towards daughterboards.
//
// A ControlPort interface is serialized into bytes along with a valid signal.
// The ControlPort supports write requests only. Byte enables are not supported.
// There is support for timed commands.
// Furthermore there are 4 state wires towards the DB. Ensure an appropriate
// hold time on the states as the transmission happens in pll_ref_clk, which is
// slower than radio_clk. Pulses of e.g. just a single clock cycle may not get
// transferred to the DB.
//
// The 20 available GPIO lines are assigned with
// - 5x empty
// - bytestream direction
// - bytestream valid
// - bytestream data (8 bits)
// - 1x empty
// - db_state (4 bits)
//
`default_nettype none
module db_gpio_interface (
// Clocks and reset
input wire radio_clk,
input wire pll_ref_clk,
// DB state lines (domain: radio_clk)
input wire [ 3:0] db_state,
// time interfaces (domain: radio_clk)
input wire [63:0] radio_time,
input wire radio_time_stb,
input wire [ 3:0] time_ignore_bits,
// Request (domain: radio_clk)
input wire ctrlport_rst,
input wire s_ctrlport_req_wr,
input wire s_ctrlport_req_rd,
input wire [19:0] s_ctrlport_req_addr,
input wire [31:0] s_ctrlport_req_data,
input wire [ 3:0] s_ctrlport_req_byte_en,
input wire s_ctrlport_req_has_time,
input wire [63:0] s_ctrlport_req_time,
// Response (domain: radio_clk)
output wire s_ctrlport_resp_ack,
output wire [ 1:0] s_ctrlport_resp_status,
output wire [31:0] s_ctrlport_resp_data,
// GPIO interface (domain: pll_ref_clk)
input wire [19:0] gpio_in,
output wire [19:0] gpio_out,
output wire [19:0] gpio_out_en,
// Version (Constant)
output wire [95:0] version_info
);
`include "../regmap/versioning_regs_regmap_utils.vh"
`include "../regmap/versioning_utils.vh"
//----------------------------------------------------------------------------
// Timed command processing
//----------------------------------------------------------------------------
wire [19:0] ctrlport_timed_req_addr;
wire [31:0] ctrlport_timed_req_data;
wire ctrlport_timed_req_rd;
wire ctrlport_timed_req_wr;
wire ctrlport_timed_resp_ack;
reg [31:0] ctrlport_timed_resp_data = 0;
reg [ 1:0] ctrlport_timed_resp_status = 0;
ctrlport_timer #(
.EXEC_LATE_CMDS(1)
) ctrlport_timer_i (
.clk (radio_clk),
.rst (ctrlport_rst),
.time_now (radio_time),
.time_now_stb (radio_time_stb),
.time_ignore_bits (time_ignore_bits),
.s_ctrlport_req_wr (s_ctrlport_req_wr),
.s_ctrlport_req_rd (s_ctrlport_req_rd),
.s_ctrlport_req_addr (s_ctrlport_req_addr),
.s_ctrlport_req_data (s_ctrlport_req_data),
.s_ctrlport_req_byte_en (s_ctrlport_req_byte_en),
.s_ctrlport_req_has_time (s_ctrlport_req_has_time),
.s_ctrlport_req_time (s_ctrlport_req_time),
.s_ctrlport_resp_ack (s_ctrlport_resp_ack),
.s_ctrlport_resp_status (s_ctrlport_resp_status),
.s_ctrlport_resp_data (s_ctrlport_resp_data),
.m_ctrlport_req_wr (ctrlport_timed_req_wr),
.m_ctrlport_req_rd (ctrlport_timed_req_rd),
.m_ctrlport_req_addr (ctrlport_timed_req_addr),
.m_ctrlport_req_data (ctrlport_timed_req_data),
.m_ctrlport_req_byte_en (),
.m_ctrlport_resp_ack (ctrlport_timed_resp_ack),
.m_ctrlport_resp_status (ctrlport_timed_resp_status),
.m_ctrlport_resp_data (ctrlport_timed_resp_data)
);
//----------------------------------------------------------------------------
// Clock domain crossing (radio_clk -> pll_ref_clk)
//----------------------------------------------------------------------------
// Radio_clk is derived from pll_ref_clk by an integer multiplier and
// originate from the same PLL.
// Therefore the clock crossing can be achieved by using simple registers.
// Static timing analysis will be able to meet setup and hold requirements on
// them.
// holding read and write flags for multiple radio_clk cycles
reg ctrlport_timed_req_wr_hold = 1'b0;
reg ctrlport_timed_req_rd_hold = 1'b0;
reg [19:0] ctrlport_req_addr_prc = 20'b0;
reg [31:0] ctrlport_req_data_prc = 32'b0;
reg ctrlport_req_rd_prc = 1'b0;
reg ctrlport_req_wr_prc = 1'b0;
wire ctrlport_resp_ack_prc;
wire [31:0] ctrlport_resp_data_prc;
wire [ 1:0] ctrlport_resp_status_prc;
reg ctrlport_req_rd_fall = 1'b0;
reg ctrlport_req_wr_fall = 1'b0;
reg [31:0] ctrlport_resp_data_fall = 32'b0;
reg [ 1:0] ctrlport_resp_status_fall = 2'b0;
reg ctrlport_resp_ack_fall = 1'b0;
// Retime signals to falling edge of radio_clk.
// Because radio_clk is more heavily loaded than pll_ref_clk, it arrives at
// the FF's later, which leads to hold time violations when moving signals
// from pll_ref_clk to radio_clk. By sampling on the falling edge of
// radio_clk, we provide (nominally) half a radio_clk period of hold, while
// reducing setup time by half. The late arrival of radio_clk adds back some
// of the lost setup margin.
always @(negedge radio_clk) begin
ctrlport_req_rd_fall <= ctrlport_req_rd_prc;
ctrlport_req_wr_fall <= ctrlport_req_wr_prc;
ctrlport_resp_ack_fall <= ctrlport_resp_ack_prc;
ctrlport_resp_status_fall <= ctrlport_resp_status_prc;
ctrlport_resp_data_fall <= ctrlport_resp_data_prc;
end
always @(posedge radio_clk) begin
if (ctrlport_req_wr_fall) begin
ctrlport_timed_req_wr_hold <= 1'b0;
end else if (ctrlport_timed_req_wr) begin
ctrlport_timed_req_wr_hold <= 1'b1;
end
if (ctrlport_req_rd_fall) begin
ctrlport_timed_req_rd_hold <= 1'b0;
end else if (ctrlport_timed_req_rd) begin
ctrlport_timed_req_rd_hold <= 1'b1;
end
// capture request address and data
if (ctrlport_timed_req_wr || ctrlport_timed_req_rd) begin
ctrlport_req_addr_prc <= ctrlport_timed_req_addr;
ctrlport_req_data_prc <= ctrlport_timed_req_data;
end
end
// capture extended flags in pll_ref_clk domain
always @(posedge pll_ref_clk) begin
ctrlport_req_wr_prc <= ctrlport_timed_req_wr_hold;
ctrlport_req_rd_prc <= ctrlport_timed_req_rd_hold;
end
// search for rising edge in response
reg [1:0] ctrlport_timed_ack_reg = 2'b0;
always @(posedge radio_clk) begin
ctrlport_timed_ack_reg = {ctrlport_timed_ack_reg[0], ctrlport_resp_ack_fall};
end
assign ctrlport_timed_resp_ack = ctrlport_timed_ack_reg[0] & ~ctrlport_timed_ack_reg[1];
// capture response data
always @(posedge radio_clk) begin
if (ctrlport_resp_ack_fall) begin
ctrlport_timed_resp_status <= ctrlport_resp_status_fall;
ctrlport_timed_resp_data <= ctrlport_resp_data_fall;
end
end
// transfer state lines
reg [3:0] db_state_prc = 4'b0;
reg [3:0] db_state_prc_fe = 4'b0;
always @(posedge pll_ref_clk) begin
db_state_prc <= db_state;
end
always @(negedge pll_ref_clk) begin
db_state_prc_fe <= db_state_prc;
end
// transfer reset
reg ctrlport_rst_hold = 1'b0;
reg ctrlport_rst_prc = 1'b0;
reg ctrlport_rst_fall = 1'b0;
always @(posedge radio_clk) begin
if (ctrlport_rst) begin
ctrlport_rst_hold <= 1'b1;
end else if (ctrlport_rst_fall) begin
ctrlport_rst_hold <= 1'b0;
end
end
always @(posedge pll_ref_clk) begin
ctrlport_rst_prc <= ctrlport_rst_hold;
end
always @(negedge radio_clk) begin
ctrlport_rst_fall <= ctrlport_rst_prc;
end
//----------------------------------------------------------------------------
// Ctrlport serializer
//----------------------------------------------------------------------------
wire [7:0] bytestream_data_in;
wire [7:0] bytestream_data_out;
wire bytestream_direction;
wire bytestream_output_enable;
wire bytestream_valid_in;
wire bytestream_valid_out;
ctrlport_byte_serializer serializer_i (
.ctrlport_clk (pll_ref_clk),
.ctrlport_rst (ctrlport_rst_prc),
.s_ctrlport_req_wr (ctrlport_req_wr_prc),
.s_ctrlport_req_rd (ctrlport_req_rd_prc),
.s_ctrlport_req_addr (ctrlport_req_addr_prc),
.s_ctrlport_req_data (ctrlport_req_data_prc),
.s_ctrlport_resp_ack (ctrlport_resp_ack_prc),
.s_ctrlport_resp_status (ctrlport_resp_status_prc),
.s_ctrlport_resp_data (ctrlport_resp_data_prc),
.bytestream_data_in (bytestream_data_in),
.bytestream_valid_in (bytestream_valid_in),
.bytestream_data_out (bytestream_data_out),
.bytestream_valid_out (bytestream_valid_out),
.bytestream_direction (bytestream_direction),
.bytestream_output_enable (bytestream_output_enable)
);
// IOB registers to drive data on the falling edge
reg [7:0] bytestream_data_out_fe;
reg bytestream_direction_fe;
reg bytestream_output_enable_fe;
reg bytestream_valid_out_fe;
// Signals are shifted into a falling edge domain to help meet
// hold requirements at CPLD
always @(negedge pll_ref_clk) begin
if (ctrlport_rst_prc) begin
bytestream_data_out_fe <= 8'b0;
bytestream_valid_out_fe <= 1'b0;
bytestream_direction_fe <= 1'b0;
bytestream_output_enable_fe <= 1'b1;
end else begin
bytestream_data_out_fe <= bytestream_data_out;
bytestream_valid_out_fe <= bytestream_valid_out;
bytestream_direction_fe <= bytestream_direction;
bytestream_output_enable_fe <= bytestream_output_enable;
end
end
//----------------------------------------------------------------------------
// wire assignment
//----------------------------------------------------------------------------
// 5 unused, 10 used, 1 unused and 4 used signals
assign gpio_out = {5'b0, bytestream_direction_fe, bytestream_valid_out_fe, bytestream_data_out_fe, 1'b0, db_state_prc_fe};
assign gpio_out_en = {5'b0, 1'b1, {9 {bytestream_output_enable_fe}}, 1'b0, {4 {1'b1}} };
assign bytestream_valid_in = gpio_in[13];
assign bytestream_data_in = gpio_in[12:5];
//----------------------------------------------------------------------------
// version_info
//----------------------------------------------------------------------------
// Version metadata, constants come from auto-generated versioning_regs_regmap_utils.vh
assign version_info = build_component_versions(
DB_GPIO_IFC_VERSION_LAST_MODIFIED_TIME,
build_version(
DB_GPIO_IFC_OLDEST_COMPATIBLE_VERSION_MAJOR,
DB_GPIO_IFC_OLDEST_COMPATIBLE_VERSION_MINOR,
DB_GPIO_IFC_OLDEST_COMPATIBLE_VERSION_BUILD),
build_version(
DB_GPIO_IFC_CURRENT_VERSION_MAJOR,
DB_GPIO_IFC_CURRENT_VERSION_MINOR,
DB_GPIO_IFC_CURRENT_VERSION_BUILD));
endmodule
`default_nettype wire
//XmlParse xml_on
//<regmap name="VERSIONING_REGS_REGMAP">
// <group name="VERSIONING_CONSTANTS">
// <enumeratedtype name="DB_GPIO_IFC_VERSION" showhex="true">
// <info>
// Daughterboard GPIO interface.{BR/}
// For guidance on when to update these revision numbers,
// please refer to the register map documentation accordingly:
// <li> Current version: @.VERSIONING_REGS_REGMAP..CURRENT_VERSION
// <li> Oldest compatible version: @.VERSIONING_REGS_REGMAP..OLDEST_COMPATIBLE_VERSION
// <li> Version last modified: @.VERSIONING_REGS_REGMAP..VERSION_LAST_MODIFIED
// </info>
// <value name="DB_GPIO_IFC_CURRENT_VERSION_MAJOR" integer="1"/>
// <value name="DB_GPIO_IFC_CURRENT_VERSION_MINOR" integer="0"/>
// <value name="DB_GPIO_IFC_CURRENT_VERSION_BUILD" integer="0"/>
// <value name="DB_GPIO_IFC_OLDEST_COMPATIBLE_VERSION_MAJOR" integer="1"/>
// <value name="DB_GPIO_IFC_OLDEST_COMPATIBLE_VERSION_MINOR" integer="0"/>
// <value name="DB_GPIO_IFC_OLDEST_COMPATIBLE_VERSION_BUILD" integer="0"/>
// <value name="DB_GPIO_IFC_VERSION_LAST_MODIFIED_TIME" integer="0x20110616"/>
// </enumeratedtype>
// </group>
//</regmap>
//XmlParse xml_off
+108
View File
@@ -0,0 +1,108 @@
//
// Copyright 2021 Ettus Research, a National Instruments Brand
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: db_gpio_reordering
//
// Description:
// Reorders the GPIO wires towards the DB CPLDs in a common way for DB 0 and 1.
//
// The digital daughterboard connector has 120 pins [A-F][1-20].
// The numbering on the motherboard traces do not match for daughterboard 0 and 1.
// This module orders the FPGA outputs MSB first and connects it to the DB
// connection with increasing letter and increasing number.
// For DB 0 this results in:
// FPGA Bit 19 = A7 (trace: DB0/1_GPIO[19])
// FPGA Bit 18 = A8 (trace: DB0/1_GPIO[17])
// ...
// FPGA Bit 0 = C19 (trace: DB0/1_GPIO[12])
// This enables usages of the same daughterboard CPLD image on both connectors.
//
`default_nettype none
module db_gpio_reordering (
// 20 bit internal interface
output wire [19:0] db0_gpio_in_int,
input wire [19:0] db0_gpio_out_int,
input wire [19:0] db0_gpio_out_en_int,
output wire [19:0] db1_gpio_in_int,
input wire [19:0] db1_gpio_out_int,
input wire [19:0] db1_gpio_out_en_int,
// 20 bit external interface
input wire [19:0] db0_gpio_in_ext,
output wire [19:0] db0_gpio_out_ext,
output wire [19:0] db0_gpio_out_en_ext,
input wire [19:0] db1_gpio_in_ext,
output wire [19:0] db1_gpio_out_ext,
output wire [19:0] db1_gpio_out_en_ext
);
//port indexes
localparam ENTRY_BITWIDTH = 5;
localparam NUM_ENTRIES = 20;
localparam [ENTRY_BITWIDTH*NUM_ENTRIES-1:0] PORT0_MAPPING = {
5'd 19,
5'd 17,
5'd 0,
5'd 14,
5'd 15,
5'd 10,
5'd 4,
5'd 5,
5'd 16,
5'd 18,
5'd 8,
5'd 6,
5'd 1,
5'd 9,
5'd 2,
5'd 3,
5'd 11,
5'd 7,
5'd 13,
5'd 12 };
localparam [ENTRY_BITWIDTH*NUM_ENTRIES-1:0] PORT1_MAPPING = {
5'd 10,
5'd 6,
5'd 7,
5'd 2,
5'd 3,
5'd 0,
5'd 1,
5'd 4,
5'd 8,
5'd 9,
5'd 11,
5'd 5,
5'd 13,
5'd 12,
5'd 15,
5'd 14,
5'd 19,
5'd 18,
5'd 17,
5'd 16 };
// reordering assignments
generate
genvar i;
for (i=0; i<NUM_ENTRIES; i=i+1) begin : reordering_gen
// input data
assign db0_gpio_in_int[i] = db0_gpio_in_ext[PORT0_MAPPING[i*ENTRY_BITWIDTH +: ENTRY_BITWIDTH]];
assign db1_gpio_in_int[i] = db1_gpio_in_ext[PORT1_MAPPING[i*ENTRY_BITWIDTH +: ENTRY_BITWIDTH]];
// output data
assign db0_gpio_out_ext[PORT0_MAPPING[i*ENTRY_BITWIDTH +: ENTRY_BITWIDTH]] = db0_gpio_out_int[i];
assign db1_gpio_out_ext[PORT1_MAPPING[i*ENTRY_BITWIDTH +: ENTRY_BITWIDTH]] = db1_gpio_out_int[i];
// output enable
assign db0_gpio_out_en_ext[PORT0_MAPPING[i*ENTRY_BITWIDTH +: ENTRY_BITWIDTH]] = db0_gpio_out_en_int[i];
assign db1_gpio_out_en_ext[PORT1_MAPPING[i*ENTRY_BITWIDTH +: ENTRY_BITWIDTH]] = db1_gpio_out_en_int[i];
end
endgenerate
endmodule
`default_nettype wire