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
+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