diff options
author | Javier Valenzuela <javier.valenzuela@ni.com> | 2021-02-05 13:15:02 -0600 |
---|---|---|
committer | Aaron Rossetto <aaron.rossetto@ni.com> | 2021-06-10 11:56:58 -0500 |
commit | 99b841c75aa91709090cbf4046bf51b7ffb4f612 (patch) | |
tree | cb8d370162f7cec179f738a52ab4d86f8a2e9d98 /fpga/usrp3/top/x400/dboards/zbx/cpld/register_endpoints | |
parent | 7015f5ed2d495f3908773b7c7d74864d0cc3871a (diff) | |
download | uhd-99b841c75aa91709090cbf4046bf51b7ffb4f612.tar.gz uhd-99b841c75aa91709090cbf4046bf51b7ffb4f612.tar.bz2 uhd-99b841c75aa91709090cbf4046bf51b7ffb4f612.zip |
fpga: x400: zbx: Add support for ZBX CPLD
Co-authored-by: Cherwa Vang <cherwa.vang@ni.com>
Co-authored-by: Martin Braun <martin.braun@ettus.com>
Co-authored-by: Max Köhler <max.koehler@ni.com>
Co-authored-by: Paul Butler <paul.butler@ni.com>
Diffstat (limited to 'fpga/usrp3/top/x400/dboards/zbx/cpld/register_endpoints')
11 files changed, 3359 insertions, 0 deletions
diff --git a/fpga/usrp3/top/x400/dboards/zbx/cpld/register_endpoints/README.md b/fpga/usrp3/top/x400/dboards/zbx/cpld/register_endpoints/README.md new file mode 100644 index 000000000..d83d11a19 --- /dev/null +++ b/fpga/usrp3/top/x400/dboards/zbx/cpld/register_endpoints/README.md @@ -0,0 +1,10 @@ +# CPLD Default values + +The memory of the CPLD is configured to set all the RF components to safe +values. That means: +- LEDs off +- DSAs are set to maximum attenuation + +The Python script `memory_init_files/gen_defaults.py` creates the .hex files +that get read into the CPLD bitfile. This is run as part of the Makefile +process, and the script does not have to be executed manually. diff --git a/fpga/usrp3/top/x400/dboards/zbx/cpld/register_endpoints/atr_controller.v b/fpga/usrp3/top/x400/dboards/zbx/cpld/register_endpoints/atr_controller.v new file mode 100644 index 000000000..abdf9983f --- /dev/null +++ b/fpga/usrp3/top/x400/dboards/zbx/cpld/register_endpoints/atr_controller.v @@ -0,0 +1,341 @@ +// +// Copyright 2021 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: atr_controller +// +// Description: +// Controller of the ATR state configuration for the other register endpoints. +// + +`default_nettype none + +module atr_controller #( + parameter [19:0] BASE_ADDRESS = 0, + parameter [19:0] SIZE_ADDRESS = 0 +) ( + // 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, + + // ATR state of FPGA + // Assumes the following assignment on the FPGA: + // {tx_running[1], rx_running[1], tx_running[0], rx_running[0]} + // where the array index indicates the RF chain. + input wire [ 3:0] atr_fpga_state, + + // derived configuration + output reg [ 7:0] atr_config_dsa_rf0 = 8'b0, + output reg [ 7:0] atr_config_dsa_rf1 = 8'b0, + output reg [ 7:0] atr_config_rf0 = 8'b0, + output reg [ 7:0] atr_config_rf1 = 8'b0 +); + + `include "../regmap/atr_regmap_utils.vh" + `include "../../../../../../lib/rfnoc/core/ctrlport.vh" + + //---------------------------------------------------------- + // Internal registers + //---------------------------------------------------------- + reg [ RF0_OPTION_SIZE-1:0] option_rf0 = SW_DEFINED; + reg [ RF1_OPTION_SIZE-1:0] option_rf1 = SW_DEFINED; + reg [RF0_DSA_OPTION_SIZE-1:0] option_dsa_rf0 = SW_DEFINED; + reg [RF1_DSA_OPTION_SIZE-1:0] option_dsa_rf1 = SW_DEFINED; + + reg [ SW_RF0_CONFIG_SIZE-1:0] sw_atr_config_rf0 = {SW_RF0_CONFIG_SIZE {1'b0}}; + reg [ SW_RF1_CONFIG_SIZE-1:0] sw_atr_config_rf1 = {SW_RF1_CONFIG_SIZE {1'b0}}; + reg [SW_RF0_DSA_CONFIG_SIZE-1:0] sw_atr_config_dsa_rf0 = {SW_RF0_DSA_CONFIG_SIZE {1'b0}}; + reg [SW_RF1_DSA_CONFIG_SIZE-1:0] sw_atr_config_dsa_rf1 = {SW_RF1_DSA_CONFIG_SIZE {1'b0}}; + + //---------------------------------------------------------- + // Handling of CtrlPort + //---------------------------------------------------------- + wire address_in_range = (s_ctrlport_req_addr >= BASE_ADDRESS) && (s_ctrlport_req_addr < BASE_ADDRESS + SIZE_ADDRESS); + + always @(posedge ctrlport_clk) begin + // reset internal registers and responses + if (ctrlport_rst) begin + option_rf0 <= SW_DEFINED; + option_rf1 <= SW_DEFINED; + option_dsa_rf0 <= SW_DEFINED; + option_dsa_rf1 <= SW_DEFINED; + + sw_atr_config_rf0 <= {SW_RF0_CONFIG_SIZE {1'b0}}; + sw_atr_config_rf1 <= {SW_RF1_CONFIG_SIZE {1'b0}}; + sw_atr_config_dsa_rf0 <= {SW_RF0_DSA_CONFIG_SIZE {1'b0}}; + sw_atr_config_dsa_rf1 <= {SW_RF1_DSA_CONFIG_SIZE {1'b0}}; + + s_ctrlport_resp_ack <= 1'b0; + s_ctrlport_resp_data <= {32{1'bx}}; + s_ctrlport_resp_status <= CTRL_STS_OKAY; + + 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 + OPTION_REG: begin + option_rf0 <= s_ctrlport_req_data[RF0_OPTION_MSB : RF0_OPTION]; + option_rf1 <= s_ctrlport_req_data[RF1_OPTION_MSB : RF1_OPTION]; + option_dsa_rf0 <= s_ctrlport_req_data[RF0_DSA_OPTION_MSB : RF0_DSA_OPTION]; + option_dsa_rf1 <= s_ctrlport_req_data[RF1_DSA_OPTION_MSB : RF1_DSA_OPTION]; + end + + BASE_ADDRESS + SW_CONFIG_REG: begin + sw_atr_config_rf0 <= s_ctrlport_req_data[SW_RF0_CONFIG_MSB : SW_RF0_CONFIG]; + sw_atr_config_rf1 <= s_ctrlport_req_data[SW_RF1_CONFIG_MSB : SW_RF1_CONFIG]; + sw_atr_config_dsa_rf0 <= s_ctrlport_req_data[SW_RF0_DSA_CONFIG_MSB : SW_RF0_DSA_CONFIG]; + sw_atr_config_dsa_rf1 <= s_ctrlport_req_data[SW_RF1_DSA_CONFIG_MSB : SW_RF1_DSA_CONFIG]; + 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 + + // read requests + 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 + CURRENT_CONFIG_REG: begin + s_ctrlport_resp_data[CURRENT_RF0_CONFIG_MSB : CURRENT_RF0_CONFIG] <= atr_config_rf0; + s_ctrlport_resp_data[CURRENT_RF1_CONFIG_MSB : CURRENT_RF1_CONFIG] <= atr_config_rf1; + s_ctrlport_resp_data[CURRENT_RF0_DSA_CONFIG_MSB : CURRENT_RF0_DSA_CONFIG] <= atr_config_dsa_rf0; + s_ctrlport_resp_data[CURRENT_RF1_DSA_CONFIG_MSB : CURRENT_RF1_DSA_CONFIG] <= atr_config_dsa_rf1; + end + + BASE_ADDRESS + OPTION_REG: begin + s_ctrlport_resp_data[RF0_OPTION_MSB : RF0_OPTION] <= option_rf0; + s_ctrlport_resp_data[RF1_OPTION_MSB : RF1_OPTION] <= option_rf1; + s_ctrlport_resp_data[RF0_DSA_OPTION_MSB : RF0_DSA_OPTION] <= option_dsa_rf0; + s_ctrlport_resp_data[RF1_DSA_OPTION_MSB : RF1_DSA_OPTION] <= option_dsa_rf1; + end + + BASE_ADDRESS + SW_CONFIG_REG: begin + s_ctrlport_resp_data[SW_RF0_CONFIG_MSB : SW_RF0_CONFIG] <= sw_atr_config_rf0; + s_ctrlport_resp_data[SW_RF1_CONFIG_MSB : SW_RF1_CONFIG] <= sw_atr_config_rf1; + s_ctrlport_resp_data[SW_RF0_DSA_CONFIG_MSB : SW_RF0_DSA_CONFIG] <= sw_atr_config_dsa_rf0; + s_ctrlport_resp_data[SW_RF1_DSA_CONFIG_MSB : SW_RF1_DSA_CONFIG] <= sw_atr_config_dsa_rf1; + end + + // error on undefined address + default: begin + s_ctrlport_resp_data <= {32{1'b0}}; + 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 + + //---------------------------------------------------------- + // derive configuration + //---------------------------------------------------------- + always @(posedge ctrlport_clk) begin + case (option_rf0) + SW_DEFINED: begin + atr_config_rf0 <= sw_atr_config_rf0; + end + CLASSIC_ATR: begin + atr_config_rf0 <= {6'b0, atr_fpga_state[1:0]}; + end + FPGA_STATE: begin + atr_config_rf0 <= {4'b0, atr_fpga_state}; + end + endcase + + case (option_rf1) + SW_DEFINED: begin + atr_config_rf1 <= sw_atr_config_rf1; + end + CLASSIC_ATR: begin + atr_config_rf1 <= {6'b0, atr_fpga_state[3:2]}; + end + FPGA_STATE: begin + atr_config_rf1 <= {4'b0, atr_fpga_state}; + end + endcase + + case (option_dsa_rf0) + SW_DEFINED: begin + atr_config_dsa_rf0 <= sw_atr_config_dsa_rf0; + end + CLASSIC_ATR: begin + atr_config_dsa_rf0 <= {6'b0, atr_fpga_state[1:0]}; + end + FPGA_STATE: begin + atr_config_dsa_rf0 <= {4'b0, atr_fpga_state}; + end + endcase + + case (option_dsa_rf1) + SW_DEFINED: begin + atr_config_dsa_rf1 <= sw_atr_config_dsa_rf1; + end + CLASSIC_ATR: begin + atr_config_dsa_rf1 <= {6'b0, atr_fpga_state[3:2]}; + end + FPGA_STATE: begin + atr_config_dsa_rf1 <= {4'b0, atr_fpga_state}; + end + endcase + end + +endmodule + +`default_nettype wire + +//XmlParse xml_on +//<regmap name="ATR_REGMAP" readablestrobes="false" generatevhdl="true" ettusguidelines="true"> +// <group name="ATR_REGISTERS"> +// <info> +// This regmap contains settings for the active configuration of RF 0 and 1. +// There are two sets of configurations. One set comprises RF switches and +// LEDs, the other set comprises the attenuators (DSA). +// </info> +// +// <enumeratedtype name="ATR_OPTIONS"> +// <info> +// Contains the options available for RF 0 and RF 1. The chosen setting +// affects how the active configuration of up to 8 bits is derived. +// </info> +// <value name="SW_DEFINED" integer="0"> +// <info> +// Uses the respective value of @.SW_CONFIG_REG as configuration. +// </info> +// </value> +// <value name="CLASSIC_ATR" integer="1"> +// <info> +// This option assumes the FPGA state to be assigned with: Bit 0 = RF 0 +// RX running, Bit 1 = RF 0 TX running, Bit 2 = RF 1 RX running, Bit 3 +// = RF 1 TX running. The configuration for each RF chain is built +// up of the 2 bits for the RF chain (4 possible states: IDLE, RX only, +// TX only, TX/RX). +// </info>0 +// </value> +// <value name="FPGA_STATE" integer="2"> +// <info> +// The 4 bit wide ATR FPGA state is used as configuration. This enables 16 states. +// </info> +// </value> +// </enumeratedtype> +// +// <register name="CURRENT_CONFIG_REG" size="32" offset="0x00" attributes="Readable"> +// <info> +// Contains the current active configuration. +// </info> +// <bitfield name="CURRENT_RF0_CONFIG" range="7..0" type="integer"> +// <info> +// Current active configuration for switches and LEDs of RF 0. +// </info> +// </bitfield> +// <bitfield name="CURRENT_RF1_CONFIG" range="15..8" type="integer"> +// <info> +// Current active configuration for switches and LEDs of RF 1. +// </info> +// </bitfield> +// <bitfield name="CURRENT_RF0_DSA_CONFIG" range="23..16" type="integer"> +// <info> +// Current active configuration for DSAs of RF 0. +// </info> +// </bitfield> +// <bitfield name="CURRENT_RF1_DSA_CONFIG" range="31..24" type="integer"> +// <info> +// Current active configuration for DSAs of RF 1. +// </info> +// </bitfield> +// </register> +// +// <register name="OPTION_REG" size="32" offset="0x04" attributes="Readable|Writable"> +// <info> +// Set the option to be used for the RF chains. +// </info> +// <bitfield name="RF0_OPTION" range="1..0" type="ATR_OPTIONS" initialvalue="SW_DEFINED"> +// <info> +// Option used for switches and LEDs of RF 0. +// </info> +// </bitfield> +// <bitfield name="RF1_OPTION" range="9..8" type="ATR_OPTIONS" initialvalue="SW_DEFINED"> +// <info> +// Option used for switches and LEDs of RF 1. +// </info> +// </bitfield> +// <bitfield name="RF0_DSA_OPTION" range="17..16" type="ATR_OPTIONS" initialvalue="SW_DEFINED"> +// <info> +// Option used for DSAs of RF 0. +// </info> +// </bitfield> +// <bitfield name="RF1_DSA_OPTION" range="25..24" type="ATR_OPTIONS" initialvalue="SW_DEFINED"> +// <info> +// Option used for DSAs of RF 1. +// </info> +// </bitfield> +// </register> +// +// <register name="SW_CONFIG_REG" size="32" offset="0x08" attributes="Readable|Writable"> +// <info> +// Contains the configuration to be applied in case SW_DEFINED option is +// chosen. +// </info> +// <bitfield name="SW_RF0_CONFIG" range="7..0" type="integer" initialvalue="0"> +// <info> +// SW defined configuration for switches and LEDs of RF 0. +// </info> +// </bitfield> +// <bitfield name="SW_RF1_CONFIG" range="15..8" type="integer" initialvalue="0"> +// <info> +// SW defined configuration for switches and LEDs of RF 1. +// </info> +// </bitfield> +// <bitfield name="SW_RF0_DSA_CONFIG" range="23..16" type="integer" initialvalue="0"> +// <info> +// SW defined configuration for DSAs of RF 0. +// </info> +// </bitfield> +// <bitfield name="SW_RF1_DSA_CONFIG" range="31..24" type="integer" initialvalue="0"> +// <info> +// SW defined configuration for DSAs of RF 1. +// </info> +// </bitfield> +// </register> +// </group> +//</regmap> +//XmlParse xml_off diff --git a/fpga/usrp3/top/x400/dboards/zbx/cpld/register_endpoints/basic_regs.v b/fpga/usrp3/top/x400/dboards/zbx/cpld/register_endpoints/basic_regs.v new file mode 100644 index 000000000..3c218de17 --- /dev/null +++ b/fpga/usrp3/top/x400/dboards/zbx/cpld/register_endpoints/basic_regs.v @@ -0,0 +1,219 @@ +// +// Copyright 2021 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: basic_regs +// +// Description: +// Basic Registers to inform software about version and capabilities. +// + +`default_nettype none + +module basic_regs #( + parameter [19:0] BASE_ADDRESS = 0, + parameter [19:0] SIZE_ADDRESS = 0 +) ( + // 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, + + //reg clk domain + input wire ctrlport_clk, + input wire ctrlport_rst +); + + `include "../regmap/basic_regs_regmap_utils.vh" + `include "../../../../../../lib/rfnoc/core/ctrlport.vh" + + //---------------------------------------------------------- + // Internal registers + //---------------------------------------------------------- + reg [SCRATCH_REG_SIZE-1:0] scratch_reg = {SCRATCH_REG_SIZE {1'b0}}; + + //---------------------------------------------------------- + // Handling of CtrlPort + //---------------------------------------------------------- + wire address_in_range = (s_ctrlport_req_addr >= BASE_ADDRESS) && (s_ctrlport_req_addr < BASE_ADDRESS + SIZE_ADDRESS); + + always @(posedge ctrlport_clk) begin + // reset internal registers and responses + if (ctrlport_rst) begin + scratch_reg <= {SCRATCH_REG_SIZE {1'b0}}; + + s_ctrlport_resp_ack <= 1'b0; + s_ctrlport_resp_data <= {32{1'bx}}; + s_ctrlport_resp_status <= CTRL_STS_OKAY; + + 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 + SLAVE_SCRATCH: begin + scratch_reg <= s_ctrlport_req_data[ SCRATCH_REG_MSB : SCRATCH_REG]; + 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 + + // read requests + 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 + SLAVE_SIGNATURE: begin + s_ctrlport_resp_data[BOARD_ID_MSB : BOARD_ID] + <= BOARD_ID_VALUE[BOARD_ID_SIZE-1:0]; + end + + BASE_ADDRESS + SLAVE_REVISION: begin + s_ctrlport_resp_data[REVISION_REG_MSB : REVISION_REG] + <= CPLD_REVISION[REVISION_REG_SIZE-1:0]; + end + + BASE_ADDRESS + SLAVE_OLDEST_REVISION: begin + s_ctrlport_resp_data[OLDEST_REVISION_REG_MSB : OLDEST_REVISION_REG] + <= OLDEST_CPLD_REVISION[OLDEST_REVISION_REG_SIZE-1:0]; + end + + BASE_ADDRESS + SLAVE_SCRATCH: begin + s_ctrlport_resp_data[SCRATCH_REG_MSB : SCRATCH_REG] <= scratch_reg; + end + + + BASE_ADDRESS + GIT_HASH_REGISTER: begin + `ifdef GIT_HASH + s_ctrlport_resp_data <= `GIT_HASH; + `else + s_ctrlport_resp_data <= 32'hDEADBEEF; + `endif + end + + // error on undefined address + default: begin + s_ctrlport_resp_data <= {32{1'b0}}; + 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 + +endmodule + +`default_nettype wire + +//XmlParse xml_on +//<regmap name="BASIC_REGS_REGMAP" readablestrobes="false" generatevhdl="true" ettusguidelines="true"> +// <group name="BASIC_REGS_REGISTERS" size="0x010"> +// <info> +// This regmap contains the revision registers, signature register, a scratch register, and a slave control reg. +// </info> +// +// <enumeratedtype name="BASIC_REGISTERS_VALUES" showhexvalue="true"> +// <info> +// This enum is used to create the constants held in the basic registers in both verilog and vhdl. +// </info> +// <value name="BOARD_ID_VALUE" integer="0x4002"/> +// <value name="CPLD_REVISION" integer="0x21031009"/> +// <value name="OLDEST_CPLD_REVISION" integer="0x20110611"/> +// </enumeratedtype> +// +// <register name="SLAVE_SIGNATURE" size="32" offset="0x00" attributes="Readable"> +// <info> +// This register contains the unique signature of the DB. This signature is the same value as the one +// stored on the board ID EEPROM +// </info> +// <bitfield name="BOARD_ID" range="15..0" type="integer"> +// <info> +// Board ID corresponds to the las 16 digits of the daughterboard part number. +// </info> +// </bitfield> +// </register> +// +// <register name="SLAVE_REVISION" size="32" offset="0x04" attributes="Readable"> +// <info> +// This register contains the revision number of the current build +// </info> +// <bitfield name="REVISION_REG" range="31..0" type="integer"> +// <info> +// Returns the revision in YYMMDDHH format +// </info> +// </bitfield> +// </register> +// +// <register name="SLAVE_OLDEST_REVISION" size="32" offset="0x08" attributes="Readable"> +// <info> +// This register contains the revision number of the oldest compatible revision +// </info> +// <bitfield name="OLDEST_REVISION_REG" range="31..0" type="integer"> +// <info> +// Returns the oldest compatible revision in YYMMDDHH format +// </info> +// </bitfield> +// </register> +// +// <register name="SLAVE_SCRATCH" size="32" offset="0x0C" attributes="Readable|Writable"> +// <info> +// Read/write scratch register +// </info> +// <bitfield name="SCRATCH_REG" range="31..0" initialvalue="0"> +// <info> +// Returns the value written here previously. +// </info> +// </bitfield> +// </register> +// +// <register name="GIT_HASH_REGISTER" offset="0x10" size="32" writable="false"> +// <info> +// Git hash of commit used to build this image.{br} +// Value equals 0xDEADBEEF if the git hash was not used during synthesis. +// </info> +// <bitfield name="GIT_CLEAN" range="31..28"> +// <info> +// 0x0 in case the git status was clean{br} +// 0xF in case there were uncommitted changes +// </info> +// </bitfield> +// <bitfield name="GIT_HASH" range="27..0"> +// <info>7 hex digit hash code of the commit</info> +// </bitfield> +// </register> +// </group> +//</regmap> +//XmlParse xml_off diff --git a/fpga/usrp3/top/x400/dboards/zbx/cpld/register_endpoints/dsa_control.v b/fpga/usrp3/top/x400/dboards/zbx/cpld/register_endpoints/dsa_control.v new file mode 100644 index 000000000..abc4b62f9 --- /dev/null +++ b/fpga/usrp3/top/x400/dboards/zbx/cpld/register_endpoints/dsa_control.v @@ -0,0 +1,736 @@ +// +// Copyright 2021 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: dsa_control +// +// Description: +// Implements control over Digital Step Attenuators via CtrlPort. Uses RAM to +// store multiple ATR configurations. Provides gain table to abstract from raw +// DSA values. +// +// IMPORTANT: The default values here must be synchronized with the default +// values in gen_defaults.py, they are not automatically kept in sync. +// + +`default_nettype none + +module dsa_control #( + parameter [19:0] BASE_ADDRESS = 0, + parameter [19:0] SIZE_ADDRESS = 0 +) ( + // 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 = 2'b0, + output reg [31:0] s_ctrlport_resp_data = 32'b0, + + // ATR switching + input wire [ 7:0] atr_config_rf0, + input wire [ 7:0] atr_config_rf1, + + // The attenuation setting for TX paths is indexed from two, + // to match schematic naming. In this case, the two LSBs + // for parallel control going into the DSA chips are connected + // to ground(those bits control fractional attenuation). + + //Tx0 DSA control (domain: ctrl_reg_clk) + output wire [6:2] tx0_dsa1, + output wire [6:2] tx0_dsa2, + + //Tx1 DSA control (domain: ctrl_reg_clk) + output wire [6:2] tx1_dsa1, + output wire [6:2] tx1_dsa2, + + // The attenuation setting for RX paths is indexed from one, + // to match schematic naming. In this case, the LSB controls + // the highest value, so re reverse the order of the vector. + // Note the these signals are active low. + + //Rx0 DSA control (domain: ctrl_reg_clk) + output wire [1:4] rx0_dsa1_n, + output wire [1:4] rx0_dsa2_n, + output wire [1:4] rx0_dsa3_a_n, + output wire [1:4] rx0_dsa3_b_n, + + //Rx1 DSA control (domain: ctrl_reg_clk) + output wire [1:4] rx1_dsa1_n, + output wire [1:4] rx1_dsa2_n, + output wire [1:4] rx1_dsa3_a_n, + output wire [1:4] rx1_dsa3_b_n +); + + `include "../regmap/dsa_setup_regmap_utils.vh" + `include "../../../../../../lib/rfnoc/core/ctrlport.vh" + + //--------------------------------------------------------------- + // register bitfields + //--------------------------------------------------------------- + reg [TX_DSA1_SIZE -1:0] tx0_dsa_1_reg = {TX_DSA1_SIZE{1'b1}}; + reg [TX_DSA2_SIZE -1:0] tx0_dsa_2_reg = {TX_DSA2_SIZE{1'b1}}; + + reg [TX_DSA1_SIZE -1:0] tx1_dsa_1_reg = {TX_DSA1_SIZE{1'b1}}; + reg [TX_DSA2_SIZE -1:0] tx1_dsa_2_reg = {TX_DSA2_SIZE{1'b1}}; + + reg [RX_DSA1_SIZE -1:0] rx0_dsa_1_reg = {RX_DSA1_SIZE{1'b1}}; + reg [RX_DSA2_SIZE -1:0] rx0_dsa_2_reg = {RX_DSA2_SIZE{1'b1}}; + reg [RX_DSA3_A_SIZE -1:0] rx0_dsa_3_a_reg = {RX_DSA3_A_SIZE{1'b1}}; + reg [RX_DSA3_B_SIZE -1:0] rx0_dsa_3_b_reg = {RX_DSA3_B_SIZE{1'b1}}; + + reg [RX_DSA1_SIZE -1:0] rx1_dsa_1_reg = {RX_DSA1_SIZE{1'b1}}; + reg [RX_DSA2_SIZE -1:0] rx1_dsa_2_reg = {RX_DSA2_SIZE{1'b1}}; + reg [RX_DSA3_A_SIZE -1:0] rx1_dsa_3_a_reg = {RX_DSA3_A_SIZE{1'b1}}; + reg [RX_DSA3_B_SIZE -1:0] rx1_dsa_3_b_reg = {RX_DSA3_B_SIZE{1'b1}}; + + //--------------------------------------------------------------- + // ATR memory signals + //--------------------------------------------------------------- + reg ram_tx0_wea = 1'b0; + wire [31:0] ram_tx0_doa; + wire [31:0] ram_tx0_dob; + reg ram_tx1_wea = 1'b0; + wire [31:0] ram_tx1_doa; + wire [31:0] ram_tx1_dob; + reg ram_rx0_wea = 1'b0; + wire [31:0] ram_rx0_doa; + wire [31:0] ram_rx0_dob; + reg ram_rx1_wea = 1'b0; + wire [31:0] ram_rx1_doa; + wire [31:0] ram_rx1_dob; + + reg table_tx0_wea = 1'b0; + wire [31:0] table_tx0_doa; + reg table_tx1_wea = 1'b0; + wire [31:0] table_tx1_doa; + reg table_rx0_wea = 1'b0; + wire [31:0] table_rx0_doa; + reg table_rx1_wea = 1'b0; + wire [31:0] table_rx1_doa; + + //--------------------------------------------------------------- + // 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 + SIZE_ADDRESS); + // Read request shift register to align memory read and response generation. + reg [ 1:0] read_req_shift_reg = 2'b0; + // Write request shift register to align gain table memory read and ATR memory + // write operation. + reg [ 1:0] write_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]}; + // Extract masked out bits from the address, which represent the register + // array index = ATR configuration index + wire [ 7:0] register_index = s_ctrlport_req_addr[9:2]; + // switch between CtrlPort data and gain table data for ATR memories + reg select_gain_table = 1'b0; + + always @(posedge ctrlport_clk) begin + // reset internal registers and responses + if (ctrlport_rst) begin + s_ctrlport_resp_ack <= 1'b0; + + read_req_shift_reg <= 2'b0; + write_req_shift_reg <= 2'b0; + + ram_tx0_wea <= 1'b0; + ram_tx1_wea <= 1'b0; + ram_rx0_wea <= 1'b0; + ram_rx1_wea <= 1'b0; + + table_tx0_wea <= 1'b0; + table_tx1_wea <= 1'b0; + table_rx0_wea <= 1'b0; + table_rx1_wea <= 1'b0; + + select_gain_table <= 1'b0; + + end else begin + // default assignments + read_req_shift_reg <= { read_req_shift_reg[0], s_ctrlport_req_rd}; + write_req_shift_reg <= {write_req_shift_reg[0], s_ctrlport_req_wr}; + + ram_tx0_wea <= 1'b0; + ram_tx1_wea <= 1'b0; + ram_rx0_wea <= 1'b0; + ram_rx1_wea <= 1'b0; + + table_tx0_wea <= 1'b0; + table_tx1_wea <= 1'b0; + table_rx0_wea <= 1'b0; + table_rx1_wea <= 1'b0; + + select_gain_table <= 1'b0; + + // Answer write requests delayed by 2 clock cycles. This compensated for + // register ram_addr and the memory internal address register to make sure + // gain table output data is up to date when forwarding data to ATR memory + if (write_req_shift_reg[1]) 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 (register_base_address) + BASE_ADDRESS + TX0_DSA_ATR(0): begin + ram_tx0_wea <= 1'b1; + end + BASE_ADDRESS + TX1_DSA_ATR(0): begin + ram_tx1_wea <= 1'b1; + end + BASE_ADDRESS + RX0_DSA_ATR(0): begin + ram_rx0_wea <= 1'b1; + end + BASE_ADDRESS + RX1_DSA_ATR(0): begin + ram_rx1_wea <= 1'b1; + end + + BASE_ADDRESS + TX0_DSA_TABLE(0): begin + table_tx0_wea <= 1'b1; + end + BASE_ADDRESS + TX1_DSA_TABLE(0): begin + table_tx1_wea <= 1'b1; + end + BASE_ADDRESS + RX0_DSA_TABLE(0): begin + table_rx0_wea <= 1'b1; + end + BASE_ADDRESS + RX1_DSA_TABLE(0): begin + table_rx1_wea <= 1'b1; + end + + BASE_ADDRESS + TX0_DSA_TABLE_SELECT(0): begin + ram_tx0_wea <= 1'b1; + select_gain_table <= 1'b1; + end + BASE_ADDRESS + TX1_DSA_TABLE_SELECT(0): begin + ram_tx1_wea <= 1'b1; + select_gain_table <= 1'b1; + end + BASE_ADDRESS + RX0_DSA_TABLE_SELECT(0): begin + ram_rx0_wea <= 1'b1; + select_gain_table <= 1'b1; + end + BASE_ADDRESS + RX1_DSA_TABLE_SELECT(0): begin + ram_rx1_wea <= 1'b1; + select_gain_table <= 1'b1; + 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 + + // Answer read requests delayed by 2 clock cycles. This compensated for + // register ram_addr and the memory internal address register to make sure + // ram_ch0_doa is up to date when generating the response. + end else if (read_req_shift_reg[1]) 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 (register_base_address) + BASE_ADDRESS + TX0_DSA_ATR(0): begin + s_ctrlport_resp_data <= ram_tx0_doa & TX_DSA_CONTROL_MASK; + end + BASE_ADDRESS + TX1_DSA_ATR(0): begin + s_ctrlport_resp_data <= ram_tx1_doa & TX_DSA_CONTROL_MASK; + end + BASE_ADDRESS + RX0_DSA_ATR(0): begin + s_ctrlport_resp_data <= ram_rx0_doa & RX_DSA_CONTROL_MASK; + end + BASE_ADDRESS + RX1_DSA_ATR(0): begin + s_ctrlport_resp_data <= ram_rx1_doa & RX_DSA_CONTROL_MASK; + end + BASE_ADDRESS + TX0_DSA_TABLE(0): begin + s_ctrlport_resp_data <= table_tx0_doa & TX_DSA_CONTROL_MASK; + end + BASE_ADDRESS + TX1_DSA_TABLE(0): begin + s_ctrlport_resp_data <= table_tx1_doa & TX_DSA_CONTROL_MASK; + end + BASE_ADDRESS + RX0_DSA_TABLE(0): begin + s_ctrlport_resp_data <= table_rx0_doa & RX_DSA_CONTROL_MASK; + end + BASE_ADDRESS + RX1_DSA_TABLE(0): begin + s_ctrlport_resp_data <= table_rx1_doa & RX_DSA_CONTROL_MASK; + end + + 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 + + // register without reset + reg [ 7:0] ram_addr = 8'b0; + reg [ 7:0] gain_table_addr = 8'b0; + reg [31:0] ram_datain = 32'b0; + always @(posedge ctrlport_clk) begin + // Capture CtrlPort data and address on requests as only in this clock cycle + // the data is valid. + if (s_ctrlport_req_wr || s_ctrlport_req_rd) begin + ram_addr <= register_index; + ram_datain <= s_ctrlport_req_data; + + case (register_base_address) + BASE_ADDRESS + TX0_DSA_TABLE_SELECT(0), + BASE_ADDRESS + TX1_DSA_TABLE_SELECT(0), + BASE_ADDRESS + RX0_DSA_TABLE_SELECT(0), + BASE_ADDRESS + RX1_DSA_TABLE_SELECT(0): begin + gain_table_addr <= s_ctrlport_req_data[TABLE_INDEX_MSB:TABLE_INDEX]; + end + default: begin + gain_table_addr <= register_index; + end + endcase + end + + // outputs + tx0_dsa_1_reg <= ram_tx0_dob[ TX_DSA1_MSB : TX_DSA1]; + tx0_dsa_2_reg <= ram_tx0_dob[ TX_DSA2_MSB : TX_DSA2]; + + tx1_dsa_1_reg <= ram_tx1_dob[ TX_DSA1_MSB : TX_DSA1]; + tx1_dsa_2_reg <= ram_tx1_dob[ TX_DSA2_MSB : TX_DSA2]; + + rx0_dsa_1_reg <= ram_rx0_dob[ RX_DSA1_MSB : RX_DSA1]; + rx0_dsa_2_reg <= ram_rx0_dob[ RX_DSA2_MSB : RX_DSA2]; + rx0_dsa_3_a_reg <= ram_rx0_dob[RX_DSA3_A_MSB : RX_DSA3_A]; + rx0_dsa_3_b_reg <= ram_rx0_dob[RX_DSA3_B_MSB : RX_DSA3_B]; + + rx1_dsa_1_reg <= ram_rx1_dob[ RX_DSA1_MSB : RX_DSA1]; + rx1_dsa_2_reg <= ram_rx1_dob[ RX_DSA2_MSB : RX_DSA2]; + rx1_dsa_3_a_reg <= ram_rx1_dob[RX_DSA3_A_MSB : RX_DSA3_A]; + rx1_dsa_3_b_reg <= ram_rx1_dob[RX_DSA3_B_MSB : RX_DSA3_B]; + end + + assign tx0_dsa1[6:2] = tx0_dsa_1_reg; + assign tx0_dsa2[6:2] = tx0_dsa_2_reg; + + assign tx1_dsa1[6:2] = tx1_dsa_1_reg; + assign tx1_dsa2[6:2] = tx1_dsa_2_reg; + + //Rx DSAs behave differently from Tx DSAs + //Flip MSB/LSB, and invert + + genvar vi; + // take care of inverting the active low logic and bit-reversing + // the DSA controls for RX paths. + generate + for (vi=1; vi<=4; vi=vi+1) begin : reverselogic + // [1:4] [3:0] + assign rx0_dsa1_n[vi] = !rx0_dsa_1_reg[4-vi]; + assign rx0_dsa2_n[vi] = !rx0_dsa_2_reg[4-vi]; + assign rx0_dsa3_a_n[vi] = !rx0_dsa_3_a_reg[4-vi]; + assign rx0_dsa3_b_n[vi] = !rx0_dsa_3_b_reg[4-vi]; + + assign rx1_dsa1_n[vi] = !rx1_dsa_1_reg[4-vi]; + assign rx1_dsa2_n[vi] = !rx1_dsa_2_reg[4-vi]; + assign rx1_dsa3_a_n[vi] = !rx1_dsa_3_a_reg[4-vi]; + assign rx1_dsa3_b_n[vi] = !rx1_dsa_3_b_reg[4-vi]; + end + endgenerate + + //--------------------------------------------------------------- + // ATR memories + //--------------------------------------------------------------- + // Choose data source for ATR configurations from CtrlPort or gain table. + wire [31:0] ram_rx0_dia = select_gain_table ? table_rx0_doa : ram_datain; + wire [31:0] ram_rx1_dia = select_gain_table ? table_rx1_doa : ram_datain; + wire [31:0] ram_tx0_dia = select_gain_table ? table_tx0_doa : ram_datain; + wire [31:0] ram_tx1_dia = select_gain_table ? table_tx1_doa : ram_datain; + + ram_2port #( + .DWIDTH (32), + .AWIDTH (8), + .RW_MODE ("READ-FIRST"), + .RAM_TYPE ("AUTOMATIC"), + .OUT_REG (0), + .INIT_FILE ("register_endpoints/memory_init_files/tx_dsa_defaults.hex") + ) ram_tx0_i ( + .clka (ctrlport_clk), + .ena (1'b1), + .wea (ram_tx0_wea), + .addra (ram_addr), + .dia (ram_tx0_dia), + .doa (ram_tx0_doa), + .clkb (ctrlport_clk), + .enb (1'b1), + .web (1'b0), + .addrb (atr_config_rf0), + .dib (0), + .dob (ram_tx0_dob) + ); + + ram_2port #( + .DWIDTH (32), + .AWIDTH (8), + .RW_MODE ("READ-FIRST"), + .RAM_TYPE ("AUTOMATIC"), + .OUT_REG (0), + .INIT_FILE ("register_endpoints/memory_init_files/tx_dsa_defaults.hex") + ) ram_tx1_i ( + .clka (ctrlport_clk), + .ena (1'b1), + .wea (ram_tx1_wea), + .addra (ram_addr), + .dia (ram_tx1_dia), + .doa (ram_tx1_doa), + .clkb (ctrlport_clk), + .enb (1'b1), + .web (1'b0), + .addrb (atr_config_rf1), + .dib (0), + .dob (ram_tx1_dob) + ); + + ram_2port #( + .DWIDTH (32), + .AWIDTH (8), + .RW_MODE ("READ-FIRST"), + .RAM_TYPE ("AUTOMATIC"), + .OUT_REG (0), + .INIT_FILE ("register_endpoints/memory_init_files/rx_dsa_defaults.hex") + ) ram_rx0_i ( + .clka (ctrlport_clk), + .ena (1'b1), + .wea (ram_rx0_wea), + .addra (ram_addr), + .dia (ram_rx0_dia), + .doa (ram_rx0_doa), + .clkb (ctrlport_clk), + .enb (1'b1), + .web (1'b0), + .addrb (atr_config_rf0), + .dib (0), + .dob (ram_rx0_dob) + ); + + ram_2port #( + .DWIDTH (32), + .AWIDTH (8), + .RW_MODE ("READ-FIRST"), + .RAM_TYPE ("AUTOMATIC"), + .OUT_REG (0), + .INIT_FILE ("register_endpoints/memory_init_files/rx_dsa_defaults.hex") + ) ram_rx1_i ( + .clka (ctrlport_clk), + .ena (1'b1), + .wea (ram_rx1_wea), + .addra (ram_addr), + .dia (ram_rx1_dia), + .doa (ram_rx1_doa), + .clkb (ctrlport_clk), + .enb (1'b1), + .web (1'b0), + .addrb (atr_config_rf1), + .dib (0), + .dob (ram_rx1_dob) + ); + + //--------------------------------------------------------------- + // Gain tables + //--------------------------------------------------------------- + + ram_2port #( + .DWIDTH (32), + .AWIDTH (8), + .RW_MODE ("READ-FIRST"), + .RAM_TYPE ("AUTOMATIC"), + .OUT_REG (0), + .INIT_FILE ("register_endpoints/memory_init_files/tx_dsa_defaults.hex") + ) table_tx0_i ( + .clka (ctrlport_clk), + .ena (1'b1), + .wea (table_tx0_wea), + .addra (gain_table_addr), + .dia (ram_datain), + .doa (table_tx0_doa), + .clkb (ctrlport_clk), + .enb (1'b1), + .web (1'b0), + .addrb (8'b0), + .dib (32'b0), + .dob () + ); + + ram_2port #( + .DWIDTH (32), + .AWIDTH (8), + .RW_MODE ("READ-FIRST"), + .RAM_TYPE ("AUTOMATIC"), + .OUT_REG (0), + .INIT_FILE ("register_endpoints/memory_init_files/tx_dsa_defaults.hex") + ) table_tx1_i ( + .clka (ctrlport_clk), + .ena (1'b1), + .wea (table_tx1_wea), + .addra (gain_table_addr), + .dia (ram_datain), + .doa (table_tx1_doa), + .clkb (ctrlport_clk), + .enb (1'b1), + .web (1'b0), + .addrb (8'b0), + .dib (32'b0), + .dob () + ); + + ram_2port #( + .DWIDTH (32), + .AWIDTH (8), + .RW_MODE ("READ-FIRST"), + .RAM_TYPE ("AUTOMATIC"), + .OUT_REG (0), + .INIT_FILE ("register_endpoints/memory_init_files/rx_dsa_defaults.hex") + ) table_rx0_i ( + .clka (ctrlport_clk), + .ena (1'b1), + .wea (table_rx0_wea), + .addra (gain_table_addr), + .dia (ram_datain), + .doa (table_rx0_doa), + .clkb (ctrlport_clk), + .enb (1'b1), + .web (1'b0), + .addrb (8'b0), + .dib (32'b0), + .dob () + ); + + ram_2port #( + .DWIDTH (32), + .AWIDTH (8), + .RW_MODE ("READ-FIRST"), + .RAM_TYPE ("AUTOMATIC"), + .OUT_REG (0), + .INIT_FILE ("register_endpoints/memory_init_files/rx_dsa_defaults.hex") + ) table_rx1_i ( + .clka (ctrlport_clk), + .ena (1'b1), + .wea (table_rx1_wea), + .addra (gain_table_addr), + .dia (ram_datain), + .doa (table_rx1_doa), + .clkb (ctrlport_clk), + .enb (1'b1), + .web (1'b0), + .addrb (8'b0), + .dib (32'b0), + .dob () + ); + +endmodule + +`default_nettype wire + +//XmlParse xml_on +//<regmap name="DSA_SETUP_REGMAP" readablestrobes="false" generatevhdl="true" ettusguidelines="true" markdown="true"> +// <group name="DSA_SETUP_REGISTERS"> +// <info> +// The following registers control the digital step attenuators (DSA). +// +// There are two ways to set the DSA values, which are applied to the DB ICs. +// +// 1. The ...DSA_ATR registers can be used to access the raw +// values of each ATR configuration. +// +// 2. Gain tables can be used as intermediate step to abstract from the +// raw DB values. This gain table can be modified using the ...DSA_TABLE +// registers according to the content of the registers from the first +// option. Initially each gain table is empty (all zeros). Each gain +// table entry can be accessed at any time. Once the table is filled with +// values the ...DSA_TABLE_SELECT registers can be used to get one gain +// table entry with index TABLE_INDEX and write it to the appropriate ATR +// configuration given by the address (see _show extended info_ link below +// the register array headlines) +// </info> +// <regtype name="TX_DSA_CONTROL" size="32" attributes="Readable|Writable"> +// <bitfield name="TX_DSA1" range="4..0" initialvalue="31"> +// <info> +// Sets the attenuation level for Tx DSA1. The resolution attenuation is 1 dB, with an attenuation range from 1 to 31 dB. Write this field with the +// attenuation setting desired. Writing zero to this field results in no attenuation (different insertion loss expected for different frequency ranges). +// </info> +// </bitfield> +// <bitfield name="TX_DSA2" range="12..8" initialvalue="31"> +// <info> +// Sets the attenuation level for Tx DSA2. The resolution attenuation is 1 dB, with an attenuation range from 1 to 31 dB. Write this field with the +// attenuation setting desired. Writing zero to this field results in no attenuation (different insertion loss expected for different frequency ranges). +// </info> +// </bitfield> +// </regtype> +// +// <regtype name="RX_DSA_CONTROL" size="32" attributes="Readable|Writable"> +// <bitfield name="RX_DSA1" range="3..0" initialvalue="15"> +// <info> +// Sets the attenuation level for Rx DSA1. The resolution attenuation is 1 dB, with an attenuation range from 1 to 15 dB. Write this field with the +// attenuation setting desired. Writing zero to this field results in no attenuation (different insertion loss expected for different frequency ranges). +// </info> +// </bitfield> +// <bitfield name="RX_DSA2" range="7..4" initialvalue="15"> +// <info> +// Sets the attenuation level for Rx DSA2. The resolution attenuation is 1 dB, with an attenuation range from 1 to 15 dB. Write this field with the +// attenuation setting desired. Writing zero to this field results in no attenuation (different insertion loss expected for different frequency ranges). +// </info> +// </bitfield> +// <bitfield name="RX_DSA3_A" range="11..8" initialvalue="15"> +// <info> +// Sets the attenuation level for Rx DSA 3a and 3b. The resolution attenuation is 1 dB, with an attenuation range from 1 to 15 dB. Write this field with the +// attenuation setting desired. Writing zero to this field results in no attenuation (different insertion loss expected for different frequency ranges). +// </info> +// </bitfield> +// <bitfield name="RX_DSA3_B" range="15..12" initialvalue="15"> +// <info> +// Sets the attenuation level for Rx DSA 3b(to input of IF1 Amplifier 2). The resolution attenuation is 1 dB, with an attenuation range from 1 to 15 dB. Write this field with the +// attenuation setting desired. Writing zero to this field results in no attenuation (different insertion loss expected for different frequency ranges).. {BR/} +// </info> +// </bitfield> +// </regtype> +// +// <regtype name="DSA_TABLE_CONTROL" size="32" attributes="Writable"> +// <bitfield name="TABLE_INDEX" range="7..0"> +// <info> +// Gain table index to be used for getting the raw attenuation values. +// </info> +// </bitfield> +// </regtype> +// +// <register name="TX0_DSA_ATR" offset="0x000" count="256" step="4" typename="TX_DSA_CONTROL"> +// <info> +// Controls the Tx0 DSAs by accessing the raw attenuation levels. +// +// This register array can hold settings for all ATR configurations. +// The register index equals the ATR configuration. +// The active configuration can be selected in @.ATR_REGMAP. +// Independently all configurations can be read/written at any time. +// </info> +// </register> +// <register name="TX1_DSA_ATR" offset="0x400" count="256" step="4" typename="TX_DSA_CONTROL"> +// <info> +// Controls the Tx1 DSAs by accessing the raw attenuation levels. +// +// This register array can hold settings for all ATR configurations. +// The register index equals the ATR configuration. +// The active configuration can be selected in @.ATR_REGMAP. +// Independently all configurations can be read/written at any time. +// </info> +// </register> +// +// <register name="RX0_DSA_ATR" offset="0x800" count="256" step="4" typename="RX_DSA_CONTROL"> +// <info> +// Controls the Rx0 DSAs by accessing the raw attenuation levels. +// +// This register array can hold settings for all ATR configurations. +// The register index equals the ATR configuration. +// The active configuration can be selected in @.ATR_REGMAP. +// Independently all configurations can be read/written at any time. +// </info> +// </register> +// <register name="RX1_DSA_ATR" offset="0xC00" count="256" step="4" typename="RX_DSA_CONTROL"> +// <info> +// Controls the Rx1 DSAs by accessing the raw attenuation levels. +// +// This register array can hold settings for all ATR configurations. +// The register index equals the ATR configuration. +// The active configuration can be selected in @.ATR_REGMAP. +// Independently all configurations can be read/written at any time. +// </info> +// </register> +// +// <register name="TX0_DSA_TABLE_SELECT" offset="0x1000" count="256" step="4" typename="DSA_TABLE_CONTROL"> +// <info> +// Controls the Tx0 DSAs by using the gain table to translate the table +// index to raw attenuation levels. The register offset (i) is targeting +// an ATR configuration to store the values from the gain table. +// </info> +// </register> +// <register name="TX1_DSA_TABLE_SELECT" offset="0x1400" count="256" step="4" typename="DSA_TABLE_CONTROL"> +// <info> +// Controls the Tx1 DSAs by using the gain table to translate the table +// index to raw attenuation levels. The register offset (i) is targeting +// an ATR configuration to store the values from the gain table. +// </info> +// </register> +// <register name="RX0_DSA_TABLE_SELECT" offset="0x1800" count="256" step="4" typename="DSA_TABLE_CONTROL"> +// <info> +// Controls the Rx0 DSAs by using the gain table to translate the table +// index to raw attenuation levels. The register offset (i) is targeting +// an ATR configuration to store the values from the gain table. +// </info> +// </register> +// <register name="RX1_DSA_TABLE_SELECT" offset="0x1C00" count="256" step="4" typename="DSA_TABLE_CONTROL"> +// <info> +// Controls the Rx1 DSAs by using the gain table to translate the table +// index to raw attenuation levels. The register offset (i) is targeting +// an ATR configuration to store the values from the gain table. +// </info> +// </register> +// +// <register name="TX0_DSA_TABLE" offset="0x2000" count="256" step="4" typename="TX_DSA_CONTROL"> +// <info> +// Provides access to the gain table for Tx0. +// +// Each entry i will be saved in the gain table without any implications +// on HW. Enables SW to use the table index in @.TX0_DSA_TABLE_SELECT to +// modify the ATR configurations. +// </info> +// </register> +// <register name="TX1_DSA_TABLE" offset="0x2400" count="256" step="4" typename="TX_DSA_CONTROL"> +// <info> +// Provides access to the gain table for Tx1. +// +// Each entry i will be saved in the gain table without any implications +// on HW. Enables SW to use the table index in @.TX1_DSA_TABLE_SELECT to +// modify the ATR configurations. +// </info> +// </register> +// <register name="RX0_DSA_TABLE" offset="0x2800" count="256" step="4" typename="RX_DSA_CONTROL"> +// <info> +// Provides access to the gain table for Rx0. +// +// Each entry i will be saved in the gain table without any implications +// on HW. Enables SW to use the table index in @.RX0_DSA_TABLE_SELECT to +// modify the ATR configurations. +// </info> +// </register> +// <register name="RX1_DSA_TABLE" offset="0x2C00" count="256" step="4" typename="RX_DSA_CONTROL"> +// <info> +// Provides access to the gain table for Rx1. +// +// Each entry i will be saved in the gain table without any implications +// on HW. Enables SW to use the table index in @.RX1_DSA_TABLE_SELECT to +// modify the ATR configurations. +// </info> +// </register> +// </group> +//</regmap> +//XmlParse xml_off diff --git a/fpga/usrp3/top/x400/dboards/zbx/cpld/register_endpoints/led_control.v b/fpga/usrp3/top/x400/dboards/zbx/cpld/register_endpoints/led_control.v new file mode 100644 index 000000000..5663d348e --- /dev/null +++ b/fpga/usrp3/top/x400/dboards/zbx/cpld/register_endpoints/led_control.v @@ -0,0 +1,259 @@ +// +// Copyright 2021 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: led_control +// +// Description: +// Implements control over LED state via CtrlPort. The default state +// has the LEDs disabled. Uses RAM to store multiple ATR configurations. +// + +`default_nettype none + +module led_control #( + parameter [19:0] BASE_ADDRESS = 0, + parameter [19:0] SIZE_ADDRESS = 0 +) ( + // 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 = 2'b0, + output reg [31:0] s_ctrlport_resp_data = 32'b0, + + // LED Control (domain: ctrlport_clk) + output reg ch0_rx2_led, + output reg ch0_tx_led, + output reg ch0_rx_led, + output reg ch1_rx2_led, + output reg ch1_tx_led, + output reg ch1_rx_led, + + // ATR switching + input wire [ 7:0] atr_config_rf0, + input wire [ 7:0] atr_config_rf1 +); + + `include "../regmap/led_setup_regmap_utils.vh" + `include "../../../../../../lib/rfnoc/core/ctrlport.vh" + + //--------------------------------------------------------------- + // ATR memory signals + //--------------------------------------------------------------- + reg ram_ch0_wea; + wire [31:0] ram_ch0_doa; + wire [31:0] ram_ch0_dob; + + reg ram_ch1_wea; + wire [31:0] ram_ch1_dob; + + //--------------------------------------------------------------- + // 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 + SIZE_ADDRESS); + // 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]}; + // Extract masked out bits from the address, which represent the register + // array index = ATR configuration index + wire [ 7:0] register_index = s_ctrlport_req_addr[9:2]; + + always @(posedge ctrlport_clk) begin + // reset internal registers and responses + if (ctrlport_rst) begin + s_ctrlport_resp_ack <= 1'b0; + + read_req_shift_reg <= 2'b0; + + ram_ch0_wea <= 1'b0; + ram_ch1_wea <= 1'b0; + + end else begin + // default assignments + read_req_shift_reg <= {read_req_shift_reg[0], s_ctrlport_req_rd}; + + ram_ch0_wea <= 1'b0; + ram_ch1_wea <= 1'b0; + + // 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 (register_base_address) + BASE_ADDRESS + LED_CONTROL(0): begin + ram_ch0_wea <= 1'b1; + ram_ch1_wea <= 1'b1; + 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 + + // Answer read requests delayed by 2 clock cycles. This compensated for + // register ram_addr and the memory internal address register to make sure + // ram_ch0_doa is up to date when generating the response. + end else if (read_req_shift_reg[1]) 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 (register_base_address) + BASE_ADDRESS + LED_CONTROL(0): begin + s_ctrlport_resp_data <= ram_ch0_doa & LED_CONTROL_TYPE_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 + + // register without reset + reg [ 7:0] ram_addr = 8'b0; + reg [31:0] ram_datain = 32'b0; + always @(posedge ctrlport_clk) begin + // memories + ram_addr <= register_index; + ram_datain <= s_ctrlport_req_data; + + //outputs + ch0_rx2_led <= ram_ch0_dob[CH0_RX2_LED_EN]; + ch0_tx_led <= ram_ch0_dob[CH0_TRX1_LED_EN + 1]; + ch0_rx_led <= ram_ch0_dob[CH0_TRX1_LED_EN + 0]; + + ch1_rx2_led <= ram_ch1_dob[CH1_RX2_LED_EN]; + ch1_tx_led <= ram_ch1_dob[CH1_TRX1_LED_EN + 1]; + ch1_rx_led <= ram_ch1_dob[CH1_TRX1_LED_EN + 0]; + end + + ram_2port #( + .DWIDTH (32), + .AWIDTH (8), + .RW_MODE ("READ-FIRST"), + .RAM_TYPE ("AUTOMATIC"), + .OUT_REG (0), + .INIT_FILE ("") + ) ram_ch0_i ( + .clka (ctrlport_clk), + .ena (1'b1), + .wea (ram_ch0_wea), + .addra (ram_addr), + .dia (ram_datain), + .doa (ram_ch0_doa), + .clkb (ctrlport_clk), + .enb (1'b1), + .web (1'b0), + .addrb (atr_config_rf0), + .dib (0), + .dob (ram_ch0_dob) + ); + + ram_2port #( + .DWIDTH (32), + .AWIDTH (8), + .RW_MODE ("READ-FIRST"), + .RAM_TYPE ("AUTOMATIC"), + .OUT_REG (0), + .INIT_FILE ("") + ) ram_ch1_i ( + .clka (ctrlport_clk), + .ena (1'b1), + .wea (ram_ch1_wea), + .addra (ram_addr), + .dia (ram_datain), + .doa (), + .clkb (ctrlport_clk), + .enb (1'b1), + .web (1'b0), + .addrb (atr_config_rf1), + .dib (0), + .dob (ram_ch1_dob)); + +endmodule + +`default_nettype wire + +//XmlParse xml_on +//<regmap name="LED_SETUP_REGMAP" readablestrobes="false" generatevhdl="true" ettusguidelines="true"> +// <group name="LED_SETUP_REGISTERS"> +// <info> +// Contains registers that control the LEDs. +// </info> +// <regtype name="LED_CONTROL_TYPE" size="32" attributes="Readable|Writable"> +// <info> +// Defines LED functionality. +// </info> +// <bitfield name="CH0_RX2_LED_EN" range="0" initialvalue="0"> +// <info> +// Enables the Ch0 Rx2 Green LED +// </info> +// </bitfield> +// <bitfield name="CH0_TRX1_LED_EN" range="2..1" initialvalue="0"> +// <info> +// This bitfield controls the RG LED{BR/} +// Bit 6 controls the Ch0 Rx Green LED{BR/} +// Bit 7 controls the Ch0 Tx Red LED{BR/} +// </info> +// </bitfield> +// <bitfield name="CH1_RX2_LED_EN" range="16" initialvalue="0"> +// <info> +// Enables the Ch1 Rx2 Green LED +// </info> +// </bitfield> +// <bitfield name="CH1_TRX1_LED_EN" range="18..17" initialvalue="0"> +// <info> +// This bitfield controls the RG LED{BR/} +// Bit 15 controls the Ch1 Rx Green LED{BR/} +// Bit 14 controls the Ch1 Tx Red LED{BR/} +// </info> +// </bitfield> +// </regtype> +// +// <register name="LED_CONTROL" offset="0x0" count="256" step="4" typename="LED_CONTROL_TYPE"> +// <info> +// This register array can hold settings for all ATR configurations. +// The register index equals the ATR configuration. +// The active configuration can be selected in @.ATR_REGMAP. +// Independently all configurations can be read/written at any time. +// </info> +// </register> +// </group> +//</regmap> +//XmlParse xml_off diff --git a/fpga/usrp3/top/x400/dboards/zbx/cpld/register_endpoints/lo_control.v b/fpga/usrp3/top/x400/dboards/zbx/cpld/register_endpoints/lo_control.v new file mode 100644 index 000000000..67a2e8c79 --- /dev/null +++ b/fpga/usrp3/top/x400/dboards/zbx/cpld/register_endpoints/lo_control.v @@ -0,0 +1,568 @@ +// +// Copyright 2021 Ettus Research, A National Instruments Brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: lo_control +// +// Description: +// Implements control over signals interacting with LMX2572 chips on the +// daughterboard. This includes a CtrlPort based control over a SPI master +// that distributes transactions across the SPI buses of the LMX2572, as +// well as the capability to synchronously generate pulses to their SYNC pins. +// + +`default_nettype none + +module lo_control #( + parameter [19:0] BASE_ADDRESS = 0, + parameter [19:0] SIZE_ADDRESS = 0 +) ( + // 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, + + //reg clk domain + input wire ctrlport_clk, + input wire ctrlport_rst, + + // LO SPI for LMX2572 + input wire [7:0] miso, + output reg [7:0] ss = {8{1'b1}}, + output wire sclk, + output reg mosi = 1'b0, + + // Incoming SYNC + input wire mb_synth_sync, + + // SYNC for LMX2572 + output wire tx0_lo1_sync, + output wire tx0_lo2_sync, + output wire tx1_lo1_sync, + output wire tx1_lo2_sync, + output wire rx0_lo1_sync, + output wire rx0_lo2_sync, + output wire rx1_lo1_sync, + output wire rx1_lo2_sync +); + + `include "../regmap/lo_control_regmap_utils.vh" + `include "../../../../../../lib/rfnoc/core/ctrlport.vh" + + //--------------------------------------------------------------- + // register bitfields + //--------------------------------------------------------------- + + reg spi_start; + reg [LO_SELECT_SIZE-1:0] spi_cs; + reg spi_rd; + reg [LO_SPI_WT_ADDR_SIZE-1:0] spi_addr; + reg [LO_SPI_WT_DATA_SIZE-1:0] spi_data; + reg spi_data_valid; + reg spi_ready = 1'b1; + reg [LO_SPI_RD_DATA_SIZE-1:0] spi_rd_data; + reg [LO_CHIP_SELECT_SIZE-1:0] lo_sync_reg = 8'b0; + reg bypass_sync = 1'b0; + + //--------------------------------------------------------------- + // Handling of CtrlPort + //--------------------------------------------------------------- + wire address_in_range = (s_ctrlport_req_addr >= BASE_ADDRESS) && (s_ctrlport_req_addr < BASE_ADDRESS + SIZE_ADDRESS); + + always @(posedge ctrlport_clk) begin + // reset internal registers and responses + if (ctrlport_rst) begin + spi_start <= 1'b0; + spi_cs <= 3'b0; + spi_rd <= 1'b0; + spi_addr <= {LO_SPI_WT_ADDR_SIZE{1'b0}}; + spi_data <= {LO_SPI_WT_DATA_SIZE{1'b0}}; + lo_sync_reg <= 8'b0; + bypass_sync <= 1'b0; + + s_ctrlport_resp_ack <= 1'b0; + s_ctrlport_resp_data <= {32{1'bx}}; + s_ctrlport_resp_status <= CTRL_STS_OKAY; + + end else begin + + //send only a pulse + spi_start <= 1'b0; + + //pulse sync lines for a maximum of one cycle + lo_sync_reg <= 8'b0; + + // 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 + LO_SPI_SETUP: begin + spi_start <= s_ctrlport_req_data[LO_SPI_START_TRANSACTION]; + spi_cs <= s_ctrlport_req_data[LO_SELECT_MSB : LO_SELECT]; + spi_rd <= s_ctrlport_req_data[LO_SPI_RD]; + spi_addr <= s_ctrlport_req_data[LO_SPI_WT_ADDR_MSB : LO_SPI_WT_ADDR]; + spi_data <= s_ctrlport_req_data[LO_SPI_WT_DATA_MSB : LO_SPI_WT_DATA]; + end + + BASE_ADDRESS + LO_PULSE_SYNC: begin + bypass_sync <= s_ctrlport_req_data[BYPASS_SYNC_REGISTER]; + lo_sync_reg[TX0_LO1] <= s_ctrlport_req_data[PULSE_TX0_LO1_SYNC]; + lo_sync_reg[TX0_LO2] <= s_ctrlport_req_data[PULSE_TX0_LO2_SYNC]; + lo_sync_reg[TX1_LO1] <= s_ctrlport_req_data[PULSE_TX1_LO1_SYNC]; + lo_sync_reg[TX1_LO2] <= s_ctrlport_req_data[PULSE_TX1_LO2_SYNC]; + lo_sync_reg[RX0_LO1] <= s_ctrlport_req_data[PULSE_RX0_LO1_SYNC]; + lo_sync_reg[RX0_LO2] <= s_ctrlport_req_data[PULSE_RX0_LO2_SYNC]; + lo_sync_reg[RX1_LO1] <= s_ctrlport_req_data[PULSE_RX1_LO1_SYNC]; + lo_sync_reg[RX1_LO2] <= s_ctrlport_req_data[PULSE_RX1_LO2_SYNC]; + 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 + + // read requests + 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 + LO_SPI_STATUS: begin //same address as *_status form regmap + s_ctrlport_resp_data[LO_SPI_DATA_VALID] <= spi_data_valid; + s_ctrlport_resp_data[LO_SELECT_MSB : LO_SELECT] <= spi_cs; + s_ctrlport_resp_data[LO_SPI_READY] <= spi_ready; + s_ctrlport_resp_data[LO_SPI_RD_ADDR_MSB : LO_SPI_RD_ADDR] <= spi_addr; + s_ctrlport_resp_data[LO_SPI_RD_DATA_MSB : LO_SPI_RD_DATA] <= spi_rd_data; + end + + // error on undefined address + default: begin + s_ctrlport_resp_data <= {32{1'b0}}; + 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 + + // Spi_top controls + reg [4:0] wb_adr_i; + reg wb_cyc_i; + reg [31:0] wb_dat_i; + reg wb_we_i; + + // Spi_top outputs + wire wb_ack_o; + wire [31:0] wb_dat_o; + wire wb_int_o; + + wire [15:0] ss_pad_o; + wire mosi_pad_o; + wire miso_pad_i; + + // There is a hold requirement of 10ns on the output path. + // To ease meeting this requirement without to much routing added to the lines + // these registers shift the output by 10ns (half 50 MHz period). + always @(negedge ctrlport_clk) begin + if (ctrlport_rst) begin + ss <= {8{1'b1}}; + mosi <= 1'b0; + end + else begin + ss <= ss_pad_o[LO_CHIP_SELECT_SIZE-1:0]; + mosi <= mosi_pad_o; + end + end + + assign miso_pad_i = ( ~ss[TX0_LO1] ) ? miso[TX0_LO1] : + ( ~ss[TX0_LO2] ) ? miso[TX0_LO2] : + ( ~ss[TX1_LO1] ) ? miso[TX1_LO1] : + ( ~ss[TX1_LO2] ) ? miso[TX1_LO2] : + ( ~ss[RX0_LO1] ) ? miso[RX0_LO1] : + ( ~ss[RX0_LO2] ) ? miso[RX0_LO2] : + ( ~ss[RX1_LO1] ) ? miso[RX1_LO1] : + ( ~ss[RX1_LO2] ) ? miso[RX1_LO2] : + 1'b0; + + // Import offsets and functions to interact with spi_top + `include "utils/spi_control_utils.vh" + + // The sclk signal generated by this spi engine will be constrained to be 1/4 of the + // ctrl port frequency. The effective frequency of the clock output of spi_top is determined + // by the equation wb_clk_i/((CLOCK_DIVIDER_VALUE+1)*2), so the value required for the clock + // divider register is 1. + localparam CLOCK_DIVIDER_VALUE = 32'h1; + + // Base Configuration for the control register. To start a transaction + // modify this value to include the GO_BUSY bit set to high. The mapping of the + // macro goes as follows: + `define CONTROL_DATA(GO_BUSY) { 18'b0, /* Reserved */ \ + 1'b1, /* Automatic SS(13) */ \ + 1'b1, /* Interrupt Enable */ \ + 1'b0, /* LSB */ \ + 1'b1, /* TX_NEG (10) */ \ + 1'b0, /* RX_NEG (9) */ \ + GO_BUSY, /* GO_BUSY (8) */ \ + 1'b0, /* Reserved (7) */ \ + 7'd24} /* Length of spi transaction */ + + // Declare the different state-machine states. + localparam RESET_STATE = 0; + localparam CONFIG_DIVIDER = 1; + localparam INIT_CONTROL = 2; + localparam IDLE = 3; + localparam LOAD_CS = 4; + localparam LOAD_DATA = 5; + localparam SEND_TRANSACTION = 6; + localparam WAIT_FOR_COMPLETION = 7; + localparam RETRIEVE_DATA = 8; + + // FSM state variable + reg [3:0] spi_state = RESET_STATE; + + always @(posedge ctrlport_clk) begin + if (ctrlport_rst) begin + // SPI_STATUS for CtrlPort + spi_state <= RESET_STATE; + spi_ready <= 1'b1; + spi_data_valid <= 1'b0; + spi_rd_data <= {LO_SPI_RD_DATA_SIZE{1'b0}}; + + // SPI_TOP Bus access control. + wb_we_i <= 1'b0; + wb_cyc_i <= 1'b0; + wb_adr_i <= 5'h00; + wb_dat_i <= 32'h00; + end else begin + case (spi_state) + RESET_STATE: + if (spi_start) begin + spi_state <= CONFIG_DIVIDER; + end + + // keep driving a write to the CLOCK_DIVIDER Register until access is acknowledged. + CONFIG_DIVIDER: + if (wb_ack_o) begin + spi_state <= INIT_CONTROL; + wb_we_i <= 1'b0; + wb_cyc_i <= 1'b0; + end else begin + wb_we_i <= 1'b1; + wb_cyc_i <= 1'b1; + wb_adr_i <= CLOCK_DIVIDER_REG; // CLOCK DIVIDER register offset + wb_dat_i <= CLOCK_DIVIDER_VALUE; + end + + // keep driving a write to the CONTROL Register until access is acknowledged. + INIT_CONTROL: + if (wb_ack_o) begin + spi_state <= LOAD_CS; + wb_we_i <= 1'b0; + wb_cyc_i <= 1'b0; + end else begin + wb_we_i <= 1'b1; + wb_cyc_i <= 1'b1; + wb_adr_i <= CONTROL_REG; //CONTROL register offset + wb_dat_i <= `CONTROL_DATA(1'b0); //Write control register value with no GO_BUSY + end + + // Wait for CtrlPort operation to trigger a SPI transaction. + IDLE : + if (spi_start) begin + spi_state <= LOAD_CS; + spi_ready <= 1'b0; + spi_data_valid <= 1'b0; + // Clear data to be written next. This will make it so that the next state(LOAD_CS) + // will only have to set the bits of the pertinent SS lines. + wb_dat_i <= 32'h00; + end else begin + spi_ready <= 1'b1; + wb_dat_i <= 32'h00; + end + + // keep driving a write to the SLAVE SELECT Register until access is acknowledged. + LOAD_CS : + if (wb_ack_o) begin + spi_state <= LOAD_DATA; + wb_we_i <= 1'b0; + wb_cyc_i <= 1'b0; + end else begin + wb_we_i <= 1'b1; + wb_cyc_i <= 1'b1; + wb_adr_i <= SS_REG; // SS Register offset. + wb_dat_i <= set_ss_bit(spi_cs); // Assign single bit. + end + + // keep driving a write to the DATA TRANSMIT Register until access is acknowledged. + // This includes the combination of CMD+ADDR+DATA to be driven on the MOSI lines. + LOAD_DATA : + if (wb_ack_o) begin + spi_state <= SEND_TRANSACTION; + wb_we_i <= 1'b0; + wb_cyc_i <= 1'b0; + end else begin + wb_we_i <= 1'b1; + wb_cyc_i <= 1'b1; + wb_adr_i <= TX_DATA_REG; // Data Transmit register offset. + wb_dat_i <= { + 8'b0, + spi_rd, + spi_addr, + spi_data + }; + end + + // Per indication in the SPI_TOP documentation, we write the same configuration as before to the + // CONTROL register, with the addition of the GO bit. + SEND_TRANSACTION : + if (wb_ack_o) begin + spi_state <= WAIT_FOR_COMPLETION; + wb_we_i <= 1'b0; + wb_cyc_i <= 1'b0; + end else begin + wb_we_i <= 1'b1; + wb_cyc_i <= 1'b1; + wb_adr_i <= CONTROL_REG; + wb_dat_i <= `CONTROL_DATA(1'b1); //Write control register value with GO_BUSY set. + end + + // This state waits until SPI access is complete + WAIT_FOR_COMPLETION: + if (wb_int_o) begin + if (spi_rd) begin // If reading, do an extra step + spi_state <= RETRIEVE_DATA; + end else begin + spi_state <= IDLE; // If not reading, wait for next transaction + end + wb_we_i <= 1'b0; + wb_cyc_i <= 1'b0; + end else begin // Keep polling CONTROL register. + wb_we_i <= 1'b0; + wb_cyc_i <= 1'b0; + end + + RETRIEVE_DATA: + if (wb_ack_o) begin + spi_state <= IDLE; // as soon as data is available, record it and go back + spi_rd_data <= wb_dat_o[LO_SPI_RD_DATA_SIZE-1:0]; // to idle. + spi_data_valid <= 1'b1; + wb_we_i <= 1'b0; + wb_cyc_i <= 1'b0; + end else begin + wb_we_i <= 1'b0; // Drive bus access. + wb_cyc_i <= 1'b1; + wb_adr_i <= RX_DATA_REG; // DATA RETRIEVE Register offset + wb_dat_i <= {LO_SPI_WT_DATA_SIZE{1'b0}}; + end + + endcase + end + end + + spi_top spi_top_i ( + .wb_clk_i (ctrlport_clk), + .wb_rst_i (ctrlport_rst), + .wb_adr_i (wb_adr_i), + .wb_dat_i (wb_dat_i), + .wb_dat_o (wb_dat_o), + .wb_sel_i (4'hF), + .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_err_o (), + .wb_int_o (wb_int_o), + .ss_pad_o (ss_pad_o), + .sclk_pad_o (sclk), + .mosi_pad_o (mosi_pad_o), + .miso_pad_i (miso_pad_i)); + + reg mb_sync_reg = 1'b0; + + // align incoming signal to clock + always @(posedge ctrlport_clk) begin + mb_sync_reg <= mb_synth_sync; + end + + // Select between bypassing into input signal or registered pulse + assign tx0_lo1_sync = bypass_sync ? mb_sync_reg : lo_sync_reg[TX0_LO1]; + assign tx0_lo2_sync = bypass_sync ? mb_sync_reg : lo_sync_reg[TX0_LO2]; + assign tx1_lo1_sync = bypass_sync ? mb_sync_reg : lo_sync_reg[TX1_LO1]; + assign tx1_lo2_sync = bypass_sync ? mb_sync_reg : lo_sync_reg[TX1_LO2]; + assign rx0_lo1_sync = bypass_sync ? mb_sync_reg : lo_sync_reg[RX0_LO1]; + assign rx0_lo2_sync = bypass_sync ? mb_sync_reg : lo_sync_reg[RX0_LO2]; + assign rx1_lo1_sync = bypass_sync ? mb_sync_reg : lo_sync_reg[RX1_LO1]; + assign rx1_lo2_sync = bypass_sync ? mb_sync_reg : lo_sync_reg[RX1_LO2]; + +endmodule + +`default_nettype wire + +//XmlParse xml_on +//<regmap name="LO_CONTROL_REGMAP" readablestrobes="false" generatevhdl="true" ettusguidelines="true"> +// <group name="LO_SPI_REGISTERS"> +// <info> +// Controls the SPI transaction to the LMX2572 +// </info> +// <enumeratedtype name="LO_CHIP_SELECT"> +// <value name="TX0_LO1" integer="0"/> +// <value name="TX0_LO2" integer="1"/> +// <value name="TX1_LO1" integer="2"/> +// <value name="TX1_LO2" integer="3"/> +// <value name="RX0_LO1" integer="4"/> +// <value name="RX0_LO2" integer="5"/> +// <value name="RX1_LO1" integer="6"/> +// <value name="RX1_LO2" integer="7"/> +// </enumeratedtype> +// <register name="LO_SPI_SETUP" size="32" offset="0x00" attributes="Writable"> +// <info> +// This register sets up the SPI transaction to read/write to/from to the LMX2572. +// </info> +// <bitfield name="LO_SPI_START_TRANSACTION" range="28" initialvalue="0" attributes="Strobe"> +// <info> +// Strobe this bit high to start the SPI transaction with the bitfields below +// </info> +// </bitfield> +// <bitfield name="LO_SELECT" range="26..24" type="LO_CHIP_SELECT" initialvalue="TX0_LO1" attributes="Strobe"> +// <info> +// Sets the CS to the selected LO. The CS will assert until after @.LO_SPI_START_TRANSACTION has been asserted. +// </info> +// </bitfield> +// <bitfield name="LO_SPI_RD" range="23" initialvalue="0"> +// <info> +// Set this bit to '1' to read from the LMX2572. Set this bit to '0' to write to the LMX2572. +// </info> +// </bitfield> +// <bitfield name="LO_SPI_WT_ADDR" range="22..16" initialvalue="0"> +// <info> +// 7 bit address of the LMX2572 +// </info> +// </bitfield> +// <bitfield name="LO_SPI_WT_DATA" range="15..0" initialvalue="0"> +// <info> +// Write Data to the LMX2572 +// </info> +// </bitfield> +// </register> +// +// <register name="LO_SPI_STATUS" size="32" offset="0x00" attributes="Readable"> +// <info> +// This register returns the SPI master status, and also returns the read data from the LMX2572 +// </info> +// <bitfield name="LO_SPI_DATA_VALID" range="31" initialvalue="0"> +// <info> +// Returns '1' when a read SPI transaction is complete. This bit will remain high until a new SPI transaction has started. +// i.e. @.LO_SPI_START_TRANSACTION is strobed. Poll this when expecting data from a read transaction. +// </info> +// </bitfield> +// <bitfield name="LO_SPI_READY" range="30" initialvalue="0"> +// <info> +// If this bit returns '1' then LMX2572 is ready for transaction. If it returns '0' then it is busy with a previous SPI transaction. +// Poll this bit before starting a SPI transaction. +// </info> +// </bitfield> +// <bitfield name="LO_SELECT_STATUS" range="26..24" type="LO_CHIP_SELECT" initialvalue="TX0_LO1"> +// <info> +// Returns the current selected CS. This bitfield will return the value written to @.LO_SELECT bitfield in the @.LO_SPI_SETUP reg. +// </info> +// </bitfield> +// <bitfield name="LO_SPI_RD_ADDR" range="22..16" initialvalue="0"> +// <info> +// Returns the address of the current SPI address setup +// </info> +// </bitfield> +// <bitfield name="LO_SPI_RD_DATA" range="15..0" initialvalue="0"> +// <info> +// Returns the data of the SPI read. This bitfield will return 0x0000 until @.LO_SPI_DATA_VALID is true. This bit field will maintain it's +// read value until a new SPI transaction has started. i.e. @.LO_SPI_START_TRANSACTION is strobed. +// </info> +// </bitfield> +// </register> +// </group> +// <group name="LO_SYNC_REGS" offset="0x04"> +// <info> +// Contains registers that control the logic lines in charge of synchronization +// </info> +// <register name="LO_PULSE_SYNC" size="32" offset="0x00" attributes="Writable"> +// <info> +// Controls pulses driven to the SYNC pins of the LMX2572 chips +// </info> +// <bitfield name="PULSE_TX0_LO1_SYNC" range="0" initialvalue="0" attributes="Strobe"> +// <info> +// Creates a single cycle pulse on the TX0_LO1_SYNC line. +// </info> +// </bitfield> +// <bitfield name="PULSE_TX0_LO2_SYNC" range="1" initialvalue="0" attributes="Strobe"> +// <info> +// Creates a single cycle pulse on the TX0_LO2_SYNC line. +// </info> +// </bitfield> +// <bitfield name="PULSE_TX1_LO1_SYNC" range="2" initialvalue="0" attributes="Strobe"> +// <info> +// Creates a single cycle pulse on the TX1_LO1_SYNC line. +// </info> +// </bitfield> +// <bitfield name="PULSE_TX1_LO2_SYNC" range="3" initialvalue="0" attributes="Strobe"> +// <info> +// Creates a single cycle pulse on the TX1_LO2_SYNC line. +// </info> +// </bitfield> +// <bitfield name="PULSE_RX0_LO1_SYNC" range="4" initialvalue="0" attributes="Strobe"> +// <info> +// Creates a single cycle pulse on the RX0_LO1_SYNC line. +// </info> +// </bitfield> +// <bitfield name="PULSE_RX0_LO2_SYNC" range="5" initialvalue="0" attributes="Strobe"> +// <info> +// Creates a single cycle pulse on the RX0_LO2_SYNC line. +// </info> +// </bitfield> +// <bitfield name="PULSE_RX1_LO1_SYNC" range="6" initialvalue="0" attributes="Strobe"> +// <info> +// Creates a single cycle pulse on the RX1_LO1_SYNC line. +// </info> +// </bitfield> +// <bitfield name="PULSE_RX1_LO2_SYNC" range="7" initialvalue="0" attributes="Strobe"> +// <info> +// Creates a single cycle pulse on the RX1_LO2_SYNC line. +// </info> +// </bitfield> +// <bitfield name="BYPASS_SYNC_REGISTER" range="8" initialvalue="0"> +// <info> +// Setting this bit to '1' will ignore writes to the PULSE_X_SYNC fields and allow +// a buffered input SYNC pulse to be driven out instead. +// </info> +// </bitfield> +// </register> +// </group> +//</regmap> +//XmlParse xml_off diff --git a/fpga/usrp3/top/x400/dboards/zbx/cpld/register_endpoints/memory_init_files/.gitignore b/fpga/usrp3/top/x400/dboards/zbx/cpld/register_endpoints/memory_init_files/.gitignore new file mode 100644 index 000000000..3eee46e45 --- /dev/null +++ b/fpga/usrp3/top/x400/dboards/zbx/cpld/register_endpoints/memory_init_files/.gitignore @@ -0,0 +1,2 @@ +zbx_cpld_regs_t.py +*.hex diff --git a/fpga/usrp3/top/x400/dboards/zbx/cpld/register_endpoints/memory_init_files/gen_defaults.py b/fpga/usrp3/top/x400/dboards/zbx/cpld/register_endpoints/memory_init_files/gen_defaults.py new file mode 100644 index 000000000..35e1e74bd --- /dev/null +++ b/fpga/usrp3/top/x400/dboards/zbx/cpld/register_endpoints/memory_init_files/gen_defaults.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python3 +# +# Copyright 2021 Ettus Research, a National Instruments Brand +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +""" +Helper script to generate memory init files for the ZBX CPLD. +""" + +import os +import pathlib + +# This is generated by running +# $ python3 /path/to/gen_zbx_cpld_regs.py zbx_cpld_regs_t.py +import zbx_cpld_regs_t + +def main(): + """ + Main function + """ + cur_dir = str(pathlib.Path(__file__).resolve().parent) + + zbx_regs = zbx_cpld_regs_t.zbx_cpld_regs_t() + + # The file dsa_control.v lists default values for documentation purposes. When + # changing these values, make sure to also update the 'initialvalue' documentation + # attributes in dsa_control.v + zbx_regs.TX0_DSA1[0] = 31 + zbx_regs.TX0_DSA2[0] = 31 + + zbx_regs.RX0_DSA1[0] = 15 + zbx_regs.RX0_DSA2[0] = 15 + zbx_regs.RX0_DSA3_A[0] = 15 + zbx_regs.RX0_DSA3_B[0] = 15 + + # Path control defaults + with open(os.path.join(cur_dir, "tx0_path_defaults.hex"), "w") as outfile: + outfile.write("\n".join([ + "{:08X}".format(zbx_regs.get_reg(zbx_regs.get_addr('TX0_IF2_1_2'))), + ] * len(zbx_regs.TX0_IF2_1_2))) + with open(os.path.join(cur_dir, "tx1_path_defaults.hex"), "w") as outfile: + outfile.write("\n".join([ + "{:08X}".format(zbx_regs.get_reg(zbx_regs.get_addr('TX1_IF2_1_2'))), + ] * len(zbx_regs.TX1_IF2_1_2))) + with open(os.path.join(cur_dir, "rx0_path_defaults.hex"), "w") as outfile: + outfile.write("\n".join([ + "{:08X}".format(zbx_regs.get_reg(zbx_regs.get_addr('RX0_ANT_1'))), + ] * len(zbx_regs.RX0_ANT_1))) + with open(os.path.join(cur_dir, "rx1_path_defaults.hex"), "w") as outfile: + outfile.write("\n".join([ + "{:08X}".format(zbx_regs.get_reg(zbx_regs.get_addr('RX1_ANT_1'))), + ] * len(zbx_regs.RX1_ANT_1))) + # DSA defaults + with open(os.path.join(cur_dir, "tx_dsa_defaults.hex"), "w") as outfile: + outfile.write("\n".join([ + "{:08X}".format(zbx_regs.get_reg(zbx_regs.get_addr('TX0_DSA1'))), + ] * len(zbx_regs.TX0_DSA1))) + with open(os.path.join(cur_dir, "rx_dsa_defaults.hex"), "w") as outfile: + outfile.write("\n".join([ + "{:08X}".format(zbx_regs.get_reg(zbx_regs.get_addr('RX0_DSA1'))), + ] * len(zbx_regs.RX0_DSA1))) + +if __name__ == "__main__": + main() diff --git a/fpga/usrp3/top/x400/dboards/zbx/cpld/register_endpoints/power_regs.v b/fpga/usrp3/top/x400/dboards/zbx/cpld/register_endpoints/power_regs.v new file mode 100644 index 000000000..f5fb6b81e --- /dev/null +++ b/fpga/usrp3/top/x400/dboards/zbx/cpld/register_endpoints/power_regs.v @@ -0,0 +1,211 @@ +// +// Copyright 2021 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: power_regs +// +// Description: +// Registers to control the power supplies and the PLL ref clock buffer. +// + +`default_nettype none + +module power_regs #( + parameter [19:0] BASE_ADDRESS = 0, + parameter [19:0] SIZE_ADDRESS = 0 +) ( + // 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, + + //reg clk domain + input wire ctrlport_clk, + input wire ctrlport_rst, + + //Power Control + output wire enable_tx_7v0, + output wire enable_rx_7v0, + output wire enable_3v3, + + //Power Good Indicators + input wire p7v_pg_b, + input wire p7v_pg_a, + + //PRC buffer + output reg pll_ref_clk_enable = 1'b0 +); + + `include "../regmap/power_regs_regmap_utils.vh" + `include "../../../../../../lib/rfnoc/core/ctrlport.vh" + + //---------------------------------------------------------- + // Internal registers + //---------------------------------------------------------- + reg enable_3v3_reg = {ENABLE_3V3_SIZE {1'b0}}; + reg enable_rx_7v0_reg = {ENABLE_RX_7V0_SIZE {1'b0}}; + reg enable_tx_7v0_reg = {ENABLE_TX_7V0_SIZE {1'b0}}; + + //---------------------------------------------------------- + // Handling of CtrlPort + //---------------------------------------------------------- + wire address_in_range = (s_ctrlport_req_addr >= BASE_ADDRESS) && (s_ctrlport_req_addr < BASE_ADDRESS + SIZE_ADDRESS); + + always @(posedge ctrlport_clk) begin + // reset internal registers and responses + if (ctrlport_rst) begin + s_ctrlport_resp_ack <= 1'b0; + s_ctrlport_resp_data <= {32{1'bx}}; + s_ctrlport_resp_status <= CTRL_STS_OKAY; + + enable_3v3_reg <= {ENABLE_3V3_SIZE {1'b0}}; + enable_rx_7v0_reg <= {ENABLE_RX_7V0_SIZE {1'b0}}; + enable_tx_7v0_reg <= {ENABLE_TX_7V0_SIZE {1'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 + RF_POWER_CONTROL: begin + enable_3v3_reg <= s_ctrlport_req_data[ENABLE_3V3]; + enable_rx_7v0_reg <= s_ctrlport_req_data[ENABLE_RX_7V0]; + enable_tx_7v0_reg <= s_ctrlport_req_data[ENABLE_TX_7V0]; + end + + BASE_ADDRESS + PRC_CONTROL: begin + pll_ref_clk_enable <= s_ctrlport_req_data[PLL_REF_CLOCK_ENABLE]; + 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 + + // read requests + 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 + RF_POWER_CONTROL: begin + s_ctrlport_resp_data[ENABLE_3V3] <= enable_3v3_reg; + s_ctrlport_resp_data[ENABLE_RX_7V0] <= enable_rx_7v0_reg; + s_ctrlport_resp_data[ENABLE_TX_7V0] <= enable_tx_7v0_reg; + end + + BASE_ADDRESS + RF_POWER_STATUS: begin + s_ctrlport_resp_data[P7V_A_STATUS] <= p7v_pg_a; + s_ctrlport_resp_data[P7V_B_STATUS] <= p7v_pg_b; + end + + BASE_ADDRESS + PRC_CONTROL: begin + s_ctrlport_resp_data[PLL_REF_CLOCK_ENABLE] <= pll_ref_clk_enable; + end + + // error on undefined address + default: begin + s_ctrlport_resp_data <= {32{1'b0}}; + 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 + + assign enable_tx_7v0 = enable_tx_7v0_reg; + assign enable_rx_7v0 = enable_rx_7v0_reg; + assign enable_3v3 = enable_3v3_reg; + +endmodule + +`default_nettype wire + +//XmlParse xml_on +//<regmap name="POWER_REGS_REGMAP" generatevhdl="true" ettusguidelines="true"> +// <group name="POWER_REGS_REGISTERS" size="0x010"> +// <info> +// This regmap contains the registers to control the power supplies and the clock buffer for PLL reference clock. +// </info> +// <register name="RF_POWER_CONTROL" size="32" offset="0x00" attributes="Readable|Writable"> +// <info> +// This register controls power supply enables to the Tx/Rx amps, switch control, and clk buffers. During normal +// operations, all three power supplies should be enabled. +// </info> +// <bitfield name="ENABLE_3v3" range="2" initialvalue="0"> +// <info> +// This power supply sources the switch control, and the clock buffers. By default this power supply is off. +// The internal LOs will not work unless this bit is enabled.{BR/} +// </info> +// </bitfield> +// <bitfield name="ENABLE_RX_7V0" range="1" initialvalue="0"> +// <info> +// This power supply sources the Rx0 and Rx1 amps. By default this power supply is off.The Rx0/1 path will not +// be active unless this power supply is enabled. Disabling this bit is similar to RX RF blanking{BR/} +// {font color="red"}note to digital engineer, this is Pos7v0B{/font} +// </info> +// </bitfield> +// <bitfield name="ENABLE_TX_7V0" range="0" initialvalue="0"> +// <info> +// This power supply sources the Tx0 and Tx1 amps. By default this power supply is off. The Tx0/1 path will not +// be active unless this power supply is enabled. Disabling this bit is similar to TX RF blanking{BR/} +// {font color="red"}note to digital engineer, this is Pos7v0A{/font} +// </info> +// </bitfield> +// </register> +// <register name="RF_POWER_STATUS" size="32" offset="0x04" attributes="Readable"> +// <info> +// Returns status of PowerGood indicators across the daughterboard. +// </info> +// <bitfield name="P7V_A_STATUS" range="0"> +// <info> +// Returns status of 7V switching regulator A.{BR/} +// </info> +// </bitfield> +// <bitfield name="P7V_B_STATUS" range="1"> +// <info> +// Returns status of 7V switching regulator B.{BR/} +// </info> +// </bitfield> +// </register> +// <register name="PRC_CONTROL" size="32" offset="0x08" attributes="Readable|Writable"> +// <info> +// Offers ability to enable or disable the PLL reference clock. +// </info> +// <bitfield name="PLL_REF_CLOCK_ENABLE" range="0" initialvalue="0"> +// <info>If set PLL reference clock is enabled.</info> +// </bitfield> +// </register> +// </group> +//</regmap> +//XmlParse xml_off diff --git a/fpga/usrp3/top/x400/dboards/zbx/cpld/register_endpoints/switch_control.v b/fpga/usrp3/top/x400/dboards/zbx/cpld/register_endpoints/switch_control.v new file mode 100644 index 000000000..63ce251b3 --- /dev/null +++ b/fpga/usrp3/top/x400/dboards/zbx/cpld/register_endpoints/switch_control.v @@ -0,0 +1,918 @@ +// +// Copyright 2021 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: switch_control +// +// Description: +// Implements control over RF switches via CtrlPort. Uses RAM to store multiple +// ATR configurations. +// + +`default_nettype none + +module switch_control #( + parameter [19:0] BASE_ADDRESS = 0, + parameter [19:0] SIZE_ADDRESS = 0 +) ( + // 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 = 2'b0, + output reg [31:0] s_ctrlport_resp_data = 32'b0, + + // ATR switching + input wire [ 7:0] atr_config_rf0, + input wire [ 7:0] atr_config_rf1, + + //Tx0 Switch control (domain: ctrl_reg_clk) + output wire tx0_sw1_sw2_ctrl, + output wire tx0_sw3_a, + output wire tx0_sw3_b, + output wire tx0_sw4_a, + output wire tx0_sw4_b, + output wire tx0_sw5_a, + output wire tx0_sw5_b, + output wire tx0_sw6_a, + output wire tx0_sw6_b, + output wire tx0_sw7_a, + output wire tx0_sw7_b, + output wire tx0_sw8_v1, + output wire tx0_sw8_v2, + output wire tx0_sw8_v3, + output wire tx0_sw9_a, + output wire tx0_sw9_b, + output wire tx0_sw10_a, + output wire tx0_sw10_b, + output wire tx0_sw11_a, + output wire tx0_sw11_b, + output wire tx0_sw13_v1, + output wire tx0_sw14_v1, + + //Tx1 Switch control (domain: ctrl_reg_clk) + output wire tx1_sw1_sw2_ctrl, + output wire tx1_sw3_a, + output wire tx1_sw3_b, + output wire tx1_sw4_a, + output wire tx1_sw4_b, + output wire tx1_sw5_a, + output wire tx1_sw5_b, + output wire tx1_sw6_a, + output wire tx1_sw6_b, + output wire tx1_sw7_a, + output wire tx1_sw7_b, + output wire tx1_sw8_v1, + output wire tx1_sw8_v2, + output wire tx1_sw8_v3, + output wire tx1_sw9_a, + output wire tx1_sw9_b, + output wire tx1_sw10_a, + output wire tx1_sw10_b, + output wire tx1_sw11_a, + output wire tx1_sw11_b, + output wire tx1_sw13_v1, + output wire tx1_sw14_v1, + + //Rx0 Switch control (domain: ctrl_reg_clk) + output wire rx0_sw1_a, + output wire rx0_sw1_b, + output wire rx0_sw2_a, + output wire rx0_sw3_v1, + output wire rx0_sw3_v2, + output wire rx0_sw3_v3, + output wire rx0_sw4_a, + output wire rx0_sw5_a, + output wire rx0_sw5_b, + output wire rx0_sw6_a, + output wire rx0_sw6_b, + output wire rx0_sw7_sw8_ctrl, + output wire rx0_sw9_v1, + output wire rx0_sw10_v1, + output wire rx0_sw11_v3, + output wire rx0_sw11_v2, + output wire rx0_sw11_v1, + + //Rx1 Switch control (domain: ctrl_reg_clk) + output wire rx1_sw1_a, + output wire rx1_sw1_b, + output wire rx1_sw2_a, + output wire rx1_sw3_v1, + output wire rx1_sw3_v2, + output wire rx1_sw3_v3, + output wire rx1_sw4_a, + output wire rx1_sw5_a, + output wire rx1_sw5_b, + output wire rx1_sw6_a, + output wire rx1_sw6_b, + output wire rx1_sw7_sw8_ctrl, + output wire rx1_sw9_v1, + output wire rx1_sw10_v1, + output wire rx1_sw11_v3, + output wire rx1_sw11_v2, + output wire rx1_sw11_v1 +); + + `include "../regmap/switch_setup_regmap_utils.vh" + `include "../../../../../../lib/rfnoc/core/ctrlport.vh" + + //--------------------------------------------------------------- + // register bitfields + //--------------------------------------------------------------- + //Tx0PathControl Register + reg [ TX_SWITCH_1_2_SIZE-1:0] tx0_switch_1_2_reg; + reg [ TX_SWITCH_3_SIZE-1:0] tx0_switch_3_reg; + reg [ TX_SWITCH_4_SIZE-1:0] tx0_switch_4_reg; + reg [ TX_SWITCH_5_SIZE-1:0] tx0_switch_5_reg; + reg [ TX_SWITCH_6_SIZE-1:0] tx0_switch_6_reg; + reg [ TX_SWITCH_7_SIZE-1:0] tx0_switch_7_reg; + reg [ TX_SWITCH_8_SIZE-1:0] tx0_switch_8_reg; + reg [ TX_SWITCH_9_SIZE-1:0] tx0_switch_9_reg; + reg [ TX_SWITCH_10_SIZE-1:0] tx0_switch_10_reg; + reg [ TX_SWITCH_11_SIZE-1:0] tx0_switch_11_reg; + reg [ TX_SWITCH_13_SIZE-1:0] tx0_switch_13_reg; + reg [ TX_SWITCH_14_SIZE-1:0] tx0_switch_14_reg; + + //Tx1PathControl Register + reg [ TX_SWITCH_1_2_SIZE-1:0] tx1_switch_1_2_reg; + reg [ TX_SWITCH_3_SIZE-1:0] tx1_switch_3_reg; + reg [ TX_SWITCH_4_SIZE-1:0] tx1_switch_4_reg; + reg [ TX_SWITCH_5_SIZE-1:0] tx1_switch_5_reg; + reg [ TX_SWITCH_6_SIZE-1:0] tx1_switch_6_reg; + reg [ TX_SWITCH_7_SIZE-1:0] tx1_switch_7_reg; + reg [ TX_SWITCH_8_SIZE-1:0] tx1_switch_8_reg; + reg [ TX_SWITCH_9_SIZE-1:0] tx1_switch_9_reg; + reg [ TX_SWITCH_10_SIZE-1:0] tx1_switch_10_reg; + reg [ TX_SWITCH_11_SIZE-1:0] tx1_switch_11_reg; + reg [ TX_SWITCH_13_SIZE-1:0] tx1_switch_13_reg; + reg [ TX_SWITCH_14_SIZE-1:0] tx1_switch_14_reg; + + //Rx0PathControl Register + reg [ RX_SWITCH_1_SIZE-1:0] rx0_switch_1_reg; + reg [ RX_SWITCH_2_SIZE-1:0] rx0_switch_2_reg; + reg [ RX_SWITCH_3_SIZE-1:0] rx0_switch_3_reg; + reg [ RX_SWITCH_4_SIZE-1:0] rx0_switch_4_reg; + reg [ RX_SWITCH_5_SIZE-1:0] rx0_switch_5_reg; + reg [ RX_SWITCH_6_SIZE-1:0] rx0_switch_6_reg; + reg [ RX_SWITCH_7_8_SIZE-1:0] rx0_switch_7_8_reg; + reg [ RX_SWITCH_9_SIZE-1:0] rx0_switch_9_reg; + reg [ RX_SWITCH_10_SIZE-1:0] rx0_switch_10_reg; + reg [ RX_SWITCH_11_SIZE-1:0] rx0_switch_11_reg; + + //Rx1PathControl Register + reg [ RX_SWITCH_1_SIZE-1:0] rx1_switch_1_reg; + reg [ RX_SWITCH_2_SIZE-1:0] rx1_switch_2_reg; + reg [ RX_SWITCH_3_SIZE-1:0] rx1_switch_3_reg; + reg [ RX_SWITCH_4_SIZE-1:0] rx1_switch_4_reg; + reg [ RX_SWITCH_5_SIZE-1:0] rx1_switch_5_reg; + reg [ RX_SWITCH_6_SIZE-1:0] rx1_switch_6_reg; + reg [ RX_SWITCH_7_8_SIZE-1:0] rx1_switch_7_8_reg; + reg [ RX_SWITCH_9_SIZE-1:0] rx1_switch_9_reg; + reg [ RX_SWITCH_10_SIZE-1:0] rx1_switch_10_reg; + reg [ RX_SWITCH_11_SIZE-1:0] rx1_switch_11_reg; + + //--------------------------------------------------------------- + // ATR memory signals + //--------------------------------------------------------------- + reg ram_rx0_wea; + wire [31:0] ram_rx0_doa; + wire [31:0] ram_rx0_dob; + + reg ram_rx1_wea; + wire [31:0] ram_rx1_doa; + wire [31:0] ram_rx1_dob; + + reg ram_tx0_wea; + wire [31:0] ram_tx0_doa; + wire [31:0] ram_tx0_dob; + + reg ram_tx1_wea; + wire [31:0] ram_tx1_doa; + wire [31:0] ram_tx1_dob; + + + //--------------------------------------------------------------- + // 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 + SIZE_ADDRESS); + // 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]}; + // Extract masked out bits from the address, which represent the register + // array index = ATR configuration index + wire [ 7:0] register_index = s_ctrlport_req_addr[9:2]; + + always @(posedge ctrlport_clk) begin + // reset internal registers and responses + if (ctrlport_rst) begin + s_ctrlport_resp_ack <= 1'b0; + + read_req_shift_reg <= 2'b0; + + ram_tx0_wea <= 1'b0; + ram_tx1_wea <= 1'b0; + ram_rx0_wea <= 1'b0; + ram_rx1_wea <= 1'b0; + + end else begin + // default assignments + read_req_shift_reg <= {read_req_shift_reg[0], s_ctrlport_req_rd}; + + ram_tx0_wea <= 1'b0; + ram_tx1_wea <= 1'b0; + ram_rx0_wea <= 1'b0; + ram_rx1_wea <= 1'b0; + + // 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 (register_base_address) + BASE_ADDRESS + TX0_PATH_CONTROL(0): begin + ram_tx0_wea <= 1'b1; + end + + BASE_ADDRESS + TX1_PATH_CONTROL(0): begin + ram_tx1_wea <= 1'b1; + end + + BASE_ADDRESS + RX0_PATH_CONTROL(0): begin + ram_rx0_wea <= 1'b1; + end + + BASE_ADDRESS + RX1_PATH_CONTROL(0): begin + ram_rx1_wea <= 1'b1; + 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 + + // Answer read requests delayed by 2 clock cycles. This compensated for + // register ram_addr and the memory internal address register to make sure + // ram_ch0_doa is up to date when generating the response. + end else if (read_req_shift_reg[1]) 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 (register_base_address) + BASE_ADDRESS + TX0_PATH_CONTROL(0): begin + s_ctrlport_resp_data <= ram_tx0_doa & TX_PATH_CONTROL_MASK; + end + BASE_ADDRESS + TX1_PATH_CONTROL(0): begin + s_ctrlport_resp_data <= ram_tx1_doa & TX_PATH_CONTROL_MASK; + end + BASE_ADDRESS + RX0_PATH_CONTROL(0): begin + s_ctrlport_resp_data <= ram_rx0_doa & RX_PATH_CONTROL_MASK; + end + BASE_ADDRESS + RX1_PATH_CONTROL(0): begin + s_ctrlport_resp_data <= ram_rx1_doa & RX_PATH_CONTROL_MASK; + end + + 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 + + // register without reset + reg [ 7:0] ram_addr = 8'b0; + reg [31:0] ram_datain = 32'b0; + always @(posedge ctrlport_clk) begin + // memories + ram_addr <= register_index; + ram_datain <= s_ctrlport_req_data; + + // outputs + tx0_switch_1_2_reg <= ram_tx0_dob[TX_SWITCH_1_2]; + tx0_switch_3_reg <= ram_tx0_dob[TX_SWITCH_3_MSB : TX_SWITCH_3]; + tx0_switch_4_reg <= ram_tx0_dob[TX_SWITCH_4_MSB : TX_SWITCH_4]; + tx0_switch_5_reg <= ram_tx0_dob[TX_SWITCH_5_MSB : TX_SWITCH_5]; + tx0_switch_6_reg <= ram_tx0_dob[TX_SWITCH_6_MSB : TX_SWITCH_6]; + tx0_switch_7_reg <= ram_tx0_dob[TX_SWITCH_7_MSB : TX_SWITCH_7]; + tx0_switch_8_reg <= ram_tx0_dob[TX_SWITCH_8_MSB : TX_SWITCH_8]; + tx0_switch_9_reg <= ram_tx0_dob[TX_SWITCH_9_MSB : TX_SWITCH_9]; + tx0_switch_10_reg <= ram_tx0_dob[TX_SWITCH_10_MSB : TX_SWITCH_10]; + tx0_switch_11_reg <= ram_tx0_dob[TX_SWITCH_11_MSB : TX_SWITCH_11]; + tx0_switch_13_reg <= ram_tx0_dob[TX_SWITCH_13]; + tx0_switch_14_reg <= ram_tx0_dob[TX_SWITCH_14]; + + tx1_switch_1_2_reg <= ram_tx1_dob[TX_SWITCH_1_2]; + tx1_switch_3_reg <= ram_tx1_dob[TX_SWITCH_3_MSB : TX_SWITCH_3]; + tx1_switch_4_reg <= ram_tx1_dob[TX_SWITCH_4_MSB : TX_SWITCH_4]; + tx1_switch_5_reg <= ram_tx1_dob[TX_SWITCH_5_MSB : TX_SWITCH_5]; + tx1_switch_6_reg <= ram_tx1_dob[TX_SWITCH_6_MSB : TX_SWITCH_6]; + tx1_switch_7_reg <= ram_tx1_dob[TX_SWITCH_7_MSB : TX_SWITCH_7]; + tx1_switch_8_reg <= ram_tx1_dob[TX_SWITCH_8_MSB : TX_SWITCH_8]; + tx1_switch_9_reg <= ram_tx1_dob[TX_SWITCH_9_MSB : TX_SWITCH_9]; + tx1_switch_10_reg <= ram_tx1_dob[TX_SWITCH_10_MSB : TX_SWITCH_10]; + tx1_switch_11_reg <= ram_tx1_dob[TX_SWITCH_11_MSB : TX_SWITCH_11]; + tx1_switch_13_reg <= ram_tx1_dob[TX_SWITCH_13]; + tx1_switch_14_reg <= ram_tx1_dob[TX_SWITCH_14]; + + rx0_switch_1_reg <= ram_rx0_dob[RX_SWITCH_1_MSB : RX_SWITCH_1]; + rx0_switch_2_reg <= ram_rx0_dob[RX_SWITCH_2]; + rx0_switch_3_reg <= ram_rx0_dob[RX_SWITCH_3_MSB : RX_SWITCH_3]; + rx0_switch_4_reg <= ram_rx0_dob[RX_SWITCH_4]; + rx0_switch_5_reg <= ram_rx0_dob[RX_SWITCH_5_MSB : RX_SWITCH_5]; + rx0_switch_6_reg <= ram_rx0_dob[RX_SWITCH_6_MSB : RX_SWITCH_6]; + rx0_switch_7_8_reg <= ram_rx0_dob[RX_SWITCH_7_8]; + rx0_switch_9_reg <= ram_rx0_dob[RX_SWITCH_9]; + rx0_switch_10_reg <= ram_rx0_dob[RX_SWITCH_10]; + rx0_switch_11_reg <= ram_rx0_dob[RX_SWITCH_11_MSB: RX_SWITCH_11]; + + rx1_switch_1_reg <= ram_rx1_dob[RX_SWITCH_1_MSB : RX_SWITCH_1]; + rx1_switch_2_reg <= ram_rx1_dob[RX_SWITCH_2]; + rx1_switch_3_reg <= ram_rx1_dob[RX_SWITCH_3_MSB : RX_SWITCH_3]; + rx1_switch_4_reg <= ram_rx1_dob[RX_SWITCH_4]; + rx1_switch_5_reg <= ram_rx1_dob[RX_SWITCH_5_MSB : RX_SWITCH_5]; + rx1_switch_6_reg <= ram_rx1_dob[RX_SWITCH_6_MSB : RX_SWITCH_6]; + rx1_switch_7_8_reg <= ram_rx1_dob[RX_SWITCH_7_8]; + rx1_switch_9_reg <= ram_rx1_dob[RX_SWITCH_9]; + rx1_switch_10_reg <= ram_rx1_dob[RX_SWITCH_10]; + rx1_switch_11_reg <= ram_rx1_dob[RX_SWITCH_11_MSB: RX_SWITCH_11]; + end + + ram_2port #( + .DWIDTH (32), + .AWIDTH (8), + .RW_MODE ("READ-FIRST"), + .RAM_TYPE ("AUTOMATIC"), + .OUT_REG (0), + .INIT_FILE ("register_endpoints/memory_init_files/tx0_path_defaults.hex") + ) ram_tx0_i ( + .clka (ctrlport_clk), + .ena (1'b1), + .wea (ram_tx0_wea), + .addra (ram_addr), + .dia (ram_datain), + .doa (ram_tx0_doa), + .clkb (ctrlport_clk), + .enb (1'b1), + .web (1'b0), + .addrb (atr_config_rf0), + .dib (0), + .dob (ram_tx0_dob)); + + ram_2port #( + .DWIDTH (32), + .AWIDTH (8), + .RW_MODE ("READ-FIRST"), + .RAM_TYPE ("AUTOMATIC"), + .OUT_REG (0), + .INIT_FILE ("register_endpoints/memory_init_files/tx1_path_defaults.hex") + ) ram_tx1_i ( + .clka (ctrlport_clk), + .ena (1'b1), + .wea (ram_tx1_wea), + .addra (ram_addr), + .dia (ram_datain), + .doa (ram_tx1_doa), + .clkb (ctrlport_clk), + .enb (1'b1), + .web (1'b0), + .addrb (atr_config_rf1), + .dib (0), + .dob (ram_tx1_dob)); + + ram_2port #( + .DWIDTH (32), + .AWIDTH (8), + .RW_MODE ("READ-FIRST"), + .RAM_TYPE ("AUTOMATIC"), + .OUT_REG (0), + .INIT_FILE ("register_endpoints/memory_init_files/rx0_path_defaults.hex") + ) ram_rx0_i ( + .clka (ctrlport_clk), + .ena (1'b1), + .wea (ram_rx0_wea), + .addra (ram_addr), + .dia (ram_datain), + .doa (ram_rx0_doa), + .clkb (ctrlport_clk), + .enb (1'b1), + .web (1'b0), + .addrb (atr_config_rf0), + .dib (0), + .dob (ram_rx0_dob)); + + ram_2port #( + .DWIDTH (32), + .AWIDTH (8), + .RW_MODE ("READ-FIRST"), + .RAM_TYPE ("AUTOMATIC"), + .OUT_REG (0), + .INIT_FILE ("register_endpoints/memory_init_files/rx1_path_defaults.hex") + ) ram_rx1_i ( + .clka (ctrlport_clk), + .ena (1'b1), + .wea (ram_rx1_wea), + .addra (ram_addr), + .dia (ram_datain), + .doa (ram_rx1_doa), + .clkb (ctrlport_clk), + .enb (1'b1), + .web (1'b0), + .addrb (atr_config_rf1), + .dib (0), + .dob (ram_rx1_dob)); + + assign tx0_sw1_sw2_ctrl = tx0_switch_1_2_reg; + assign tx0_sw3_a = tx0_switch_3_reg[0]; + assign tx0_sw3_b = tx0_switch_3_reg[1]; + assign tx0_sw4_a = tx0_switch_4_reg[0]; + assign tx0_sw4_b = tx0_switch_4_reg[1]; + assign tx0_sw5_a = tx0_switch_5_reg[0]; + assign tx0_sw5_b = tx0_switch_5_reg[1]; + assign tx0_sw6_a = tx0_switch_6_reg[0]; + assign tx0_sw6_b = tx0_switch_6_reg[1]; + assign tx0_sw7_a = tx0_switch_7_reg[0]; + assign tx0_sw7_b = tx0_switch_7_reg[1]; + assign tx0_sw8_v1 = tx0_switch_8_reg[0]; + assign tx0_sw8_v2 = tx0_switch_8_reg[1]; + assign tx0_sw8_v3 = tx0_switch_8_reg[2]; + assign tx0_sw9_a = tx0_switch_9_reg[0]; + assign tx0_sw9_b = tx0_switch_9_reg[1]; + assign tx0_sw10_a = tx0_switch_10_reg[0]; + assign tx0_sw10_b = tx0_switch_10_reg[1]; + assign tx0_sw11_a = tx0_switch_11_reg[0]; + assign tx0_sw11_b = tx0_switch_11_reg[1]; + assign tx0_sw13_v1 = tx0_switch_13_reg; + assign tx0_sw14_v1 = tx0_switch_14_reg; + + assign tx1_sw1_sw2_ctrl = tx1_switch_1_2_reg; + assign tx1_sw3_a = tx1_switch_3_reg[0]; + assign tx1_sw3_b = tx1_switch_3_reg[1]; + assign tx1_sw4_a = tx1_switch_4_reg[0]; + assign tx1_sw4_b = tx1_switch_4_reg[1]; + assign tx1_sw5_a = tx1_switch_5_reg[0]; + assign tx1_sw5_b = tx1_switch_5_reg[1]; + assign tx1_sw6_a = tx1_switch_6_reg[0]; + assign tx1_sw6_b = tx1_switch_6_reg[1]; + assign tx1_sw7_a = tx1_switch_7_reg[0]; + assign tx1_sw7_b = tx1_switch_7_reg[1]; + assign tx1_sw8_v1 = tx1_switch_8_reg[0]; + assign tx1_sw8_v2 = tx1_switch_8_reg[1]; + assign tx1_sw8_v3 = tx1_switch_8_reg[2]; + assign tx1_sw9_a = tx1_switch_9_reg[0]; + assign tx1_sw9_b = tx1_switch_9_reg[1]; + assign tx1_sw10_a = tx1_switch_10_reg[0]; + assign tx1_sw10_b = tx1_switch_10_reg[1]; + assign tx1_sw11_a = tx1_switch_11_reg[0]; + assign tx1_sw11_b = tx1_switch_11_reg[1]; + assign tx1_sw13_v1 = tx1_switch_13_reg; + assign tx1_sw14_v1 = tx1_switch_14_reg; + + assign rx0_sw1_a = rx0_switch_1_reg[0]; + assign rx0_sw1_b = rx0_switch_1_reg[1]; + assign rx0_sw2_a = rx0_switch_2_reg; + assign rx0_sw3_v1 = rx0_switch_3_reg[0]; + assign rx0_sw3_v2 = rx0_switch_3_reg[1]; + assign rx0_sw3_v3 = rx0_switch_3_reg[2]; + assign rx0_sw4_a = rx0_switch_4_reg; + assign rx0_sw5_a = rx0_switch_5_reg[0]; + assign rx0_sw5_b = rx0_switch_5_reg[1]; + assign rx0_sw6_a = rx0_switch_6_reg[0]; + assign rx0_sw6_b = rx0_switch_6_reg[1]; + assign rx0_sw7_sw8_ctrl = rx0_switch_7_8_reg; + assign rx0_sw9_v1 = rx0_switch_9_reg; + assign rx0_sw10_v1 = rx0_switch_10_reg; + assign rx0_sw11_v1 = rx0_switch_11_reg[0]; + assign rx0_sw11_v2 = rx0_switch_11_reg[1]; + assign rx0_sw11_v3 = rx0_switch_11_reg[2]; + + assign rx1_sw1_a = rx1_switch_1_reg[0]; + assign rx1_sw1_b = rx1_switch_1_reg[1]; + assign rx1_sw2_a = rx1_switch_2_reg; + assign rx1_sw3_v1 = rx1_switch_3_reg[0]; + assign rx1_sw3_v2 = rx1_switch_3_reg[1]; + assign rx1_sw3_v3 = rx1_switch_3_reg[2]; + assign rx1_sw4_a = rx1_switch_4_reg; + assign rx1_sw5_a = rx1_switch_5_reg[0]; + assign rx1_sw5_b = rx1_switch_5_reg[1]; + assign rx1_sw6_a = rx1_switch_6_reg[0]; + assign rx1_sw6_b = rx1_switch_6_reg[1]; + assign rx1_sw7_sw8_ctrl = rx1_switch_7_8_reg; + assign rx1_sw9_v1 = rx1_switch_9_reg; + assign rx1_sw10_v1 = rx1_switch_10_reg; + assign rx1_sw11_v1 = rx1_switch_11_reg[0]; + assign rx1_sw11_v2 = rx1_switch_11_reg[1]; + assign rx1_sw11_v3 = rx1_switch_11_reg[2]; + +endmodule + +`default_nettype wire + +//XmlParse xml_on +//<regmap name="SWITCH_SETUP_REGMAP" readablestrobes="false" generatevhdl="true" ettusguidelines="true"> +// <group name="SWITCH_SETUP_REGISTERS"> +// <info> +// The following registers are used to control the path that the RF signal +// takes for both Tx and Rx{BR/}{BR/} +// </info> +// <regtype name="TX_PATH_CONTROL" size="32" attributes="Readable|Writable"> +// <info> +// This Register controls the switches along the Tx path. Note: default +// values refer to the RX0 path. RX1 has the same defaults, but their +// bit values may differ. +// </info> +// <bitfield name="TX_SWITCH_1_2" range="0" initialvalue="0"> +// <info> +// Write 0 to select Tx IF2 filter 2, CF = 2050 MHz, BW = 400 MHz{BR/} +// Write 1 to select Tx IF2 filter 1, CF = 1060 MHz, BW = 400 MHz{BR/} +// </info> +// </bitfield> +// <bitfield name="TX_SWITCH_3" range="3..2" initialvalue="0"> +// <info> +// {font color="red"}note to digital designer: control A is LSB, and control B is MSB{/font}{BR/} +// Control for Tx Switch 3. The configuration of this switch changes between TX paths.{BR/} +// {b}FOR TX0:{/b}{BR/} +// Write 0 to select Tx If1 Filter 1,2,3, or 50 ohm termination. See @.TX_SWITCH_4 for those controls{BR/} +// Write 1 to select Tx If1 Filter 4, 5.7 GHz to 6.4 GHz{BR/} +// Write 2 to select Tx If1 Filter 6, 7.0 GHz to 8.0 GHz{BR/} +// Write 3 to select Tx If1 Filter 5, 6.4 GHz to 7.0 GHz{BR/} +// {b}FOR TX1:{/b}{BR/} +// Write 0 to select Tx If1 Filter 6, 7.0 GHz to 8.0 GHz{BR/} +// Write 1 to select Tx If1 Filter 5, 6.4 GHz to 7.0 GHz{BR/} +// Write 2 to select Tx If1 Filter 4, 5.7 GHz to 6.4 GHz{BR/} +// Write 3 to select Tx If1 Filter 1,2,3, or 50 ohm termination. See @.TX_SWITCH_4 for those controls{BR/} +// </info> +// </bitfield> +// <bitfield name="TX_SWITCH_4" range="5..4" initialvalue="0"> +// <info> +// {font color="red"}note to digital designer: control A is LSB, and control B is MSB{/font}{BR/} +// Control for Tx Switch 4. This switch path is only taken if @.TX_SWITCH_4 is set to 0. +// The configuration of this switch changes between TX paths.{BR/} +// {b}FOR TX0:{/b}{BR/} +// Write 0 to select 50 ohm termination{BR/} +// Write 1 to select Tx If1 Filter 1, 3.1 GHz to 4.3 GHz{BR/} +// Write 2 to select Tx If1 Filter 2, 4.3 GHz to 5.1 GHz{BR/} +// Write 3 to select Tx If1 Filter 3, 5.1 GHz to 5.7 GHz{BR/} +// {b}FOR TX1:{/b}{BR/} +// Write 0 to select Tx If1 Filter 3, 5.1 GHz to 5.7 GHz{BR/} +// Write 1 to select Tx If1 Filter 2, 4.3 GHz to 5.1 GHz{BR/} +// Write 2 to select Tx If1 Filter 1, 3.1 GHz to 4.3 GHz{BR/} +// Write 3 to select 50 ohm termination{BR/} +// </info> +// </bitfield> +// <bitfield name="TX_SWITCH_5" range="7..6" initialvalue="0"> +// <info> +// {font color="red"}note to digital designer: control A is LSB, and control B is MSB{/font}{BR/} +// Control for Tx Switch 5. This switch path is only taken if @.TX_SWITCH_6 is set to 0. +// The configuration of this switch changes between TX paths.{BR/} +// {b}FOR TX0:{/b}{BR/} +// Write 0 to select Tx If1 Filter 3, 5.1 GHz to 5.7 GHz{BR/} +// Write 1 to select Tx If1 Filter 2, 4.3 GHz to 5.1 GHz{BR/} +// Write 2 to select Tx If1 Filter 1, 3.1 GHz to 4.3 GHz{BR/} +// Write 3 to select Tx If1 Filter 50 ohm termination{BR/} +// {b}FOR TX1:{/b}{BR/} +// Write 0 to select Tx If1 Filter 50 ohm termination{BR/} +// Write 1 to select Tx If1 Filter 1, 3.1 GHz to 4.3 GHz{BR/} +// Write 2 to select Tx If1 Filter 2, 4.3 GHz to 5.1 GHz{BR/} +// Write 3 to select Tx If1 Filter 3, 5.1 GHz to 5.7 GHz{BR/} +// </info> +// </bitfield> +// <bitfield name="TX_SWITCH_6" range="9..8" initialvalue="0"> +// <info> +// {font color="red"}note to digital designer: control A is LSB, and control B is MSB{/font}{BR/} +// Control for Tx Switch 6. +// The configuration of this switch changes between TX paths.{BR/} +// {b}FOR TX0:{/b}{BR/} +// Write 0 to select Tx If1 Filter 6, 7.0 GHz to 8.0 GHz{BR/} +// Write 1 to select Tx If1 Filter 5, 6.4 GHz to 7.0 GHz{BR/} +// Write 2 to select Tx If1 Filter 4, 5.7 GHz to 6.4 GHz{BR/} +// Write 3 to select Tx If1 Filter 1, 2, 3, or 50 ohm termination. See @.TX_SWITCH_5 for those controls{/font}{BR/} +// {b}FOR TX1:{/b}{BR/} +// Write 0 to select Tx If1 Filter 1, 2, 3, or 50 ohm termination. See @.TX_SWITCH_5 for those controls{/font}{BR/} +// Write 1 to select Tx If1 Filter 4, 5.7 GHz to 6.4 GHz{BR/} +// Write 2 to select Tx If1 Filter 5, 6.4 GHz to 7.0 GHz{BR/} +// Write 3 to select Tx If1 Filter 6, 7.0 GHz to 8.0 GHz{BR/} +// </info> +// </bitfield> +// <bitfield name="TX_SWITCH_7" range="11..10" initialvalue="0"> +// <info> +// {font color="red"}note to digital designer: control A is LSB, and control B is MSB{/font}{BR/} +// Control for Tx Switch 7. +// The configuration of this switch changes between TX paths.{BR/} +// {b}FOR TX0:{/b}{BR/} +// Write 0 to select 50 ohm termination{BR/} +// Write 1 to select no connect{BR/} +// Write 2 to select Tx highBand RF4 path, 3.1 GHz to 8 GHz{BR/} +// Write 3 to select Tx lowbands RF1, RF2, RF3 path. See @.TX_SWITCH_8 for those controls{BR/} +// {b}FOR TX1:{/b}{BR/} +// Write 0 to select Tx lowbands RF1, RF2, RF3 path. See @.TX_SWITCH_8 for those controls{BR/} +// Write 1 to select Tx highBand RF4 path, 3.1 GHz to 8 GHz{BR/} +// Write 2 to select no connect{BR/} +// Write 3 to select 50 ohm termination{BR/} +// </info> +// </bitfield> +// <bitfield name="TX_SWITCH_8" range="14..12" initialvalue="0"> +// <info> +// Control for Tx Switch 8, note this is one hot encoding and not binary. +// The configuration of this switch changes between TX paths.{BR/} +// {b}FOR TX0:{/b}{BR/} +// Write 1 to select Tx RF3 path, 2.3 GHz to 3.1 GHz{BR/} +// Write 2 to select Tx RF1 path, 1.0 MHz to 1.95 GHz{BR/} +// Write 4 to select Tx RF2 path, 1.95 GHz to 2.3 GHz{BR/} +// {b}FOR TX1:{/b}{BR/} +// Write 1 to select Tx RF2 path, 1.95 GHz to 2.3 GHz{BR/} +// Write 2 to select Tx RF1 path, 1.0 MHz to 1.95 GHz{BR/} +// Write 4 to select Tx RF3 path, 2.3 GHz to 3.1 GHz{BR/} +// {i}*All other values are invalid{/i}{BR/} +// </info> +// </bitfield> +// <bitfield name="TX_SWITCH_9" range="17..16" initialvalue="0"> +// <info> +// {font color="red"}note to digital designer: control A is LSB, and control B is MSB{/font}{BR/} +// Control for Tx Switch 9. +// The configuration of this switch changes between TX paths.{BR/} +// {b}FOR TX0:{/b}{BR/} +// Write 0 to select Tx RF3 path, 2.3 GHz to 3.1 GHz{BR/} +// Write 1 to select Tx RF1 path, 1.0 MHz to 1.95 GHz{BR/} +// Write 2 to select Tx RF2 path, 1.95 GHz to 2.3 GHz{BR/} +// Write 3 to select Tx RF4 path, 3.1 GHz to 8.0 GHz{BR/} +// {b}FOR TX1:{/b}{BR/} +// Write 0 to select Tx RF4 path, 3.1 GHz to 8.0 GHz{BR/} +// Write 1 to select Tx RF2 path, 1.95 GHz to 2.3 GHz{BR/} +// Write 2 to select Tx RF1 path, 1.0 MHz to 1.95 GHz{BR/} +// Write 3 to select Tx RF3 path, 2.3 GHz to 3.1 GHz{BR/} +// </info> +// </bitfield> +// <bitfield name="TX_SWITCH_10" range="19..18" initialvalue="0"> +// <info> +// {font color="red"}note to digital designer: control A is LSB, and control B is MSB{/font}{BR/} +// Control for Tx Switch 10. +// The configuration of this switch changes between TX paths.{BR/} +// {b}FOR TX0:{/b}{BR/} +// Write 0 to select Tx amplifier bypass path{BR/} +// Write 1 to select Tx calibration loopback path{BR/} +// Write 2 to select Tx lowband amp path. @.TX_Switch_11 must also match this path.{BR/} +// Write 3 to select Tx highband amp path. @.TX_Switch_11 must also match this path.{BR/} +// {b}FOR TX1:{/b}{BR/} +// Write 0 to select Tx highband amp path. @.TX_Switch_11 must also match this path.{BR/} +// Write 1 to select Tx lowband amp path. @.TX_Switch_11 must also match this path.{BR/} +// Write 2 to select Tx amplifier bypass path{BR/} +// Write 3 to select Tx calibration loopback path{BR/} +// </info> +// </bitfield> +// <bitfield name="TX_SWITCH_11" range="21..20" initialvalue="0"> +// <info> +// {font color="red"}note to digital designer: control A is LSB, and control B is MSB{/font}{BR/} +// Control for Tx Switch 11. +// The configuration of this switch changes between TX paths.{BR/} +// {b}FOR TX0:{/b}{BR/} +// Write 0 to select Tx Rx path, @.RX_SWITCH_1 must also select the correct path{BR/} +// Write 1 to select Tx highband amp path. @.TX_SWITCH_10 must also match this path.{BR/} +// Write 2 to select Tx lowband amp path. @.TX_SWITCH_10 must also match this path.{BR/} +// Write 3 to select Tx amplifier bypass path{BR/} +// {b}FOR TX1:{/b}{BR/} +// Write 0 to select Tx Rx path, @.RX_SWITCH_1 must also select the correct path{BR/} +// Write 1 to select Tx amplifier bypass path{BR/} +// Write 2 to select Tx lowband amp path. @.TX_SWITCH_10 must also match this path.{BR/} +// Write 3 to select Tx highband amp path. @.TX_SWITCH_10 must also match this path.{BR/} +// </info> +// </bitfield> +// <bitfield name="TX_SWITCH_13" range="24" initialvalue="0"> +// <info> +// Control for Tx0 Switch 13 LO path. +// The configuration of this switch changes between TX paths.{BR/} +// {b}FOR TX0:{/b}{BR/} +// Write 0 to select Tx0 internal LO path{BR/} +// Write 1 to select Tx0 external LO path{BR/} +// {b}FOR TX1:{/b}{BR/} +// Write 0 to select Tx0 external LO path{BR/} +// Write 1 to select Tx0 internal LO path{BR/} +// </info> +// </bitfield> +// <bitfield name="TX_SWITCH_14" range="26" initialvalue="0"> +// <info> +// Control for Tx Switch 13 LO path. +// The configuration of this switch changes between TX paths.{BR/} +// {b}FOR TX0:{/b}{BR/} +// Write 0 to select Tx external LO path{BR/} +// Write 1 to select Tx internal LO path{BR/} +// {b}FOR TX1:{/b}{BR/} +// Write 0 to select Tx internal LO path{BR/} +// Write 1 to select Tx external LO path{BR/} +// </info> +// </bitfield> +// </regtype> +// +// <regtype name="RX_PATH_CONTROL" size="32" attributes="Readable|Writable"> +// <info> +// This Register controls switches along Rx paths. Note: default +// values refer to the RX0 path. RX1 has the same defaults, but their +// bit values may differ. +// </info> +// <bitfield name="RX_SWITCH_1" range="1..0" initialvalue="0"> +// <info> +// {font color="red"}note to digital designer: control A is LSB, and control B is MSB{/font}{BR/} +// Control for Rx Switch 1. +// The configuration of this switch changes between RX paths.{BR/} +// {b}FOR RX0:{/b}{BR/} +// Write 0 to select Rx calibration loopback{BR/} +// Write 1 to select Rx 50 ohm termination path{BR/} +// Write 2 to select Tx Rx path, @.TX_SWITCH_11 must also select the correct path{BR/} +// Write 3 to select Rx input port{BR/} +// {b}FOR RX1:{/b}{BR/} +// Write 0 to select Rx calibration loopback{BR/} +// Write 1 to select Tx Rx path, @.TX_SWITCH_11 must also select the correct path{BR/} +// Write 2 to select Rx input port{BR/} +// Write 3 to select Rx 50 ohm termination path{BR/} +// </info> +// </bitfield> +// <bitfield name="RX_SWITCH_2" range="2" initialvalue="0"> +// <info> +// {font color="red"}note to digital designer: control A is the only control, and control B is pulled high{/font}{BR/} +// Control for Rx Switch 2. The configuration of this switch changes between RX paths.{BR/} +// {b}FOR RX0:{/b}{BR/} +// Write 0 to select Rx RF3 highband path{BR/} +// Write 1 to select Rx RF1/2 lowband path{BR/} +// {b}FOR RX1:{/b}{BR/} +// Write 0 to select Rx RF1/2 lowband path{BR/} +// Write 1 to select Rx RF3 highband path{BR/} +// </info> +// </bitfield> +// <bitfield name="RX_SWITCH_3" range="6..4" initialvalue="0"> +// <info> +// Control for Rx Switch 3, note this is one hot encoding and not binary. +// The configuration of this switch changes between RX paths.{BR/} +// {b}FOR RX0:{/b}{BR/} +// Write 1 to select Rx RF filter 2 path, 1.80 GHz - 2.30 GHz{BR/} +// Write 2 to select Rx RF filter 1 path, 1.00 MHz - 1.80 GHz{BR/} +// Write 4 to select Rx RF filter 3 path, 2.30 MHz - 3.00 GHz{BR/} +// {b}FOR RX1:{/b}{BR/} +// Write 1 to select Rx RF filter 3 path, 2.30 MHz - 3.00 GHz{BR/} +// Write 2 to select Rx RF filter 1 path, 1.00 MHz - 1.80 GHz{BR/} +// Write 4 to select Rx RF filter 2 path, 1.80 GHz - 2.30 GHz{BR/} +// {i}*All other values are invalid{/i}{BR/} +// </info> +// </bitfield> +// <bitfield name="RX_SWITCH_4" range="8" initialvalue="0"> +// <info> +// {font color="red"}note to digital designer: control A is the only control, and control B is tied to ground{/font}{BR/} +// Control for Rx Switch 4.{BR/} +// Write 0 to select Rx RF1/2 lowband path{BR/} +// Write 1 to select Rx RF3 highband path{BR/} +// </info> +// </bitfield> +// <bitfield name="RX_SWITCH_5" range="11..10" initialvalue="0"> +// <info> +// {font color="red"}note to digital designer: control A is LSB, and control B is MSB{/font}{BR/}{BR/} +// +// Control for Rx Switch 5. The configuration of this switch changes between RX paths.{BR/} +// {b}FOR RX0:{/b}{BR/} +// Write 0 to select Rx RF filter 4 path, 7.0 - 8 GHz GHz, @.RX_SWITCH_6 must also select this path{BR/} +// Write 1 to select Rx RF filter 3 path, 5.6 - 8 GHz, @.RX_SWITCH_6 must also select this path{BR/} +// Write 2 to select Rx RF filter 2 path, 4.2 - 5.6 GHz, @.RX_SWITCH_6 must also select this path{BR/} +// Write 3 to select Rx RF filter 1 path, 3.0 - 4.2 GHz, @.RX_SWITCH_6 must also select this path{BR/} +// {b}FOR RX1:{/b}{BR/} +// Write 0 to select Rx RF filter 1 path, 3.0 - 4.2 GHz, @.RX_SWITCH_6 must also select this path{BR/} +// Write 1 to select Rx RF filter 2 path, 4.2 - 5.6 GHz, @.RX_SWITCH_6 must also select this path{BR/} +// Write 2 to select Rx RF filter 3 path, 5.6 - 8 GHz, @.RX_SWITCH_6 must also select this path{BR/} +// Write 3 to select Rx RF filter 4 path, 7.0 - 8 GHz GHz, @.RX_SWITCH_6 must also select this path{BR/} +// </info> +// </bitfield> +// <bitfield name="RX_SWITCH_6" range="13..12" initialvalue="0"> +// <info> +// {font color="red"}note to digital designer: control A is LSB, and control B is MSB{/font}{BR/}{BR/} +// +// Control for Rx Switch 6. The configuration of this switch changes between RX paths.{BR/} +// {b}FOR RX0:{/b}{BR/} +// Write 0 to select Rx RF filter 1 path, 3.0 - 4.2 GHz, @.RX_SWITCH_6 must also select this path{BR/} +// Write 1 to select Rx RF filter 2 path, 4.2 - 5.6 GHz, @.RX_SWITCH_6 must also select this path{BR/} +// Write 2 to select Rx RF filter 3 path, 5.6 - 8 GHz, @.RX_SWITCH_6 must also select this path{BR/} +// Write 3 to select Rx RF filter 4 path, 7.0 - 8 GHz GHz, @.RX_SWITCH_6 must also select this path{BR/} +// {b}FOR RX1:{/b}{BR/} +// Write 0 to select Rx RF filter 4 path, 7.0 - 8 GHz GHz, @.RX_SWITCH_6 must also select this path{BR/} +// Write 1 to select Rx RF filter 3 path, 5.6 - 8 GHz, @.RX_SWITCH_6 must also select this path{BR/} +// Write 2 to select Rx RF filter 2 path, 4.2 - 5.6 GHz, @.RX_SWITCH_6 must also select this path{BR/} +// Write 3 to select Rx RF filter 1 path, 3.0 - 4.2 GHz, @.RX_SWITCH_6 must also select this path{BR/} +// </info> +// </bitfield> +// <bitfield name="RX_SWITCH_7_8" range="14" initialvalue="0"> +// <info> +// Shared control for Rx switch 7 and switch 8.{BR/} +// {b}FOR RX0:{/b}{BR/} +// Write 0 to select Rx IF2 filter 2, CF = 2050 MHz, BW = 400 MHz{BR/} +// Write 1 to select Rx IF2 filter 1, CF = 1060 MHz, BW = 400 MHz{BR/} +// {b}FOR RX1:{/b}{BR/} +// Write 0 to select Rx IF2 filter 1, CF = 1060 MHz, BW = 400 MHz{BR/} +// Write 1 to select Rx IF2 filter 2, CF = 2050 MHz, BW = 400 MHz{BR/} +// </info> +// </bitfield> +// <bitfield name="RX_SWITCH_9" range="16" initialvalue="0"> +// <info> +// Control for Rx Switch 9 LO path. The configuration of this switch changes between RX paths.{BR/} +// {b}FOR RX0:{/b}{BR/} +// Write 0 to select Rx internal LO path{BR/} +// Write 1 to select Rx external LO path{BR/} +// {b}FOR RX1:{/b}{BR/} +// Write 0 to select Rx external LO path{BR/} +// Write 1 to select Rx internal LO path{BR/} +// </info> +// </bitfield> +// <bitfield name="RX_SWITCH_10" range="18" initialvalue="0"> +// <info> +// Control for Rx Switch 10 LO path. The configuration of this switch changes between RX paths.{BR/} +// {b}FOR RX0:{/b}{BR/} +// Write 0 to select Rx internal LO path{BR/} +// Write 1 to select Rx external LO path{BR/} +// {b}FOR RX1:{/b}{BR/} +// Write 0 to select Rx external LO path{BR/} +// Write 1 to select Rx internal LO path{BR/} +// </info> +// </bitfield> +// <bitfield name="RX_SWITCH_11" range="22..20" initialvalue="0"> +// <info> +// Control for Rx Switch 11, note to digital designer: Control V2 is pulled to ground.{BR/}{BR/} +// The configuration of this switch changes between RX paths.{BR/} +// {b}FOR RX0:{/b}{BR/} +// Write 1 to select Rx1 RF filter 3 path, 2.30 MHz - 3.00 GHz{BR/} +// Write 2 to select Rx1 RF filter 1 path, 1.00 MHz - 1.80 GHz{BR/} +// Write 4 to select Rx1 RF filter 2 path, 1.80 GHz - 2.30 GHz{BR/} +// {b}FOR RX1:{/b}{BR/} +// Write 1 to select Rx1 RF filter 2 path, 1.80 GHz - 2.30 GHz{BR/} +// Write 2 to select Rx1 RF filter 1 path, 1.00 MHz - 1.80 GHz{BR/} +// Write 4 to select Rx1 RF filter 3 path, 2.30 MHz - 3.00 GHz{BR/} +// </info> +// </bitfield> +// </regtype> +// +// <register name="TX0_PATH_CONTROL" typename="TX_PATH_CONTROL" offset="0x00" count="256" step="4"> +// <info> +// This Register controls the Tx0 paths.{br} +// This register array can hold settings for all ATR configurations. +// The register index equals the ATR configuration. +// The active configuration can be selected in @.ATR_REGMAP. +// Independently all configurations can be read/written at any time. +// </info> +// </register> +// <register name="TX1_PATH_CONTROL" typename="TX_PATH_CONTROL" offset="0x400" count="256" step="4"> +// <info> +// This Register controls the Tx1 paths.{br} +// This register array can hold settings for all ATR configurations. +// The register index equals the ATR configuration. +// The active configuration can be selected in @.ATR_REGMAP. +// Independently all configurations can be read/written at any time. +// </info> +// </register> +// +// <register name="RX0_PATH_CONTROL" typename="RX_PATH_CONTROL" offset="0x800" count="256" step="4"> +// <info> +// This Register controls the Rx0 paths.{br} +// This register array can hold settings for all ATR configurations. +// The register index equals the ATR configuration. +// The active configuration can be selected in @.ATR_REGMAP. +// Independently all configurations can be read/written at any time. +// </info> +// </register> +// <register name="RX1_PATH_CONTROL" typename="RX_PATH_CONTROL" offset="0xC00" count="256" step="4"> +// <info> +// This Register controls the Rx1 paths.{br} +// This register array can hold settings for all ATR configurations. +// The register index equals the ATR configuration. +// The active configuration can be selected in @.ATR_REGMAP. +// Independently all configurations can be read/written at any time. +// </info> +// </register> +// </group> +//</regmap> +//XmlParse xml_off diff --git a/fpga/usrp3/top/x400/dboards/zbx/cpld/register_endpoints/utils/spi_control_utils.vh b/fpga/usrp3/top/x400/dboards/zbx/cpld/register_endpoints/utils/spi_control_utils.vh new file mode 100644 index 000000000..5a6ab27e2 --- /dev/null +++ b/fpga/usrp3/top/x400/dboards/zbx/cpld/register_endpoints/utils/spi_control_utils.vh @@ -0,0 +1,30 @@ +// +// Copyright 2021 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: spi_control_utils +// +// Description: +// Contains constants and functions common to blocks that interact +// with the wishbone spi engine. +// + +// SPI Master Control Register Offsets +localparam TX_DATA_REG = 5'h00; +localparam RX_DATA_REG = 5'h00; +localparam CLOCK_DIVIDER_REG = 5'h14; +localparam CONTROL_REG = 5'h10; +localparam SS_REG = 5'h18; + +// Simple function to return a vector of 0's with only position +// ss_input set to 1. +function automatic [31:0] set_ss_bit; +input [3:0] ss_input; +reg [31:0] ss_data; +begin + ss_data = 32'h0; + ss_data[ss_input] = 1'b1; + set_ss_bit = ss_data; +end +endfunction |