fpga: Add X440/FBX support

Co-authored-by: Martin Braun <martin.braun@ettus.com>
Co-authored-by: Wade Fife <wade.fife@ni.com>
Co-authored-by: Ryan Marlow <ryan@lmarlow.com>


Original-commit: 596760a12e4834e47589c12f8a4fd083aa2f7c25
This commit is contained in:
Javier Valenzuela
2023-06-12 10:27:29 -05:00
committed by Aki Tomita
co-authored by Martin Braun Wade Fife Ryan Marlow
parent a405111ce7
commit 5cadf901c7
121 changed files with 20670 additions and 8739 deletions
+162
View File
@@ -0,0 +1,162 @@
//
// Copyright 2022 Ettus Research, a National Instruments Brand
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: clock_en_control
//
// Description:
// Implements control over clock enable. clk_in is always active.
// The enable controls whether clk_out is active or not.
//
// Parameters:
//
// REG_BASE : Base address to use for registers.
// REG_SIZE : Register space size.
//
`default_nettype none
module clock_en_control #(
parameter BASE_ADDRESS = 0,
parameter REGMAP_SIZE = 8'h4
) (
// 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,
output reg [ 1:0] s_ctrlport_resp_status,
output reg [31:0] s_ctrlport_resp_data,
// Clock Enable (domain: ctrlport_clk)
input wire clk_in,
output wire clk_out
);
`include "../../../../lib/rfnoc/core/ctrlport.vh"
`include "regmap/clock_en_regmap_utils.vh"
//---------------------------------------------------------------
// ATR memory signals
//---------------------------------------------------------------
reg [31:0] clk_ctrl_reg;
//---------------------------------------------------------------
// Handling of CtrlPort
//---------------------------------------------------------------
// Check of request address is targeted for this module.
wire address_in_range = (s_ctrlport_req_addr >= BASE_ADDRESS) && (s_ctrlport_req_addr < BASE_ADDRESS + REGMAP_SIZE);
always @(posedge ctrlport_clk) begin
// reset internal registers and responses
if (ctrlport_rst) begin
s_ctrlport_resp_ack <= 1'b0;
s_ctrlport_resp_status <= 2'b0;
s_ctrlport_resp_data <= 32'b0;
clk_ctrl_reg <= 32'b0;
end else begin
// write requests
if (s_ctrlport_req_wr) begin
// always issue an ack and no data
s_ctrlport_resp_ack <= 1'b1;
s_ctrlport_resp_data <= {32{1'bx}};
s_ctrlport_resp_status <= CTRL_STS_OKAY;
case (s_ctrlport_req_addr)
BASE_ADDRESS + CLK_EN_CONTROL: begin
clk_ctrl_reg <= s_ctrlport_req_data;
end
// error on undefined address
default: begin
if (address_in_range) begin
s_ctrlport_resp_status <= CTRL_STS_CMDERR;
// no response if out of range
end else begin
s_ctrlport_resp_ack <= 1'b0;
end
end
endcase
//req_rd not delayed
end else if (s_ctrlport_req_rd) begin
// default assumption: valid request
s_ctrlport_resp_ack <= 1'b1;
s_ctrlport_resp_status <= CTRL_STS_OKAY;
s_ctrlport_resp_data <= {32{1'b0}};
case (s_ctrlport_req_addr)
BASE_ADDRESS + CLK_EN_CONTROL: begin
s_ctrlport_resp_data <= clk_ctrl_reg & CLK_EN_CONTROL_MASK;
end
// error on undefined address
default: begin
if (address_in_range) begin
s_ctrlport_resp_status <= CTRL_STS_CMDERR;
// no response if out of range
end else begin
s_ctrlport_resp_ack <= 1'b0;
end
end
endcase
// no request
end else begin
s_ctrlport_resp_ack <= 1'b0;
end
end
end
//---------------------------------------------------------------
// Clock Enable
//---------------------------------------------------------------
wire clk_en;
synchronizer synchronizer_i (
.clk(clk_in ),
.rst(1'b0 ),
.in (clk_ctrl_reg[CLK_EN]),
.out(clk_en )
);
BUFGCE BUFGCE_i (
.O (clk_out),
.CE(clk_en ),
.I (clk_in )
);
endmodule
`default_nettype wire
//XmlParse xml_on
//<regmap name="CLK_EN_REGMAP" readablestrobes="false" generatevhdl="true" ettusguidelines="true">
// <group name="CLK_EN_REGISTERS">
// <info>
// Clock Enable Register
// </info>
// <register name="CLK_EN_CONTROL" size="32" offset="0x0" attributes="Readable|Writable">
// <info>
// This register configures Clock Enable.
// </info>
// <bitfield name="CLK_EN" range="0" initialvalue="0">
// <info>
// Enables the Clock.
// </info>
// </bitfield>
// </register>
// </group>
//</regmap>
//XmlParse xml_off
@@ -0,0 +1,618 @@
//
// Copyright 2022 Ettus Research, A National Instruments Brand
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: ctrlport_to_i2c_sync_ctrl
//
// Description:
//
// This module wraps a I2C WB master and provides a ControlPort interface
// specific to the SYNC IO expander peripheral.
// Sync switch control sequence is as follows:
// 1. Setup core and IO expander:
// a. Write to SETUP_REG
// b. Poll/read from SETUP_STATUS_REG until bit SETUP_STATUS == 1
// 2. Write sync switch configuration to SYNC_[1-5]_REG and RFS_EN_REG
// 3. Initiate io expander config
// a. Write to CONFIG_IO_REG
// b. Poll/read from CONFIG_IO_STATUS_REG until bit CONFIG_IO_STATUS == 1
// Step 1 only needs to happen once after power up or core reset.
// Repeat steps 2 and 3 as needed.
//
// Parameters:
//
// BASE_ADDRESS : Base address for CtrlPort registers.
// PRESCALE : Scaling factor to determine clock speed of I2C SCL.
// Must be divisible by 5.
//
`default_nettype wire
module ctrlport_to_i2c_sync_ctrl #(
parameter BASE_ADDRESS = 0,
parameter [15:0] PRESCALE = 'd500
) (
//---------------------------------------------------------------
// ControlPort Slave
//---------------------------------------------------------------
input wire ctrlport_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,
output reg s_ctrlport_resp_ack,
output reg [ 1:0] s_ctrlport_resp_status = 2'b0,
output reg [31:0] s_ctrlport_resp_data = 32'b0,
//---------------------------------------------------------------
// I2C signals
//---------------------------------------------------------------
// i2c clock line
input wire scl_pad_i, // SCL-line input
output wire scl_pad_o, // SCL-line output
output wire scl_pad_en_o, // SCL-line output enable (active low)
// i2c data line
input wire sda_pad_i, // SDA-line input
output wire sda_pad_o, // SDA-line output
output wire sda_pad_en_o // SDA-line output enable (active low)
);
`include "../../../../lib/rfnoc/core/ctrlport.vh"
`include "../../../../lib/wishbone/i2c_master.vh"
`include "./regmap/rf_sync_regmap_utils.vh"
//---------------------------------------------------------------
// CtrlPort Interface Regs and Triggers to Initiate I2C
//---------------------------------------------------------------
reg [2:0] sync1, sync2, sync3, sync4, sync5;
reg rfs_en;
reg setup_trig; // initiate setup
reg config_io_trig; // configure IO
reg setup_finished;
reg setup_finished_hold;
reg config_io_finished;
reg config_io_finished_hold;
//---------------------------------------------------------------
// WishBone interface
//---------------------------------------------------------------
reg wb_cyc_i; // Active bus cycle
reg wb_we_i = 1'b0; // Write access
reg [2:0] wb_adr_i = 3'b0;
reg [7:0] wb_dat_i = 8'b0;
wire wb_ack_o;
wire [7:0] wb_dat_o;
// Check for address to be in range [base_addr..base_addr+32)
localparam NUM_ADDRESSES = 32;
wire address_in_range = (s_ctrlport_req_addr >= BASE_ADDRESS) &&
(s_ctrlport_req_addr < BASE_ADDRESS + NUM_ADDRESSES);
// The scaling factor (PRESCALE) of the input clock (ctrlport_clk) to SCL
// isn't direct but instead the relationship between the input clock and
// the state machine inside the i2c_master that controls SCL.
// This state machine has 5 repeated stages per SCL clock cycle so
// the scaling is divided by a factor of 5. The division here
// obscures a need for the user to do an extra step to calculate the
// PRESCALE parameter.
// For example, if a user wants to have an actual rescaling of 1:500
// (SCL to ctrlpor_clk), the PRESCALE parameter is divided by 5
// here so the i2c_master prescale value is set to 100.
if (PRESCALE % 5 != 0) begin : gen_assertion
ERROR_PRESCALE_must_be_div_by_5();
end
// constants to configure wb i2c master core
localparam PRESCALE_5 = PRESCALE/5;
localparam PRER_LO_CONST = PRESCALE_5[7:0];
localparam PRER_HI_CONST = PRESCALE_5[15:8];
//constants for interfacing with i2c master core
localparam I2C_WR = 1'b0;
localparam I2C_RD = 1'b1;
localparam SYNC_IO_SLV_ADR = 7'h20;
// CtrlPort Interface
// configure sync switch IO and trigger I2C transactions
always @(posedge ctrlport_clk) begin
// Reset internal registers and responses
if (ctrlport_rst) begin
s_ctrlport_resp_ack <= 1'b0;
s_ctrlport_resp_status <= 2'b0;
s_ctrlport_resp_data <= 32'b0;
setup_trig <= 1'b0;
config_io_trig <= 1'b0;
setup_finished_hold <= 1'b0;
config_io_finished_hold <= 1'b0;
sync1 <= 3'b0;
sync2 <= 3'b0;
sync3 <= 3'b0;
sync4 <= 3'b0;
sync5 <= 3'b0;
rfs_en <= 1'b0;
end else begin
// Only ack under certain conditions
s_ctrlport_resp_ack <= 1'b0;
if (setup_finished) begin
setup_finished_hold <= 1'b1;
end
if (config_io_finished) begin
config_io_finished_hold <= 1'b1;
end
if (s_ctrlport_req_wr) begin // Write requests
// if address is normal ctrlport, immediately ack
if (address_in_range) begin
s_ctrlport_resp_ack <= 1'b1;
s_ctrlport_resp_status <= CTRL_STS_OKAY;
end
case (s_ctrlport_req_addr)
BASE_ADDRESS + SYNC_1_REG: begin
sync1 <= s_ctrlport_req_data[2:0];
end
BASE_ADDRESS + SYNC_2_REG: begin
sync2 <= s_ctrlport_req_data[2:0];
end
BASE_ADDRESS + SYNC_3_REG: begin
sync3 <= s_ctrlport_req_data[2:0];
end
BASE_ADDRESS + SYNC_4_REG: begin
sync4 <= s_ctrlport_req_data[2:0];
end
BASE_ADDRESS + SYNC_5_REG: begin
sync5 <= s_ctrlport_req_data[2:0];
end
BASE_ADDRESS + RFS_EN_REG: begin
rfs_en <= s_ctrlport_req_data[0];
end
//initialize SYNC_IO peripheral
BASE_ADDRESS + SETUP_REG: begin
setup_trig <= 1'b1;
setup_finished_hold <= 1'b0;
end
//configure IO
BASE_ADDRESS + CONFIG_IO_REG: begin
config_io_trig <= 1'b1;
config_io_finished_hold <= 1'b0;
end
endcase
// Read requests
end else if (s_ctrlport_req_rd) begin
// Acknowledge by default
if (address_in_range) begin
s_ctrlport_resp_ack <= 1'b1;
s_ctrlport_resp_status <= CTRL_STS_OKAY;
end
case (s_ctrlport_req_addr)
BASE_ADDRESS + SYNC_1_REG: begin
s_ctrlport_resp_data[2:0] <= sync1;
end
BASE_ADDRESS + SYNC_2_REG: begin
s_ctrlport_resp_data[2:0] <= sync2;
end
BASE_ADDRESS + SYNC_3_REG: begin
s_ctrlport_resp_data[2:0] <= sync3;
end
BASE_ADDRESS + SYNC_4_REG: begin
s_ctrlport_resp_data[2:0] <= sync4;
end
BASE_ADDRESS + SYNC_5_REG: begin
s_ctrlport_resp_data[2:0] <= sync5;
end
BASE_ADDRESS + RFS_EN_REG: begin
s_ctrlport_resp_data[2:0] <= {2'b00, rfs_en};
end
BASE_ADDRESS + SETUP_STATUS_REG: begin
s_ctrlport_resp_data[2:0] <= {2'b00, setup_finished_hold};
if(setup_finished_hold) begin
setup_trig <= 1'b0;
end
end
BASE_ADDRESS + CONFIG_IO_STATUS_REG: begin
s_ctrlport_resp_data[2:0] <= {2'b00, config_io_finished_hold};
if(config_io_finished_hold) begin
config_io_trig <= 1'b0;
end
end
// Respond with 0
default: begin
if (address_in_range) begin
s_ctrlport_resp_status <= CTRL_STS_CMDERR;
end
s_ctrlport_resp_ack <= 1'b0;
s_ctrlport_resp_data <= 32'b0;
end
endcase
// No request
end else begin
s_ctrlport_resp_ack <= 1'b0;
end
end
end // always
// state machine for I2C Write Transactions and WB Controls
localparam I2C_IDLE = 0;
localparam I2C_PRE_LO = 1;
localparam I2C_PRE_HI = 2;
localparam I2C_EN = 3;
localparam I2C_TXR = 4;
localparam I2C_CR = 5;
localparam I2C_TIP_START = 6;
localparam I2C_TIP = 7;
localparam I2C_TIP_FIN = 8;
reg i2c_tip_fin; // indicates transfer is finished
reg i2c_master_en; // indicates i2c master setup and enabled
reg [3:0] i2c_state;
wire wb_cyc_valid; // determines what states wb_cyc_i should be high
reg i2c_wr; //trigger an i2c wr cmd
reg i2c_core_setup; //trigger i2c master setup
reg [7:0] wb_txr;
reg [7:0] wb_cr;
assign wb_cyc_valid = (i2c_state >= I2C_PRE_LO ) && (i2c_state < I2C_TIP_FIN);
always @(posedge ctrlport_clk) begin
if (ctrlport_rst) begin
i2c_state <= I2C_IDLE;
wb_cyc_i <= 1'b0;
wb_we_i <= 1'b0;
wb_adr_i <= 3'b0;
wb_dat_i <= 8'b0;
i2c_tip_fin <= 1'b0;
i2c_master_en <= 1'b0;
//more regs need to be set here.
end
else begin
//handle wb_cyc_i for all states. dependent on i2c transaction states
//and wb_ack_o
if (wb_cyc_i) begin
if (wb_ack_o) begin
wb_cyc_i <= 1'b0;
end
end else begin
if (wb_cyc_valid) begin
wb_cyc_i <= 1'b1;
end
end
case(i2c_state)
I2C_IDLE: begin
i2c_tip_fin <= 1'b0;
if (i2c_wr) begin
i2c_state <= I2C_TXR;
end
else if (i2c_core_setup) begin
i2c_state <= I2C_PRE_LO;
end
end //I2C_IDLE
//begin cases to setup i2c master core
I2C_PRE_LO: begin
wb_adr_i <= WB_PRER_LO;
wb_dat_i <= PRER_LO_CONST;
wb_we_i <= 1'b1;
if (wb_ack_o) begin
i2c_state <= I2C_PRE_HI;
end
end
I2C_PRE_HI: begin
wb_adr_i <= WB_PRER_HI;
wb_dat_i <= PRER_HI_CONST;
wb_we_i <= 1'b1;
if (wb_ack_o) begin
i2c_state <= I2C_EN;
end
end
I2C_EN: begin
wb_adr_i <= WB_CTR;
wb_dat_i <= WB_CORE_EN;
wb_we_i <= 1'b1;
i2c_master_en <= 1'b1;
if (wb_ack_o) begin
i2c_state <= I2C_IDLE;
end
end
//end cases to setup i2c master core
//begin cases to initiate i2c write transfer
I2C_TXR: begin
wb_adr_i <= WB_TXR;
wb_dat_i <= wb_txr;
wb_we_i <= 1'b1;
if (wb_ack_o) begin
i2c_state <= I2C_CR;
end
end
I2C_CR: begin
wb_adr_i <= WB_CR;
wb_dat_i <= wb_cr;
wb_we_i <= 1'b1;
if (wb_ack_o) begin
i2c_state <= I2C_TIP_START;
end
end
I2C_TIP_START: begin
wb_adr_i <= WB_SR;
wb_dat_i <= 8'b0;
wb_we_i <= 1'b0;
if (wb_ack_o && wb_dat_o[1]) begin
i2c_state <= I2C_TIP;
end
end
I2C_TIP: begin //TIP transfer in progress
wb_adr_i <= WB_SR;
wb_dat_i <= 8'b0;
wb_we_i <= 1'b0;
if (wb_ack_o && !wb_dat_o[1]) begin
i2c_state <= I2C_TIP_FIN;
i2c_tip_fin <= 1'b1; //pulse this as we transition to final state
end
end
I2C_TIP_FIN: begin
i2c_tip_fin <= 1'b0;
if (!i2c_wr) begin
i2c_state <= I2C_IDLE;
end
end
//end cases to initiate i2c write transfer
//default case, just go to I2C_IDLE
default : begin
i2c_state <= I2C_IDLE;
end
endcase
end
end //always
// i2c master top controller state machine
localparam IDLE = 0;
localparam EN = 1;
localparam IO_EXP_CONFIG_1 = 2;
localparam IO_EXP_CONFIG_2 = 3;
localparam IO_EXP_CONFIG_3 = 4;
localparam IO_EXP_CONFIG_4 = 5;
localparam IO_EXP_FIN = 6;
wire [15:0] io_config;
assign io_config = { rfs_en, sync5, sync4, sync3, sync2, sync1 };
reg [2:0] master_state;
always @(posedge ctrlport_clk) begin
if (ctrlport_rst) begin
master_state <= IDLE;
wb_txr <= 8'b0;
wb_cr <= 8'b0;
i2c_wr <= 1'b0;
setup_finished <= 1'b0;
config_io_finished <= 1'b0;
i2c_core_setup <= 1'b0;
end
else begin
case(master_state)
IDLE: begin
i2c_wr <= 1'b0;
setup_finished <= 1'b0;
config_io_finished <= 1'b0;
i2c_core_setup <= 1'b0;
if (setup_trig) begin
master_state <= EN;
end
else if (config_io_trig) begin
master_state <= IO_EXP_CONFIG_1;
end
end
EN: begin //all the prescale and enable setup happens in i2c_state machine
i2c_core_setup <= 1'b1; //triggers setup sequence in i2c state machine.
i2c_wr <= 1'b0;
if (i2c_master_en) begin //indicates setup sequence finished
master_state <= IO_EXP_CONFIG_1;
end
end
IO_EXP_CONFIG_1: begin //first stage of setting up IO EXP with startup configurations
wb_txr <= { SYNC_IO_SLV_ADR, I2C_WR};
wb_cr <= CR_START_AND_WRITE;
if (i2c_tip_fin) begin //when transfer is done, i2c_wr is disabled
i2c_wr <= 1'b0;
master_state <= IO_EXP_CONFIG_2;
end else begin
i2c_wr <= 1'b1;
end
end
IO_EXP_CONFIG_2: begin
if (setup_trig) begin
wb_txr <= IO_EXP_CONFIG0_REG; //CONFIG0 reg is what we set to configure I/O as output
end else if (config_io_trig) begin
wb_txr <= IO_EXP_OUTPUT_PORT0_REG;
end
wb_cr <= CR_WRITE;
if (i2c_tip_fin) begin //when transfer is done, i2c_wr is disabled
i2c_wr <= 1'b0;
master_state <= IO_EXP_CONFIG_3;
end else begin
i2c_wr <= 1'b1;
end
end
IO_EXP_CONFIG_3: begin
if (setup_trig) begin
wb_txr <= 1'b0;
end else if (config_io_trig) begin
wb_txr <= io_config[7:0];
end
wb_cr <= CR_WRITE;
if (i2c_tip_fin) begin //when transfer is done, i2c_wr is disabled
i2c_wr <= 1'b0;
master_state <= IO_EXP_CONFIG_4;
end else begin
i2c_wr <= 1'b1;
end
end
IO_EXP_CONFIG_4: begin
if (setup_trig) begin
wb_txr <= 1'b0;
end else if (config_io_trig) begin
wb_txr <= io_config[15:8];
end
wb_cr <= CR_WRITE_AND_STOP;
if (i2c_tip_fin) begin //when transfer is done, i2c_wr is disabled
i2c_wr <= 1'b0;
setup_finished <= setup_trig;
config_io_finished <= config_io_trig;
master_state <= IO_EXP_FIN;
end else begin
i2c_wr <= 1'b1;
end
end
IO_EXP_FIN : begin //final state to make sure triggers are unset before returning to IDLE;
i2c_wr <= 1'b0;
setup_finished <= 1'b0;
config_io_finished <= 1'b0;
if (!setup_trig && !config_io_trig) begin
master_state <= IDLE;
end
end
default : begin
master_state <= IDLE;
end
endcase
end
end //always
//wishbone-based i2c core
i2c_master_top #(
.ARST_LVL(1)
) i2c_master (
.wb_clk_i(ctrlport_clk),
.wb_rst_i(ctrlport_rst),
.arst_i(1'b0),
.wb_adr_i(wb_adr_i),
.wb_dat_i(wb_dat_i),
.wb_dat_o(wb_dat_o),
.wb_we_i(wb_we_i),
.wb_stb_i(wb_cyc_i),
.wb_cyc_i(wb_cyc_i),
.wb_ack_o(wb_ack_o),
.wb_inta_o(),
.scl_pad_i(scl_pad_i),
.scl_pad_o(scl_pad_o),
.scl_padoen_o(scl_pad_en_o),
.sda_pad_i(sda_pad_i),
.sda_pad_o(sda_pad_o),
.sda_padoen_o(sda_pad_en_o)
);
endmodule
//XmlParse xml_on
//<regmap name="RF_SYNC_REGMAP" readablestrobes="false" generatevhdl="true" ettusguidelines="true">
// <group name="RF_SYNC_REGISTERS">
// <info>
// Each channel in the FBX daughterboard has 4 switches in its path. 3 of these are HMC849A 2:1
// switches and the last one is a PE42442 4:1 switch. The latter, as well as the enable lines for
// all four switches are not considered time critical controls, and are hence driven by a
// TCA6416A I/O expander controlled via I2C.
// This register map controls that I/O expander. The first 6 registers in
// this space set the values of the 5 3-pin sync switches and then an
// RFS enable bit. The 2 additional registers trigger a init sequence for
// the expander peripheral and configuring the I/O with the contents of
// the value registers both with a series of I2C commands.
// </info>
// <regtype name="SYNC_SWITCH" size="32" attributes="Readable|Writable">
// <info>
// Sets I/O to control Sync Switch.
// </info>
// <bitfield name="CONTROL_PIN_V1" range="0" initialvalue="0"/>
// <bitfield name="CONTROL_PIN_V2" range="1" initialvalue="0"/>
// <bitfield name="CONTROL_PIN_V3" range="2" initialvalue="0"/>
// </regtype>
// <register name="SYNC_1_REG" offset="0x00" typename="SYNC_SWITCH">
// <info>
// Sets I/O state to control Sync Switch 1.
// </info>
// </register>
// <register name="SYNC_2_REG" offset="0x04" typename="SYNC_SWITCH">
// <info>
// Sets I/O state to control Sync Switch 2.
// </info>
// </register>
// <register name="SYNC_3_REG" offset="0x08" typename="SYNC_SWITCH">
// <info>
// Sets I/O state to control Sync Switch 3.
// </info>
// </register>
// <register name="SYNC_4_REG" offset="0x0C" typename="SYNC_SWITCH">
// <info>
// Sets I/O state to control Sync Switch 4.
// </info>
// </register>
// <register name="SYNC_5_REG" offset="0x10" typename="SYNC_SWITCH">
// <info>
// Sets I/O state to control Sync Switch 5.
// </info>
// </register>
// <register name="RFS_EN_REG" offset="0x014" size="32" attributes="Readable|Writable">
// <info>
// Sets I/O state to control RFS Enable.
// </info>
// <bitfield name="RFS_EN_PIN" range="0" initialvalue="0" />
// </register>
// <register name="SETUP_REG" offset="0x18" size="32" attributes="Writable">
// <info>
// Write to this register to trigger initialization sequence of
// I2C Master core and TCA6416A I/O expander peripheral.
// </info>
// <bitfield name="SETUP_TRIG" range="0" initialvalue="0"/>
// </register>
// <register name="SETUP_STATUS_REG" offset="0x18" size="32" attributes="Readable">
// <info>
// Read from this register to check the status of setup.
// </info>
// <bitfield name="SETUP_STATUS" range="0" initialvalue="0"/>
// </register>
// <register name="CONFIG_IO_REG" offset="0x1C" size="32" attributes="Writable">
// <info>
// Write to this register to trigger I/O configuration I2C sequence of
// TCA6416A I/O expander peripheral.
// Read from this register to check the status of reconfiguring the setup.
// </info>
// <bitfield name="CONFIG_IO_TRIG" range="0" initialvalue="0"/>
// </register>
// <register name="CONFIG_IO_STATUS_REG" offset="0x1C" size="32" attributes="Readable">
// <info>
// Read from this register to check the status of reconfiguring the setup.
// </info>
// <bitfield name="CONFIG_IO_STATUS" range="0" initialvalue="0"/>
// </register>
//
// <enumeratedtype name="IO_EXPANDER_REGISTER_ADRS">
// <info>
// This is not a register spaces for this ctrlport interface but
// instead register addresses on the TCA6416A. Therefore, we will just
// define an enum with these addresses so there is no clash with the
// above ctrlport regmap.
// </info>
// <value name="IO_EXP_INPUT_PORT0_REG" integer="0"/>
// <value name="IO_EXP_INPUT_PORT1_REG" integer="1"/>
// <value name="IO_EXP_OUTPUT_PORT0_REG" integer="2"/>
// <value name="IO_EXP_OUTPUT_PORT1_REG" integer="3"/>
// <value name="IO_EXP_POLARITY_INV0_REG" integer="4"/>
// <value name="IO_EXP_POLARITY_INV1_REG" integer="5"/>
// <value name="IO_EXP_CONFIG0_REG" integer="6"/>
// <value name="IO_EXP_CONFIG1_REG" integer="7"/>
// </enumeratedtype>
// </group>
//</regmap>
//XmlParse xml_off
+444
View File
@@ -0,0 +1,444 @@
//
// Copyright 2022 Ettus Research, a National Instruments Brand
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: db_gpio_interface
//
// Description:
// Interface for GPIO interface towards FBX daughterboards.
//
//
// The 20 available GPIO lines are assigned with
// - 12x RF switches(3x per channel)
// - 2x I2C to Sync switches IO Expander
// - 6x empty
//
`default_nettype none
module db_gpio_interface #(
parameter LED_REGISTER_ADDRESS = 0
) (
// Clocks and reset
input wire radio_clk,
input wire pll_ref_clk,
input wire in_sync_clk,
output wire out_sync_clk,
// DB state lines (domain: radio_clk)
input wire [ 7:0] db_state,
// 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,
// 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,
// ControlPort request to CPLD (domain: radio_clk)
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,
output wire [ 3:0] m_ctrlport_req_byte_en,
// ControlPort response from CPLD (domain: radio_clk)
input wire m_ctrlport_resp_ack,
input wire [ 1:0] m_ctrlport_resp_status,
input wire [31:0] m_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/x440/versioning_regs_regmap_utils.vh"
`include "regmap/fbx_ctrl_regmap_utils.vh"
`include "../../regmap/versioning_utils.vh"
//----------------------------------------------------------------------------
// Radio_clk -> pll_ref_clk clock crossing
//----------------------------------------------------------------------------
wire ctrlport_rst_prc;
wire ctrlport_req_wr_prc;
wire ctrlport_req_rd_prc;
wire [19:0] ctrlport_req_addr_prc;
wire [31:0] ctrlport_req_data_prc;
wire ctrlport_resp_ack_prc;
wire [ 1:0] ctrlport_resp_status_prc;
wire [31:0] ctrlport_resp_data_prc;
ctrlport_clk_cross core_clk_cross_slave (
.rst (ctrlport_rst),
.s_ctrlport_clk (radio_clk),
.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_portid (),
.s_ctrlport_req_rem_epid (),
.s_ctrlport_req_rem_portid (),
.s_ctrlport_req_data (s_ctrlport_req_data),
.s_ctrlport_req_byte_en (),
.s_ctrlport_req_has_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_clk (pll_ref_clk),
.m_ctrlport_req_wr (ctrlport_req_wr_prc),
.m_ctrlport_req_rd (ctrlport_req_rd_prc),
.m_ctrlport_req_addr (ctrlport_req_addr_prc),
.m_ctrlport_req_portid (),
.m_ctrlport_req_rem_epid (),
.m_ctrlport_req_rem_portid (),
.m_ctrlport_req_data (ctrlport_req_data_prc),
.m_ctrlport_req_byte_en (),
.m_ctrlport_req_has_time (),
.m_ctrlport_req_time (),
.m_ctrlport_resp_ack (ctrlport_resp_ack_prc),
.m_ctrlport_resp_status (ctrlport_resp_status_prc),
.m_ctrlport_resp_data (ctrlport_resp_data_prc)
);
reset_sync reset_sync_prc (
.clk (pll_ref_clk),
.reset_in (ctrlport_rst),
.reset_out (ctrlport_rst_prc)
);
wire [7:0] db_state_prc;
handshake #(
.WIDTH (8)
) synchronizer_db_state (
.clk_a (radio_clk),
.rst_a (ctrlport_rst),
.valid_a (1'b1),
.data_a (db_state),
.busy_a (),
.clk_b (pll_ref_clk),
.valid_b (),
.data_b (db_state_prc)
);
//----------------------------------------------------------------------------
// CtrlPort Splitter
//----------------------------------------------------------------------------
wire [19:0] rf_atr_ctrlport_req_addr;
wire [31:0] rf_atr_ctrlport_req_data;
wire rf_atr_ctrlport_req_rd;
wire rf_atr_ctrlport_req_wr;
wire rf_atr_ctrlport_resp_ack;
wire [31:0] rf_atr_ctrlport_resp_data;
wire [ 1:0] rf_atr_ctrlport_resp_status;
wire [19:0] sync_ctrlport_req_addr;
wire [31:0] sync_ctrlport_req_data;
wire sync_ctrlport_req_rd;
wire sync_ctrlport_req_wr;
wire sync_ctrlport_resp_ack;
wire [31:0] sync_ctrlport_resp_data;
wire [ 1:0] sync_ctrlport_resp_status;
wire [19:0] led_atr_ctrlport_req_addr;
wire [31:0] led_atr_ctrlport_req_data;
wire led_atr_ctrlport_req_rd;
wire led_atr_ctrlport_req_wr;
wire led_atr_ctrlport_resp_ack;
wire [31:0] led_atr_ctrlport_resp_data;
wire [ 1:0] led_atr_ctrlport_resp_status;
wire [19:0] clk_en_ctrlport_req_addr;
wire [31:0] clk_en_ctrlport_req_data;
wire clk_en_ctrlport_req_rd;
wire clk_en_ctrlport_req_wr;
wire clk_en_ctrlport_resp_ack;
wire [31:0] clk_en_ctrlport_resp_data;
wire [ 1:0] clk_en_ctrlport_resp_status;
ctrlport_splitter #(
.NUM_SLAVES (4)
) fbx_ctrlport_splitter (
.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_req_byte_en (4'hF),
.s_ctrlport_req_has_time (1'b0),
.s_ctrlport_req_time (64'b0),
.s_ctrlport_resp_ack (ctrlport_resp_ack_prc),
.s_ctrlport_resp_status (ctrlport_resp_status_prc),
.s_ctrlport_resp_data (ctrlport_resp_data_prc),
.m_ctrlport_req_wr ({ clk_en_ctrlport_req_wr, led_atr_ctrlport_req_wr, sync_ctrlport_req_wr, rf_atr_ctrlport_req_wr }),
.m_ctrlport_req_rd ({ clk_en_ctrlport_req_rd, led_atr_ctrlport_req_rd, sync_ctrlport_req_rd, rf_atr_ctrlport_req_rd }),
.m_ctrlport_req_addr ({ clk_en_ctrlport_req_addr, led_atr_ctrlport_req_addr, sync_ctrlport_req_addr, rf_atr_ctrlport_req_addr }),
.m_ctrlport_req_data ({ clk_en_ctrlport_req_data, led_atr_ctrlport_req_data, sync_ctrlport_req_data, rf_atr_ctrlport_req_data }),
.m_ctrlport_req_byte_en (),
.m_ctrlport_req_has_time (),
.m_ctrlport_req_time (),
.m_ctrlport_resp_ack ({ clk_en_ctrlport_resp_ack, led_atr_ctrlport_resp_ack, sync_ctrlport_resp_ack, rf_atr_ctrlport_resp_ack }),
.m_ctrlport_resp_status ({ clk_en_ctrlport_resp_status, led_atr_ctrlport_resp_status, sync_ctrlport_resp_status, rf_atr_ctrlport_resp_status }),
.m_ctrlport_resp_data ({ clk_en_ctrlport_resp_data, led_atr_ctrlport_resp_data, sync_ctrlport_resp_data, rf_atr_ctrlport_resp_data })
);
//----------------------------------------------------------------------------
// Switch Control
//----------------------------------------------------------------------------
wire rf0_tx_rx_rfs, rf0_rx_rfs, rf0_tdds;
wire rf1_tx_rx_rfs, rf1_rx_rfs, rf1_tdds;
wire rf2_tx_rx_rfs, rf2_rx_rfs, rf2_tdds;
wire rf3_tx_rx_rfs, rf3_rx_rfs, rf3_tdds;
rf_atr_control #(
.REG_BASE (RF_ATR_REGS),
.REG_SIZE (RF_ATR_REGS_SIZE)
) rf_atr_control_i (
.ctrlport_clk (pll_ref_clk),
.ctrlport_rst (ctrlport_rst_prc),
.s_ctrlport_req_wr (rf_atr_ctrlport_req_wr),
.s_ctrlport_req_rd (rf_atr_ctrlport_req_rd),
.s_ctrlport_req_addr (rf_atr_ctrlport_req_addr),
.s_ctrlport_req_data (rf_atr_ctrlport_req_data),
.s_ctrlport_resp_ack (rf_atr_ctrlport_resp_ack),
.s_ctrlport_resp_status (rf_atr_ctrlport_resp_status),
.s_ctrlport_resp_data (rf_atr_ctrlport_resp_data),
.db_state (db_state_prc),
.rf0_tx_rx_rfs (rf0_tx_rx_rfs),
.rf0_rx_rfs (rf0_rx_rfs),
.rf0_tdds (rf0_tdds),
.rf1_tx_rx_rfs (rf1_tx_rx_rfs),
.rf1_rx_rfs (rf1_rx_rfs),
.rf1_tdds (rf1_tdds),
.rf2_tx_rx_rfs (rf2_tx_rx_rfs),
.rf2_rx_rfs (rf2_rx_rfs),
.rf2_tdds (rf2_tdds),
.rf3_tx_rx_rfs (rf3_tx_rx_rfs),
.rf3_rx_rfs (rf3_rx_rfs),
.rf3_tdds (rf3_tdds)
);
//----------------------------------------------------------------------------
// LED Control
//----------------------------------------------------------------------------
wire cpld_ctrlport_req_wr;
wire cpld_ctrlport_req_rd;
wire [19:0] cpld_ctrlport_req_addr;
wire [31:0] cpld_ctrlport_req_data;
wire [ 3:0] cpld_ctrlport_req_byte_en;
wire cpld_ctrlport_resp_ack;
wire [ 1:0] cpld_ctrlport_resp_status;
wire [31:0] cpld_ctrlport_resp_data;
led_atr_control #(
.LED_REGISTER_ADDRESS (LED_REGISTER_ADDRESS),
.REG_BASE (LED_ATR_REGS),
.REG_SIZE (LED_ATR_REGS_SIZE)
) led_atr_control_i (
.ctrlport_clk (pll_ref_clk),
.ctrlport_rst (ctrlport_rst_prc),
.s_ctrlport_req_wr (led_atr_ctrlport_req_wr),
.s_ctrlport_req_rd (led_atr_ctrlport_req_rd),
.s_ctrlport_req_addr (led_atr_ctrlport_req_addr),
.s_ctrlport_req_data (led_atr_ctrlport_req_data),
.s_ctrlport_resp_ack (led_atr_ctrlport_resp_ack),
.s_ctrlport_resp_status (led_atr_ctrlport_resp_status),
.s_ctrlport_resp_data (led_atr_ctrlport_resp_data),
.db_state (db_state_prc),
.m_ctrlport_req_wr (cpld_ctrlport_req_wr),
.m_ctrlport_req_rd (cpld_ctrlport_req_rd),
.m_ctrlport_req_addr (cpld_ctrlport_req_addr),
.m_ctrlport_req_data (cpld_ctrlport_req_data),
.m_ctrlport_req_byte_en (cpld_ctrlport_req_byte_en),
.m_ctrlport_resp_ack (cpld_ctrlport_resp_ack),
.m_ctrlport_resp_status (cpld_ctrlport_resp_status),
.m_ctrlport_resp_data (cpld_ctrlport_resp_data)
);
ctrlport_clk_cross core_clk_cross_cpld_master (
.rst (ctrlport_rst_prc),
.s_ctrlport_clk (pll_ref_clk),
.s_ctrlport_req_wr (cpld_ctrlport_req_wr),
.s_ctrlport_req_rd (cpld_ctrlport_req_rd),
.s_ctrlport_req_addr (cpld_ctrlport_req_addr),
.s_ctrlport_req_portid (),
.s_ctrlport_req_rem_epid (),
.s_ctrlport_req_rem_portid (),
.s_ctrlport_req_data (cpld_ctrlport_req_data),
.s_ctrlport_req_byte_en (cpld_ctrlport_req_byte_en),
.s_ctrlport_req_has_time (),
.s_ctrlport_req_time (),
.s_ctrlport_resp_ack (cpld_ctrlport_resp_ack),
.s_ctrlport_resp_status (cpld_ctrlport_resp_status),
.s_ctrlport_resp_data (cpld_ctrlport_resp_data),
.m_ctrlport_clk (radio_clk),
.m_ctrlport_req_wr (m_ctrlport_req_wr),
.m_ctrlport_req_rd (m_ctrlport_req_rd),
.m_ctrlport_req_addr (m_ctrlport_req_addr),
.m_ctrlport_req_portid (),
.m_ctrlport_req_rem_epid (),
.m_ctrlport_req_rem_portid (),
.m_ctrlport_req_data (m_ctrlport_req_data),
.m_ctrlport_req_byte_en (m_ctrlport_req_byte_en),
.m_ctrlport_req_has_time (),
.m_ctrlport_req_time (),
.m_ctrlport_resp_ack (m_ctrlport_resp_ack),
.m_ctrlport_resp_status (m_ctrlport_resp_status),
.m_ctrlport_resp_data (m_ctrlport_resp_data)
);
//----------------------------------------------------------------------------
// I2C Control
//----------------------------------------------------------------------------
wire i2c_scl_i, i2c_scl_o, i2c_scl_en_o;
wire i2c_sda_i, i2c_sda_o, i2c_sda_en_o;
ctrlport_to_i2c_sync_ctrl #(
.BASE_ADDRESS(RF_SYNC_REGS),
.PRESCALE(1000)
) ctrlport_to_i2c_inst (
.ctrlport_clk (pll_ref_clk),
.ctrlport_rst (ctrlport_rst_prc),
.s_ctrlport_req_wr (sync_ctrlport_req_wr),
.s_ctrlport_req_rd (sync_ctrlport_req_rd),
.s_ctrlport_req_addr (sync_ctrlport_req_addr),
.s_ctrlport_req_data (sync_ctrlport_req_data),
.s_ctrlport_resp_ack (sync_ctrlport_resp_ack),
.s_ctrlport_resp_status (sync_ctrlport_resp_status),
.s_ctrlport_resp_data (sync_ctrlport_resp_data),
.scl_pad_i (i2c_scl_i),
.scl_pad_o (i2c_scl_o),
.scl_pad_en_o (i2c_scl_en_o),
.sda_pad_i (i2c_sda_i),
.sda_pad_o (i2c_sda_o),
.sda_pad_en_o (i2c_sda_en_o)
);
//----------------------------------------------------------------------------
// Sync Clock Enable
//----------------------------------------------------------------------------
clock_en_control #(
.BASE_ADDRESS(SYNC_CLK_EN_REGS)
) clock_en_control_inst (
.ctrlport_clk (pll_ref_clk),
.ctrlport_rst (ctrlport_rst_prc),
.s_ctrlport_req_wr (clk_en_ctrlport_req_wr),
.s_ctrlport_req_rd (clk_en_ctrlport_req_rd),
.s_ctrlport_req_addr (clk_en_ctrlport_req_addr),
.s_ctrlport_req_data (clk_en_ctrlport_req_data),
.s_ctrlport_resp_ack (clk_en_ctrlport_resp_ack),
.s_ctrlport_resp_status (clk_en_ctrlport_resp_status),
.s_ctrlport_resp_data (clk_en_ctrlport_resp_data),
.clk_in (in_sync_clk),
.clk_out (out_sync_clk)
);
//----------------------------------------------------------------------------
// wire assignment
//----------------------------------------------------------------------------
// RFS1, RFS2, RFS3, RFS4, RFS5, RFS6, RFS7, RFS8, TDDS1, TDDS2, TDDS3, TDDS4,
// 2 unused, 2 for I2C, 4 unused.
assign i2c_sda_i = gpio_in[4];
assign i2c_scl_i = gpio_in[5];
assign gpio_out = {rf0_tx_rx_rfs, rf0_rx_rfs,
rf1_tx_rx_rfs, rf1_rx_rfs,
rf2_tx_rx_rfs, rf2_rx_rfs,
rf3_tx_rx_rfs, rf3_rx_rfs,
rf0_tdds, rf1_tdds,
rf2_tdds, rf3_tdds,
2'b0, // Unused
i2c_scl_o, i2c_sda_o, // I2C
4'b0 // Unused
};
assign gpio_out_en = {12'hFFF, // Switches
2'b0, // Unused
~i2c_scl_en_o, ~i2c_sda_en_o, // I2C enables tri-state when HIGH
4'b0 // Unused
};
//----------------------------------------------------------------------------
// 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="0x22070116"/>
// </enumeratedtype>
// </group>
//</regmap>
//<regmap name="FBX_CTRL_REGMAP" readablestrobes="false" generatevhdl="true" ettusguidelines="true">
// <info>
// This map contains register windows for controlling the different sources
// that drive the state of FBX control lines.
// </info>
// <group name="FBX_CONTROLS">
// <window name="RF_ATR_REGS" offset="0x0" size="0x2000" targetregmap="RF_ATR_REGMAP">
// <info>Control RF switches in FBX daughterboard based on the ATR state of the accessed radio</info>
// </window>
// <window name="RF_SYNC_REGS" offset="0x2000" size="0x2000" targetregmap="RF_SYNC_REGMAP">
// <info>I2C interface to FBX daughterboard IO Expander that controls SYNC switches and rfs en</info>
// </window>
// <window name="LED_ATR_REGS" offset="0x4000" size="0x2000" targetregmap="LED_ATR_REGMAP">
// <info>Control TX/RX LEDs based on the ATR state of the accessed radio</info>
// </window>
// <window name="SYNC_CLK_EN_REGS" offset="0x6000" size="0x2000" targetregmap="CLK_EN_REGMAP">
// <info>Clock enable register for SYNC INJECT 5 MHz clock</info>
// </window>
// </group>
//</regmap>
//XmlParse xml_off
+569
View File
@@ -0,0 +1,569 @@
//
// Copyright 2022 Ettus Research, A National Instruments Brand
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: led_atr_control
//
// Description:
// Translates db_status to implement control over RF LEDs via CtrlPort.
// Uses RAM to store multiple ATR configurations. Triggers CtrlPort
// requests to transfer changes to LEDs to MB CPLD.
// There are three supported control schemes for these switches:
// - ATR Disabled - Single persistent state.
// - Classic ATR - Each channel's LEDs depend on the transmission state
// of the respective channel.
// - DB State - Each channel's LEDs depend on the transmission state
// of all channels in this radio.
//
// Parameters:
//
// LED_REGISTER_ADDRESS : Address of LED register within CPLD.
// REG_BASE : Base address to use for registers.
// REG_SIZE : Register space size.
//
`default_nettype none
module led_atr_control #(
parameter LED_REGISTER_ADDRESS = 0,
parameter REG_BASE = 'h2000,
parameter REG_SIZE = 'h2000
) (
// Common ControlPort signals
input wire ctrlport_clk,
input wire ctrlport_rst,
// Slave ctrlport inteledace
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,
output reg s_ctrlport_resp_ack = 1'b0,
output reg [ 1:0] s_ctrlport_resp_status = 2'b00,
output reg [31:0] s_ctrlport_resp_data = {32 {1'b0}},
// DB state lines
input wire [7:0] db_state,
// ControlPort request
output reg 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,
output wire [ 3:0] m_ctrlport_req_byte_en,
// ControlPort response
input wire m_ctrlport_resp_ack,
input wire [ 1:0] m_ctrlport_resp_status,
input wire [31:0] m_ctrlport_resp_data
);
`include "../../cpld/regmap/x440/led_setup_regmap_utils.vh"
`include "../../../../lib/rfnoc/core/ctrlport.vh"
`include "regmap/led_atr_regmap_utils.vh"
//---------------------------------------------------------------
// ATR memory signals
//---------------------------------------------------------------
reg ram_led0_wea;
wire [LED_SIZE-1:0] ram_led0_doa;
wire [LED_SIZE-1:0] ram_led0_dob;
reg ram_led1_wea;
wire [LED_SIZE-1:0] ram_led1_doa;
wire [LED_SIZE-1:0] ram_led1_dob;
reg ram_led2_wea;
wire [LED_SIZE-1:0] ram_led2_doa;
wire [LED_SIZE-1:0] ram_led2_dob;
reg ram_led3_wea;
wire [LED_SIZE-1:0] ram_led3_doa;
wire [LED_SIZE-1:0] ram_led3_dob;
//---------------------------------------------------------------
// ATR Scheme signals
//---------------------------------------------------------------
reg [3:0] atr_disable = 4'b0;
// DB state/Classic ATR selector
reg [3:0] atr_mode = 4'b0;
//---------------------------------------------------------------------------
// Control inteledace handling
//---------------------------------------------------------------------------
// Check that address is within this module's range.
wire address_in_range = (s_ctrlport_req_addr >= REG_BASE) && (s_ctrlport_req_addr < REG_BASE + REG_SIZE);
// Check that address is targeting an ATR state.
wire address_is_atr = (s_ctrlport_req_addr >= REG_BASE + LED0_ATR_STATE(0)) && (s_ctrlport_req_addr <= REG_BASE + LED3_ATR_STATE(LED3_ATR_STATE_COUNT-1));
// Read request shift register to align memory read and response generation.
reg [ 1:0] read_req_shift_reg = 2'b0;
// Mask out 8 bits for ATR configurations to be able to compare all ATR
// configurations against the same base register address.
wire [31:0] register_base_address = {s_ctrlport_req_addr[19:10], 8'b0, s_ctrlport_req_addr[1:0]};
// Decode the ATR state being addressed.
wire [ 7:0] atr_address = s_ctrlport_req_addr[9:2];
always @ (posedge ctrlport_clk) begin
if (ctrlport_rst) begin
s_ctrlport_resp_ack <= 1'b0;
s_ctrlport_resp_data <= 32'b0;
s_ctrlport_resp_status <= 2'b00;
atr_disable <= 4'b0;
atr_mode <= 4'b0;
ram_led0_wea <= 1'b0;
ram_led1_wea <= 1'b0;
ram_led2_wea <= 1'b0;
ram_led3_wea <= 1'b0;
end else begin
// default assignments
read_req_shift_reg <= {read_req_shift_reg[0], s_ctrlport_req_rd};
ram_led0_wea <= 1'b0;
ram_led1_wea <= 1'b0;
ram_led2_wea <= 1'b0;
ram_led3_wea <= 1'b0;
// Write registers
if (s_ctrlport_req_wr) begin
// Acknowledge by default
s_ctrlport_resp_ack <= 1'b1;
s_ctrlport_resp_status <= CTRL_STS_OKAY;
// Address ATR state writes
if(address_is_atr) begin
case (register_base_address)
REG_BASE + LED0_ATR_STATE(0): begin
ram_led0_wea <= 1'b1;
end
REG_BASE + LED1_ATR_STATE(0): begin
ram_led1_wea <= 1'b1;
end
REG_BASE + LED2_ATR_STATE(0): begin
ram_led2_wea <= 1'b1;
end
REG_BASE + LED3_ATR_STATE(0): begin
ram_led3_wea <= 1'b1;
end
// error on undefined address
default: begin
s_ctrlport_resp_status <= CTRL_STS_CMDERR;
end
endcase
end else begin
// Address writes to the rest of the register space
case (s_ctrlport_req_addr)
REG_BASE + LED_ATR_OPTION_REGISTER: begin
atr_mode[0] <= s_ctrlport_req_data[LED0_ATR_OPTION];
atr_mode[1] <= s_ctrlport_req_data[LED1_ATR_OPTION];
atr_mode[2] <= s_ctrlport_req_data[LED2_ATR_OPTION];
atr_mode[3] <= s_ctrlport_req_data[LED3_ATR_OPTION];
end
REG_BASE + LED_ATR_DISABLED: begin
atr_disable[0] <= s_ctrlport_req_data[LED0_ATR_DISABLED];
atr_disable[1] <= s_ctrlport_req_data[LED1_ATR_DISABLED];
atr_disable[2] <= s_ctrlport_req_data[LED2_ATR_DISABLED];
atr_disable[3] <= s_ctrlport_req_data[LED3_ATR_DISABLED];
end
// No register implementation for provided address
default: begin
// Acknowledge and provide error status if address is in range
if (address_in_range) begin
s_ctrlport_resp_status <= CTRL_STS_CMDERR;
// No response if out of range
end else begin
s_ctrlport_resp_ack <= 1'b0;
end
end
endcase
end
// Read registers
end else if (read_req_shift_reg[1]) begin
// Acknowledge by default
s_ctrlport_resp_ack <= 1'b1;
s_ctrlport_resp_status <= CTRL_STS_OKAY;
// Address ATR state reads
if(address_is_atr) begin
case (register_base_address)
REG_BASE + LED0_ATR_STATE(0): begin
s_ctrlport_resp_data <= ram_led0_doa & LED_ATR_STATE_MASK;
end
REG_BASE + LED1_ATR_STATE(0): begin
s_ctrlport_resp_data <= ram_led1_doa & LED_ATR_STATE_MASK;
end
REG_BASE + LED2_ATR_STATE(0): begin
s_ctrlport_resp_data <= ram_led2_doa & LED_ATR_STATE_MASK;
end
REG_BASE + LED3_ATR_STATE(0): begin
s_ctrlport_resp_data <= ram_led3_doa & LED_ATR_STATE_MASK;
end
default: begin
s_ctrlport_resp_status <= CTRL_STS_CMDERR;
end
endcase
end else begin
// Address reads to the rest of the register space
case (s_ctrlport_req_addr)
REG_BASE + LED_ATR_OPTION_REGISTER: begin
s_ctrlport_resp_data[LED0_ATR_OPTION] <= atr_mode[0];
s_ctrlport_resp_data[LED1_ATR_OPTION] <= atr_mode[1];
s_ctrlport_resp_data[LED2_ATR_OPTION] <= atr_mode[2];
s_ctrlport_resp_data[LED3_ATR_OPTION] <= atr_mode[3];
end
REG_BASE + LED_ATR_DISABLED: begin
s_ctrlport_resp_data[LED0_ATR_DISABLED] <= atr_disable[0];
s_ctrlport_resp_data[LED1_ATR_DISABLED] <= atr_disable[1];
s_ctrlport_resp_data[LED2_ATR_DISABLED] <= atr_disable[2];
s_ctrlport_resp_data[LED3_ATR_DISABLED] <= atr_disable[3];
end
// No register implementation for provided address
default: begin
// Acknowledge and provide error status if address is in range
if (address_in_range) begin
s_ctrlport_resp_status <= CTRL_STS_CMDERR;
// No response if out of range
end else begin
s_ctrlport_resp_ack <= 1'b0;
end
end
endcase
end
end else begin
s_ctrlport_resp_ack <= 1'b0;
end
end
end
// register without reset
reg [ 7:0] ram_addr = 8'b0;
reg [LED_SIZE-1:0] ram_datain = {LED_SIZE{1'b0}};
always @(posedge ctrlport_clk) begin
// memories
ram_addr <= atr_address;
ram_datain <= s_ctrlport_req_data[LED_SIZE-1:0];
end
// ATR Scheme selection
reg [7:0] atr_config_led [3:0];
generate
genvar i;
for (i = 0; i < 4; i = i + 1) begin: read_address_gen
always @(posedge ctrlport_clk) begin
if (atr_disable[i]) begin
atr_config_led[i] <= 8'b0;
end else begin
if (atr_mode[i]) begin
atr_config_led[i] <= {6'b0, db_state[2*i+:2]};
end else begin
atr_config_led[i] <= db_state;
end
end
end
end
endgenerate
reg [31:0] led_combined = 32'b0;
always @(posedge ctrlport_clk) begin
led_combined[CH0_RX2_LED_EN] <= ram_led0_dob[RX2_LED];
led_combined[CH0_TRX1_LED_RED_EN] <= ram_led0_dob[TXRX_RED_LED];
led_combined[CH0_TRX1_LED_GR_EN] <= ram_led0_dob[TXRX_GR_LED];
led_combined[CH1_RX2_LED_EN] <= ram_led1_dob[RX2_LED];
led_combined[CH1_TRX1_LED_RED_EN] <= ram_led1_dob[TXRX_RED_LED];
led_combined[CH1_TRX1_LED_GR_EN] <= ram_led1_dob[TXRX_GR_LED];
led_combined[CH2_RX2_LED_EN] <= ram_led2_dob[RX2_LED];
led_combined[CH2_TRX1_LED_RED_EN] <= ram_led2_dob[TXRX_RED_LED];
led_combined[CH2_TRX1_LED_GR_EN] <= ram_led2_dob[TXRX_GR_LED];
led_combined[CH3_RX2_LED_EN] <= ram_led3_dob[RX2_LED];
led_combined[CH3_TRX1_LED_RED_EN] <= ram_led3_dob[TXRX_RED_LED];
led_combined[CH3_TRX1_LED_GR_EN] <= ram_led3_dob[TXRX_GR_LED];
end
//---------------------------------------------------------------
// ATR memory
//---------------------------------------------------------------
ram_2port #(
.DWIDTH (LED_SIZE),
.AWIDTH (8),
.RW_MODE ("READ-FIRST"),
.RAM_TYPE ("AUTOMATIC"),
.OUT_REG (0)
) ram_led0_i (
.clka (ctrlport_clk),
.ena (1'b1),
.wea (ram_led0_wea),
.addra (ram_addr),
.dia (ram_datain),
.doa (ram_led0_doa),
.clkb (ctrlport_clk),
.enb (1'b1),
.web (1'b0),
.addrb (atr_config_led[0]),
.dib ({LED_SIZE{1'b0}}),
.dob (ram_led0_dob));
ram_2port #(
.DWIDTH (LED_SIZE),
.AWIDTH (8),
.RW_MODE ("READ-FIRST"),
.RAM_TYPE ("AUTOMATIC"),
.OUT_REG (0)
) ram_led1_i (
.clka (ctrlport_clk),
.ena (1'b1),
.wea (ram_led1_wea),
.addra (ram_addr),
.dia (ram_datain),
.doa (ram_led1_doa),
.clkb (ctrlport_clk),
.enb (1'b1),
.web (1'b0),
.addrb (atr_config_led[1]),
.dib ({LED_SIZE{1'b0}}),
.dob (ram_led1_dob));
ram_2port #(
.DWIDTH (LED_SIZE),
.AWIDTH (8),
.RW_MODE ("READ-FIRST"),
.RAM_TYPE ("AUTOMATIC"),
.OUT_REG (0)
) ram_led2_i (
.clka (ctrlport_clk),
.ena (1'b1),
.wea (ram_led2_wea),
.addra (ram_addr),
.dia (ram_datain),
.doa (ram_led2_doa),
.clkb (ctrlport_clk),
.enb (1'b1),
.web (1'b0),
.addrb (atr_config_led[2]),
.dib ({LED_SIZE{1'b0}}),
.dob (ram_led2_dob));
ram_2port #(
.DWIDTH (LED_SIZE),
.AWIDTH (8),
.RW_MODE ("READ-FIRST"),
.RAM_TYPE ("AUTOMATIC"),
.OUT_REG (0)
) ram_led3_i (
.clka (ctrlport_clk),
.ena (1'b1),
.wea (ram_led3_wea),
.addra (ram_addr),
.dia (ram_datain),
.doa (ram_led3_doa),
.clkb (ctrlport_clk),
.enb (1'b1),
.web (1'b0),
.addrb (atr_config_led[3]),
.dib ({LED_SIZE{1'b0}}),
.dob (ram_led3_dob));
//----------------------------------------------------------
// Logic to wait for response after triggering request
//----------------------------------------------------------
reg transfer_in_progress;
reg [31:0] led_combined_delayed = 32'b0;
always @(posedge ctrlport_clk) begin
if (ctrlport_rst) begin
m_ctrlport_req_wr <= 1'b0;
transfer_in_progress <= 1'b0;
led_combined_delayed <= 16'b0;
end else begin
// Default assignment
m_ctrlport_req_wr <= 1'b0;
// Issue new request on change if no request is pending
if (led_combined != led_combined_delayed && ~transfer_in_progress) begin
transfer_in_progress <= 1'b1;
m_ctrlport_req_wr <= 1'b1;
led_combined_delayed <= led_combined;
end
// Reset pending request
if (m_ctrlport_resp_ack) begin
transfer_in_progress <= 1'b0;
end
end
end
//----------------------------------------------------------
// Static ControlPort assignments
//----------------------------------------------------------
assign m_ctrlport_req_rd = 0;
assign m_ctrlport_req_byte_en = 4'b1111;
assign m_ctrlport_req_addr = LED_REGISTER_ADDRESS;
assign m_ctrlport_req_data = {led_combined_delayed};
endmodule
//XmlParse xml_on
//<regmap name="LED_ATR_REGMAP" readablestrobes="false" generatevhdl="true" ettusguidelines="true">
// <group name="LED_ATR_REGISTERS">
// <info>
// Each channel in the FBX daughterboard has 3 LEDs. TXRX Red/Green LEDs and RX2 Green LED.
// This register map describes how to control the behavior of the 3 LEDs.
// There are three supported control schemes for these LEDs:</br>
// <ul>
// <li>ATR Disabled - Single persistent state.</li>
// <li>Classic ATR - Each channel's LEDs depend on the transmission state
// of the respective channel.</li>
// <li>DB State - Each channel's LEDs depend on the transmission state
// of all channels in this radio.</li>
// </ul>
// </info>
//
// <enumeratedtype name="LED_SIZE_TYPE">
// <value name="LED_SIZE" integer="3"/>
// </enumeratedtype>
//
// <regtype name="LED_ATR_STATE" size="32">
// <info>Holds the value for the control lines of each channel's LEDs
// for a particular ATR sate</info>
// <bitfield name="RX2_LED" range="0" initialvalue="0"/>
// <bitfield name="TXRX_RED_LED" range="1" initialvalue="0"/>
// <bitfield name="TXRX_GR_LED" range="2" initialvalue="0"/>
// </regtype>
//
// <register name="LED0_ATR_STATE" typename="LED_ATR_STATE" offset="0x00" count="256" options="--step 4">
// <info>
// Describes led behavior for the different ATR states. When @.LED0_ATR_OPTION
// is set to use the DB states, TX and RX states for LED0-LED3 are
// combined to create a single vector. This creates 256 different
// combinations, each with its own register. When @.LED0_ATR_OPTION is set to
// classic ATR, the first 4 offsets in this register group will be driven
// in accordance with the state of RF0.
// CLASSIC ATR MAPPING: Idle[RF0: TX=0, RX=0], RX[RF0: TX=0, RX=1,
// TX[RF0: TX=1, RX=0], FDX[RF0: TX=1, RX=1]
// </info>
// </register>
//
// <register name="LED1_ATR_STATE" typename="LED_ATR_STATE" offset="0x400" count="256" options="--step 4">
// <info>
// Describes led behavior for the different ATR states. When @.LED1_ATR_OPTION
// is set to use the DB states, TX and RX states for LED0-LED3 are
// combined to create a single vector. This creates 256 different
// combinations, each with its own register. When @.LED1_ATR_OPTION is set to
// classic ATR, the first 4 offsets in this register group will be driven
// in accordance with the state of RF1.
// CLASSIC ATR MAPPING: Idle[RF1: TX=0, RX=0], RX[RF1: TX=0, RX=1,
// TX[RF1: TX=1, RX=0], FDX[RF1: TX=1, RX=1]
// </info>
// </register>
//
// <register name="LED2_ATR_STATE" typename="LED_ATR_STATE" offset="0x800" count="256" options="--step 4">
// <info>
// Describes led behavior for the different ATR states. When @.LED2_ATR_OPTION
// is set to use the DB states, TX and RX states for LED0-LED3 are
// combined to create a single vector. This creates 256 different
// combinations, each with its own register. When @.LED2_ATR_OPTION is set to
// classic ATR, the first 4 offsets in this register group will be driven
// in accordance with the state of RF2.
// CLASSIC ATR MAPPING: Idle[RF2: TX=0, RX=0], RX[RF2: TX=0, RX=1,
// TX[RF2: TX=1, RX=0], FDX[RF2: TX=1, RX=1]
// </info>
// </register>
//
// <register name="LED3_ATR_STATE" typename="LED_ATR_STATE" offset="0xC00" count="256" options="--step 4">
// <info>
// Describes led behavior for the different ATR states. When @.LED3_ATR_OPTION
// is set to use the DB states, TX and RX states for LED0-LED3 are
// combined to create a single vector. This creates 256 different
// combinations, each with its own register. When @.LED3_ATR_OPTION is set to
// classic ATR, the first 4 offsets in this register group will be driven
// in accordance with the state of RF3.
// CLASSIC ATR MAPPING: Idle[RF3: TX=0, RX=0], RX[RF3: TX=0, RX=1,
// TX[RF3: TX=1, RX=0], FDX[RF3: TX=1, RX=1]
// </info>
// </register>
// <register name="LED_ATR_OPTION_REGISTER" offset="0x1000" size="32">
// <info>
// Controls whether switch control lines use the TX and RX state of
// their respective channel (Classic ATR) or the daughterboard state
// to select which state to use from values set in LED_ATR_STATE registers.
// For each particular bit:</br>
// 0: Use DB state for ATR</br>
// 1: Classic ATR mode.
// </info>
// <bitfield name="LED0_ATR_OPTION" range="0" initialvalue="0">
// <info>
// Control ATR scheme for RF0.
// </info>
// </bitfield>
// <bitfield name="LED1_ATR_OPTION" range="1" initialvalue="0">
// <info>
// Control ATR scheme for RF1.
// </info>
// </bitfield>
// <bitfield name="LED2_ATR_OPTION" range="2" initialvalue="0">
// <info>
// Control ATR scheme for RF2.
// </info>
// </bitfield>
// <bitfield name="LED3_ATR_OPTION" range="3" initialvalue="0">
// <info>
// Control ATR scheme for RF3.
// </info>
// </bitfield>
// </register>
// <register name="LED_ATR_DISABLED" offset="0x1004" size="32">
// <info>
// Disable ATR Control. DB state 0 will be reflected regardless of the ATR state.
// </info>
// <bitfield name="LED0_ATR_DISABLED" range="0" initialvalue="0"/>
// <bitfield name="LED1_ATR_DISABLED" range="1" initialvalue="0"/>
// <bitfield name="LED2_ATR_DISABLED" range="2" initialvalue="0"/>
// <bitfield name="LED3_ATR_DISABLED" range="3" initialvalue="0"/>
// </register>
// </group>
//</regmap>
//XmlParse xml_off
`default_nettype wire
@@ -0,0 +1,30 @@
//
// Copyright 2022 Ettus Research, A National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: clock_en_regmap_utils.vh
// Description:
// The constants in this file are autogenerated by XmlParse.
//===============================================================================
// A numerically ordered list of registers and their HDL source files
//===============================================================================
// CLK_EN_CONTROL : 0x0 (clock_en_control.v)
//===============================================================================
// RegTypes
//===============================================================================
//===============================================================================
// Register Group CLOCK_EN_REGISTERS
//===============================================================================
// CLK_EN_CONTROL Register (from clock_en_control.v)
localparam CLK_EN_CONTROL = 'h0; // Register Offset
localparam CLK_EN_CONTROL_SIZE = 32; // register width in bits
localparam CLK_EN_CONTROL_MASK = 32'h1;
localparam CLK_EN_SIZE = 1; //CLK_EN_CONTROL:CLK_EN
localparam CLK_EN_MSB = 0; //CLK_EN_CONTROL:CLK_EN
localparam CLK_EN = 0; //CLK_EN_CONTROL:CLK_EN
@@ -0,0 +1,41 @@
//
// Copyright 2023 Ettus Research, A National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: fbx_ctrl_regmap_utils.vh
// Description:
// The constants in this file are autogenerated by XmlParse.
//===============================================================================
// A numerically ordered list of registers and their HDL source files
//===============================================================================
// RF_ATR_REGS : 0x0 (db_gpio_interface.v)
// RF_SYNC_REGS : 0x2000 (db_gpio_interface.v)
// LED_ATR_REGS : 0x4000 (db_gpio_interface.v)
// SYNC_CLK_EN_REGS : 0x6000 (db_gpio_interface.v)
//===============================================================================
// RegTypes
//===============================================================================
//===============================================================================
// Register Group FBX_CONTROLS
//===============================================================================
// RF_ATR_REGS Window (from db_gpio_interface.v)
localparam RF_ATR_REGS = 'h0; // Window Offset
localparam RF_ATR_REGS_SIZE = 'h2000; // size in bytes
// RF_SYNC_REGS Window (from db_gpio_interface.v)
localparam RF_SYNC_REGS = 'h2000; // Window Offset
localparam RF_SYNC_REGS_SIZE = 'h2000; // size in bytes
// LED_ATR_REGS Window (from db_gpio_interface.v)
localparam LED_ATR_REGS = 'h4000; // Window Offset
localparam LED_ATR_REGS_SIZE = 'h2000; // size in bytes
// SYNC_CLK_EN_REGS Window (from db_gpio_interface.v)
localparam SYNC_CLK_EN_REGS = 'h6000; // Window Offset
localparam SYNC_CLK_EN_REGS_SIZE = 'h2000; // size in bytes
@@ -0,0 +1,110 @@
//
// Copyright 2023 Ettus Research, A National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: led_atr_regmap_utils.vh
// Description:
// The constants in this file are autogenerated by XmlParse.
//===============================================================================
// A numerically ordered list of registers and their HDL source files
//===============================================================================
// LED0_ATR_STATE : 0x0 (led_atr_control.v)
// LED1_ATR_STATE : 0x400 (led_atr_control.v)
// LED2_ATR_STATE : 0x800 (led_atr_control.v)
// LED3_ATR_STATE : 0xC00 (led_atr_control.v)
// LED_ATR_OPTION_REGISTER : 0x1000 (led_atr_control.v)
// LED_ATR_DISABLED : 0x1004 (led_atr_control.v)
//===============================================================================
// RegTypes
//===============================================================================
// LED_ATR_STATE Type (from led_atr_control.v)
localparam LED_ATR_STATE_SIZE = 32;
localparam LED_ATR_STATE_MASK = 32'h7;
localparam RX2_LED_SIZE = 1; //LED_ATR_STATE:RX2_LED
localparam RX2_LED_MSB = 0; //LED_ATR_STATE:RX2_LED
localparam RX2_LED = 0; //LED_ATR_STATE:RX2_LED
localparam TXRX_RED_LED_SIZE = 1; //LED_ATR_STATE:TXRX_RED_LED
localparam TXRX_RED_LED_MSB = 1; //LED_ATR_STATE:TXRX_RED_LED
localparam TXRX_RED_LED = 1; //LED_ATR_STATE:TXRX_RED_LED
localparam TXRX_GR_LED_SIZE = 1; //LED_ATR_STATE:TXRX_GR_LED
localparam TXRX_GR_LED_MSB = 2; //LED_ATR_STATE:TXRX_GR_LED
localparam TXRX_GR_LED = 2; //LED_ATR_STATE:TXRX_GR_LED
//===============================================================================
// Register Group LED_ATR_REGISTERS
//===============================================================================
// Enumerated type LED_SIZE_TYPE
localparam LED_SIZE_TYPE_SIZE = 1;
localparam LED_SIZE = 'h3; // LED_SIZE_TYPE:LED_SIZE
// LED0_ATR_STATE Register (from led_atr_control.v)
localparam LED0_ATR_STATE_COUNT = 256; // Number of elements in array
// LED1_ATR_STATE Register (from led_atr_control.v)
localparam LED1_ATR_STATE_COUNT = 256; // Number of elements in array
// LED2_ATR_STATE Register (from led_atr_control.v)
localparam LED2_ATR_STATE_COUNT = 256; // Number of elements in array
// LED3_ATR_STATE Register (from led_atr_control.v)
localparam LED3_ATR_STATE_COUNT = 256; // Number of elements in array
// LED_ATR_OPTION_REGISTER Register (from led_atr_control.v)
localparam LED_ATR_OPTION_REGISTER = 'h1000; // Register Offset
localparam LED_ATR_OPTION_REGISTER_SIZE = 32; // register width in bits
localparam LED_ATR_OPTION_REGISTER_MASK = 32'hF;
localparam LED0_ATR_OPTION_SIZE = 1; //LED_ATR_OPTION_REGISTER:LED0_ATR_OPTION
localparam LED0_ATR_OPTION_MSB = 0; //LED_ATR_OPTION_REGISTER:LED0_ATR_OPTION
localparam LED0_ATR_OPTION = 0; //LED_ATR_OPTION_REGISTER:LED0_ATR_OPTION
localparam LED1_ATR_OPTION_SIZE = 1; //LED_ATR_OPTION_REGISTER:LED1_ATR_OPTION
localparam LED1_ATR_OPTION_MSB = 1; //LED_ATR_OPTION_REGISTER:LED1_ATR_OPTION
localparam LED1_ATR_OPTION = 1; //LED_ATR_OPTION_REGISTER:LED1_ATR_OPTION
localparam LED2_ATR_OPTION_SIZE = 1; //LED_ATR_OPTION_REGISTER:LED2_ATR_OPTION
localparam LED2_ATR_OPTION_MSB = 2; //LED_ATR_OPTION_REGISTER:LED2_ATR_OPTION
localparam LED2_ATR_OPTION = 2; //LED_ATR_OPTION_REGISTER:LED2_ATR_OPTION
localparam LED3_ATR_OPTION_SIZE = 1; //LED_ATR_OPTION_REGISTER:LED3_ATR_OPTION
localparam LED3_ATR_OPTION_MSB = 3; //LED_ATR_OPTION_REGISTER:LED3_ATR_OPTION
localparam LED3_ATR_OPTION = 3; //LED_ATR_OPTION_REGISTER:LED3_ATR_OPTION
// LED_ATR_DISABLED Register (from led_atr_control.v)
localparam LED_ATR_DISABLED = 'h1004; // Register Offset
localparam LED_ATR_DISABLED_SIZE = 32; // register width in bits
localparam LED_ATR_DISABLED_MASK = 32'hF;
localparam LED0_ATR_DISABLED_SIZE = 1; //LED_ATR_DISABLED:LED0_ATR_DISABLED
localparam LED0_ATR_DISABLED_MSB = 0; //LED_ATR_DISABLED:LED0_ATR_DISABLED
localparam LED0_ATR_DISABLED = 0; //LED_ATR_DISABLED:LED0_ATR_DISABLED
localparam LED1_ATR_DISABLED_SIZE = 1; //LED_ATR_DISABLED:LED1_ATR_DISABLED
localparam LED1_ATR_DISABLED_MSB = 1; //LED_ATR_DISABLED:LED1_ATR_DISABLED
localparam LED1_ATR_DISABLED = 1; //LED_ATR_DISABLED:LED1_ATR_DISABLED
localparam LED2_ATR_DISABLED_SIZE = 1; //LED_ATR_DISABLED:LED2_ATR_DISABLED
localparam LED2_ATR_DISABLED_MSB = 2; //LED_ATR_DISABLED:LED2_ATR_DISABLED
localparam LED2_ATR_DISABLED = 2; //LED_ATR_DISABLED:LED2_ATR_DISABLED
localparam LED3_ATR_DISABLED_SIZE = 1; //LED_ATR_DISABLED:LED3_ATR_DISABLED
localparam LED3_ATR_DISABLED_MSB = 3; //LED_ATR_DISABLED:LED3_ATR_DISABLED
localparam LED3_ATR_DISABLED = 3; //LED_ATR_DISABLED:LED3_ATR_DISABLED
// Return the offset of an element of register array LED0_ATR_STATE
function integer LED0_ATR_STATE (input integer i);
LED0_ATR_STATE = (i * 'h4) + 'h0;
endfunction
// Return the offset of an element of register array LED1_ATR_STATE
function integer LED1_ATR_STATE (input integer i);
LED1_ATR_STATE = (i * 'h4) + 'h400;
endfunction
// Return the offset of an element of register array LED2_ATR_STATE
function integer LED2_ATR_STATE (input integer i);
LED2_ATR_STATE = (i * 'h4) + 'h800;
endfunction
// Return the offset of an element of register array LED3_ATR_STATE
function integer LED3_ATR_STATE (input integer i);
LED3_ATR_STATE = (i * 'h4) + 'hC00;
endfunction
@@ -0,0 +1,110 @@
//
// Copyright 2023 Ettus Research, A National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: rf_atr_regmap_utils.vh
// Description:
// The constants in this file are autogenerated by XmlParse.
//===============================================================================
// A numerically ordered list of registers and their HDL source files
//===============================================================================
// RF0_ATR_STATE : 0x0 (rf_atr_control.v)
// RF1_ATR_STATE : 0x400 (rf_atr_control.v)
// RF2_ATR_STATE : 0x800 (rf_atr_control.v)
// RF3_ATR_STATE : 0xC00 (rf_atr_control.v)
// ATR_OPTION_REGISTER : 0x1000 (rf_atr_control.v)
// RF_ATR_DISABLED : 0x1004 (rf_atr_control.v)
//===============================================================================
// RegTypes
//===============================================================================
// RF_ATR_STATE Type (from rf_atr_control.v)
localparam RF_ATR_STATE_SIZE = 32;
localparam RF_ATR_STATE_MASK = 32'h7;
localparam TX_RX_RFS_SIZE = 1; //RF_ATR_STATE:TX_RX_RFS
localparam TX_RX_RFS_MSB = 0; //RF_ATR_STATE:TX_RX_RFS
localparam TX_RX_RFS = 0; //RF_ATR_STATE:TX_RX_RFS
localparam RX_RFS_SIZE = 1; //RF_ATR_STATE:RX_RFS
localparam RX_RFS_MSB = 1; //RF_ATR_STATE:RX_RFS
localparam RX_RFS = 1; //RF_ATR_STATE:RX_RFS
localparam TDDS_SIZE = 1; //RF_ATR_STATE:TDDS
localparam TDDS_MSB = 2; //RF_ATR_STATE:TDDS
localparam TDDS = 2; //RF_ATR_STATE:TDDS
//===============================================================================
// Register Group RF_ATR_REGISTERS
//===============================================================================
// Enumerated type RF_SWITCHES_SIZE_TYPE
localparam RF_SWITCHES_SIZE_TYPE_SIZE = 1;
localparam RFS_SIZE = 'h3; // RF_SWITCHES_SIZE_TYPE:RFS_SIZE
// RF0_ATR_STATE Register (from rf_atr_control.v)
localparam RF0_ATR_STATE_COUNT = 256; // Number of elements in array
// RF1_ATR_STATE Register (from rf_atr_control.v)
localparam RF1_ATR_STATE_COUNT = 256; // Number of elements in array
// RF2_ATR_STATE Register (from rf_atr_control.v)
localparam RF2_ATR_STATE_COUNT = 256; // Number of elements in array
// RF3_ATR_STATE Register (from rf_atr_control.v)
localparam RF3_ATR_STATE_COUNT = 256; // Number of elements in array
// ATR_OPTION_REGISTER Register (from rf_atr_control.v)
localparam ATR_OPTION_REGISTER = 'h1000; // Register Offset
localparam ATR_OPTION_REGISTER_SIZE = 32; // register width in bits
localparam ATR_OPTION_REGISTER_MASK = 32'hF;
localparam RF0_ATR_OPTION_SIZE = 1; //ATR_OPTION_REGISTER:RF0_ATR_OPTION
localparam RF0_ATR_OPTION_MSB = 0; //ATR_OPTION_REGISTER:RF0_ATR_OPTION
localparam RF0_ATR_OPTION = 0; //ATR_OPTION_REGISTER:RF0_ATR_OPTION
localparam RF1_ATR_OPTION_SIZE = 1; //ATR_OPTION_REGISTER:RF1_ATR_OPTION
localparam RF1_ATR_OPTION_MSB = 1; //ATR_OPTION_REGISTER:RF1_ATR_OPTION
localparam RF1_ATR_OPTION = 1; //ATR_OPTION_REGISTER:RF1_ATR_OPTION
localparam RF2_ATR_OPTION_SIZE = 1; //ATR_OPTION_REGISTER:RF2_ATR_OPTION
localparam RF2_ATR_OPTION_MSB = 2; //ATR_OPTION_REGISTER:RF2_ATR_OPTION
localparam RF2_ATR_OPTION = 2; //ATR_OPTION_REGISTER:RF2_ATR_OPTION
localparam RF3_ATR_OPTION_SIZE = 1; //ATR_OPTION_REGISTER:RF3_ATR_OPTION
localparam RF3_ATR_OPTION_MSB = 3; //ATR_OPTION_REGISTER:RF3_ATR_OPTION
localparam RF3_ATR_OPTION = 3; //ATR_OPTION_REGISTER:RF3_ATR_OPTION
// RF_ATR_DISABLED Register (from rf_atr_control.v)
localparam RF_ATR_DISABLED = 'h1004; // Register Offset
localparam RF_ATR_DISABLED_SIZE = 32; // register width in bits
localparam RF_ATR_DISABLED_MASK = 32'hF;
localparam RF0_ATR_DISABLED_SIZE = 1; //RF_ATR_DISABLED:RF0_ATR_DISABLED
localparam RF0_ATR_DISABLED_MSB = 0; //RF_ATR_DISABLED:RF0_ATR_DISABLED
localparam RF0_ATR_DISABLED = 0; //RF_ATR_DISABLED:RF0_ATR_DISABLED
localparam RF1_ATR_DISABLED_SIZE = 1; //RF_ATR_DISABLED:RF1_ATR_DISABLED
localparam RF1_ATR_DISABLED_MSB = 1; //RF_ATR_DISABLED:RF1_ATR_DISABLED
localparam RF1_ATR_DISABLED = 1; //RF_ATR_DISABLED:RF1_ATR_DISABLED
localparam RF2_ATR_DISABLED_SIZE = 1; //RF_ATR_DISABLED:RF2_ATR_DISABLED
localparam RF2_ATR_DISABLED_MSB = 2; //RF_ATR_DISABLED:RF2_ATR_DISABLED
localparam RF2_ATR_DISABLED = 2; //RF_ATR_DISABLED:RF2_ATR_DISABLED
localparam RF3_ATR_DISABLED_SIZE = 1; //RF_ATR_DISABLED:RF3_ATR_DISABLED
localparam RF3_ATR_DISABLED_MSB = 3; //RF_ATR_DISABLED:RF3_ATR_DISABLED
localparam RF3_ATR_DISABLED = 3; //RF_ATR_DISABLED:RF3_ATR_DISABLED
// Return the offset of an element of register array RF0_ATR_STATE
function integer RF0_ATR_STATE (input integer i);
RF0_ATR_STATE = (i * 'h4) + 'h0;
endfunction
// Return the offset of an element of register array RF1_ATR_STATE
function integer RF1_ATR_STATE (input integer i);
RF1_ATR_STATE = (i * 'h4) + 'h400;
endfunction
// Return the offset of an element of register array RF2_ATR_STATE
function integer RF2_ATR_STATE (input integer i);
RF2_ATR_STATE = (i * 'h4) + 'h800;
endfunction
// Return the offset of an element of register array RF3_ATR_STATE
function integer RF3_ATR_STATE (input integer i);
RF3_ATR_STATE = (i * 'h4) + 'hC00;
endfunction
@@ -0,0 +1,113 @@
//
// Copyright 2023 Ettus Research, A National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: rf_sync_regmap_utils.vh
// Description:
// The constants in this file are autogenerated by XmlParse.
//===============================================================================
// A numerically ordered list of registers and their HDL source files
//===============================================================================
// SYNC_1_REG : 0x0 (ctrlport_to_i2c_sync_ctrl.v)
// SYNC_2_REG : 0x4 (ctrlport_to_i2c_sync_ctrl.v)
// SYNC_3_REG : 0x8 (ctrlport_to_i2c_sync_ctrl.v)
// SYNC_4_REG : 0xC (ctrlport_to_i2c_sync_ctrl.v)
// SYNC_5_REG : 0x10 (ctrlport_to_i2c_sync_ctrl.v)
// RFS_EN_REG : 0x14 (ctrlport_to_i2c_sync_ctrl.v)
// SETUP_REG/SETUP_STATUS_REG : 0x18 (ctrlport_to_i2c_sync_ctrl.v, ctrlport_to_i2c_sync_ctrl.v)
// CONFIG_IO_REG/CONFIG_IO_STATUS_REG : 0x1C (ctrlport_to_i2c_sync_ctrl.v, ctrlport_to_i2c_sync_ctrl.v)
//===============================================================================
// RegTypes
//===============================================================================
// SYNC_SWITCH Type (from ctrlport_to_i2c_sync_ctrl.v)
localparam SYNC_SWITCH_SIZE = 32;
localparam SYNC_SWITCH_MASK = 32'h7;
localparam CONTROL_PIN_V1_SIZE = 1; //SYNC_SWITCH:CONTROL_PIN_V1
localparam CONTROL_PIN_V1_MSB = 0; //SYNC_SWITCH:CONTROL_PIN_V1
localparam CONTROL_PIN_V1 = 0; //SYNC_SWITCH:CONTROL_PIN_V1
localparam CONTROL_PIN_V2_SIZE = 1; //SYNC_SWITCH:CONTROL_PIN_V2
localparam CONTROL_PIN_V2_MSB = 1; //SYNC_SWITCH:CONTROL_PIN_V2
localparam CONTROL_PIN_V2 = 1; //SYNC_SWITCH:CONTROL_PIN_V2
localparam CONTROL_PIN_V3_SIZE = 1; //SYNC_SWITCH:CONTROL_PIN_V3
localparam CONTROL_PIN_V3_MSB = 2; //SYNC_SWITCH:CONTROL_PIN_V3
localparam CONTROL_PIN_V3 = 2; //SYNC_SWITCH:CONTROL_PIN_V3
//===============================================================================
// Register Group RF_SYNC_REGISTERS
//===============================================================================
// Enumerated type IO_EXPANDER_REGISTER_ADRS
localparam IO_EXPANDER_REGISTER_ADRS_SIZE = 8;
localparam IO_EXP_INPUT_PORT0_REG = 'h0; // IO_EXPANDER_REGISTER_ADRS:IO_EXP_INPUT_PORT0_REG
localparam IO_EXP_INPUT_PORT1_REG = 'h1; // IO_EXPANDER_REGISTER_ADRS:IO_EXP_INPUT_PORT1_REG
localparam IO_EXP_OUTPUT_PORT0_REG = 'h2; // IO_EXPANDER_REGISTER_ADRS:IO_EXP_OUTPUT_PORT0_REG
localparam IO_EXP_OUTPUT_PORT1_REG = 'h3; // IO_EXPANDER_REGISTER_ADRS:IO_EXP_OUTPUT_PORT1_REG
localparam IO_EXP_POLARITY_INV0_REG = 'h4; // IO_EXPANDER_REGISTER_ADRS:IO_EXP_POLARITY_INV0_REG
localparam IO_EXP_POLARITY_INV1_REG = 'h5; // IO_EXPANDER_REGISTER_ADRS:IO_EXP_POLARITY_INV1_REG
localparam IO_EXP_CONFIG0_REG = 'h6; // IO_EXPANDER_REGISTER_ADRS:IO_EXP_CONFIG0_REG
localparam IO_EXP_CONFIG1_REG = 'h7; // IO_EXPANDER_REGISTER_ADRS:IO_EXP_CONFIG1_REG
// SYNC_1_REG Register (from ctrlport_to_i2c_sync_ctrl.v)
localparam SYNC_1_REG = 'h0; // Register Offset
localparam SYNC_1_REG_SIZE = 32; // register width in bits
// SYNC_2_REG Register (from ctrlport_to_i2c_sync_ctrl.v)
localparam SYNC_2_REG = 'h4; // Register Offset
localparam SYNC_2_REG_SIZE = 32; // register width in bits
// SYNC_3_REG Register (from ctrlport_to_i2c_sync_ctrl.v)
localparam SYNC_3_REG = 'h8; // Register Offset
localparam SYNC_3_REG_SIZE = 32; // register width in bits
// SYNC_4_REG Register (from ctrlport_to_i2c_sync_ctrl.v)
localparam SYNC_4_REG = 'hC; // Register Offset
localparam SYNC_4_REG_SIZE = 32; // register width in bits
// SYNC_5_REG Register (from ctrlport_to_i2c_sync_ctrl.v)
localparam SYNC_5_REG = 'h10; // Register Offset
localparam SYNC_5_REG_SIZE = 32; // register width in bits
// RFS_EN_REG Register (from ctrlport_to_i2c_sync_ctrl.v)
localparam RFS_EN_REG = 'h14; // Register Offset
localparam RFS_EN_REG_SIZE = 32; // register width in bits
localparam RFS_EN_REG_MASK = 32'h1;
localparam RFS_EN_PIN_SIZE = 1; //RFS_EN_REG:RFS_EN_PIN
localparam RFS_EN_PIN_MSB = 0; //RFS_EN_REG:RFS_EN_PIN
localparam RFS_EN_PIN = 0; //RFS_EN_REG:RFS_EN_PIN
// SETUP_REG Register (from ctrlport_to_i2c_sync_ctrl.v)
localparam SETUP_REG = 'h18; // Register Offset
localparam SETUP_REG_SIZE = 32; // register width in bits
localparam SETUP_REG_MASK = 32'h1;
localparam SETUP_TRIG_SIZE = 1; //SETUP_REG:SETUP_TRIG
localparam SETUP_TRIG_MSB = 0; //SETUP_REG:SETUP_TRIG
localparam SETUP_TRIG = 0; //SETUP_REG:SETUP_TRIG
// SETUP_STATUS_REG Register (from ctrlport_to_i2c_sync_ctrl.v)
localparam SETUP_STATUS_REG = 'h18; // Register Offset
localparam SETUP_STATUS_REG_SIZE = 32; // register width in bits
localparam SETUP_STATUS_REG_MASK = 32'h1;
localparam SETUP_STATUS_SIZE = 1; //SETUP_STATUS_REG:SETUP_STATUS
localparam SETUP_STATUS_MSB = 0; //SETUP_STATUS_REG:SETUP_STATUS
localparam SETUP_STATUS = 0; //SETUP_STATUS_REG:SETUP_STATUS
// CONFIG_IO_REG Register (from ctrlport_to_i2c_sync_ctrl.v)
localparam CONFIG_IO_REG = 'h1C; // Register Offset
localparam CONFIG_IO_REG_SIZE = 32; // register width in bits
localparam CONFIG_IO_REG_MASK = 32'h1;
localparam CONFIG_IO_TRIG_SIZE = 1; //CONFIG_IO_REG:CONFIG_IO_TRIG
localparam CONFIG_IO_TRIG_MSB = 0; //CONFIG_IO_REG:CONFIG_IO_TRIG
localparam CONFIG_IO_TRIG = 0; //CONFIG_IO_REG:CONFIG_IO_TRIG
// CONFIG_IO_STATUS_REG Register (from ctrlport_to_i2c_sync_ctrl.v)
localparam CONFIG_IO_STATUS_REG = 'h1C; // Register Offset
localparam CONFIG_IO_STATUS_REG_SIZE = 32; // register width in bits
localparam CONFIG_IO_STATUS_REG_MASK = 32'h1;
localparam CONFIG_IO_STATUS_SIZE = 1; //CONFIG_IO_STATUS_REG:CONFIG_IO_STATUS
localparam CONFIG_IO_STATUS_MSB = 0; //CONFIG_IO_STATUS_REG:CONFIG_IO_STATUS
localparam CONFIG_IO_STATUS = 0; //CONFIG_IO_STATUS_REG:CONFIG_IO_STATUS
+519
View File
@@ -0,0 +1,519 @@
//
// Copyright 2022 Ettus Research, A National Instruments Brand
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: rf_atr_control
//
// Description:
//
// Implements control over RF switches via CtrlPort. Uses RAM to store multiple
// ATR configurations.
// There are three supported control schemes for these switches:
// - ATR Disabled - Single persistent state.
// - Classic ATR - Each channel's switches depend on the transmission state
// of the respective channel.
// - DB State - Each channel's switches depend on the transmission state
// of all channels in this radio.
//
// Parameters:
//
// REG_BASE : Base address to use for registers.
// REG_SIZE : Register space size.
//
module rf_atr_control #(
parameter REG_BASE = 0,
parameter REG_SIZE = 'h2000
) (
// Slave ctrlport interface
input wire ctrlport_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,
output reg s_ctrlport_resp_ack = 1'b0,
output reg [ 1:0] s_ctrlport_resp_status = 2'b00,
output reg [31:0] s_ctrlport_resp_data = {32 {1'b0}},
// Run state signals that indicate tx and rx operation
input wire [7:0] db_state,
// Switch control outputs
output reg rf0_tx_rx_rfs,
output reg rf0_rx_rfs,
output reg rf0_tdds,
output reg rf1_tx_rx_rfs,
output reg rf1_rx_rfs,
output reg rf1_tdds,
output reg rf2_tx_rx_rfs,
output reg rf2_rx_rfs,
output reg rf2_tdds,
output reg rf3_tx_rx_rfs,
output reg rf3_rx_rfs,
output reg rf3_tdds
);
`include "../../../../lib/rfnoc/core/ctrlport.vh"
`include "regmap/rf_atr_regmap_utils.vh"
//---------------------------------------------------------------
// ATR memory signals
//---------------------------------------------------------------
reg ram_rf0_wea;
wire [RFS_SIZE-1:0] ram_rf0_doa;
wire [RFS_SIZE-1:0] ram_rf0_dob;
reg ram_rf1_wea;
wire [RFS_SIZE-1:0] ram_rf1_doa;
wire [RFS_SIZE-1:0] ram_rf1_dob;
reg ram_rf2_wea;
wire [RFS_SIZE-1:0] ram_rf2_doa;
wire [RFS_SIZE-1:0] ram_rf2_dob;
reg ram_rf3_wea;
wire [RFS_SIZE-1:0] ram_rf3_doa;
wire [RFS_SIZE-1:0] ram_rf3_dob;
//---------------------------------------------------------------
// ATR Scheme signals
//---------------------------------------------------------------
reg [3:0] atr_disable = 4'b0;
// DB state/Classic ATR selector
reg [3:0] atr_mode = 4'b0;
//---------------------------------------------------------------------------
// Control interface handling
//---------------------------------------------------------------------------
// Check that address is within this module's range.
wire address_in_range = (s_ctrlport_req_addr >= REG_BASE) && (s_ctrlport_req_addr < REG_BASE + REG_SIZE);
// Check that address is targeting an ATR state.
wire address_is_atr = (s_ctrlport_req_addr >= REG_BASE + RF0_ATR_STATE(0)) && (s_ctrlport_req_addr <= REG_BASE + RF3_ATR_STATE(RF3_ATR_STATE_COUNT-1));
// Read request shift register to align memory read and response generation.
reg [ 1:0] read_req_shift_reg = 2'b0;
// Mask out 8 bits for ATR configurations to be able to compare all ATR
// configurations against the same base register address.
wire [31:0] register_base_address = {s_ctrlport_req_addr[19:10], 8'b0, s_ctrlport_req_addr[1:0]};
// Decode the ATR state being addressed.
wire [ 7:0] atr_address = s_ctrlport_req_addr[9:2];
always @ (posedge ctrlport_clk) begin
if (ctrlport_rst) begin
s_ctrlport_resp_ack <= 1'b0;
s_ctrlport_resp_data <= 32'b0;
s_ctrlport_resp_status <= 2'b00;
atr_disable <= 4'b0;
atr_mode <= 4'b0;
ram_rf0_wea <= 1'b0;
ram_rf1_wea <= 1'b0;
ram_rf2_wea <= 1'b0;
ram_rf3_wea <= 1'b0;
end else begin
// default assignments
read_req_shift_reg <= {read_req_shift_reg[0], s_ctrlport_req_rd};
ram_rf0_wea <= 1'b0;
ram_rf1_wea <= 1'b0;
ram_rf2_wea <= 1'b0;
ram_rf3_wea <= 1'b0;
// Write registers
if (s_ctrlport_req_wr) begin
// Acknowledge by default
s_ctrlport_resp_ack <= 1'b1;
s_ctrlport_resp_status <= CTRL_STS_OKAY;
// Address ATR state writes
if(address_is_atr) begin
case (register_base_address)
REG_BASE + RF0_ATR_STATE(0): begin
ram_rf0_wea <= 1'b1;
end
REG_BASE + RF1_ATR_STATE(0): begin
ram_rf1_wea <= 1'b1;
end
REG_BASE + RF2_ATR_STATE(0): begin
ram_rf2_wea <= 1'b1;
end
REG_BASE + RF3_ATR_STATE(0): begin
ram_rf3_wea <= 1'b1;
end
// error on undefined address
default: begin
s_ctrlport_resp_status <= CTRL_STS_CMDERR;
end
endcase
end else begin
// Address writes to the rest of the register space
case (s_ctrlport_req_addr)
REG_BASE + ATR_OPTION_REGISTER: begin
atr_mode[0] <= s_ctrlport_req_data[RF0_ATR_OPTION];
atr_mode[1] <= s_ctrlport_req_data[RF1_ATR_OPTION];
atr_mode[2] <= s_ctrlport_req_data[RF2_ATR_OPTION];
atr_mode[3] <= s_ctrlport_req_data[RF3_ATR_OPTION];
end
REG_BASE + RF_ATR_DISABLED: begin
atr_disable[0] <= s_ctrlport_req_data[RF0_ATR_DISABLED];
atr_disable[1] <= s_ctrlport_req_data[RF1_ATR_DISABLED];
atr_disable[2] <= s_ctrlport_req_data[RF2_ATR_DISABLED];
atr_disable[3] <= s_ctrlport_req_data[RF3_ATR_DISABLED];
end
// No register implementation for provided address
default: begin
// Acknowledge and provide error status if address is in range
if (address_in_range) begin
s_ctrlport_resp_status <= CTRL_STS_CMDERR;
// No response if out of range
end else begin
s_ctrlport_resp_ack <= 1'b0;
end
end
endcase
end
// Read registers
end else if (read_req_shift_reg[1]) begin
// Acknowledge by default
s_ctrlport_resp_ack <= 1'b1;
s_ctrlport_resp_status <= CTRL_STS_OKAY;
// Address ATR state reads
if(address_is_atr) begin
case (register_base_address)
REG_BASE + RF0_ATR_STATE(0): begin
s_ctrlport_resp_data <= ram_rf0_doa & RF_ATR_STATE_MASK;
end
REG_BASE + RF1_ATR_STATE(0): begin
s_ctrlport_resp_data <= ram_rf1_doa & RF_ATR_STATE_MASK;
end
REG_BASE + RF2_ATR_STATE(0): begin
s_ctrlport_resp_data <= ram_rf2_doa & RF_ATR_STATE_MASK;
end
REG_BASE + RF3_ATR_STATE(0): begin
s_ctrlport_resp_data <= ram_rf3_doa & RF_ATR_STATE_MASK;
end
default: begin
s_ctrlport_resp_status <= CTRL_STS_CMDERR;
end
endcase
end else begin
// Address reads to the rest of the register space
case (s_ctrlport_req_addr)
REG_BASE + ATR_OPTION_REGISTER: begin
s_ctrlport_resp_data[RF0_ATR_OPTION] <= atr_mode[0];
s_ctrlport_resp_data[RF1_ATR_OPTION] <= atr_mode[1];
s_ctrlport_resp_data[RF2_ATR_OPTION] <= atr_mode[2];
s_ctrlport_resp_data[RF3_ATR_OPTION] <= atr_mode[3];
end
REG_BASE + RF_ATR_DISABLED: begin
s_ctrlport_resp_data[RF0_ATR_DISABLED] <= atr_disable[0];
s_ctrlport_resp_data[RF1_ATR_DISABLED] <= atr_disable[1];
s_ctrlport_resp_data[RF2_ATR_DISABLED] <= atr_disable[2];
s_ctrlport_resp_data[RF3_ATR_DISABLED] <= atr_disable[3];
end
// No register implementation for provided address
default: begin
// Acknowledge and provide error status if address is in range
if (address_in_range) begin
s_ctrlport_resp_status <= CTRL_STS_CMDERR;
// No response if out of range
end else begin
s_ctrlport_resp_ack <= 1'b0;
end
end
endcase
end
end else begin
s_ctrlport_resp_ack <= 1'b0;
end
end
end
// register without reset
reg [ 7:0] ram_addr = 8'b0;
reg [RFS_SIZE-1:0] ram_datain = {RFS_SIZE{1'b0}};
always @(posedge ctrlport_clk) begin
// memories
ram_addr <= atr_address;
ram_datain <= s_ctrlport_req_data[RFS_SIZE-1:0];
end
// ATR Scheme selection
reg [7:0] atr_config_rf [3:0];
generate
genvar i;
for (i = 0; i < 4; i = i + 1) begin: read_address_gen
always @(posedge ctrlport_clk) begin
if (atr_disable[i]) begin
atr_config_rf[i] <= 8'b0;
end else begin
if (atr_mode[i]) begin
atr_config_rf[i] <= {6'b0, db_state[2*i+:2]};
end else begin
atr_config_rf[i] <= db_state;
end
end
end
end
endgenerate
// Output decoding
always @(posedge ctrlport_clk) begin
rf0_tx_rx_rfs <= ram_rf0_dob[TX_RX_RFS];
rf0_rx_rfs <= ram_rf0_dob[RX_RFS];
rf0_tdds <= ram_rf0_dob[TDDS];
rf1_tx_rx_rfs <= ram_rf1_dob[TX_RX_RFS];
rf1_rx_rfs <= ram_rf1_dob[RX_RFS];
rf1_tdds <= ram_rf1_dob[TDDS];
rf2_tx_rx_rfs <= ram_rf2_dob[TX_RX_RFS];
rf2_rx_rfs <= ram_rf2_dob[RX_RFS];
rf2_tdds <= ram_rf2_dob[TDDS];
rf3_tx_rx_rfs <= ram_rf3_dob[TX_RX_RFS];
rf3_rx_rfs <= ram_rf3_dob[RX_RFS];
rf3_tdds <= ram_rf3_dob[TDDS];
end
//---------------------------------------------------------------
// ATR memory
//---------------------------------------------------------------
ram_2port #(
.DWIDTH (RFS_SIZE),
.AWIDTH (8),
.RW_MODE ("READ-FIRST"),
.RAM_TYPE ("AUTOMATIC"),
.OUT_REG (0)
) ram_rf0_i (
.clka (ctrlport_clk),
.ena (1'b1),
.wea (ram_rf0_wea),
.addra (ram_addr),
.dia (ram_datain),
.doa (ram_rf0_doa),
.clkb (ctrlport_clk),
.enb (1'b1),
.web (1'b0),
.addrb (atr_config_rf[0]),
.dib ({RFS_SIZE{1'b0}}),
.dob (ram_rf0_dob));
ram_2port #(
.DWIDTH (RFS_SIZE),
.AWIDTH (8),
.RW_MODE ("READ-FIRST"),
.RAM_TYPE ("AUTOMATIC"),
.OUT_REG (0)
) ram_rf1_i (
.clka (ctrlport_clk),
.ena (1'b1),
.wea (ram_rf1_wea),
.addra (ram_addr),
.dia (ram_datain),
.doa (ram_rf1_doa),
.clkb (ctrlport_clk),
.enb (1'b1),
.web (1'b0),
.addrb (atr_config_rf[1]),
.dib ({RFS_SIZE{1'b0}}),
.dob (ram_rf1_dob));
ram_2port #(
.DWIDTH (RFS_SIZE),
.AWIDTH (8),
.RW_MODE ("READ-FIRST"),
.RAM_TYPE ("AUTOMATIC"),
.OUT_REG (0)
) ram_rf2_i (
.clka (ctrlport_clk),
.ena (1'b1),
.wea (ram_rf2_wea),
.addra (ram_addr),
.dia (ram_datain),
.doa (ram_rf2_doa),
.clkb (ctrlport_clk),
.enb (1'b1),
.web (1'b0),
.addrb (atr_config_rf[2]),
.dib ({RFS_SIZE{1'b0}}),
.dob (ram_rf2_dob));
ram_2port #(
.DWIDTH (RFS_SIZE),
.AWIDTH (8),
.RW_MODE ("READ-FIRST"),
.RAM_TYPE ("AUTOMATIC"),
.OUT_REG (0)
) ram_rf3_i (
.clka (ctrlport_clk),
.ena (1'b1),
.wea (ram_rf3_wea),
.addra (ram_addr),
.dia (ram_datain),
.doa (ram_rf3_doa),
.clkb (ctrlport_clk),
.enb (1'b1),
.web (1'b0),
.addrb (atr_config_rf[3]),
.dib ({RFS_SIZE{1'b0}}),
.dob (ram_rf3_dob));
endmodule
//XmlParse xml_on
//<regmap name="RF_ATR_REGMAP" readablestrobes="false" generatevhdl="true" ettusguidelines="true">
// <group name="RF_ATR_REGISTERS">
// <info>
// Each channel in the FBX daughterboard has 4 switches in its path. 3 of these are HMC849A 2:1
// switches and the last one is a PE42442 4:1 switch. The latter, as well as the enable lines for
// all four switches are not considered time critical controls, and are hence driven by an I/O
// expander controlled via I2C.
// This register map describes how to control the behavior of the 3 HMC849A switches' control lines.
// There are three supported control schemes for these switches:</br>
// <ul>
// <li>ATR Disabled - Single persistent state.</li>
// <li>Classic ATR - Each channel's switches depend on the transmission state
// of the respective channel.</li>
// <li>DB State - Each channel's switches depend on the transmission state
// of all channels in this radio.</li>
// </ul>
// </info>
//
// <enumeratedtype name="RF_SWITCHES_SIZE_TYPE">
// <value name="RFS_SIZE" integer="3"/>
// </enumeratedtype>
//
// <regtype name="RF_ATR_STATE" size="32">
// <info>Holds the value for the control lines of each channel's switches
// for a particular ATR sate</info>
// <bitfield name="TX_RX_RFS" range="0" initialvalue="0"/>
// <bitfield name="RX_RFS" range="1" initialvalue="0"/>
// <bitfield name="TDDS" range="2" initialvalue="0"/>
// </regtype>
//
// <register name="RF0_ATR_STATE" typename="RF_ATR_STATE" offset="0x00" count="256" options="--step 4">
// <info>
// Describes switch control behavior for the different ATR states. When @.RF0_ATR_OPTION
// is set to use the DB states, TX and RX states for RF0-RF3 are
// combined to create a single vector. This creates 256 different
// combinations, each with its own register. When @.RF0_ATR_OPTION is set to
// classic ATR, the first 4 offsets in this register group will be driven
// in accordance with the state of RF0.
// CLASSIC ATR MAPPING: Idle[RF0: TX=0, RX=0], RX[RF0: TX=0, RX=1,
// TX[RF0: TX=1, RX=0], FDX[RF0: TX=1, RX=1]
// </info>
// </register>
//
// <register name="RF1_ATR_STATE" typename="RF_ATR_STATE" offset="0x400" count="256" options="--step 4">
// <info>
// Describes switch control behavior for the different ATR states. When @.RF1_ATR_OPTION
// is set to use the DB states, TX and RX states for RF0-RF3 are
// combined to create a single vector. This creates 256 different
// combinations, each with its own register. When @.RF1_ATR_OPTION is set to
// classic ATR, the first 4 offsets in this register group will be driven
// in accordance with the state of RF1.
// CLASSIC ATR MAPPING: Idle[RF1: TX=0, RX=0], RX[RF1: TX=0, RX=1,
// TX[RF1: TX=1, RX=0], FDX[RF1: TX=1, RX=1]
// </info>
// </register>
//
// <register name="RF2_ATR_STATE" typename="RF_ATR_STATE" offset="0x800" count="256" options="--step 4">
// <info>
// Describes switch control behavior for the different ATR states. When @.RF2_ATR_OPTION
// is set to use the DB states, TX and RX states for RF0-RF3 are
// combined to create a single vector. This creates 256 different
// combinations, each with its own register. When @.RF2_ATR_OPTION is set to
// classic ATR, the first 4 offsets in this register group will be driven
// in accordance with the state of RF2.
// CLASSIC ATR MAPPING: Idle[RF2: TX=0, RX=0], RX[RF2: TX=0, RX=1,
// TX[RF2: TX=1, RX=0], FDX[RF2: TX=1, RX=1]
// </info>
// </register>
//
// <register name="RF3_ATR_STATE" typename="RF_ATR_STATE" offset="0xC00" count="256" options="--step 4">
// <info>
// Describes switch control behavior for the different ATR states. When @.RF3_ATR_OPTION
// is set to use the DB states, TX and RX states for RF0-RF3 are
// combined to create a single vector. This creates 256 different
// combinations, each with its own register. When @.RF3_ATR_OPTION is set to
// classic ATR, the first 4 offsets in this register group will be driven
// in accordance with the state of RF3.
// CLASSIC ATR MAPPING: Idle[RF3: TX=0, RX=0], RX[RF3: TX=0, RX=1,
// TX[RF3: TX=1, RX=0], FDX[RF3: TX=1, RX=1]
// </info>
// </register>
// <register name="ATR_OPTION_REGISTER" offset="0x1000" size="32">
// <info>
// Controls whether switch control lines use the TX and RX state of
// their respective channel (Classic ATR) or the daughterboard state
// to select which state to use from values set in RF_ATR_STATE registers.
// For each particular bit:</br>
// 0: Use DB state for ATR</br>
// 1: Classic ATR mode.
// </info>
// <bitfield name="RF0_ATR_OPTION" range="0" initialvalue="0">
// <info>
// Control ATR scheme for RF0.
// </info>
// </bitfield>
// <bitfield name="RF1_ATR_OPTION" range="1" initialvalue="0">
// <info>
// Control ATR scheme for RF1.
// </info>
// </bitfield>
// <bitfield name="RF2_ATR_OPTION" range="2" initialvalue="0">
// <info>
// Control ATR scheme for RF2.
// </info>
// </bitfield>
// <bitfield name="RF3_ATR_OPTION" range="3" initialvalue="0">
// <info>
// Control ATR scheme for RF3.
// </info>
// </bitfield>
// </register>
// <register name="RF_ATR_DISABLED" offset="0x1004" size="32">
// <info>
// Disable ATR Control. DB state 0 will be reflected regardless of the ATR state.
// </info>
// <bitfield name="RF0_ATR_DISABLED" range="0" initialvalue="0"/>
// <bitfield name="RF1_ATR_DISABLED" range="1" initialvalue="0"/>
// <bitfield name="RF2_ATR_DISABLED" range="2" initialvalue="0"/>
// <bitfield name="RF3_ATR_DISABLED" range="3" initialvalue="0"/>
// </register>
// </group>
//</regmap>
//XmlParse xml_off
@@ -0,0 +1,74 @@
#
# Copyright 2022 Ettus Research, a National Instruments Brand
#
# SPDX-License-Identifier: LGPL-3.0-or-later
#
#-------------------------------------------------
# Top-of-Makefile
#-------------------------------------------------
# Define BASE_DIR to point to the "top" dir.
BASE_DIR = ../../../../..
# Include viv_sim_preample after defining BASE_DIR
include $(BASE_DIR)/../tools/make/viv_sim_preamble.mak
#-------------------------------------------------
# Design Specific
#-------------------------------------------------
# Define part using PART_ID (<device>/<package>/<speedgrade>)
ARCH = zynquplusRFSOC
PART_ID = xczu28dr/ffvg1517/-1/e
# Include makefiles and sources for the DUT and its dependencies
include $(BASE_DIR)/../lib/control/Makefile.srcs
DESIGN_SRCS += $(abspath \
$(FIFO_SRCS) \
$(AXI_SRCS) \
$(CONTROL_LIB_SRCS) \
$(WISHBONE_SRCS) \
)
DESIGN_SRCS += $(abspath \
../../regmap/fbx_ctrl_regmap_utils.vh \
../../regmap/clock_en_regmap_utils.vh \
../../clock_en_control.v \
)
#-------------------------------------------------
# IP Specific
#-------------------------------------------------
# If simulation contains IP, define the IP_DIR and point
# it to the base level IP directory
IP_DIR = $(BASE_DIR)/x400/ip
LIB_IP_DIR = $(BASE_DIR)/../lib/ip
# Include makefiles and sources for all IP components
# *after* defining the IP_DIR
#
# These TBs don't use any IP yet :)
#-------------------------------------------------
# Testbench Specific
#-------------------------------------------------
include $(BASE_DIR)/../sim/general/Makefile.srcs
# Define only one top-level module
SIM_TOP = clock_en_control_tb glbl
# Simulation runtime in microseconds
SIM_RUNTIME_US = 100000
SIM_SRCS = \
$(abspath clock_en_control_tb.sv) \
$(VIVADO_PATH)/data/verilog/src/glbl.v \
#-------------------------------------------------
# Bottom-of-Makefile
#-------------------------------------------------
# Include all simulator specific makefiles here
# Each should define a unique target to simulate
# e.g. xsim, vsim, etc and a common "clean" target
include $(BASE_DIR)/../tools/make/viv_simulator.mak
@@ -0,0 +1,172 @@
//
// Copyright 2022 Ettus Research, a National Instruments Brand
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: clock_en_control_tb
//
// Description:
// Testbench for clock_en_control and clock_div modules. Tasks defined for ctrlport write and
// read transactions. Tests clock enable control with ctrlport reads and writes.
//
`timescale 1ns / 1ps
`define NS_PER_TICK 1
`define NUM_TEST_CASES 4
`include "sim_exec_report.vh"
`include "sim_clks_rsts.vh"
module clock_en_control_tb();
import PkgRandom::*;
PkgRandom::Rand #(5) rand_clk_count;
`TEST_BENCH_INIT("clock_en_control_tb", `NUM_TEST_CASES, `NS_PER_TICK);
//sets up clock
localparam CLK_PERIOD = $ceil(1e9/50.0e6);
localparam CLK_PERIOD_10 = $ceil(1e9/10.0e6);
`DEFINE_CLK(clk50, CLK_PERIOD, 50);
`DEFINE_CLK(clk10, CLK_PERIOD_10, 50);
localparam N = 2;
localparam N_DIV2 = N/2;
reg reset_clk50;
reg clk10_rst;
reg s_ctrlport_req_wr;
reg s_ctrlport_req_rd;
reg [19:0] s_ctrlport_req_addr;
reg [31:0] s_ctrlport_req_data;
// Response
wire s_ctrlport_resp_ack;
wire [ 1:0] s_ctrlport_resp_status;
wire [31:0] s_ctrlport_resp_data;
wire clk5, clk5_buf;
`include "../../regmap/clock_en_regmap_utils.vh"
task cp_write;
input [19:0] a;
input [31:0] d;
begin
s_ctrlport_req_addr = a;
s_ctrlport_req_data = d;
@(posedge clk50);
s_ctrlport_req_wr = 1;
@(posedge clk50);
while(~s_ctrlport_resp_ack) @(posedge clk50);
s_ctrlport_req_wr = 0;
@(posedge clk50);
end
endtask
task cp_read;
input [19:0] a;
input [31:0] d;
input debug;
begin
s_ctrlport_req_addr = a;
@(posedge clk50);
s_ctrlport_req_rd = 1;
@(posedge clk50);
while(~s_ctrlport_resp_ack) @(posedge clk50);
s_ctrlport_req_rd = 0;
@(posedge clk50);
if(debug) begin
$display("status: read addr %h at %t value = %h", a, $time, s_ctrlport_resp_data);
end
`ASSERT_ERROR( s_ctrlport_resp_data == d, "CtrlPort read returned unexpected value.");
end
endtask
clock_div #(
.N(N)
) clock_div_5mhz (
.clk_in (clk10),
.clk_in_rst (clk10_rst),
.clk_out (clk5)
);
clock_en_control #(
.BASE_ADDRESS(0)
) clock_en_control_inst (
.ctrlport_clk (clk50),
.ctrlport_rst (reset_clk50),
.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_resp_ack (s_ctrlport_resp_ack),
.s_ctrlport_resp_status (s_ctrlport_resp_status),
.s_ctrlport_resp_data (s_ctrlport_resp_data),
.clk_in (clk5),
.clk_out (clk5_buf)
);
// clock counters to verify clock division
reg counter_reset;
reg [8:0] clock_counter;
reg [10:0] div_clock_counter;
reg [10:0] expected_clock_count;
reg [8:0] expected_div_clock_count;
always @(posedge clk10) begin
if(counter_reset) begin
clock_counter <= 0;
end else begin
clock_counter <= clock_counter + 1;
end
end
always @(posedge clk5_buf) begin
if(counter_reset) begin
div_clock_counter <= 0;
end else begin
div_clock_counter <= div_clock_counter + 1;
end
end
// main test cases
initial begin : tb_main
`TEST_CASE_START("initialize UUT");
reset_clk50 = 1;
clk10_rst = 1;
s_ctrlport_req_wr = 0;
s_ctrlport_req_rd = 0;
s_ctrlport_req_addr = 0;
s_ctrlport_req_data = 0;
#200 //wait a cycle for the 10mhz clk rst
reset_clk50 = 0;
clk10_rst = 0;
$display("status: %t done reset here", $time);
`TEST_CASE_DONE(~reset_clk50);
// trigger setup
`TEST_CASE_START("Check that clock_out is not running");
@(posedge clk5);
@(posedge clk10);
`ASSERT_ERROR( clk5_buf == 0, "clk5_buf should be zero now.");
repeat (N) @(posedge clk10);
`TEST_CASE_DONE(clk5_buf == 0 && clk5 == 1);
`TEST_CASE_START("Enable clock with clock_en_control enable register");
cp_read(CLK_EN_CONTROL, 0, 1); //initial value should be zero
cp_write(CLK_EN_CONTROL, CLK_EN_CONTROL_MASK);
cp_read(CLK_EN_CONTROL, CLK_EN_CONTROL_MASK, 1);
@(posedge clk5_buf);
repeat (N_DIV2+1) @(posedge clk10);
`ASSERT_ERROR( clk5_buf == 0, "clk5_buf should be zero now.");
repeat (N_DIV2) @(posedge clk10);
`TEST_CASE_DONE(clk5_buf == 1 && s_ctrlport_resp_data == CLK_EN_CONTROL_MASK);
`TEST_CASE_START("Verify expected clock division.");
expected_div_clock_count = 5 + rand_clk_count.rand_bit();
expected_clock_count = N*expected_div_clock_count;
$display("Reset clock counters @ time %t and then count main clock &d times and divided clock %d times", $time, expected_clock_count, expected_div_clock_count);
@(posedge clk5_buf);
counter_reset = 1;
@(posedge clk5_buf);
counter_reset = 0;
repeat (expected_div_clock_count) @(posedge clk5_buf);
@(posedge clk10);
`TEST_CASE_DONE(div_clock_counter == expected_div_clock_count && clock_counter == expected_clock_count);
`TEST_BENCH_DONE;
end
endmodule
@@ -0,0 +1,75 @@
#
# Copyright 2022 Ettus Research, a National Instruments Brand
#
# SPDX-License-Identifier: LGPL-3.0-or-later
#
#-------------------------------------------------
# Top-of-Makefile
#-------------------------------------------------
# Define BASE_DIR to point to the "top" dir.
BASE_DIR = ../../../../..
# Include viv_sim_preample after defining BASE_DIR
include $(BASE_DIR)/../tools/make/viv_sim_preamble.mak
#-------------------------------------------------
# Design Specific
#-------------------------------------------------
# Define part using PART_ID (<device>/<package>/<speedgrade>)
ARCH = zynquplusRFSOC
PART_ID = xczu28dr/ffvg1517/-1/e
# Include makefiles and sources for the DUT and its dependencies
include $(BASE_DIR)/../lib/control/Makefile.srcs
include $(BASE_DIR)/../lib/wishbone/Makefile.srcs
DESIGN_SRCS += $(abspath \
$(FIFO_SRCS) \
$(AXI_SRCS) \
$(CONTROL_LIB_SRCS) \
$(WISHBONE_SRCS) \
)
DESIGN_SRCS += $(abspath \
../../regmap/fbx_ctrl_regmap_utils.vh \
../../regmap/rf_sync_regmap_utils.vh \
../../ctrlport_to_i2c_sync_ctrl.v \
)
#-------------------------------------------------
# IP Specific
#-------------------------------------------------
# If simulation contains IP, define the IP_DIR and point
# it to the base level IP directory
IP_DIR = $(BASE_DIR)/x400/ip
LIB_IP_DIR = $(BASE_DIR)/../lib/ip
# Include makefiles and sources for all IP components
# *after* defining the IP_DIR
#
# These TBs don't use any IP yet :)
#-------------------------------------------------
# Testbench Specific
#-------------------------------------------------
include $(BASE_DIR)/../sim/general/Makefile.srcs
# Define only one top-level module
SIM_TOP = ctrlport_to_i2c_sync_ctrl_tb
# Simulation runtime in microseconds
SIM_RUNTIME_US = 200000
SIM_SRCS = \
$(abspath ctrlport_to_i2c_sync_ctrl_tb.sv) \
$(abspath $(BASE_DIR)/../lib/sim/wishbone/i2c/i2c_slave_model.v) \
#-------------------------------------------------
# Bottom-of-Makefile
#-------------------------------------------------
# Include all simulator specific makefiles here
# Each should define a unique target to simulate
# e.g. xsim, vsim, etc and a common "clean" target
include $(BASE_DIR)/../tools/make/viv_simulator.mak
@@ -0,0 +1,204 @@
//
// Copyright 2022 Ettus Research, a National Instruments Brand
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: ctrlport_to_i2c_sync_ctrl_tb
//
// Description:
// testbench for ctrlport_to_i2c_sync_ctrl module. Tasks defined for ctrlport write and
// read transactions. Tests ability to write to SYNC/RFS_EN regs and then
// initialize i2c_master and i2c peripheral and then configure io through the
// i2c interface to the io expander.
//
`timescale 1ns / 1ps
`define NS_PER_TICK 1
`define NUM_TEST_CASES 5
`include "sim_exec_report.vh"
`include "sim_clks_rsts.vh"
`define SIM_TIMEOUT_US 200000 //overwrite this def from sim_exec_report.vh
module ctrlport_to_i2c_sync_ctrl_tb();
import PkgRandom::*;
`TEST_BENCH_INIT("ctrlport_to_i2c_sync_ctrl_tb", `NUM_TEST_CASES, `NS_PER_TICK);
//sets up clock
localparam CLK_PERIOD = $ceil(1e9/50.0e6);
`DEFINE_CLK(clk50, CLK_PERIOD, 50);
reg reset_clk50;
reg s_ctrlport_req_wr;
reg s_ctrlport_req_rd;
reg [19:0] s_ctrlport_req_addr;
reg [31:0] s_ctrlport_req_data;
// Response
wire s_ctrlport_resp_ack;
wire [ 1:0] s_ctrlport_resp_status;
wire [31:0] s_ctrlport_resp_data;
wire i2c_scl_i, i2c_scl_o, i2c_scl_en_o;
wire i2c_sda_i, i2c_sda_o, i2c_sda_en_o;
PkgRandom::Rand #(3) rand_sync;
PkgRandom::Rand #(1) rand_rfs_en;
reg [2:0] sync1, sync2, sync3, sync4, sync5;
reg rfs_en;
`include "../../regmap/rf_sync_regmap_utils.vh"
task cp_write;
input [19:0] a;
input [31:0] d;
begin
s_ctrlport_req_addr = a;
s_ctrlport_req_data = d;
@(posedge clk50);
s_ctrlport_req_wr = 1;
@(posedge clk50);
while(~s_ctrlport_resp_ack) @(posedge clk50);
s_ctrlport_req_wr = 0;
@(posedge clk50);
end
endtask
task cp_read;
input [19:0] a;
input [31:0] d;
input debug;
begin
s_ctrlport_req_addr = a;
s_ctrlport_req_rd = 1;
@(posedge clk50);
while(~s_ctrlport_resp_ack) @(posedge clk50);
s_ctrlport_req_rd = 0;
@(posedge clk50);
if(debug) begin
$display("status: read addr %h at %t value = %h", a, $time, s_ctrlport_resp_data);
end
`ASSERT_ERROR( s_ctrlport_resp_data == d, "CtrlPort read returned unexpected value.");
end
endtask
task cp_poll;
input [19:0] a;
input [31:0] d;
input debug;
begin
s_ctrlport_req_addr = a;
s_ctrlport_req_rd = 1;
@(posedge clk50);
while(~s_ctrlport_resp_ack) @(posedge clk50);
s_ctrlport_req_rd = 0;
@(posedge clk50);
while(s_ctrlport_resp_data != d && s_ctrlport_req_addr == a) begin
s_ctrlport_req_addr = a;
s_ctrlport_req_rd = 1;
@(posedge clk50);
while(~s_ctrlport_resp_ack) @(posedge clk50);
s_ctrlport_req_rd = 0;
@(posedge clk50);
end
if(debug) begin
$display("status: read addr %h at %t value = %h", a, $time, s_ctrlport_resp_data);
end
end
endtask
ctrlport_to_i2c_sync_ctrl #(
.BASE_ADDRESS(0)
) ctrlport_to_i2c_inst (
.ctrlport_clk (clk50),
.ctrlport_rst (reset_clk50),
.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_resp_ack (s_ctrlport_resp_ack),
.s_ctrlport_resp_status (s_ctrlport_resp_status),
.s_ctrlport_resp_data (s_ctrlport_resp_data),
.scl_pad_i (i2c_scl_i),
.scl_pad_o (i2c_scl_o),
.scl_pad_en_o (i2c_scl_en_o),
.sda_pad_i (i2c_sda_i),
.sda_pad_o (i2c_sda_o),
.sda_pad_en_o (i2c_sda_en_o)
);
// hookup i2c slave model
i2c_slave_model #(
ctrlport_to_i2c_inst.SYNC_IO_SLV_ADR
) i2c_slave (
.scl(i2c_scl_i),
.sda(i2c_sda_i)
);
// create i2c lines
delay m0_scl (i2c_scl_en_o ? 1'bz : i2c_scl_o, i2c_scl_i),
m0_sda (i2c_sda_en_o ? 1'bz : i2c_sda_o, i2c_sda_i);
pullup p1(i2c_scl_i); // pullup scl line
pullup p2(i2c_sda_i); // pullup sda line
initial begin : tb_main
`TEST_CASE_START("initialize UUT");
clk50 = 0;
reset_clk50 = 1;
s_ctrlport_req_wr = 0;
s_ctrlport_req_rd = 0;
s_ctrlport_req_addr = 0;
s_ctrlport_req_data = 0;
#100
reset_clk50 = 0;
$display("status: %t done reset here", $time);
`TEST_CASE_DONE(~reset_clk50);
// trigger setup
`TEST_CASE_START("Initialize core and I2C peripheral");
cp_write(SETUP_REG, 1);
cp_poll(SETUP_STATUS_REG,1,1);
`TEST_CASE_DONE(i2c_slave.mem[7] == 0 & i2c_slave.mem[6] == 0);
$display("status: %t SETUP DONE", $time);
// configure SYNC and RFS_EN Regs
for (int i=0; i<3; i=i+1) begin
`TEST_CASE_START("configure SYNC and RFS_EN Regs loop");
$display("loop # %d", i);
sync1 = rand_sync.rand_bit();
sync2 = rand_sync.rand_bit();
sync3 = rand_sync.rand_bit();
sync4 = rand_sync.rand_bit();
sync5 = rand_sync.rand_bit();
rfs_en = rand_rfs_en.rand_bit();
cp_write(SYNC_1_REG, sync1);
cp_write(SYNC_2_REG, sync2);
cp_write(SYNC_3_REG, sync3);
cp_write(SYNC_4_REG, sync4);
cp_write(SYNC_5_REG, sync5);
cp_write(RFS_EN_REG, rfs_en);
cp_read(SYNC_1_REG, {28'b0, sync1}, 1);
cp_read(SYNC_2_REG, {28'b0, sync2}, 1);
cp_read(SYNC_3_REG, {28'b0, sync3}, 1);
cp_read(SYNC_4_REG, {28'b0, sync4}, 1);
cp_read(SYNC_5_REG, {28'b0, sync5}, 1);
cp_read(RFS_EN_REG, {31'b0, rfs_en}, 1);
$display("status: %t Configured ControlPort regs, now configure I2C peripheral.", $time);
cp_write(CONFIG_IO_REG, 1);
cp_poll(CONFIG_IO_STATUS_REG,32'h1,1);
`TEST_CASE_DONE(i2c_slave.mem[2] == {sync3[1:0], sync2, sync1} &
i2c_slave.mem[3] == {rfs_en, sync5, sync4, sync3[2]});
end
`TEST_BENCH_DONE;
end
endmodule
module delay (in, out);
input in;
output out;
assign out = in;
specify
(in => out) = (600,600);
endspecify
endmodule