diff options
author | Max Köhler <max.koehler@ni.com> | 2021-02-05 13:14:41 -0600 |
---|---|---|
committer | Aaron Rossetto <aaron.rossetto@ni.com> | 2021-06-10 11:56:58 -0500 |
commit | 7015f5ed2d495f3908773b7c7d74864d0cc3871a (patch) | |
tree | e9c9f7d95f5c35c089bfc9534707934bfe41344a | |
parent | 6d3765605262016a80f71e36357f749ea35cbe5a (diff) | |
download | uhd-7015f5ed2d495f3908773b7c7d74864d0cc3871a.tar.gz uhd-7015f5ed2d495f3908773b7c7d74864d0cc3871a.tar.bz2 uhd-7015f5ed2d495f3908773b7c7d74864d0cc3871a.zip |
fpga: x400: cpld: Add support for X410 motherboard CPLD
Co-authored-by: Humberto Jimenez <humberto.jimenez@ni.com>
Co-authored-by: Javier Valenzuela <javier.valenzuela@ni.com>
42 files changed, 8377 insertions, 0 deletions
diff --git a/fpga/usrp3/top/x400/cpld/.gitignore b/fpga/usrp3/top/x400/cpld/.gitignore new file mode 100644 index 000000000..fcdcdf540 --- /dev/null +++ b/fpga/usrp3/top/x400/cpld/.gitignore @@ -0,0 +1,7 @@ +# Ignore Quartus generated files upon project opening. +*.qws +db/ +incremental_db/ +output_files/ +*.sopcinfo +build/ diff --git a/fpga/usrp3/top/x400/cpld/Makefile b/fpga/usrp3/top/x400/cpld/Makefile new file mode 100644 index 000000000..68c6c8908 --- /dev/null +++ b/fpga/usrp3/top/x400/cpld/Makefile @@ -0,0 +1,77 @@ +# +# Copyright 2021 Ettus Research, a National Instruments Brand +# +# SPDX-License-Identifier: LGPL-3.0-or-later +# + +GIT_HASH = $(shell ../../../tools/scripts/git-hash.sh) + +build: ip + @echo -ne "\n---- Make: Synthesis ...\n\n"; + @quartus_map mb_cpld --verilog_macro="GIT_HASH=32'h$(GIT_HASH)"; + @echo -ne "\n---- Make: Partition Merge ...\n\n"; + @quartus_cdb mb_cpld --merge=on --incremental_compilation_import + @echo -ne "\n\n---- Make: Implementation ...\n\n"; + @quartus_fit mb_cpld; + @echo -ne "\n\n---- Make: Analyzing timing ...\n\n"; + @quartus_sta mb_cpld; + @# grep for unconstrained path warning + @grep "332102" output_files/mb_cpld.sta.rpt; \ + if [ $$? -eq 0 ]; then false; else true; fi + @# grep for timing closure critical warning + @grep "332148" output_files/mb_cpld.sta.rpt; \ + if [ $$? -eq 0 ]; then false; else true; fi + @# expect no warnings + @grep -iw "warning" output_files/mb_cpld.sta.rpt; \ + if [ $$? -eq 0 ]; then false; else true; fi + @# expect no critical warning except "review power analyzer report file" + @grep -i "critical warning" output_files/* | grep -v 16562; \ + if [ $$? -eq 0 ]; then false; else true; fi + @# PS chip select analysis + @quartus_sta -t scripts/ps_cs_analysis.tcl + @echo -ne "\n\n---- Make: Generating bitfile...\n\n"; + @quartus_asm mb_cpld; + @echo -ne "\n\n---- Make: Converting bitfile to svf format (ISP enabled)...\n\n"; + @quartus_cpf --convert \ + --frequency 10.0MHz \ + --voltage 2.5 \ + --operation p \ + ./output_files/mb_cpld.pof ./output_files/mb_cpld_isp_on.svf -o background_programming=on; + @echo -ne "\n\n---- Make: Converting bitfile to svf format (ISP disabled)...\n\n"; + @quartus_cpf --convert \ + --frequency 10.0MHz \ + --voltage 2.5 \ + --operation p \ + ./output_files/mb_cpld.pof ./output_files/mb_cpld_isp_off.svf; + @echo -ne "\n\n---- Make: Converting bitfile to rdp format...\n\n"; + @quartus_cpf -c raw_conversion.cof + @echo -ne "\n\n---- Make: Copy final files...\n\n"; + @mkdir -p build + @cp output_files/mb_cpld.pof build/usrp_x410_cpld.pof + @cp output_files/mb_cpld_isp_off.svf build/usrp_x410_cpld_isp_off.svf + @cp output_files/mb_cpld_isp_on.svf build/usrp_x410_cpld.svf + @cp output_files/mb_cpld_converted_cfm0_auto.rpd build/usrp_x410_cpld.rpd + @echo -ne "\n\n---- Make: MB CPLD ready!\n"; + @echo -ne " Use build/usrp_x410_cpld.pof via JTAG programmer or\n" + @echo -ne " build/usrp_x410_cpld.svf (ISP on) via PS JTAG-engine (background programming) or\n" + @echo -ne " build/usrp_x410_cpld.rpd via reconfig engine or\n" + @echo -ne " build/usrp_x410_cpld_isp_off.svf via JTAG test points (initial programming)\n" + +clean: + @echo -ne "\nCleaning MB CPLD...\n"; + @git clean -Xdf + +QSYS_PATH=$(subst \,/,$(QSYS_ROOTDIR)) + +ip: ip/flash/on_chip_flash/simulation/on_chip_flash.v \ + ip/clkctrl/clkctrl/simulation/clkctrl.v + +ip/flash/on_chip_flash/simulation/on_chip_flash.v: + $(QSYS_PATH)/qsys-generate ip/flash/on_chip_flash.qsys --simulation=VERILOG + +ip/clkctrl/clkctrl/simulation/clkctrl.v: + $(QSYS_PATH)/qsys-generate ip/clkctrl/clkctrl.qsys --simulation=VERILOG + +all: build + +.PHONY: all build clean ip diff --git a/fpga/usrp3/top/x400/cpld/ctrlport_to_jtag.v b/fpga/usrp3/top/x400/cpld/ctrlport_to_jtag.v new file mode 100644 index 000000000..dedc66e36 --- /dev/null +++ b/fpga/usrp3/top/x400/cpld/ctrlport_to_jtag.v @@ -0,0 +1,275 @@ +// +// Copyright 2021 Ettus Research, A National Instruments Brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: ctrlport_to_jtag +// +// Description: +// +// This module wraps a JTAG master and provides a ControlPort slave +// interface. +// +// Parameters: +// +// BASE_ADDRESS : Base address for CtrlPort registers +// DEFAULT_PRESCALAR : Default clock divider to use +// + +`default_nettype none + + +module ctrlport_to_jtag #( + parameter BASE_ADDRESS = 0, + parameter DEFAULT_PRESCALAR = 0 +) ( + //--------------------------------------------------------------------------- + // ControlPort Slave + //--------------------------------------------------------------------------- + + input wire ctrlport_clk, + input wire ctrlport_rst, + + input wire s_ctrlport_req_wr, + input wire s_ctrlport_req_rd, + input wire [19:0] s_ctrlport_req_addr, + input wire [31:0] s_ctrlport_req_data, + output reg s_ctrlport_resp_ack, + + output reg [ 1:0] s_ctrlport_resp_status = 0, + output reg [31:0] s_ctrlport_resp_data = 0, + + //--------------------------------------------------------------------------- + // JTAG Signals + //--------------------------------------------------------------------------- + + output wire tck, + output wire tdi, + input wire tdo, + output wire tms +); + + `include "../../../lib/rfnoc/core/ctrlport.vh" + `include "./regmap/jtag_regmap_utils.vh" + + //--------------------------------------------------------------------------- + // Local Registers + //--------------------------------------------------------------------------- + + reg [ TX_DATA_SIZE-1:0] tx_data_reg; + reg [ STB_DATA_SIZE-1:0] stb_data_reg; + reg [PRESCALAR_SIZE-1:0] prescalar_reg = DEFAULT_PRESCALAR; + reg [ LENGTH_SIZE-1:0] length_reg; + reg start_reg; + reg soft_rst_stb_reg; + + //--------------------------------------------------------------------------- + // Readback Signals from JTAG Master + //--------------------------------------------------------------------------- + + wire [31:0] rd_data; + wire ready; + + //--------------------------------------------------------------------------- + // Handling of CtrlPort + //--------------------------------------------------------------------------- + + localparam NUM_ADDRESSES = 32; + wire address_in_range = (s_ctrlport_req_addr >= BASE_ADDRESS) && + (s_ctrlport_req_addr < BASE_ADDRESS + NUM_ADDRESSES); + wire soft_rst_requested = (s_ctrlport_req_addr == BASE_ADDRESS + CONTROL) && + (s_ctrlport_req_data[RESET] == 1'b1); + + always @(posedge ctrlport_clk) begin + // Reset internal registers and responses + if (ctrlport_rst) begin + tx_data_reg <= {TX_DATA_SIZE {1'b0}}; + stb_data_reg <= {STB_DATA_SIZE {1'b0}}; + prescalar_reg <= DEFAULT_PRESCALAR; + length_reg <= {LENGTH_SIZE {1'b0}}; + start_reg <= 1'b0; + soft_rst_stb_reg <= 1'b0; + s_ctrlport_resp_ack <= 1'b0; + + end else begin + // Request independent default assignments + start_reg <= 1'b0; + soft_rst_stb_reg <= 1'b0; // self-clearing strobe + + // 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 <= {CTRLPORT_DATA_W{1'bx}}; + s_ctrlport_resp_status <= CTRL_STS_OKAY; + + // Process write requests only in case ready is asserted because JTAG + // module requires these values to be stable when it is not ready. + // + // The one exception is when a soft-reset is requested to reset the + // bitq_fsm, in that case that is a valid write. + if (soft_rst_requested) begin + soft_rst_stb_reg <= 1'b1; + + end else if (ready) begin + case (s_ctrlport_req_addr) + BASE_ADDRESS + TX_DATA: begin + tx_data_reg <= s_ctrlport_req_data; + end + + BASE_ADDRESS + STB_DATA: begin + stb_data_reg <= s_ctrlport_req_data; + end + + BASE_ADDRESS + CONTROL: begin + length_reg <= s_ctrlport_req_data[LENGTH_MSB:LENGTH]; + prescalar_reg <= s_ctrlport_req_data[PRESCALAR_MSB:PRESCALAR]; + // When the RESET bit is high, a soft-reset (i.e. no start strobe) + // must take place, which is handled by the default assignment. + // Otherwise, if the RESET bit is low, a start strobe should be + // issued, triggering a transaction. + start_reg <= (s_ctrlport_req_data[RESET] == 1'b0); + 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 + + // Error in case ready is not asserted + end else begin + s_ctrlport_resp_status <= CTRL_STS_CMDERR; + end + + // 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; + + case (s_ctrlport_req_addr) + BASE_ADDRESS + RX_DATA: begin + s_ctrlport_resp_data <= rd_data; + end + + BASE_ADDRESS + CONTROL: begin + s_ctrlport_resp_data <= {CTRLPORT_DATA_W {1'b0}}; + s_ctrlport_resp_data[LENGTH_MSB:LENGTH] <= length_reg; + s_ctrlport_resp_data[PRESCALAR_MSB:PRESCALAR] <= prescalar_reg; + s_ctrlport_resp_data[READY] <= ready; + end + + // Error on undefined address + default: begin + s_ctrlport_resp_data <= {CTRLPORT_DATA_W {1'bx}}; + 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 + + //--------------------------------------------------------------------------- + // JTAG Master + //--------------------------------------------------------------------------- + + // bitq_fsm reset is asserted by either the ctrlport_rst or the soft-reset + // strobe triggered through software. + wire bitq_resetn = ~(ctrlport_rst | soft_rst_stb_reg); + + bitq_fsm #( + .IDLE_VALUE (1'b0) + ) jtag_master ( + .clk (ctrlport_clk), + .rstn (bitq_resetn), + .prescalar (prescalar_reg), + .bit_clk (tck), + .bit_in (tdo), + .bit_out (tdi), + .bit_stb (tms), + .start (start_reg), + .ready (ready), + .len (length_reg), + .wr_data (tx_data_reg), + .stb_data (stb_data_reg), + .rd_data (rd_data) + ); + +endmodule + + +`default_nettype wire + + +//XmlParse xml_on +//<regmap name="JTAG_REGMAP" readablestrobes="false" markdown="true" generatevhdl="true" ettusguidelines="true"> +// +// <group name="JTAG_REGS"> +// <info> +// This register map is present for each JTAG module. +// +// Basic operation would be: +// +// - poll @.ready until asserted +// - write / read data +// - write @.CONTROL register along with @.reset deasserted to start a transaction +// +// For resetting the BITQ FSM, simply assert @.reset. +// +// This operation seems a little strange, but it is what the axi_bitq driver +// expects. This behavior has been implemented in previous products. +// +// </info> +// +// <register name="TX_DATA" readable="false" offset="0x00" size="32"> +// <info>Data to be transmitted (TDI)</info> +// </register> +// +// <register name="STB_DATA" readable="false" offset="0x04" size="32"> +// <info>Data to be transmitted (TMS)</info> +// </register> +// +// <register name="CONTROL" offset="0x08" size="32"> +// <info>JTAG module status and control</info> +// <bitfield name="prescalar" range="7..0" initialvalue="true"> +// <info>Clock divider. Resulting JTAG frequency will be f_ctrlport / (2*(prescalar + 1)). See window description for details on the initial/minimum value.</info> +// </bitfield> +// <bitfield name="length" range="12..8"> +// <info>(Number of bits - 1) to be transferred</info> +// </bitfield> +// <bitfield name="reset" readable="false" range="31"> +// <info>When asserted ('1') a soft-reset for the bitq FSM is triggered, +// preventing any transactions to take place. +// +// Deassert this bit, along with values for @.prescalar and @.length +// to trigger a new transaction (start strobe).</info> +// </bitfield> +// <bitfield name="ready" writable="false" range="31"> +// <info>Bitq FSM is ready for input (no data transmission in progress).</info> +// </bitfield> +// </register> +// +// <register name="RX_DATA" offset="0x0C" writable="false" size="32"> +// <info>Received data (TDO)</info> +// </register> +// +// </group> +//</regmap> +//XmlParse xml_off diff --git a/fpga/usrp3/top/x400/cpld/ctrlport_to_spi.v b/fpga/usrp3/top/x400/cpld/ctrlport_to_spi.v new file mode 100644 index 000000000..d4b72a72d --- /dev/null +++ b/fpga/usrp3/top/x400/cpld/ctrlport_to_spi.v @@ -0,0 +1,276 @@ +// +// Copyright 2021 Ettus Research, A National Instruments Brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: ctrlport_to_spi +// +// Description: +// +// This module wraps a SPI master and provides a ControlPort interface. +// +// Parameters: +// +// BASE_ADDRESS : Base address for CtrlPort registers. +// + +`default_nettype none + + +module ctrlport_to_spi #( + parameter BASE_ADDRESS = 0 +) ( + //--------------------------------------------------------------- + // ControlPort Slave + //--------------------------------------------------------------- + + input wire ctrlport_clk, + input wire ctrlport_rst, + + input wire s_ctrlport_req_wr, + input wire s_ctrlport_req_rd, + input wire [19:0] s_ctrlport_req_addr, + input wire [31:0] s_ctrlport_req_data, + + output reg s_ctrlport_resp_ack, + output reg [ 1:0] s_ctrlport_resp_status = 0, + output reg [31:0] s_ctrlport_resp_data = 0, + + //--------------------------------------------------------------- + // SPI Signals + //--------------------------------------------------------------- + + output wire sclk, + output wire mosi, + output wire [15:0] ss, + input wire miso +); + + `include "../../../lib/rfnoc/core/ctrlport.vh" + `include "./regmap/spi_regmap_utils.vh" + + //--------------------------------------------------------------- + // Translating CtrlPort <-> Wishbone + //--------------------------------------------------------------- + + reg wb_cyc_i; // Active bus cycle + reg wb_we_i = 1'b0; // Write access + reg [ 4:0] wb_adr_i = 5'b0; + reg [31:0] wb_dat_i = 32'b0; + wire wb_ack_o; + wire [31:0] wb_dat_o; + wire wb_err_o; + + // Check for address to be in range [base_addr..base_addr+32) + localparam NUM_ADDRESSES = 32; + wire address_in_range = (s_ctrlport_req_addr >= BASE_ADDRESS) && + (s_ctrlport_req_addr < BASE_ADDRESS + NUM_ADDRESSES); + + // Following chapter 3.2.3 (classic standard SINGLE WRITE cycle) of + // https://cdn.opencores.org/downloads/wbspec_b4.pdf + always @(posedge ctrlport_clk) begin + // Reset internal registers and responses + if (ctrlport_rst) begin + wb_cyc_i <= 1'b0; + s_ctrlport_resp_ack <= 1'b0; + + end else begin + // Request independent default assignments + s_ctrlport_resp_ack <= 1'b0; + + // Wait for ack on active bus transactions + if (wb_cyc_i) begin + if (wb_ack_o) begin + // End bus cycle and generate response + wb_cyc_i <= 1'b0; + s_ctrlport_resp_ack <= 1'b1; + s_ctrlport_resp_data <= wb_dat_o; + + if (wb_err_o) begin + s_ctrlport_resp_status <= CTRL_STS_CMDERR; + end else begin + s_ctrlport_resp_status <= CTRL_STS_OKAY; + end + end + + // Write requests + end else if (s_ctrlport_req_wr) begin + // Assume there is a valid address + wb_cyc_i <= 1'b1; + wb_we_i <= 1'b1; + wb_dat_i <= s_ctrlport_req_data; + + case (s_ctrlport_req_addr) + BASE_ADDRESS + TX_DATA_LOW: begin + wb_adr_i <= 5'h00; + end + + BASE_ADDRESS + TX_DATA_HIGH: begin + wb_adr_i <= 5'h04; + end + + BASE_ADDRESS + CONTROL: begin + wb_adr_i <= 5'h10; + end + + BASE_ADDRESS + CLOCK_DIVIDER: begin + wb_adr_i <= 5'h14; + end + + BASE_ADDRESS + SLAVE_SELECT: begin + wb_adr_i <= 5'h18; + end + + // Error on undefined address + default: begin + wb_cyc_i <= 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 + + // Read requests + end else if (s_ctrlport_req_rd) begin + // Assume there is a valid address + wb_cyc_i <= 1'b1; + wb_we_i <= 1'b0; + + case (s_ctrlport_req_addr) + BASE_ADDRESS + RX_DATA_LOW: begin + wb_adr_i <= 5'h00; + end + + BASE_ADDRESS + RX_DATA_HIGH: begin + wb_adr_i <= 5'h04; + end + + BASE_ADDRESS + CONTROL: begin + wb_adr_i <= 5'h10; + end + + BASE_ADDRESS + CLOCK_DIVIDER: begin + wb_adr_i <= 5'h14; + end + + BASE_ADDRESS + SLAVE_SELECT: begin + wb_adr_i <= 5'h18; + end + + // Error on undefined address + default: begin + wb_cyc_i <= 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 Master + //--------------------------------------------------------------- + + spi_top spi_master ( + .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_err_o), + .wb_int_o (), + .ss_pad_o (ss), + .sclk_pad_o (sclk), + .mosi_pad_o (mosi), + .miso_pad_i (miso) + ); + +endmodule + + +`default_nettype wire + + +//XmlParse xml_on +//<regmap name="SPI_REGMAP" readablestrobes="false" markdown="true" generatevhdl="true" ettusguidelines="true"> +// +// <group name="SPI_REGS"> +// <info> +// This register map is present for each SPI master. +// +// For information about the register content and the way to interact with the core see the +// <a href="https://opencores.org/websvn/filedetails?repname=spi&path=%2Fspi%2Ftrunk%2Fdoc%2Fspi.pdf" target="_blank">documentation</a> +// of the SPI master from opencores used internally. +// +// The core is configured to operate with 16 slave signal signals, up to 128 bits per transmission and 8 bit clock divider. +// Only 64 bits of data are available via this register interface. +// +// For the different SPI modes use the following table to derive the bits in @.CONTROL register. Only option 0 (CPOL=0, CPHA=0) has been tested. +// +//| CPOL | CPHA | TX_NEG | RX_NEG | +//| ------- | -------- | -------- | ------- | +//| 0 | 0 | 1 | 0 | +//| 0 | 1 | 0 | 1 | +//| 1 | 0 | 0 | 1 | +//| 1 | 1 | 1 | 0 | +// </info> +// +// <register name="RX_DATA_LOW" offset="0x00" writable="false" size="32"> +// <info>Lower 32 bits of the received word. (RxWord[31:0])</info> +// </register> +// +// <register name="RX_DATA_HIGH" offset="0x04" writable="false" size="32"> +// <info>Higher 32 bits of the received word. (RxWord[63:32])</info> +// </register> +// +// <register name="TX_DATA_LOW" offset="0x08" readable="false" size="32"> +// <info>Lower 32 bits of the received word. (TxWord[31:0])</info> +// </register> +// +// <register name="TX_DATA_HIGH" offset="0x0C" readable="false" size="32"> +// <info>Higher 32 bits of the received word. (TxWord[63:32])</info> +// </register> +// +// <register name="CONTROL" offset="0x10" size="32"> +// <info>Control register</info> +// </register> + +// <register name="CLOCK_DIVIDER" offset="0x14" size="8"> +// <bitfield name="Divider" range="7..0"> +// <info> +// Clock Divider. +// </info> +// </bitfield> +// </register> +// <register name="SLAVE_SELECT" offset="0x18" size="16"> +// <bitfield name="SS" range="15..0"> +// <info> +// Slave select. +// </info> +// </bitfield> +// </register> +// +// </group> +//</regmap> +//XmlParse xml_off diff --git a/fpga/usrp3/top/x400/cpld/db_spi_shared_constants.sdc b/fpga/usrp3/top/x400/cpld/db_spi_shared_constants.sdc new file mode 100644 index 000000000..21935c2e7 --- /dev/null +++ b/fpga/usrp3/top/x400/cpld/db_spi_shared_constants.sdc @@ -0,0 +1,20 @@ +# +# Copyright 2021 Ettus Research, a National Instruments Brand +# +# SPDX-License-Identifier: LGPL-3.0-or-later +# +# Description: +# +# Timing constants for the MB CPLD <-> DB CPLD SPI interface +# + +# Delays are rounded to integer values which leave a slack of >1ns on each setup +# and hold path without requirement for adding hold delays (as reported +# by Quartus fitter report). +# The signal might change before the SCLK edge as the internal +# registers are driven by PLL reference clock rather than the SPI clock used +# for the port timing constaints. +set db_cpld_spi_max_out 14.000 +set db_cpld_spi_min_out 2.000 +set db_cpld_spi_max_in 2.000 +set db_cpld_spi_min_in -2.000 diff --git a/fpga/usrp3/top/x400/cpld/ip/clkctrl/.gitignore b/fpga/usrp3/top/x400/cpld/ip/clkctrl/.gitignore new file mode 100644 index 000000000..9776d9b81 --- /dev/null +++ b/fpga/usrp3/top/x400/cpld/ip/clkctrl/.gitignore @@ -0,0 +1,3 @@ +# generate files +clkctrl/ +clkctrl.sopcinfo
\ No newline at end of file diff --git a/fpga/usrp3/top/x400/cpld/ip/clkctrl/clkctrl.qsys b/fpga/usrp3/top/x400/cpld/ip/clkctrl/clkctrl.qsys new file mode 100644 index 000000000..b9fc219fa --- /dev/null +++ b/fpga/usrp3/top/x400/cpld/ip/clkctrl/clkctrl.qsys @@ -0,0 +1,73 @@ +<?xml version="1.0" encoding="UTF-8"?> +<system name="$${FILENAME}"> + <component + name="$${FILENAME}" + displayName="$${FILENAME}" + version="1.0" + description="" + tags="INTERNAL_COMPONENT=true" + categories="" /> + <parameter name="bonusData"><![CDATA[bonusData +{ + element altclkctrl_0 + { + datum _sortIndex + { + value = "0"; + type = "int"; + } + } +} +]]></parameter> + <parameter name="clockCrossingAdapter" value="HANDSHAKE" /> + <parameter name="device" value="10M04SAU169I7G" /> + <parameter name="deviceFamily" value="MAX 10" /> + <parameter name="deviceSpeedGrade" value="7" /> + <parameter name="fabricMode" value="QSYS" /> + <parameter name="generateLegacySim" value="false" /> + <parameter name="generationId" value="0" /> + <parameter name="globalResetBus" value="false" /> + <parameter name="hdlLanguage" value="VERILOG" /> + <parameter name="hideFromIPCatalog" value="true" /> + <parameter name="lockedInterfaceDefinition" value="" /> + <parameter name="maxAdditionalLatency" value="1" /> + <parameter name="projectName" value="" /> + <parameter name="sopcBorderPoints" value="false" /> + <parameter name="systemHash" value="0" /> + <parameter name="testBenchDutName" value="" /> + <parameter name="timeStamp" value="0" /> + <parameter name="useTestBenchNamingPattern" value="false" /> + <instanceScript></instanceScript> + <interface + name="altclkctrl_input" + internal="altclkctrl_0.altclkctrl_input" + type="conduit" + dir="end"> + <port name="inclk" internal="inclk" /> + <port name="ena" internal="ena" /> + </interface> + <interface + name="altclkctrl_output" + internal="altclkctrl_0.altclkctrl_output" + type="conduit" + dir="end"> + <port name="outclk" internal="outclk" /> + </interface> + <module + name="altclkctrl_0" + kind="altclkctrl" + version="18.1" + enabled="1" + autoexport="1"> + <parameter name="CLOCK_TYPE" value="1" /> + <parameter name="DEVICE_FAMILY" value="MAX 10" /> + <parameter name="ENA_REGISTER_MODE" value="1" /> + <parameter name="GUI_USE_ENA" value="true" /> + <parameter name="NUMBER_OF_CLOCKS" value="1" /> + <parameter name="USE_GLITCH_FREE_SWITCH_OVER_IMPLEMENTATION" value="false" /> + </module> + <interconnectRequirement for="$system" name="qsys_mm.clockCrossingAdapter" value="HANDSHAKE" /> + <interconnectRequirement for="$system" name="qsys_mm.enableEccProtection" value="FALSE" /> + <interconnectRequirement for="$system" name="qsys_mm.insertDefaultSlave" value="FALSE" /> + <interconnectRequirement for="$system" name="qsys_mm.maxAdditionalLatency" value="1" /> +</system> diff --git a/fpga/usrp3/top/x400/cpld/ip/cmi/.gitignore b/fpga/usrp3/top/x400/cpld/ip/cmi/.gitignore new file mode 100644 index 000000000..f479dbc97 --- /dev/null +++ b/fpga/usrp3/top/x400/cpld/ip/cmi/.gitignore @@ -0,0 +1,2 @@ +# GUI logfile +PcieCmi.qarlog diff --git a/fpga/usrp3/top/x400/cpld/ip/cmi/PcieCmi.qxp b/fpga/usrp3/top/x400/cpld/ip/cmi/PcieCmi.qxp Binary files differnew file mode 100644 index 000000000..c03dfd331 --- /dev/null +++ b/fpga/usrp3/top/x400/cpld/ip/cmi/PcieCmi.qxp diff --git a/fpga/usrp3/top/x400/cpld/ip/cmi/PcieCmi.vhd b/fpga/usrp3/top/x400/cpld/ip/cmi/PcieCmi.vhd new file mode 100644 index 000000000..8bd0fbb1b --- /dev/null +++ b/fpga/usrp3/top/x400/cpld/ip/cmi/PcieCmi.vhd @@ -0,0 +1,38 @@ +-- +-- Copyright 2021 Ettus Research, a National Instruments Brand +-- +-- SPDX-License-Identifier: LGPL-3.0-or-later +-- +-- Module: PcieCmi +-- +-- Description: +-- +-- This is an automatically generated file. +-- Do not modify this file directly! +-- + +library ieee; + use ieee.std_logic_1164.all; + use ieee.numeric_std.all; + +entity PcieCmi is + generic ( + kSimulation : natural := 0 + ); + port ( + Clk : in std_logic ; + acReset : in std_logic ; + cSerialNumber : in std_logic_vector (39 downto 0); + cBoardIsReady : in std_logic ; + cCmiReset : out std_logic ; + cOtherSideDetected : out std_logic ; + aCblPrsnt_n : in std_logic ; + aSdaIn : in std_logic ; + aSdaOut : out std_logic ; + aSclIn : in std_logic ; + aSclOut : out std_logic + ); +end entity PcieCmi; +architecture rtl of PcieCmi is +begin +end architecture rtl; diff --git a/fpga/usrp3/top/x400/cpld/ip/cmi/PcieCmiWrapper.vhd b/fpga/usrp3/top/x400/cpld/ip/cmi/PcieCmiWrapper.vhd new file mode 100644 index 000000000..2037d10ed --- /dev/null +++ b/fpga/usrp3/top/x400/cpld/ip/cmi/PcieCmiWrapper.vhd @@ -0,0 +1,93 @@ +-- +-- Copyright 2021 Ettus Research, a National Instruments Brand +-- +-- SPDX-License-Identifier: LGPL-3.0-or-later +-- +-- Module: PcieCmiWrapper +-- +-- Description: +-- +-- This is an automatically generated file. +-- Do not modify this file directly! +-- + + +library ieee; + use ieee.std_logic_1164.all; + use ieee.numeric_std.all; + +--synopsys translate_off +--For synthesis, netlist comes from an qxp and there is no external library +--For simulation in client, netlist comes from PcieCmiLib external library +--For simulation in dev branch, netlist comes from work library. +--Binding will work fine in both simulation cases as long as PcieCmi is compiled +-- to either library. In dev branch PcieCmiLib will be an empty library just so +-- ModelSim doesn't complain. +library PcieCmiLib; +--synopsys translate_on + +entity PcieCmiWrapper is + generic ( + kSimulation : natural := 0 -- set to 1 to speedup simulation + ); + port ( + Clk : in std_logic; -- 40 MHz clock + acReset : in std_logic; + + cSerialNumber : in std_logic_vector(39 downto 0); + cBoardIsReady : in std_logic; + cCmiReset : out std_logic; + cOtherSideDetected : out std_logic; + + aCblPrsnt_n : in std_logic; + + aSdaIn : in std_logic; + aSdaOut : out std_logic; + aSclIn : in std_logic; + aSclOut : out std_logic + ); +end PcieCmiWrapper; + +architecture rtl of PcieCmiWrapper is + + component PcieCmi + generic (kSimulation : natural := 0); + port ( + Clk : in std_logic; + acReset : in std_logic; + cSerialNumber : in std_logic_vector(39 downto 0); + cBoardIsReady : in std_logic; + cCmiReset : out std_logic; + cOtherSideDetected : out std_logic; + aCblPrsnt_n : in std_logic; + aSdaIn : in std_logic; + aSdaOut : out std_logic; + aSclIn : in std_logic; + aSclOut : out std_logic); + end component; + +begin + + -- Just forward all signals to lower level entity. + -- Leave the simulation generic in place as it important to be able to + -- simulate the netlist in reasonable time. For the synthesis in the client + -- the generic is ignored as the netlist is translated with kSimulation set to + -- default value and "overwrites" it. + + --vhook PcieCmi + PcieCmix: PcieCmi + generic map (kSimulation => kSimulation) --natural:=0 + port map ( + Clk => Clk, --in std_logic + acReset => acReset, --in std_logic + cSerialNumber => cSerialNumber, --in std_logic_vector(39:0) + cBoardIsReady => cBoardIsReady, --in std_logic + cCmiReset => cCmiReset, --out std_logic + cOtherSideDetected => cOtherSideDetected, --out std_logic + aCblPrsnt_n => aCblPrsnt_n, --in std_logic + aSdaIn => aSdaIn, --in std_logic + aSdaOut => aSdaOut, --out std_logic + aSclIn => aSclIn, --in std_logic + aSclOut => aSclOut); --out std_logic + +end architecture rtl;
\ No newline at end of file diff --git a/fpga/usrp3/top/x400/cpld/ip/flash/.gitignore b/fpga/usrp3/top/x400/cpld/ip/flash/.gitignore new file mode 100644 index 000000000..585bc126d --- /dev/null +++ b/fpga/usrp3/top/x400/cpld/ip/flash/.gitignore @@ -0,0 +1,3 @@ +# generate files +on_chip_flash/ +on_chip_flash.sopcinfo diff --git a/fpga/usrp3/top/x400/cpld/ip/flash/on_chip_flash.qsys b/fpga/usrp3/top/x400/cpld/ip/flash/on_chip_flash.qsys new file mode 100644 index 000000000..4cbe8726a --- /dev/null +++ b/fpga/usrp3/top/x400/cpld/ip/flash/on_chip_flash.qsys @@ -0,0 +1,90 @@ +<?xml version="1.0" encoding="UTF-8"?> +<system name="$${FILENAME}"> + <component + name="$${FILENAME}" + displayName="$${FILENAME}" + version="1.0" + description="" + tags="INTERNAL_COMPONENT=true" + categories="System" /> + <parameter name="bonusData"><![CDATA[bonusData +{ + element onchip_flash_0 + { + datum _sortIndex + { + value = "0"; + type = "int"; + } + } +} +]]></parameter> + <parameter name="clockCrossingAdapter" value="HANDSHAKE" /> + <parameter name="device" value="10M04SAU169I7G" /> + <parameter name="deviceFamily" value="MAX 10" /> + <parameter name="deviceSpeedGrade" value="7" /> + <parameter name="fabricMode" value="QSYS" /> + <parameter name="generateLegacySim" value="false" /> + <parameter name="generationId" value="0" /> + <parameter name="globalResetBus" value="false" /> + <parameter name="hdlLanguage" value="VERILOG" /> + <parameter name="hideFromIPCatalog" value="true" /> + <parameter name="lockedInterfaceDefinition" value="" /> + <parameter name="maxAdditionalLatency" value="1" /> + <parameter name="projectName" value="" /> + <parameter name="sopcBorderPoints" value="false" /> + <parameter name="systemHash" value="0" /> + <parameter name="testBenchDutName" value="" /> + <parameter name="timeStamp" value="0" /> + <parameter name="useTestBenchNamingPattern" value="false" /> + <instanceScript></instanceScript> + <interface name="clk" internal="onchip_flash_0.clk" type="clock" dir="end"> + <port name="clock" internal="clock" /> + </interface> + <interface name="csr" internal="onchip_flash_0.csr" type="avalon" dir="end"> + <port name="avmm_csr_addr" internal="avmm_csr_addr" /> + <port name="avmm_csr_read" internal="avmm_csr_read" /> + <port name="avmm_csr_writedata" internal="avmm_csr_writedata" /> + <port name="avmm_csr_write" internal="avmm_csr_write" /> + <port name="avmm_csr_readdata" internal="avmm_csr_readdata" /> + </interface> + <interface name="data" internal="onchip_flash_0.data" type="avalon" dir="end"> + <port name="avmm_data_addr" internal="avmm_data_addr" /> + <port name="avmm_data_read" internal="avmm_data_read" /> + <port name="avmm_data_writedata" internal="avmm_data_writedata" /> + <port name="avmm_data_write" internal="avmm_data_write" /> + <port name="avmm_data_readdata" internal="avmm_data_readdata" /> + <port name="avmm_data_waitrequest" internal="avmm_data_waitrequest" /> + <port name="avmm_data_readdatavalid" internal="avmm_data_readdatavalid" /> + <port name="avmm_data_burstcount" internal="avmm_data_burstcount" /> + </interface> + <interface name="nreset" internal="onchip_flash_0.nreset" type="reset" dir="end"> + <port name="reset_n" internal="reset_n" /> + </interface> + <module + name="onchip_flash_0" + kind="altera_onchip_flash" + version="18.1" + enabled="1" + autoexport="1"> + <parameter name="AUTO_CLOCK_RATE" value="0" /> + <parameter name="CLOCK_FREQUENCY" value="50.0" /> + <parameter name="CONFIGURATION_MODE">Single Compressed Image</parameter> + <parameter name="CONFIGURATION_SCHEME">Internal Configuration</parameter> + <parameter name="DATA_INTERFACE" value="Parallel" /> + <parameter name="DEVICE_FAMILY" value="MAX 10" /> + <parameter name="PART_NAME" value="10M04SAU169I7G" /> + <parameter name="READ_BURST_COUNT" value="8" /> + <parameter name="READ_BURST_MODE" value="Incrementing" /> + <parameter name="SECTOR_ACCESS_MODE">Read and write,Read and write,Read and write,Read and write,Read and write</parameter> + <parameter name="autoInitializationFileName">$${FILENAME}_onchip_flash_0</parameter> + <parameter name="initFlashContent" value="false" /> + <parameter name="initializationFileName">altera_onchip_flash.hex</parameter> + <parameter name="initializationFileNameForSim">altera_onchip_flash.dat</parameter> + <parameter name="useNonDefaultInitFile" value="false" /> + </module> + <interconnectRequirement for="$system" name="qsys_mm.clockCrossingAdapter" value="HANDSHAKE" /> + <interconnectRequirement for="$system" name="qsys_mm.enableEccProtection" value="FALSE" /> + <interconnectRequirement for="$system" name="qsys_mm.insertDefaultSlave" value="FALSE" /> + <interconnectRequirement for="$system" name="qsys_mm.maxAdditionalLatency" value="1" /> +</system> diff --git a/fpga/usrp3/top/x400/cpld/ip/oddr/oddr.qip b/fpga/usrp3/top/x400/cpld/ip/oddr/oddr.qip new file mode 100644 index 000000000..206cf7b45 --- /dev/null +++ b/fpga/usrp3/top/x400/cpld/ip/oddr/oddr.qip @@ -0,0 +1,74 @@ +set_global_assignment -entity "oddr" -library "oddr" -name IP_TOOL_NAME "altera_gpio_lite" +set_global_assignment -entity "oddr" -library "oddr" -name IP_TOOL_VERSION "20.1" +set_global_assignment -entity "oddr" -library "oddr" -name IP_TOOL_ENV "mwpim" +set_global_assignment -library "oddr" -name MISC_FILE [file join $::quartus(qip_path) "oddr.cmp"] +set_global_assignment -entity "oddr" -library "oddr" -name IP_TARGETED_DEVICE_FAMILY "MAX 10" +set_global_assignment -entity "oddr" -library "oddr" -name IP_GENERATED_DEVICE_FAMILY "{MAX 10}" +set_global_assignment -entity "oddr" -library "oddr" -name IP_QSYS_MODE "UNKNOWN" +set_global_assignment -name SYNTHESIS_ONLY_QIP ON +set_global_assignment -entity "oddr" -library "oddr" -name IP_COMPONENT_NAME "b2Rkcg==" +set_global_assignment -entity "oddr" -library "oddr" -name IP_COMPONENT_DISPLAY_NAME "R1BJTyBMaXRlIEludGVsIEZQR0EgSVA=" +set_global_assignment -entity "oddr" -library "oddr" -name IP_COMPONENT_REPORT_HIERARCHY "Off" +set_global_assignment -entity "oddr" -library "oddr" -name IP_COMPONENT_INTERNAL "Off" +set_global_assignment -entity "oddr" -library "oddr" -name IP_COMPONENT_AUTHOR "SW50ZWwgQ29ycG9yYXRpb24=" +set_global_assignment -entity "oddr" -library "oddr" -name IP_COMPONENT_VERSION "MjAuMQ==" +set_global_assignment -entity "oddr" -library "oddr" -name IP_COMPONENT_DESCRIPTION "R1BJTyBMaXRlIEludGVsIEZQR0EgSVA=" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_NAME "YWx0ZXJhX2dwaW9fbGl0ZQ==" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_DISPLAY_NAME "R1BJTyBMaXRlIEludGVsIEZQR0EgSVA=" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_REPORT_HIERARCHY "Off" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_INTERNAL "Off" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_AUTHOR "SW50ZWwgQ29ycG9yYXRpb24=" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_VERSION "MjAuMQ==" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_DESCRIPTION "R1BJTyBMaXRlIEludGVsIEZQR0EgSVA=" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "REVWSUNFX0ZBTUlMWQ==::TUFYIDEw::RGV2aWNlIGZhbWlseQ==" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "UElOX1RZUEU=::b3V0cHV0::RGF0YSBkaXJlY3Rpb24=" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "U0laRQ==::MQ==::RGF0YSB3aWR0aA==" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "Z3VpX3RydWVfZGlmZl9idWY=::ZmFsc2U=::VXNlIHRydWUgZGlmZmVyZW50aWFsIGJ1ZmZlcg==" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "Z3VpX3BzZXVkb19kaWZmX2J1Zg==::ZmFsc2U=::VXNlIHBzZXVkbyBkaWZmZXJlbnRpYWwgYnVmZmVy" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "Z3VpX2J1c19ob2xk::ZmFsc2U=::VXNlIGJ1cy1ob2xkIGNpcmN1aXRyeQ==" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "Z3VpX29wZW5fZHJhaW4=::ZmFsc2U=::VXNlIG9wZW4gZHJhaW4gb3V0cHV0" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "Z3VpX2VuYWJsZV9vZV9wb3J0::ZmFsc2U=::RW5hYmxlIG9lIHBvcnQ=" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "Z3VpX2lvX3JlZ19tb2Rl::ZGRy::UmVnaXN0ZXIgbW9kZQ==" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "Z3VpX2VuYWJsZV9hY2xyX3BvcnQ=::dHJ1ZQ==::RW5hYmxlIGFjbHIgcG9ydA==" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "Z3VpX2Nsb2NrX2VuYWJsZQ==::ZmFsc2U=::RW5hYmxlIGluY2xvY2tlbi9vdXRjbG9ja2VuIHBvcnRz" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "Z3VpX2ludmVydF9vdXRwdXQ=::ZmFsc2U=::SW52ZXJ0IGRpbg==" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "Z3VpX3VzZV9yZWdpc3Rlcl90b19kcml2ZV9vYnVmX29l::ZmFsc2U=::VXNlIGEgc2luZ2xlIHJlZ2lzdGVyIHRvIGRyaXZlIHRoZSBvdXRwdXQgZW5hYmxlIChvZSkgc2lnbmFsIGF0IHRoZSBJL08gYnVmZmVy" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "Z3VpX3VzZV9kZGlvX3JlZ190b19kcml2ZV9vZQ==::ZmFsc2U=::VXNlIERESU8gcmVnaXN0ZXJzIHRvIGRyaXZlIHRoZSBvdXRwdXQgZW5hYmxlIChvZSkgc2lnbmFsIGF0IHRoZSBJL08gYnVmZmVy" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "Z3VpX3VzZV9hZHZhbmNlZF9kZHJfZmVhdHVyZXM=::ZmFsc2U=::RW5hYmxlIGFkdmFuY2VkIEREUiBmZWF0dXJlcw==" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "Z3VpX2VuYWJsZV9waGFzZV9kZXRlY3Rvcl9mb3JfY2s=::ZmFsc2U=::RW5hYmxlIFBoYXNlIERldGVjdG9yIGZyb20gQ0sgbG9vcGJhY2sgc2lnbmFs" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "Z3VpX2VuYWJsZV9vZV9oYWxmX2N5Y2xlX2RlbGF5::dHJ1ZQ==::QWRkIGhhbGYtY3ljbGUgZGVsYXkgdG8gT0Ugc2lnbmFs" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "Z3VpX2VuYWJsZV9ocl9jbG9jaw==::ZmFsc2U=::RW5hYmxlIGhhbGYtcmF0ZSBjbG9jayBwb3J0" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "Z3VpX2VuYWJsZV9pbnZlcnRfaHJfY2xvY2tfcG9ydA==::ZmFsc2U=::RW5hYmxlIGludmVydF9ocl9jbG9jayBwb3J0" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "Z3VpX2ludmVydF9jbGtkaXZfaW5wdXRfY2xvY2s=::ZmFsc2U=::SW52ZXJ0IGNsb2NrIGRpdmlkZXIgaW5wdXQgY2xvY2s=" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "Z3VpX2ludmVydF9vdXRwdXRfY2xvY2s=::ZmFsc2U=::SW52ZXJ0IERESU8gb3V0Y2xvY2s=" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "Z3VpX2ludmVydF9vZV9pbmNsb2Nr::ZmFsc2U=::SW52ZXJ0IG91dHB1dCBlbmFibGUgKG9lKSByZWdpc3RlciBpbmNsb2Nr" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "UkVHSVNURVJfTU9ERQ==::ZGRy::UkVHSVNURVJfTU9ERQ==" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "QlVGRkVSX1RZUEU=::c2luZ2xlLWVuZGVk::QlVGRkVSX1RZUEU=" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "QVNZTkNfTU9ERQ==::Y2xlYXI=::QVNZTkNfTU9ERQ==" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "U1lOQ19NT0RF::bm9uZQ==::U1lOQ19NT0RF" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "QlVTX0hPTEQ=::ZmFsc2U=::QlVTX0hPTEQ=" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "T1BFTl9EUkFJTl9PVVRQVVQ=::ZmFsc2U=::T1BFTl9EUkFJTl9PVVRQVVQ=" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "RU5BQkxFX09FX1BPUlQ=::ZmFsc2U=::RU5BQkxFX09FX1BPUlQ=" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "RU5BQkxFX05TTEVFUF9QT1JU::ZmFsc2U=::RU5BQkxFX05TTEVFUF9QT1JU" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "RU5BQkxFX0NMT0NLX0VOQV9QT1JU::ZmFsc2U=::RU5BQkxFX0NMT0NLX0VOQV9QT1JU" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "U0VUX1JFR0lTVEVSX09VVFBVVFNfSElHSA==::ZmFsc2U=::U0VUX1JFR0lTVEVSX09VVFBVVFNfSElHSA==" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "SU5WRVJUX09VVFBVVA==::ZmFsc2U=::SU5WRVJUX09VVFBVVA==" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "SU5WRVJUX0lOUFVUX0NMT0NL::ZmFsc2U=::SU5WRVJUX0lOUFVUX0NMT0NL" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "VVNFX09ORV9SRUdfVE9fRFJJVkVfT0U=::ZmFsc2U=::VVNFX09ORV9SRUdfVE9fRFJJVkVfT0U=" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "VVNFX0RESU9fUkVHX1RPX0RSSVZFX09F::ZmFsc2U=::VVNFX0RESU9fUkVHX1RPX0RSSVZFX09F" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "VVNFX0FEVkFOQ0VEX0REUl9GRUFUVVJFUw==::ZmFsc2U=::VVNFX0FEVkFOQ0VEX0REUl9GRUFUVVJFUw==" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "VVNFX0FEVkFOQ0VEX0REUl9GRUFUVVJFU19GT1JfSU5QVVRfT05MWQ==::ZmFsc2U=::VVNFX0FEVkFOQ0VEX0REUl9GRUFUVVJFU19GT1JfSU5QVVRfT05MWQ==" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "RU5BQkxFX09FX0hBTEZfQ1lDTEVfREVMQVk=::dHJ1ZQ==::RU5BQkxFX09FX0hBTEZfQ1lDTEVfREVMQVk=" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "SU5WRVJUX0NMS0RJVl9JTlBVVF9DTE9DSw==::ZmFsc2U=::SU5WRVJUX0NMS0RJVl9JTlBVVF9DTE9DSw==" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "RU5BQkxFX1BIQVNFX0lOVkVSVF9DVFJMX1BPUlQ=::ZmFsc2U=::RU5BQkxFX1BIQVNFX0lOVkVSVF9DVFJMX1BPUlQ=" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "RU5BQkxFX0hSX0NMT0NL::ZmFsc2U=::RU5BQkxFX0hSX0NMT0NL" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "SU5WRVJUX09VVFBVVF9DTE9DSw==::ZmFsc2U=::SU5WRVJUX09VVFBVVF9DTE9DSw==" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "SU5WRVJUX09FX0lOQ0xPQ0s=::ZmFsc2U=::SU5WRVJUX09FX0lOQ0xPQ0s=" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "RU5BQkxFX1BIQVNFX0RFVEVDVE9SX0ZPUl9DSw==::ZmFsc2U=::RU5BQkxFX1BIQVNFX0RFVEVDVE9SX0ZPUl9DSw==" + +set_global_assignment -library "oddr" -name VERILOG_FILE [file join $::quartus(qip_path) "oddr.v"] +set_global_assignment -library "oddr" -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) "oddr/altera_gpio_lite.sv"] + +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_TOOL_NAME "altera_gpio_lite" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_TOOL_VERSION "20.1" +set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_TOOL_ENV "mwpim" diff --git a/fpga/usrp3/top/x400/cpld/ip/oddr/oddr.v b/fpga/usrp3/top/x400/cpld/ip/oddr/oddr.v new file mode 100644 index 000000000..7888cbcf5 --- /dev/null +++ b/fpga/usrp3/top/x400/cpld/ip/oddr/oddr.v @@ -0,0 +1,124 @@ +// megafunction wizard: %GPIO Lite Intel FPGA IP v20.1% +// GENERATION: XML +// oddr.v + +// Generated using ACDS version 20.1 711 + +`timescale 1 ps / 1 ps +module oddr ( + input wire outclock, // outclock.export + input wire [1:0] din, // din.export + output wire [0:0] pad_out, // pad_out.export + input wire aclr // aclr.export + ); + + altera_gpio_lite #( + .PIN_TYPE ("output"), + .SIZE (1), + .REGISTER_MODE ("ddr"), + .BUFFER_TYPE ("single-ended"), + .ASYNC_MODE ("clear"), + .SYNC_MODE ("none"), + .BUS_HOLD ("false"), + .OPEN_DRAIN_OUTPUT ("false"), + .ENABLE_OE_PORT ("false"), + .ENABLE_NSLEEP_PORT ("false"), + .ENABLE_CLOCK_ENA_PORT ("false"), + .SET_REGISTER_OUTPUTS_HIGH ("false"), + .INVERT_OUTPUT ("false"), + .INVERT_INPUT_CLOCK ("false"), + .USE_ONE_REG_TO_DRIVE_OE ("false"), + .USE_DDIO_REG_TO_DRIVE_OE ("false"), + .USE_ADVANCED_DDR_FEATURES ("false"), + .USE_ADVANCED_DDR_FEATURES_FOR_INPUT_ONLY ("false"), + .ENABLE_OE_HALF_CYCLE_DELAY ("true"), + .INVERT_CLKDIV_INPUT_CLOCK ("false"), + .ENABLE_PHASE_INVERT_CTRL_PORT ("false"), + .ENABLE_HR_CLOCK ("false"), + .INVERT_OUTPUT_CLOCK ("false"), + .INVERT_OE_INCLOCK ("false"), + .ENABLE_PHASE_DETECTOR_FOR_CK ("false") + ) oddr_inst ( + .outclock (outclock), // outclock.export + .din (din), // din.export + .pad_out (pad_out), // pad_out.export + .aclr (aclr), // aclr.export + .outclocken (1'b1), // (terminated) + .inclock (1'b0), // (terminated) + .inclocken (1'b0), // (terminated) + .fr_clock (), // (terminated) + .hr_clock (), // (terminated) + .invert_hr_clock (1'b0), // (terminated) + .phy_mem_clock (1'b0), // (terminated) + .mimic_clock (), // (terminated) + .dout (), // (terminated) + .pad_io (), // (terminated) + .pad_io_b (), // (terminated) + .pad_in (1'b0), // (terminated) + .pad_in_b (1'b0), // (terminated) + .pad_out_b (), // (terminated) + .aset (1'b0), // (terminated) + .sclr (1'b0), // (terminated) + .nsleep (1'b0), // (terminated) + .oe (1'b0) // (terminated) + ); + +endmodule +// Retrieval info: <?xml version="1.0"?> +//<!-- +// Generated by Altera MegaWizard Launcher Utility version 1.0 +// ************************************************************ +// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! +// ************************************************************ +// Copyright (C) 1991-2020 Altera Corporation +// Any megafunction design, and related net list (encrypted or decrypted), +// support information, device programming or simulation file, and any other +// associated documentation or information provided by Altera or a partner +// under Altera's Megafunction Partnership Program may be used only to +// program PLD devices (but not masked PLD devices) from Altera. Any other +// use of such megafunction design, net list, support information, device +// programming or simulation file, or any other related documentation or +// information is prohibited for any other purpose, including, but not +// limited to modification, reverse engineering, de-compiling, or use with +// any other silicon devices, unless such use is explicitly licensed under +// a separate agreement with Altera or a megafunction partner. Title to +// the intellectual property, including patents, copyrights, trademarks, +// trade secrets, or maskworks, embodied in any such megafunction design, +// net list, support information, device programming or simulation file, or +// any other related documentation or information provided by Altera or a +// megafunction partner, remains with Altera, the megafunction partner, or +// their respective licensors. No other licenses, including any licenses +// needed under any third party's intellectual property, are provided herein. +//--> +// Retrieval info: <instance entity-name="altera_gpio_lite" version="20.1" > +// Retrieval info: <generic name="DEVICE_FAMILY" value="MAX 10" /> +// Retrieval info: <generic name="PIN_TYPE" value="output" /> +// Retrieval info: <generic name="SIZE" value="1" /> +// Retrieval info: <generic name="gui_true_diff_buf" value="false" /> +// Retrieval info: <generic name="gui_pseudo_diff_buf" value="false" /> +// Retrieval info: <generic name="gui_bus_hold" value="false" /> +// Retrieval info: <generic name="gui_open_drain" value="false" /> +// Retrieval info: <generic name="gui_enable_oe_port" value="false" /> +// Retrieval info: <generic name="gui_enable_nsleep_port" value="false" /> +// Retrieval info: <generic name="gui_io_reg_mode" value="ddr" /> +// Retrieval info: <generic name="gui_enable_aclr_port" value="true" /> +// Retrieval info: <generic name="gui_enable_aset_port" value="false" /> +// Retrieval info: <generic name="gui_enable_sclr_port" value="false" /> +// Retrieval info: <generic name="gui_set_registers_to_power_up_high" value="false" /> +// Retrieval info: <generic name="gui_clock_enable" value="false" /> +// Retrieval info: <generic name="gui_invert_output" value="false" /> +// Retrieval info: <generic name="gui_invert_input_clock" value="false" /> +// Retrieval info: <generic name="gui_use_register_to_drive_obuf_oe" value="false" /> +// Retrieval info: <generic name="gui_use_ddio_reg_to_drive_oe" value="false" /> +// Retrieval info: <generic name="gui_use_advanced_ddr_features" value="false" /> +// Retrieval info: <generic name="gui_enable_phase_detector_for_ck" value="false" /> +// Retrieval info: <generic name="gui_enable_oe_half_cycle_delay" value="true" /> +// Retrieval info: <generic name="gui_enable_hr_clock" value="false" /> +// Retrieval info: <generic name="gui_enable_invert_hr_clock_port" value="false" /> +// Retrieval info: <generic name="gui_invert_clkdiv_input_clock" value="false" /> +// Retrieval info: <generic name="gui_invert_output_clock" value="false" /> +// Retrieval info: <generic name="gui_invert_oe_inclock" value="false" /> +// Retrieval info: <generic name="gui_use_hardened_ddio_input_registers" value="false" /> +// Retrieval info: </instance> +// IPFS_FILES : oddr.vo +// RELATED_FILES: oddr.v, altera_gpio_lite.sv diff --git a/fpga/usrp3/top/x400/cpld/ip/oddr/oddr/altera_gpio_lite.sv b/fpga/usrp3/top/x400/cpld/ip/oddr/oddr/altera_gpio_lite.sv new file mode 100644 index 000000000..7db369453 --- /dev/null +++ b/fpga/usrp3/top/x400/cpld/ip/oddr/oddr/altera_gpio_lite.sv @@ -0,0 +1,1200 @@ +// (C) 2001-2020 Intel Corporation. All rights reserved. +// Your use of Intel Corporation's design tools, logic functions and other +// software and tools, and its AMPP partner logic functions, and any output +// files from any of the foregoing (including device programming or simulation +// files), and any associated documentation or information are expressly subject +// to the terms and conditions of the Intel Program License Subscription +// Agreement, Intel FPGA IP License Agreement, or other applicable +// license agreement, including, without limitation, that your use is for the +// sole purpose of programming logic devices manufactured by Intel and sold by +// Intel or its authorized distributors. Please refer to the applicable +// agreement for further details. + + +`timescale 1 ps / 1 ps + +module altgpio_one_bit( + inclock, + outclock, + phy_mem_clock, + inclocken, + outclocken, + oe, + din, + dout, + pad, + pad_b, + aset, + sclr, + hr_clock, + fr_clock, + mimic_clock, + nsleep +); + + parameter PIN_TYPE = "output"; + parameter BUFFER_TYPE = "single-ended"; + parameter REGISTER_MODE = "bypass"; + parameter ASYNC_MODE = "none"; + parameter SYNC_MODE = "none"; + parameter BUS_HOLD = "false"; + parameter SET_REGISTER_OUTPUTS_HIGH = "false"; + parameter USE_ENHANCED_DDR_HIO_REGISTER = "false"; + parameter BYPASS_THREE_QUARTER_REGISTER = "true"; + parameter INVERT_OUTPUT = "false"; + parameter INVERT_INPUT_CLOCK = "false"; + parameter INVERT_OUTPUT_CLOCK = "false"; + parameter INVERT_OE_INCLOCK = "false"; + parameter USE_ONE_REG_TO_DRIVE_OE = "false"; + parameter USE_DDIO_REG_TO_DRIVE_OE = "false"; + parameter OPEN_DRAIN_OUTPUT = "false"; + parameter ENABLE_OE_HALF_CYCLE_DELAY = "true"; + parameter USE_ADVANCED_DDR_FEATURES_FOR_INPUT_ONLY = "false"; + parameter ENABLE_CLOCK_ENA_PORT = "false"; + parameter ENABLE_HR_CLOCK = "false"; + parameter ENABLE_PHASE_DETECTOR_FOR_CK = "false"; + parameter ENABLE_NSLEEP_PORT = "false"; + + localparam DATA_SIZE = (REGISTER_MODE == "ddr") ? 2:1; + localparam DDIO_REG_POWER_UP = (ASYNC_MODE == "preset" || SET_REGISTER_OUTPUTS_HIGH == "true") ? "high" : "low"; + + input inclock; + input outclock; + input inclocken; + input outclocken; + input oe; + input nsleep; + input [DATA_SIZE - 1:0] din; + output [DATA_SIZE - 1:0] dout; + inout pad; + inout pad_b; + input aset; + input sclr; + input phy_mem_clock; + input hr_clock; + (* altera_attribute = "-name GLOBAL_SIGNAL\"OFF\"" *) output fr_clock; + output mimic_clock; + + wire din_ddr; + wire buf_in; + + wire oe_out; + wire nsleep_in; + + generate + if (PIN_TYPE == "output" || PIN_TYPE == "bidir") + begin + wire [1:0] din_fr; + if (INVERT_OUTPUT == "false") + begin + assign din_fr = din; + end + else + begin + assign din_fr = ~din; + end + + wire outclock_wire; + if (REGISTER_MODE != "bypass") + begin + if (INVERT_OUTPUT_CLOCK == "false") + begin: normal_input_clock + assign outclock_wire = outclock; + end + else + begin: inverted_output_clock + assign outclock_wire = ~outclock; + end + end + + wire outclocken_wire; + assign outclocken_wire = (ENABLE_CLOCK_ENA_PORT == "true") ? outclocken : 1'b1; + + if (REGISTER_MODE == "ddr" && USE_ENHANCED_DDR_HIO_REGISTER == "true") + begin + if (ASYNC_MODE != "none") + begin: async_mode_out_path_enhanced_ddr + fiftyfivenm_ddio_out + #( + .async_mode(ASYNC_MODE), + .sync_mode(SYNC_MODE), + .use_enhanced_ddr_hio(USE_ENHANCED_DDR_HIO_REGISTER), + .bypass_three_quarter_register(BYPASS_THREE_QUARTER_REGISTER), + .power_up(DDIO_REG_POWER_UP), + .use_new_clocking_model("true") + ) fr_out_data_ddio ( + .datainhi(din_fr[0]), + .datainlo(din_fr[1]), + .dataout(din_ddr), + .clkhi(outclock_wire), + .clklo(outclock_wire), + .muxsel(outclock_wire), + .areset(aset), + .ena(outclocken_wire), + .phymemclock(phy_mem_clock) + `ifndef ALTERA_RESERVED_QIS + , + .clk (outclock_wire), + .sreset(1'b0), + .dfflo(), + .dffhi(), + .devpor(1'b1), + .devclrn(1'b1) + `endif + ); + end + else if (SYNC_MODE != "none") + begin: sync_mode_out_path_enhanced_ddr + fiftyfivenm_ddio_out + #( + .async_mode(ASYNC_MODE), + .sync_mode(SYNC_MODE), + .use_enhanced_ddr_hio(USE_ENHANCED_DDR_HIO_REGISTER), + .bypass_three_quarter_register(BYPASS_THREE_QUARTER_REGISTER), + .power_up(DDIO_REG_POWER_UP), + .use_new_clocking_model("true") + ) fr_out_data_ddio ( + .datainhi(din_fr[0]), + .datainlo(din_fr[1]), + .dataout(din_ddr), + .clkhi(outclock_wire), + .clklo(outclock_wire), + .muxsel(outclock_wire), + .sreset(sclr), + .ena(outclocken_wire), + .phymemclock(phy_mem_clock) + `ifndef ALTERA_RESERVED_QIS + , + .clk (outclock_wire), + .areset(1'b0), + .dfflo(), + .dffhi(), + .devpor(1'b1), + .devclrn(1'b1) + `endif + ); + end + else + begin: out_path_enhanced_ddr + fiftyfivenm_ddio_out + #( + .async_mode(ASYNC_MODE), + .sync_mode(SYNC_MODE), + .use_enhanced_ddr_hio(USE_ENHANCED_DDR_HIO_REGISTER), + .bypass_three_quarter_register(BYPASS_THREE_QUARTER_REGISTER), + .power_up(DDIO_REG_POWER_UP), + .use_new_clocking_model("true") + ) fr_out_data_ddio ( + .datainhi(din_fr[0]), + .datainlo(din_fr[1]), + .dataout(din_ddr), + .clkhi(outclock_wire), + .clklo(outclock_wire), + .muxsel(outclock_wire), + .ena(outclocken_wire), + .phymemclock(phy_mem_clock) + `ifndef ALTERA_RESERVED_QIS + , + .areset(1'b0), + .clk(1'b0), + .sreset(1'b0), + .dfflo(), + .dffhi(), + .devpor(1'b1), + .devclrn(1'b1) + `endif + ); + end + end + else if (REGISTER_MODE == "ddr" && USE_ENHANCED_DDR_HIO_REGISTER == "false") + begin + if (ASYNC_MODE != "none") + begin: async_mode_out_path_ddr + fiftyfivenm_ddio_out + #( + .async_mode(ASYNC_MODE), + .sync_mode(SYNC_MODE), + .power_up(DDIO_REG_POWER_UP), + .use_new_clocking_model("true"), + .bypass_three_quarter_register(BYPASS_THREE_QUARTER_REGISTER) + ) fr_out_data_ddio ( + .datainhi(din_fr[0]), + .datainlo(din_fr[1]), + .dataout(din_ddr), + .clkhi(outclock_wire), + .clklo(outclock_wire), + .muxsel(outclock_wire), + .areset(aset), + .ena(outclocken_wire) + `ifndef ALTERA_RESERVED_QIS + , + .clk(1'b0), + .phymemclock(1'b0), + .sreset(1'b0), + .dfflo(), + .dffhi(), + .devpor(1'b1), + .devclrn(1'b1) + `endif + ); + end + else if (SYNC_MODE != "none") + begin: sync_mode_out_path_ddr + fiftyfivenm_ddio_out + #( + .async_mode(ASYNC_MODE), + .sync_mode(SYNC_MODE), + .power_up(DDIO_REG_POWER_UP), + .use_new_clocking_model("true"), + .bypass_three_quarter_register(BYPASS_THREE_QUARTER_REGISTER) + ) fr_out_data_ddio ( + .datainhi(din_fr[0]), + .datainlo(din_fr[1]), + .dataout(din_ddr), + .clkhi(outclock_wire), + .clklo(outclock_wire), + .muxsel(outclock_wire), + .sreset(sclr), + .ena(outclocken_wire) + `ifndef ALTERA_RESERVED_QIS + , + .areset(1'b0), + .clk(1'b0), + .phymemclock(1'b0), + .dfflo(), + .dffhi(), + .devpor(1'b1), + .devclrn(1'b1) + `endif + ); + end + else + begin: out_path_ddr + fiftyfivenm_ddio_out + #( + .async_mode(ASYNC_MODE), + .sync_mode(SYNC_MODE), + .power_up(DDIO_REG_POWER_UP), + .use_new_clocking_model("true"), + .bypass_three_quarter_register(BYPASS_THREE_QUARTER_REGISTER) + ) fr_out_data_ddio ( + .datainhi(din_fr[0]), + .datainlo(din_fr[1]), + .dataout(din_ddr), + .clkhi(outclock_wire), + .clklo(outclock_wire), + .muxsel(outclock_wire), + .ena(outclocken_wire) + `ifndef ALTERA_RESERVED_QIS + , + .areset(1'b0), + .clk(1'b0), + .phymemclock(1'b0), + .sreset(1'b0), + .dfflo(), + .dffhi(), + .devpor(1'b1), + .devclrn(1'b1) + `endif + ); + end + end + else if (REGISTER_MODE == "single-register") + begin: out_path_sdr + reg reg_data_out /* synthesis altera_attribute="FAST_OUTPUT_REGISTER=on" */; + always @(posedge outclock_wire) + reg_data_out <= din_fr[0]; + + assign din_ddr = reg_data_out; + end + else + begin: out_path_reg_none + assign din_ddr = din_fr[0]; + end + end + endgenerate + + generate + + if (PIN_TYPE == "bidir" || PIN_TYPE == "output") + begin + wire oe_inclk_wire; + if (USE_ONE_REG_TO_DRIVE_OE == "true" || USE_DDIO_REG_TO_DRIVE_OE == "true") + begin + if (INVERT_OE_INCLOCK == "false") + begin: normal_oe_inclock + assign oe_inclk_wire = outclock; + end + else + begin: inverted_oe_inclock + assign oe_inclk_wire = ~outclock; + end + end + + wire oe_outclocken_wire; + assign oe_outclocken_wire = (ENABLE_CLOCK_ENA_PORT == "true") ? outclocken : 1'b1; + + if (USE_DDIO_REG_TO_DRIVE_OE == "true") + begin + if (REGISTER_MODE == "ddr" && USE_ENHANCED_DDR_HIO_REGISTER == "true") + begin + if (ASYNC_MODE != "none") + begin: async_mode_oe_path_enhanced_ddr + fiftyfivenm_ddio_oe + #( + .async_mode(ASYNC_MODE), + .sync_mode(SYNC_MODE), + .use_enhanced_ddr_hio(USE_ENHANCED_DDR_HIO_REGISTER), + .bypass_three_quarter_register(BYPASS_THREE_QUARTER_REGISTER), + .enable_half_cycle_delay(ENABLE_OE_HALF_CYCLE_DELAY), + .power_up(DDIO_REG_POWER_UP) + ) fr_oe_data_ddio ( + .oe(~oe), + .dataout(oe_out), + .clk(oe_inclk_wire), + .areset(aset), + .ena(oe_outclocken_wire), + .phymemclock(phy_mem_clock) + `ifndef ALTERA_RESERVED_QIS + , + .sreset(1'b0), + .dfflo(), + .dffhi(), + .devpor(1'b1), + .devclrn(1'b1) + `endif + ); + end + else if (SYNC_MODE != "none") + begin: sync_mode_oe_path_enhanced_ddr + fiftyfivenm_ddio_oe + #( + .async_mode(ASYNC_MODE), + .sync_mode(SYNC_MODE), + .use_enhanced_ddr_hio(USE_ENHANCED_DDR_HIO_REGISTER), + .bypass_three_quarter_register(BYPASS_THREE_QUARTER_REGISTER), + .enable_half_cycle_delay(ENABLE_OE_HALF_CYCLE_DELAY), + .power_up(DDIO_REG_POWER_UP) + ) fr_oe_data_ddio ( + .oe(~oe), + .dataout(oe_out), + .clk(oe_inclk_wire), + .sreset(sclr), + .ena(oe_outclocken_wire), + .phymemclock(phy_mem_clock) + `ifndef ALTERA_RESERVED_QIS + , + .areset(1'b0), + .dfflo(), + .dffhi(), + .devpor(1'b1), + .devclrn(1'b1) + `endif + ); + end + else + begin: oe_path_enhanced_ddr + fiftyfivenm_ddio_oe + #( + .async_mode(ASYNC_MODE), + .sync_mode(SYNC_MODE), + .use_enhanced_ddr_hio(USE_ENHANCED_DDR_HIO_REGISTER), + .bypass_three_quarter_register(BYPASS_THREE_QUARTER_REGISTER), + .enable_half_cycle_delay(ENABLE_OE_HALF_CYCLE_DELAY), + .power_up(DDIO_REG_POWER_UP) + ) fr_oe_data_ddio ( + .oe(~oe), + .dataout(oe_out), + .clk(oe_inclk_wire), + .ena(oe_outclocken_wire), + .phymemclock(phy_mem_clock) + `ifndef ALTERA_RESERVED_QIS + , + .areset(1'b0), + .sreset(1'b0), + .dfflo(), + .dffhi(), + .devpor(1'b1), + .devclrn(1'b1) + `endif + ); + end + end + else if (REGISTER_MODE == "ddr" && USE_ENHANCED_DDR_HIO_REGISTER == "false") + begin + if (ASYNC_MODE != "none") + begin: async_mode_oe_path_ddr + fiftyfivenm_ddio_oe + #( + .async_mode(ASYNC_MODE), + .sync_mode(SYNC_MODE), + .enable_half_cycle_delay(ENABLE_OE_HALF_CYCLE_DELAY), + .power_up(DDIO_REG_POWER_UP), + .bypass_three_quarter_register(BYPASS_THREE_QUARTER_REGISTER) + ) fr_oe_data_ddio ( + .oe(~oe), + .dataout(oe_out), + .clk(oe_inclk_wire), + .areset(aset), + .ena(oe_outclocken_wire) + `ifndef ALTERA_RESERVED_QIS + , + .phymemclock(1'b0), + .sreset(1'b0), + .dfflo(), + .dffhi(), + .devpor(1'b1), + .devclrn(1'b1) + `endif + ); + end + else if (SYNC_MODE != "none") + begin: sync_mode_oe_path_ddr + fiftyfivenm_ddio_oe + #( + .async_mode(ASYNC_MODE), + .sync_mode(SYNC_MODE), + .enable_half_cycle_delay(ENABLE_OE_HALF_CYCLE_DELAY), + .power_up(DDIO_REG_POWER_UP), + .bypass_three_quarter_register(BYPASS_THREE_QUARTER_REGISTER) + ) fr_oe_data_ddio ( + .oe(~oe), + .dataout(oe_out), + .clk(oe_inclk_wire), + .sreset(sclr), + .ena(oe_outclocken_wire) + `ifndef ALTERA_RESERVED_QIS + , + .areset(1'b0), + .phymemclock(1'b0), + .dfflo(), + .dffhi(), + .devpor(1'b1), + .devclrn(1'b1) + `endif + ); + end + else + begin: oe_path_ddr + fiftyfivenm_ddio_oe + #( + .async_mode(ASYNC_MODE), + .sync_mode(SYNC_MODE), + .enable_half_cycle_delay(ENABLE_OE_HALF_CYCLE_DELAY), + .power_up(DDIO_REG_POWER_UP), + .bypass_three_quarter_register(BYPASS_THREE_QUARTER_REGISTER) + ) fr_oe_data_ddio ( + .oe(~oe), + .dataout(oe_out), + .clk(oe_inclk_wire), + .ena(oe_outclocken_wire) + `ifndef ALTERA_RESERVED_QIS + , + .areset(1'b0), + .phymemclock(1'b0), + .sreset(1'b0), + .dfflo(), + .dffhi(), + .devpor(1'b1), + .devclrn(1'b1) + `endif + ); + end + end + end + else if (USE_ONE_REG_TO_DRIVE_OE == "true") + begin: oe_path_sdr + fiftyfivenm_ff oe_reg ( + .clk(oe_inclk_wire), + .d(~oe), + .clrn(1'b1), + .ena(1'b1), + .q(oe_out) + ); + end + else if (USE_ONE_REG_TO_DRIVE_OE == "false" && USE_DDIO_REG_TO_DRIVE_OE == "false") + begin: oe_path_reg_none + assign oe_out = ~oe; + end + end + endgenerate + + generate + if (PIN_TYPE == "input" || PIN_TYPE == "bidir") + begin + wire [1:0] ddr_input; + wire inclock_wire; + + if (REGISTER_MODE != "bypass") + begin + if (INVERT_INPUT_CLOCK == "false") + begin: normal_input_clock + assign inclock_wire = inclock; + end + else + begin: inverted_input_clock + assign inclock_wire = ~inclock; + end + end + + wire inclocken_wire; + assign inclocken_wire = (ENABLE_CLOCK_ENA_PORT == "true") ? inclocken : 1'b1; + + if (REGISTER_MODE == "ddr") + begin + if (USE_ENHANCED_DDR_HIO_REGISTER == "true" || USE_ADVANCED_DDR_FEATURES_FOR_INPUT_ONLY == "true") + begin + if (ENABLE_HR_CLOCK == "true") + begin + if (ASYNC_MODE != "none") + begin: async_mode_in_path_enhanced_ddr_with_halfrateresyncclk + fiftyfivenm_ddio_in + #( + .async_mode(ASYNC_MODE), + .sync_mode(SYNC_MODE), + .power_up(DDIO_REG_POWER_UP), + .invert_input_clock(INVERT_INPUT_CLOCK) + ) fr_in_ddio ( + .datain(buf_in), + .clk(inclock_wire), + .ena(inclocken_wire), + .halfrateresyncclk(hr_clock), + .regouthi(ddr_input[1]), + .regoutlo(ddr_input[0]), + .clkout(fr_clock), + .areset(aset) + `ifndef ALTERA_RESERVED_QIS + , + .sreset(1'b0), + .dfflo(), + .devpor(1'b1), + .devclrn(1'b1) + `endif + ); + end + else if (SYNC_MODE != "none") + begin:sync_mode_in_path_enhanced_ddr_with_halfrateresyncclk + fiftyfivenm_ddio_in + #( + .async_mode(ASYNC_MODE), + .sync_mode(SYNC_MODE), + .power_up(DDIO_REG_POWER_UP), + .invert_input_clock(INVERT_INPUT_CLOCK) + ) fr_in_ddio ( + .datain(buf_in), + .clk (inclock_wire), + .ena(inclocken_wire), + .sreset(sclr), + .halfrateresyncclk(hr_clock), + .regouthi(ddr_input[1]), + .regoutlo(ddr_input[0]), + .clkout(fr_clock) + `ifndef ALTERA_RESERVED_QIS + , + .areset(1'b0), + .dfflo(), + .devpor(1'b1), + .devclrn(1'b1) + `endif + ); + end + else + begin:in_path_enhanced_ddr_with_halfrateresyncclk + fiftyfivenm_ddio_in + #( + .async_mode(ASYNC_MODE), + .sync_mode(SYNC_MODE), + .power_up(DDIO_REG_POWER_UP), + .invert_input_clock(INVERT_INPUT_CLOCK) + ) fr_in_ddio ( + .datain(buf_in), + .clk (inclock_wire), + .ena(inclocken_wire), + .halfrateresyncclk(hr_clock), + .regouthi(ddr_input[1]), + .regoutlo(ddr_input[0]), + .clkout(fr_clock) + `ifndef ALTERA_RESERVED_QIS + , + .sreset(1'b0), + .areset(1'b0), + .dfflo(), + .devpor(1'b1), + .devclrn(1'b1) + `endif + ); + end + end + else + begin + if (ASYNC_MODE != "none") + begin: async_mode_in_path_enhanced_ddr + fiftyfivenm_ddio_in + #( + .async_mode(ASYNC_MODE), + .sync_mode(SYNC_MODE), + .power_up(DDIO_REG_POWER_UP), + .invert_input_clock(INVERT_INPUT_CLOCK) + ) fr_in_ddio ( + .datain(buf_in), + .clk(inclock_wire), + .ena(inclocken_wire), + .regouthi(ddr_input[1]), + .regoutlo(ddr_input[0]), + .clkout(fr_clock), + .areset(aset) + `ifndef ALTERA_RESERVED_QIS + , + .sreset(1'b0), + .dfflo(), + .devpor(1'b1), + .devclrn(1'b1), + .halfrateresyncclk(1'b0) + `endif + ); + end + else if (SYNC_MODE != "none") + begin:sync_mode_in_path_enhanced_ddr + fiftyfivenm_ddio_in + #( + .async_mode(ASYNC_MODE), + .sync_mode(SYNC_MODE), + .power_up(DDIO_REG_POWER_UP), + .invert_input_clock(INVERT_INPUT_CLOCK) + ) fr_in_ddio ( + .datain(buf_in), + .clk (inclock_wire), + .ena(inclocken_wire), + .sreset(sclr), + .regouthi(ddr_input[1]), + .regoutlo(ddr_input[0]), + .clkout(fr_clock) + `ifndef ALTERA_RESERVED_QIS + , + .areset(1'b0), + .dfflo(), + .devpor(1'b1), + .devclrn(1'b1), + .halfrateresyncclk(1'b0) + `endif + ); + end + else + begin:in_path_enhanced_ddr + fiftyfivenm_ddio_in + #( + .async_mode(ASYNC_MODE), + .sync_mode(SYNC_MODE), + .power_up(DDIO_REG_POWER_UP), + .invert_input_clock(INVERT_INPUT_CLOCK) + ) fr_in_ddio ( + .datain(buf_in), + .clk (inclock_wire), + .ena(inclocken_wire), + .regouthi(ddr_input[1]), + .regoutlo(ddr_input[0]), + .clkout(fr_clock) + `ifndef ALTERA_RESERVED_QIS + , + .sreset(1'b0), + .areset(1'b0), + .dfflo(), + .devpor(1'b1), + .devclrn(1'b1), + .halfrateresyncclk(1'b0) + `endif + ); + end + end + end + else if (ENABLE_PHASE_DETECTOR_FOR_CK == "true") + begin + assign mimic_clock = buf_in; + end + else + begin: in_path_ddr + wire input_cell_l_q; + wire input_aset; + + assign input_aset = ( ASYNC_MODE == "clear") ? !aset : aset; + + fiftyfivenm_ff input_cell_l ( + .clk(inclock_wire), + .d(buf_in), + .clrn(input_aset), + .ena(inclocken_wire), + .q(input_cell_l_q) + ); + + fiftyfivenm_ff input_latch_l ( + .clk(~inclock_wire), + .d(input_cell_l_q), + .clrn(input_aset), + .ena(inclocken_wire), + .q(ddr_input[0]) + ); + + fiftyfivenm_ff input_cell_h ( + .clk(~inclock_wire), + .d(buf_in), + .clrn(input_aset), + .ena(inclocken_wire), + .q(ddr_input[1]) + ); + + end + end + else if (REGISTER_MODE == "single-register") + begin: in_path_sdr + reg reg_data_in /* synthesis altera_attribute="FAST_INPUT_REGISTER=on" */; + always @(posedge inclock_wire) begin + reg_data_in <= buf_in; + end + assign ddr_input[0] = reg_data_in; + end + else + begin: in_path_reg_none + assign ddr_input[0] = buf_in; + end + + assign dout[DATA_SIZE - 1:0] = ddr_input[DATA_SIZE - 1:0]; + + end + endgenerate + + generate + if (PIN_TYPE == "output" || PIN_TYPE == "bidir") + begin + if(BUFFER_TYPE == "pseudo_differential") + begin: pseudo_diff_output_buf + + wire wire_pseudo_diff_o; + wire wire_pseudo_diff_o_bar; + + fiftyfivenm_io_obuf + #( + .bus_hold(BUS_HOLD), + .open_drain_output(OPEN_DRAIN_OUTPUT) + ) obuf_a ( + .i(wire_pseudo_diff_o), + .oe(~oe_out), + .o(pad), + .obar() + `ifndef ALTERA_RESERVED_QIS + , + .seriesterminationcontrol(16'b0), + .devoe(1'b1) + `endif + ); + + fiftyfivenm_io_obuf + #( + .bus_hold(BUS_HOLD), + .open_drain_output(OPEN_DRAIN_OUTPUT) + ) obuf_a_bar ( + .i(wire_pseudo_diff_o_bar), + .oe(~oe_out), + .o(pad_b), + .obar() + `ifndef ALTERA_RESERVED_QIS + , + .seriesterminationcontrol(16'b0), + .devoe(1'b1) + `endif + ); + + fiftyfivenm_pseudo_diff_out pseudo_diff_a + ( + .i(din_ddr), + .o(wire_pseudo_diff_o), + .obar(wire_pseudo_diff_o_bar) + ); + + + + end + else if (BUFFER_TYPE == "true_differential") + begin: true_diff_output_buf + fiftyfivenm_io_obuf + #( + .bus_hold(BUS_HOLD), + .open_drain_output(OPEN_DRAIN_OUTPUT) + ) obuf ( + .i(din_ddr), + .oe(~oe_out), + .o(pad), + .obar(pad_b) + `ifndef ALTERA_RESERVED_QIS + , + .seriesterminationcontrol(16'b0), + .devoe(1'b1) + `endif + ); + end + else + begin: output_buf + fiftyfivenm_io_obuf + #( + .bus_hold(BUS_HOLD), + .open_drain_output(OPEN_DRAIN_OUTPUT) + ) obuf ( + .i(din_ddr), + .oe(~oe_out), + .o(pad), + .obar() + `ifndef ALTERA_RESERVED_QIS + , + .seriesterminationcontrol(16'b0), + .devoe(1'b1) + `endif + ); + end + end + endgenerate + + assign nsleep_in = (ENABLE_NSLEEP_PORT == "true") ? nsleep : 1'b1; + + generate + if (PIN_TYPE == "input" || PIN_TYPE == "bidir") + begin + if(BUFFER_TYPE == "true_differential" || BUFFER_TYPE == "pseudo_differential") + begin: diff_input_buf + if (ENABLE_NSLEEP_PORT == "true") + begin: diff_input_buf_with_nsleep + fiftyfivenm_io_ibuf + #( + .bus_hold(BUS_HOLD) + ) ibuf ( + .i(pad), + .ibar(pad_b), + .o(buf_in), + .nsleep(nsleep_in) + ); + end + else + begin: diff_input_buf_without_nsleep + fiftyfivenm_io_ibuf + #( + .bus_hold(BUS_HOLD) + ) ibuf ( + .i(pad), + .ibar(pad_b), + .o(buf_in) + ); + end + end + else + begin:input_buf + if (ENABLE_NSLEEP_PORT == "true") + begin: input_buf_with_nsleep + fiftyfivenm_io_ibuf + #( + .bus_hold(BUS_HOLD) + ) ibuf ( + .i(pad), + .o(buf_in), + .nsleep(nsleep_in) + `ifndef ALTERA_RESERVED_QIS + , + .ibar(1'b0) + `endif + ); + end + else + begin: input_buf_without_nsleep + fiftyfivenm_io_ibuf + #( + .bus_hold(BUS_HOLD) + ) ibuf ( + .i(pad), + .o(buf_in) + `ifndef ALTERA_RESERVED_QIS + , + .ibar(1'b0) + `endif + ); + end + end + end + endgenerate + + generate + if (PIN_TYPE == "output") + begin + assign dout = {DATA_SIZE{1'b0}}; + end + + if (PIN_TYPE == "output" || REGISTER_MODE != "ddr" || USE_ENHANCED_DDR_HIO_REGISTER == "false") + begin + assign fr_clock = 1'b0; + end + + if (PIN_TYPE == "input" || PIN_TYPE == "output" || REGISTER_MODE != "ddr" || ENABLE_PHASE_DETECTOR_FOR_CK == "false") + begin + assign mimic_clock = 1'b0; + end + endgenerate + +endmodule + +module altera_gpio_lite( + inclock, + outclock, + inclocken, + outclocken, + oe, + din, + dout, + pad_io, + pad_io_b, + pad_in, + pad_in_b, + pad_out, + pad_out_b, + aset, + aclr, + phy_mem_clock, + sclr, + hr_clock, + fr_clock, + invert_hr_clock, + mimic_clock, + nsleep +); + + parameter PIN_TYPE = "output"; + parameter BUFFER_TYPE = "single-ended"; + parameter REGISTER_MODE = "bypass"; + parameter SIZE = 4; + parameter ASYNC_MODE = "none"; + parameter SYNC_MODE = "none"; + parameter BUS_HOLD = "false"; + parameter SET_REGISTER_OUTPUTS_HIGH = "false"; + parameter INVERT_OUTPUT = "false"; + parameter INVERT_INPUT_CLOCK = "false"; + parameter INVERT_OUTPUT_CLOCK = "false"; + parameter INVERT_OE_INCLOCK = "false"; + parameter USE_ONE_REG_TO_DRIVE_OE = "false"; + parameter USE_DDIO_REG_TO_DRIVE_OE = "false"; + parameter OPEN_DRAIN_OUTPUT = "false"; + parameter USE_ADVANCED_DDR_FEATURES = "false"; + parameter USE_ADVANCED_DDR_FEATURES_FOR_INPUT_ONLY = "false"; + parameter INVERT_CLKDIV_INPUT_CLOCK = "false"; + parameter ENABLE_HR_CLOCK = "false"; + parameter ENABLE_OE_HALF_CYCLE_DELAY = "true"; + parameter ENABLE_OE_PORT = "false"; + parameter ENABLE_CLOCK_ENA_PORT = "false"; + parameter ENABLE_PHASE_INVERT_CTRL_PORT = "false"; + parameter ENABLE_PHASE_DETECTOR_FOR_CK = "false"; + parameter ENABLE_NSLEEP_PORT = "false"; + + localparam USE_ENHANCED_DDR_HIO_REGISTER = USE_ADVANCED_DDR_FEATURES; + localparam BYPASS_THREE_QUARTER_REGISTER = (USE_ADVANCED_DDR_FEATURES == "true") ? "false" : "true"; + localparam DATA_SIZE = (REGISTER_MODE == "ddr") ? 2 : 1; + + input inclock; + input outclock; + input inclocken; + input outclocken; + input [SIZE - 1:0] oe; + input [SIZE - 1:0] nsleep; + input [SIZE * DATA_SIZE - 1:0] din; + output [SIZE * DATA_SIZE - 1:0] dout; + inout [SIZE - 1:0] pad_io; + inout [SIZE - 1:0] pad_io_b; + input [SIZE - 1:0] pad_in; + input [SIZE - 1:0] pad_in_b; + output [SIZE - 1:0] pad_out; + output [SIZE - 1:0] pad_out_b; + input aset; + input aclr; + input sclr; + input phy_mem_clock; + input invert_hr_clock; + output [SIZE - 1:0] fr_clock; + output wire hr_clock; + output [SIZE - 1:0] mimic_clock; + + wire [SIZE * DATA_SIZE - 1:0] din_reordered; + wire [SIZE * DATA_SIZE - 1:0] dout_reordered; + wire aclr_aset_wire; + wire sclr_wire; + wire [SIZE - 1:0] pad_io; + wire [SIZE - 1:0] pad_io_b; + + + assign aclr_aset_wire = (ASYNC_MODE == "clear") ? aclr : (ASYNC_MODE == "preset") ? aset : 1'b1; + assign sclr_wire = (SYNC_MODE == "clear") ? sclr : 1'b0; + + generate + if (PIN_TYPE == "input") + begin + assign pad_io = pad_in; + assign pad_io_b = pad_in_b; + assign pad_out = {SIZE{1'b0}}; + assign pad_out_b = {SIZE{1'b0}}; + end + else if (PIN_TYPE == "output") + begin + assign pad_out = pad_io; + assign pad_out_b = pad_io_b; + end + else begin + assign pad_out = {SIZE{1'b0}}; + assign pad_out_b = {SIZE{1'b0}}; + end + endgenerate + + genvar j, k; + generate + begin : reorder + for(j = 0; j < SIZE ; j = j + 1) begin : j_loop + for(k = 0; k < DATA_SIZE; k = k + 1) begin : k_d_loop + assign din_reordered[j * DATA_SIZE + k] = din[j + k * SIZE]; + assign dout[j + k * SIZE] = dout_reordered[j * DATA_SIZE + k]; + end + end + end + endgenerate + + genvar i; + generate + begin : gpio_one_bit + for(i = 0 ; i < SIZE ; i = i + 1) begin : i_loop + wire oe_wire; + wire nsleep_wire; + + + assign oe_wire = (PIN_TYPE == "output" && ENABLE_OE_PORT == "false") ? 1'b1 : + (PIN_TYPE == "input") ? 1'b0 : oe[i]; + + + assign nsleep_wire = (PIN_TYPE == "input" && ENABLE_NSLEEP_PORT == "false") ? 1'b1 : + (PIN_TYPE == "output") ? 1'b0 : nsleep[i]; + + altgpio_one_bit #( + .PIN_TYPE(PIN_TYPE), + .BUFFER_TYPE(BUFFER_TYPE), + .REGISTER_MODE(REGISTER_MODE), + .ASYNC_MODE(ASYNC_MODE), + .SYNC_MODE(SYNC_MODE), + .BUS_HOLD(BUS_HOLD), + .SET_REGISTER_OUTPUTS_HIGH(SET_REGISTER_OUTPUTS_HIGH), + .USE_ENHANCED_DDR_HIO_REGISTER(USE_ENHANCED_DDR_HIO_REGISTER), + .USE_ADVANCED_DDR_FEATURES_FOR_INPUT_ONLY(USE_ADVANCED_DDR_FEATURES_FOR_INPUT_ONLY), + .BYPASS_THREE_QUARTER_REGISTER(BYPASS_THREE_QUARTER_REGISTER), + .INVERT_OUTPUT(INVERT_OUTPUT), + .INVERT_INPUT_CLOCK(INVERT_INPUT_CLOCK), + .INVERT_OUTPUT_CLOCK(INVERT_OUTPUT_CLOCK), + .INVERT_OE_INCLOCK(INVERT_OE_INCLOCK), + .USE_ONE_REG_TO_DRIVE_OE(USE_ONE_REG_TO_DRIVE_OE), + .USE_DDIO_REG_TO_DRIVE_OE(USE_DDIO_REG_TO_DRIVE_OE), + .OPEN_DRAIN_OUTPUT(OPEN_DRAIN_OUTPUT), + .ENABLE_OE_HALF_CYCLE_DELAY(ENABLE_OE_HALF_CYCLE_DELAY), + .ENABLE_CLOCK_ENA_PORT(ENABLE_CLOCK_ENA_PORT), + .ENABLE_HR_CLOCK(ENABLE_HR_CLOCK), + .ENABLE_PHASE_DETECTOR_FOR_CK(ENABLE_PHASE_DETECTOR_FOR_CK), + .ENABLE_NSLEEP_PORT(ENABLE_NSLEEP_PORT) + ) altgpio_bit_i ( + .inclock(inclock), + .outclock(outclock), + .phy_mem_clock(phy_mem_clock), + .inclocken(inclocken), + .outclocken(outclocken), + .oe(oe_wire), + .din(din_reordered[(i + 1) * DATA_SIZE - 1 : i * DATA_SIZE]), + .dout(dout_reordered[(i + 1) * DATA_SIZE - 1 : i * DATA_SIZE]), + .pad(pad_io[i]), + .pad_b(pad_io_b[i]), + .aset(aclr_aset_wire), + .sclr(sclr_wire), + .fr_clock(fr_clock[i]), + .hr_clock(hr_clock), + .mimic_clock(mimic_clock[i]), + .nsleep(nsleep_wire) + ); + end + end + endgenerate + + generate + if ((PIN_TYPE == "input" || PIN_TYPE == "bidir") && (ENABLE_HR_CLOCK == "true")) + begin + if (ENABLE_PHASE_INVERT_CTRL_PORT == "true") + begin + if (SYNC_MODE == "clear") + begin : clock_divider_sync_mode_invert_hr_clock + fiftyfivenm_io_clock_divider + #( + .invert_input_clock_phase(INVERT_CLKDIV_INPUT_CLOCK), + .use_phasectrlin(ENABLE_PHASE_INVERT_CTRL_PORT), + .sync_mode(SYNC_MODE) + ) io_clkdiv ( + .clk(inclock), + .phaseinvertctrl(invert_hr_clock), + .sreset(sclr_wire), + .clkout(hr_clock) + ); + end + else + begin : clock_divider_invert_hr_clock + fiftyfivenm_io_clock_divider + #( + .invert_input_clock_phase(INVERT_CLKDIV_INPUT_CLOCK), + .use_phasectrlin(ENABLE_PHASE_INVERT_CTRL_PORT), + .sync_mode(SYNC_MODE) + ) io_clkdiv ( + .clk(inclock), + .phaseinvertctrl(invert_hr_clock), + .clkout(hr_clock) + `ifndef ALTERA_RESERVED_QIS + , + .sreset(1'b0) + `endif + ); + end + end + else + begin + if (SYNC_MODE == "clear") + begin : clock_divider_sync_mode + fiftyfivenm_io_clock_divider + #( + .invert_input_clock_phase(INVERT_CLKDIV_INPUT_CLOCK), + .use_phasectrlin(ENABLE_PHASE_INVERT_CTRL_PORT), + .sync_mode(SYNC_MODE) + ) io_clkdiv ( + .clk(inclock), + .sreset(sclr_wire), + .clkout(hr_clock) + `ifndef ALTERA_RESERVED_QIS + , + .phaseinvertctrl(1'b0) + `endif + ); + end + else + begin : clock_divider + fiftyfivenm_io_clock_divider + #( + .invert_input_clock_phase(INVERT_CLKDIV_INPUT_CLOCK), + .use_phasectrlin(ENABLE_PHASE_INVERT_CTRL_PORT), + .sync_mode(SYNC_MODE) + ) io_clkdiv ( + .clk(inclock), + .clkout(hr_clock) + `ifndef ALTERA_RESERVED_QIS + , + .sreset(1'b0), + .phaseinvertctrl(1'b0) + `endif + ); + end + end + end + else begin + assign hr_clock = 1'b0; + end + endgenerate + +endmodule diff --git a/fpga/usrp3/top/x400/cpld/ip/pll/pll.ppf b/fpga/usrp3/top/x400/cpld/ip/pll/pll.ppf new file mode 100644 index 000000000..a48517653 --- /dev/null +++ b/fpga/usrp3/top/x400/cpld/ip/pll/pll.ppf @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!DOCTYPE pinplan> +<pinplan intended_family="MAX 10" variation_name="pll" megafunction_name="ALTPLL" specifies="all_ports"> +<global> +<pin name="inclk0" direction="input" scope="external" source="clock" /> +<pin name="c0" direction="output" scope="external" source="clock" /> +<pin name="c1" direction="output" scope="external" source="clock" /> +<pin name="c2" direction="output" scope="external" source="clock" /> +<pin name="locked" direction="output" scope="external" /> + +</global> +</pinplan> diff --git a/fpga/usrp3/top/x400/cpld/ip/pll/pll.qip b/fpga/usrp3/top/x400/cpld/ip/pll/pll.qip new file mode 100644 index 000000000..6bafc09f8 --- /dev/null +++ b/fpga/usrp3/top/x400/cpld/ip/pll/pll.qip @@ -0,0 +1,5 @@ +set_global_assignment -name IP_TOOL_NAME "ALTPLL" +set_global_assignment -name IP_TOOL_VERSION "20.1" +set_global_assignment -name IP_GENERATED_DEVICE_FAMILY "{MAX 10}" +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "pll.v"] +set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "pll.ppf"] diff --git a/fpga/usrp3/top/x400/cpld/ip/pll/pll.v b/fpga/usrp3/top/x400/cpld/ip/pll/pll.v new file mode 100644 index 000000000..36b96bda9 --- /dev/null +++ b/fpga/usrp3/top/x400/cpld/ip/pll/pll.v @@ -0,0 +1,368 @@ +// megafunction wizard: %ALTPLL% +// GENERATION: STANDARD +// VERSION: WM1.0 +// MODULE: altpll + +// ============================================================ +// File Name: pll.v +// Megafunction Name(s): +// altpll +// +// Simulation Library Files(s): +// altera_mf +// ============================================================ +// ************************************************************ +// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! +// +// 20.1.0 Build 711 06/05/2020 SJ Standard Edition +// ************************************************************ + + +//Copyright (C) 2020 Intel Corporation. All rights reserved. +//Your use of Intel Corporation's design tools, logic functions +//and other software and tools, and any partner logic +//functions, and any output files from any of the foregoing +//(including device programming or simulation files), and any +//associated documentation or information are expressly subject +//to the terms and conditions of the Intel Program License +//Subscription Agreement, the Intel Quartus Prime License Agreement, +//the Intel FPGA IP License Agreement, or other applicable license +//agreement, including, without limitation, that your use is for +//the sole purpose of programming logic devices manufactured by +//Intel and sold by Intel or its authorized distributors. Please +//refer to the applicable agreement for further details, at +//https://fpgasoftware.intel.com/eula. + + +// synopsys translate_off +`timescale 1 ps / 1 ps +// synopsys translate_on +module pll ( + inclk0, + c0, + c1, + c2, + locked); + + input inclk0; + output c0; + output c1; + output c2; + output locked; + + wire [0:0] sub_wire2 = 1'h0; + wire [4:0] sub_wire3; + wire sub_wire7; + wire sub_wire0 = inclk0; + wire [1:0] sub_wire1 = {sub_wire2, sub_wire0}; + wire [2:2] sub_wire6 = sub_wire3[2:2]; + wire [1:1] sub_wire5 = sub_wire3[1:1]; + wire [0:0] sub_wire4 = sub_wire3[0:0]; + wire c0 = sub_wire4; + wire c1 = sub_wire5; + wire c2 = sub_wire6; + wire locked = sub_wire7; + + altpll altpll_component ( + .inclk (sub_wire1), + .clk (sub_wire3), + .locked (sub_wire7), + .activeclock (), + .areset (1'b0), + .clkbad (), + .clkena ({6{1'b1}}), + .clkloss (), + .clkswitch (1'b0), + .configupdate (1'b0), + .enable0 (), + .enable1 (), + .extclk (), + .extclkena ({4{1'b1}}), + .fbin (1'b1), + .fbmimicbidir (), + .fbout (), + .fref (), + .icdrclk (), + .pfdena (1'b1), + .phasecounterselect ({4{1'b1}}), + .phasedone (), + .phasestep (1'b1), + .phaseupdown (1'b1), + .pllena (1'b1), + .scanaclr (1'b0), + .scanclk (1'b0), + .scanclkena (1'b1), + .scandata (1'b0), + .scandataout (), + .scandone (), + .scanread (1'b0), + .scanwrite (1'b0), + .sclkout0 (), + .sclkout1 (), + .vcooverrange (), + .vcounderrange ()); + defparam + altpll_component.bandwidth_type = "AUTO", + altpll_component.clk0_divide_by = 2, + altpll_component.clk0_duty_cycle = 50, + altpll_component.clk0_multiply_by = 1, + altpll_component.clk0_phase_shift = "0", + altpll_component.clk1_divide_by = 2, + altpll_component.clk1_duty_cycle = 50, + altpll_component.clk1_multiply_by = 5, + altpll_component.clk1_phase_shift = "0", + altpll_component.clk2_divide_by = 5, + altpll_component.clk2_duty_cycle = 50, + altpll_component.clk2_multiply_by = 2, + altpll_component.clk2_phase_shift = "0", + altpll_component.compensate_clock = "CLK0", + altpll_component.inclk0_input_frequency = 10000, + altpll_component.intended_device_family = "MAX 10", + altpll_component.lpm_hint = "CBX_MODULE_PREFIX=pll", + altpll_component.lpm_type = "altpll", + altpll_component.operation_mode = "NORMAL", + altpll_component.pll_type = "AUTO", + altpll_component.port_activeclock = "PORT_UNUSED", + altpll_component.port_areset = "PORT_UNUSED", + altpll_component.port_clkbad0 = "PORT_UNUSED", + altpll_component.port_clkbad1 = "PORT_UNUSED", + altpll_component.port_clkloss = "PORT_UNUSED", + altpll_component.port_clkswitch = "PORT_UNUSED", + altpll_component.port_configupdate = "PORT_UNUSED", + altpll_component.port_fbin = "PORT_UNUSED", + altpll_component.port_inclk0 = "PORT_USED", + altpll_component.port_inclk1 = "PORT_UNUSED", + altpll_component.port_locked = "PORT_USED", + altpll_component.port_pfdena = "PORT_UNUSED", + altpll_component.port_phasecounterselect = "PORT_UNUSED", + altpll_component.port_phasedone = "PORT_UNUSED", + altpll_component.port_phasestep = "PORT_UNUSED", + altpll_component.port_phaseupdown = "PORT_UNUSED", + altpll_component.port_pllena = "PORT_UNUSED", + altpll_component.port_scanaclr = "PORT_UNUSED", + altpll_component.port_scanclk = "PORT_UNUSED", + altpll_component.port_scanclkena = "PORT_UNUSED", + altpll_component.port_scandata = "PORT_UNUSED", + altpll_component.port_scandataout = "PORT_UNUSED", + altpll_component.port_scandone = "PORT_UNUSED", + altpll_component.port_scanread = "PORT_UNUSED", + altpll_component.port_scanwrite = "PORT_UNUSED", + altpll_component.port_clk0 = "PORT_USED", + altpll_component.port_clk1 = "PORT_USED", + altpll_component.port_clk2 = "PORT_USED", + altpll_component.port_clk3 = "PORT_UNUSED", + altpll_component.port_clk4 = "PORT_UNUSED", + altpll_component.port_clk5 = "PORT_UNUSED", + altpll_component.port_clkena0 = "PORT_UNUSED", + altpll_component.port_clkena1 = "PORT_UNUSED", + altpll_component.port_clkena2 = "PORT_UNUSED", + altpll_component.port_clkena3 = "PORT_UNUSED", + altpll_component.port_clkena4 = "PORT_UNUSED", + altpll_component.port_clkena5 = "PORT_UNUSED", + altpll_component.port_extclk0 = "PORT_UNUSED", + altpll_component.port_extclk1 = "PORT_UNUSED", + altpll_component.port_extclk2 = "PORT_UNUSED", + altpll_component.port_extclk3 = "PORT_UNUSED", + altpll_component.self_reset_on_loss_lock = "OFF", + altpll_component.width_clock = 5; + + +endmodule + +// ============================================================ +// CNX file retrieval info +// ============================================================ +// Retrieval info: PRIVATE: ACTIVECLK_CHECK STRING "0" +// Retrieval info: PRIVATE: BANDWIDTH STRING "1.000" +// Retrieval info: PRIVATE: BANDWIDTH_FEATURE_ENABLED STRING "1" +// Retrieval info: PRIVATE: BANDWIDTH_FREQ_UNIT STRING "MHz" +// Retrieval info: PRIVATE: BANDWIDTH_PRESET STRING "Low" +// Retrieval info: PRIVATE: BANDWIDTH_USE_AUTO STRING "1" +// Retrieval info: PRIVATE: BANDWIDTH_USE_PRESET STRING "0" +// Retrieval info: PRIVATE: CLKBAD_SWITCHOVER_CHECK STRING "0" +// Retrieval info: PRIVATE: CLKLOSS_CHECK STRING "0" +// Retrieval info: PRIVATE: CLKSWITCH_CHECK STRING "0" +// Retrieval info: PRIVATE: CNX_NO_COMPENSATE_RADIO STRING "0" +// Retrieval info: PRIVATE: CREATE_CLKBAD_CHECK STRING "0" +// Retrieval info: PRIVATE: CREATE_INCLK1_CHECK STRING "0" +// Retrieval info: PRIVATE: CUR_DEDICATED_CLK STRING "c0" +// Retrieval info: PRIVATE: CUR_FBIN_CLK STRING "c0" +// Retrieval info: PRIVATE: DEVICE_SPEED_GRADE STRING "7" +// Retrieval info: PRIVATE: DIV_FACTOR0 NUMERIC "2" +// Retrieval info: PRIVATE: DIV_FACTOR1 NUMERIC "2" +// Retrieval info: PRIVATE: DIV_FACTOR2 NUMERIC "1" +// Retrieval info: PRIVATE: DUTY_CYCLE0 STRING "50.00000000" +// Retrieval info: PRIVATE: DUTY_CYCLE1 STRING "50.00000000" +// Retrieval info: PRIVATE: DUTY_CYCLE2 STRING "50.00000000" +// Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE0 STRING "50.000000" +// Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE1 STRING "250.000000" +// Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE2 STRING "40.000000" +// Retrieval info: PRIVATE: EXPLICIT_SWITCHOVER_COUNTER STRING "0" +// Retrieval info: PRIVATE: EXT_FEEDBACK_RADIO STRING "0" +// Retrieval info: PRIVATE: GLOCKED_COUNTER_EDIT_CHANGED STRING "1" +// Retrieval info: PRIVATE: GLOCKED_FEATURE_ENABLED STRING "0" +// Retrieval info: PRIVATE: GLOCKED_MODE_CHECK STRING "0" +// Retrieval info: PRIVATE: GLOCK_COUNTER_EDIT NUMERIC "1048575" +// Retrieval info: PRIVATE: HAS_MANUAL_SWITCHOVER STRING "1" +// Retrieval info: PRIVATE: INCLK0_FREQ_EDIT STRING "100.000" +// Retrieval info: PRIVATE: INCLK0_FREQ_UNIT_COMBO STRING "MHz" +// Retrieval info: PRIVATE: INCLK1_FREQ_EDIT STRING "100.000" +// Retrieval info: PRIVATE: INCLK1_FREQ_EDIT_CHANGED STRING "1" +// Retrieval info: PRIVATE: INCLK1_FREQ_UNIT_CHANGED STRING "1" +// Retrieval info: PRIVATE: INCLK1_FREQ_UNIT_COMBO STRING "MHz" +// Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "MAX 10" +// Retrieval info: PRIVATE: INT_FEEDBACK__MODE_RADIO STRING "1" +// Retrieval info: PRIVATE: LOCKED_OUTPUT_CHECK STRING "1" +// Retrieval info: PRIVATE: LONG_SCAN_RADIO STRING "1" +// Retrieval info: PRIVATE: LVDS_MODE_DATA_RATE STRING "Not Available" +// Retrieval info: PRIVATE: LVDS_MODE_DATA_RATE_DIRTY NUMERIC "0" +// Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT0 STRING "deg" +// Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT1 STRING "deg" +// Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT2 STRING "ps" +// Retrieval info: PRIVATE: MIG_DEVICE_SPEED_GRADE STRING "Any" +// Retrieval info: PRIVATE: MIRROR_CLK0 STRING "0" +// Retrieval info: PRIVATE: MIRROR_CLK1 STRING "0" +// Retrieval info: PRIVATE: MIRROR_CLK2 STRING "0" +// Retrieval info: PRIVATE: MULT_FACTOR0 NUMERIC "1" +// Retrieval info: PRIVATE: MULT_FACTOR1 NUMERIC "5" +// Retrieval info: PRIVATE: MULT_FACTOR2 NUMERIC "1" +// Retrieval info: PRIVATE: NORMAL_MODE_RADIO STRING "1" +// Retrieval info: PRIVATE: OUTPUT_FREQ0 STRING "100.00000000" +// Retrieval info: PRIVATE: OUTPUT_FREQ1 STRING "100.00000000" +// Retrieval info: PRIVATE: OUTPUT_FREQ2 STRING "40.00000000" +// Retrieval info: PRIVATE: OUTPUT_FREQ_MODE0 STRING "0" +// Retrieval info: PRIVATE: OUTPUT_FREQ_MODE1 STRING "0" +// Retrieval info: PRIVATE: OUTPUT_FREQ_MODE2 STRING "1" +// Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT0 STRING "MHz" +// Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT1 STRING "MHz" +// Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT2 STRING "MHz" +// Retrieval info: PRIVATE: PHASE_RECONFIG_FEATURE_ENABLED STRING "1" +// Retrieval info: PRIVATE: PHASE_RECONFIG_INPUTS_CHECK STRING "0" +// Retrieval info: PRIVATE: PHASE_SHIFT0 STRING "0.00000000" +// Retrieval info: PRIVATE: PHASE_SHIFT1 STRING "0.00000000" +// Retrieval info: PRIVATE: PHASE_SHIFT2 STRING "0.00000000" +// Retrieval info: PRIVATE: PHASE_SHIFT_STEP_ENABLED_CHECK STRING "0" +// Retrieval info: PRIVATE: PHASE_SHIFT_UNIT0 STRING "deg" +// Retrieval info: PRIVATE: PHASE_SHIFT_UNIT1 STRING "deg" +// Retrieval info: PRIVATE: PHASE_SHIFT_UNIT2 STRING "ps" +// Retrieval info: PRIVATE: PLL_ADVANCED_PARAM_CHECK STRING "0" +// Retrieval info: PRIVATE: PLL_ARESET_CHECK STRING "0" +// Retrieval info: PRIVATE: PLL_AUTOPLL_CHECK NUMERIC "1" +// Retrieval info: PRIVATE: PLL_ENHPLL_CHECK NUMERIC "0" +// Retrieval info: PRIVATE: PLL_FASTPLL_CHECK NUMERIC "0" +// Retrieval info: PRIVATE: PLL_FBMIMIC_CHECK STRING "0" +// Retrieval info: PRIVATE: PLL_LVDS_PLL_CHECK NUMERIC "0" +// Retrieval info: PRIVATE: PLL_PFDENA_CHECK STRING "0" +// Retrieval info: PRIVATE: PLL_TARGET_HARCOPY_CHECK NUMERIC "0" +// Retrieval info: PRIVATE: PRIMARY_CLK_COMBO STRING "inclk0" +// Retrieval info: PRIVATE: RECONFIG_FILE STRING "pll.mif" +// Retrieval info: PRIVATE: SACN_INPUTS_CHECK STRING "0" +// Retrieval info: PRIVATE: SCAN_FEATURE_ENABLED STRING "1" +// Retrieval info: PRIVATE: SELF_RESET_LOCK_LOSS STRING "0" +// Retrieval info: PRIVATE: SHORT_SCAN_RADIO STRING "0" +// Retrieval info: PRIVATE: SPREAD_FEATURE_ENABLED STRING "0" +// Retrieval info: PRIVATE: SPREAD_FREQ STRING "50.000" +// Retrieval info: PRIVATE: SPREAD_FREQ_UNIT STRING "KHz" +// Retrieval info: PRIVATE: SPREAD_PERCENT STRING "0.500" +// Retrieval info: PRIVATE: SPREAD_USE STRING "0" +// Retrieval info: PRIVATE: SRC_SYNCH_COMP_RADIO STRING "0" +// Retrieval info: PRIVATE: STICKY_CLK0 STRING "1" +// Retrieval info: PRIVATE: STICKY_CLK1 STRING "1" +// Retrieval info: PRIVATE: STICKY_CLK2 STRING "1" +// Retrieval info: PRIVATE: STICKY_CLK3 STRING "0" +// Retrieval info: PRIVATE: STICKY_CLK4 STRING "0" +// Retrieval info: PRIVATE: SWITCHOVER_COUNT_EDIT NUMERIC "1" +// Retrieval info: PRIVATE: SWITCHOVER_FEATURE_ENABLED STRING "1" +// Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0" +// Retrieval info: PRIVATE: USE_CLK0 STRING "1" +// Retrieval info: PRIVATE: USE_CLK1 STRING "1" +// Retrieval info: PRIVATE: USE_CLK2 STRING "1" +// Retrieval info: PRIVATE: USE_CLKENA0 STRING "0" +// Retrieval info: PRIVATE: USE_CLKENA1 STRING "0" +// Retrieval info: PRIVATE: USE_CLKENA2 STRING "0" +// Retrieval info: PRIVATE: USE_MIL_SPEED_GRADE NUMERIC "0" +// Retrieval info: PRIVATE: ZERO_DELAY_RADIO STRING "0" +// Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all +// Retrieval info: CONSTANT: BANDWIDTH_TYPE STRING "AUTO" +// Retrieval info: CONSTANT: CLK0_DIVIDE_BY NUMERIC "2" +// Retrieval info: CONSTANT: CLK0_DUTY_CYCLE NUMERIC "50" +// Retrieval info: CONSTANT: CLK0_MULTIPLY_BY NUMERIC "1" +// Retrieval info: CONSTANT: CLK0_PHASE_SHIFT STRING "0" +// Retrieval info: CONSTANT: CLK1_DIVIDE_BY NUMERIC "2" +// Retrieval info: CONSTANT: CLK1_DUTY_CYCLE NUMERIC "50" +// Retrieval info: CONSTANT: CLK1_MULTIPLY_BY NUMERIC "5" +// Retrieval info: CONSTANT: CLK1_PHASE_SHIFT STRING "0" +// Retrieval info: CONSTANT: CLK2_DIVIDE_BY NUMERIC "5" +// Retrieval info: CONSTANT: CLK2_DUTY_CYCLE NUMERIC "50" +// Retrieval info: CONSTANT: CLK2_MULTIPLY_BY NUMERIC "2" +// Retrieval info: CONSTANT: CLK2_PHASE_SHIFT STRING "0" +// Retrieval info: CONSTANT: COMPENSATE_CLOCK STRING "CLK0" +// Retrieval info: CONSTANT: INCLK0_INPUT_FREQUENCY NUMERIC "10000" +// Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "MAX 10" +// Retrieval info: CONSTANT: LPM_TYPE STRING "altpll" +// Retrieval info: CONSTANT: OPERATION_MODE STRING "NORMAL" +// Retrieval info: CONSTANT: PLL_TYPE STRING "AUTO" +// Retrieval info: CONSTANT: PORT_ACTIVECLOCK STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_ARESET STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_CLKBAD0 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_CLKBAD1 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_CLKLOSS STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_CLKSWITCH STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_CONFIGUPDATE STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_FBIN STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_INCLK0 STRING "PORT_USED" +// Retrieval info: CONSTANT: PORT_INCLK1 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_LOCKED STRING "PORT_USED" +// Retrieval info: CONSTANT: PORT_PFDENA STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PHASECOUNTERSELECT STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PHASEDONE STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PHASESTEP STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PHASEUPDOWN STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PLLENA STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANACLR STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANCLK STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANCLKENA STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANDATA STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANDATAOUT STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANDONE STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANREAD STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANWRITE STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clk0 STRING "PORT_USED" +// Retrieval info: CONSTANT: PORT_clk1 STRING "PORT_USED" +// Retrieval info: CONSTANT: PORT_clk2 STRING "PORT_USED" +// Retrieval info: CONSTANT: PORT_clk3 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clk4 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clk5 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena0 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena1 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena2 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena3 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena4 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena5 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_extclk0 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_extclk1 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_extclk2 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_extclk3 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: SELF_RESET_ON_LOSS_LOCK STRING "OFF" +// Retrieval info: CONSTANT: WIDTH_CLOCK NUMERIC "5" +// Retrieval info: USED_PORT: @clk 0 0 5 0 OUTPUT_CLK_EXT VCC "@clk[4..0]" +// Retrieval info: USED_PORT: c0 0 0 0 0 OUTPUT_CLK_EXT VCC "c0" +// Retrieval info: USED_PORT: c1 0 0 0 0 OUTPUT_CLK_EXT VCC "c1" +// Retrieval info: USED_PORT: c2 0 0 0 0 OUTPUT_CLK_EXT VCC "c2" +// Retrieval info: USED_PORT: inclk0 0 0 0 0 INPUT_CLK_EXT GND "inclk0" +// Retrieval info: USED_PORT: locked 0 0 0 0 OUTPUT GND "locked" +// Retrieval info: CONNECT: @inclk 0 0 1 1 GND 0 0 0 0 +// Retrieval info: CONNECT: @inclk 0 0 1 0 inclk0 0 0 0 0 +// Retrieval info: CONNECT: c0 0 0 0 0 @clk 0 0 1 0 +// Retrieval info: CONNECT: c1 0 0 0 0 @clk 0 0 1 1 +// Retrieval info: CONNECT: c2 0 0 0 0 @clk 0 0 1 2 +// Retrieval info: CONNECT: locked 0 0 0 0 @locked 0 0 0 0 +// Retrieval info: GEN_FILE: TYPE_NORMAL pll.v TRUE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll.ppf TRUE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll.inc FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll.cmp FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll.bsf FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll_inst.v FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll_bb.v FALSE +// Retrieval info: LIB_FILE: altera_mf +// Retrieval info: CBX_MODULE_PREFIX: ON diff --git a/fpga/usrp3/top/x400/cpld/mb_cpld.qpf b/fpga/usrp3/top/x400/cpld/mb_cpld.qpf new file mode 100644 index 000000000..0e34c0ac5 --- /dev/null +++ b/fpga/usrp3/top/x400/cpld/mb_cpld.qpf @@ -0,0 +1,30 @@ +# -------------------------------------------------------------------------- # +# +# Copyright (C) 2018 Intel Corporation. All rights reserved. +# Your use of Intel Corporation's design tools, logic functions +# and other software and tools, and its AMPP partner logic +# functions, and any output files from any of the foregoing +# (including device programming or simulation files), and any +# associated documentation or information are expressly subject +# to the terms and conditions of the Intel Program License +# Subscription Agreement, the Intel Quartus Prime License Agreement, +# the Intel FPGA IP License Agreement, or other applicable license +# agreement, including, without limitation, that your use is for +# the sole purpose of programming logic devices manufactured by +# Intel and sold by Intel or its authorized distributors. Please +# refer to the applicable agreement for further details. +# +# -------------------------------------------------------------------------- # +# +# Quartus Prime +# Version 18.1.0 Build 625 09/12/2018 SJ Lite Edition +# Date created = 13:40:17 August 15, 2019 +# +# -------------------------------------------------------------------------- # + +QUARTUS_VERSION = "18.1" +DATE = "13:40:17 August 15, 2019" + +# Revisions + +PROJECT_REVISION = "mb_cpld" diff --git a/fpga/usrp3/top/x400/cpld/mb_cpld.qsf b/fpga/usrp3/top/x400/cpld/mb_cpld.qsf new file mode 100644 index 000000000..47ab072ce --- /dev/null +++ b/fpga/usrp3/top/x400/cpld/mb_cpld.qsf @@ -0,0 +1,431 @@ +# -------------------------------------------------------------------------- # +# +# Copyright (C) 2018 Intel Corporation. All rights reserved. +# Your use of Intel Corporation's design tools, logic functions +# and other software and tools, and its AMPP partner logic +# functions, and any output files from any of the foregoing +# (including device programming or simulation files), and any +# associated documentation or information are expressly subject +# to the terms and conditions of the Intel Program License +# Subscription Agreement, the Intel Quartus Prime License Agreement, +# the Intel FPGA IP License Agreement, or other applicable license +# agreement, including, without limitation, that your use is for +# the sole purpose of programming logic devices manufactured by +# Intel and sold by Intel or its authorized distributors. Please +# refer to the applicable agreement for further details. +# +# -------------------------------------------------------------------------- # +# +# Quartus Prime +# Version 18.1.0 Build 625 09/12/2018 SJ Lite Edition +# Date created = 12:02:17 February 20, 2019 +# +# -------------------------------------------------------------------------- # +# +# Notes: +# +# 1) The default values for assignments are stored in the file: +# TopCpld_assignment_defaults.qdf +# If this file doesn't exist, see file: +# assignment_defaults.qdf +# +# 2) Altera recommends that you do not modify this file. This +# file is updated automatically by the Quartus Prime software +# and any changes you make may be lost or overwritten. +# +# -------------------------------------------------------------------------- # + + + +#-------------------------------------------------------------------------- +# Project properties/settings +#-------------------------------------------------------------------------- +set_global_assignment -name FAMILY "MAX 10" +set_global_assignment -name DEVICE 10M04SAU169I7G +set_global_assignment -name TOP_LEVEL_ENTITY mb_cpld +set_global_assignment -name ORIGINAL_QUARTUS_VERSION 18.1.0 +set_global_assignment -name PROJECT_CREATION_TIME_DATE "12:02:17 FEBRUARY 20, 2019" +set_global_assignment -name LAST_QUARTUS_VERSION "20.1.0 Standard Edition" +set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files +set_global_assignment -name MIN_CORE_JUNCTION_TEMP "-40" +set_global_assignment -name MAX_CORE_JUNCTION_TEMP 100 +set_global_assignment -name ERROR_CHECK_FREQUENCY_DIVISOR 256 +set_global_assignment -name POWER_PRESET_COOLING_SOLUTION "23 MM HEAT SINK WITH 200 LFPM AIRFLOW" +set_global_assignment -name POWER_BOARD_THERMAL_MODEL "NONE (CONSERVATIVE)" +set_global_assignment -name FLOW_ENABLE_POWER_ANALYZER ON +set_global_assignment -name POWER_DEFAULT_INPUT_IO_TOGGLE_RATE "12.5 %" +set_global_assignment -name ENABLE_OCT_DONE OFF +set_global_assignment -name ENABLE_CONFIGURATION_PINS OFF +set_global_assignment -name ENABLE_JTAG_PIN_SHARING ON +set_global_assignment -name GENERATE_SVF_FILE OFF +set_global_assignment -name USE_CONFIGURATION_DEVICE OFF +set_global_assignment -name CRC_ERROR_OPEN_DRAIN OFF +set_global_assignment -name OUTPUT_IO_TIMING_NEAR_END_VMEAS "HALF VCCIO" -rise +set_global_assignment -name OUTPUT_IO_TIMING_NEAR_END_VMEAS "HALF VCCIO" -fall +set_global_assignment -name OUTPUT_IO_TIMING_FAR_END_VMEAS "HALF SIGNAL SWING" -rise +set_global_assignment -name OUTPUT_IO_TIMING_FAR_END_VMEAS "HALF SIGNAL SWING" -fall + +set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top +set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id Top +set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top + +set_global_assignment -name NUM_PARALLEL_PROCESSORS 2 + +#-------------------------------------------------------------------------- +# Pin constraints +#-------------------------------------------------------------------------- + +# Clocking. +#------------------------------------------ + +# CPLD's PLL reference clock. +set_location_assignment PIN_H6 -to PLL_REF_CLK +set_location_assignment PIN_G5 -to "PLL_REF_CLK(n)" +set_instance_assignment -name IO_STANDARD "DIFFERENTIAL LVPECL" -to PLL_REF_CLK + +# Reliable clock (100 MHz). +set_location_assignment PIN_H4 -to CLK_100 +set_location_assignment PIN_H5 -to "CLK_100(n)" +set_instance_assignment -name IO_STANDARD "DIFFERENTIAL LVPECL" -to CLK_100 + +# Power supply clocks. +set_location_assignment PIN_H8 -to PWR_SUPPLY_CLK_CORE +set_location_assignment PIN_H9 -to PWR_SUPPLY_CLK_DDR4_S +set_location_assignment PIN_G12 -to PWR_SUPPLY_CLK_DDR4_N +set_location_assignment PIN_L13 -to PWR_SUPPLY_CLK_0P9V +set_location_assignment PIN_G13 -to PWR_SUPPLY_CLK_1P8V +set_location_assignment PIN_K10 -to PWR_SUPPLY_CLK_2P5V +set_location_assignment PIN_J10 -to PWR_SUPPLY_CLK_3P3V +set_location_assignment PIN_L12 -to PWR_SUPPLY_CLK_3P6V +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to PWR_SUPPLY_CLK_0P9V +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to PWR_SUPPLY_CLK_1P8V +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to PWR_SUPPLY_CLK_2P5V +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to PWR_SUPPLY_CLK_3P3V +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to PWR_SUPPLY_CLK_3P6V +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to PWR_SUPPLY_CLK_CORE +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to PWR_SUPPLY_CLK_DDR4_N +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to PWR_SUPPLY_CLK_DDR4_S + +# Oscillator power supply +set_location_assignment PIN_L2 -to PWR_EN_5V_OSC_100 +set_location_assignment PIN_N2 -to PWR_EN_5V_OSC_122_88 +set_instance_assignment -name IO_STANDARD "2.5 V" -to PWR_EN_5V_OSC_100 +set_instance_assignment -name IO_STANDARD "2.5 V" -to PWR_EN_5V_OSC_122_88 + + +# Interfaces from/to RFSoC. +#------------------------------------------ + +# PL SPI slave interface. +set_location_assignment PIN_G2 -to PL_CPLD_SCLK +set_location_assignment PIN_F5 -to PL_CPLD_MOSI +set_location_assignment PIN_F6 -to PL_CPLD_MISO +set_location_assignment PIN_G1 -to PL_CPLD_CS_N[0] +set_location_assignment PIN_G4 -to PL_CPLD_CS_N[1] +set_instance_assignment -name IO_STANDARD "1.8 V" -to PL_CPLD_SCLK +set_instance_assignment -name IO_STANDARD "1.8 V" -to PL_CPLD_MOSI +set_instance_assignment -name IO_STANDARD "1.8 V" -to PL_CPLD_MISO +set_instance_assignment -name IO_STANDARD "1.8 V" -to PL_CPLD_CS_N[0] +set_instance_assignment -name IO_STANDARD "1.8 V" -to PL_CPLD_CS_N[1] + +# IRQ to PL. +set_location_assignment PIN_F4 -to PL_CPLD_IRQ +set_instance_assignment -name IO_STANDARD "1.8 V" -to PL_CPLD_IRQ + +# PS SPI slave interface. +set_location_assignment PIN_E3 -to PS_CPLD_SCLK +set_location_assignment PIN_E1 -to PS_CPLD_MOSI +set_location_assignment PIN_F1 -to PS_CPLD_MISO +set_location_assignment PIN_B1 -to PS_CPLD_CS_N[0] +set_location_assignment PIN_C1 -to PS_CPLD_CS_N[1] +set_location_assignment PIN_E4 -to PS_CPLD_CS_N[2] +set_location_assignment PIN_D1 -to PS_CPLD_CS_N[3] +set_instance_assignment -name IO_STANDARD "1.8-V" -to PS_CPLD_SCLK +set_instance_assignment -name IO_STANDARD "1.8-V" -to PS_CPLD_MOSI +set_instance_assignment -name IO_STANDARD "1.8-V" -to PS_CPLD_MISO +set_instance_assignment -name IO_STANDARD "1.8-V" -to PS_CPLD_CS_N[0] +set_instance_assignment -name IO_STANDARD "1.8-V" -to PS_CPLD_CS_N[1] +set_instance_assignment -name IO_STANDARD "1.8-V" -to PS_CPLD_CS_N[2] +set_instance_assignment -name IO_STANDARD "1.8-V" -to PS_CPLD_CS_N[3] + + +# PL Interfaces to/from motherboard. +#------------------------------------------ + +# White Rabbit DAC SPI master interface. +set_location_assignment PIN_A12 -to CLK_DB_SCLK +set_location_assignment PIN_B13 -to CLK_DB_MOSI +set_location_assignment PIN_D12 -to CLK_DB_MISO +set_location_assignment PIN_D9 -to CLK_DB_CS_N +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to CLK_DB_SCLK +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to CLK_DB_MOSI +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to CLK_DB_MISO +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to CLK_DB_CS_N + +# iPASS interfaces. +set_location_assignment PIN_A6 -to IPASS_SCL[0] +set_location_assignment PIN_H2 -to IPASS_SCL[1] +set_location_assignment PIN_A7 -to IPASS_SDA[0] +set_location_assignment PIN_H3 -to IPASS_SDA[1] +set_instance_assignment -name IO_STANDARD "1.8 V" -to IPASS_SCL[0] +set_instance_assignment -name IO_STANDARD "1.8 V" -to IPASS_SCL[1] +set_instance_assignment -name IO_STANDARD "1.8 V" -to IPASS_SDA[0] +set_instance_assignment -name IO_STANDARD "1.8 V" -to IPASS_SDA[1] + +set_location_assignment PIN_B11 -to IPASS_PRESENT_N[0] +set_location_assignment PIN_F8 -to IPASS_PRESENT_N[1] +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to IPASS_PRESENT_N[0] +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to IPASS_PRESENT_N[1] + +# QSFP LEDs. +set_location_assignment PIN_E12 -to QSFP0_LED_ACTIVE[0] +set_location_assignment PIN_F12 -to QSFP0_LED_ACTIVE[1] +set_location_assignment PIN_E9 -to QSFP0_LED_ACTIVE[2] +set_location_assignment PIN_J1 -to QSFP0_LED_ACTIVE[3] +set_location_assignment PIN_F10 -to QSFP0_LED_LINK[0] +set_location_assignment PIN_F9 -to QSFP0_LED_LINK[1] +set_location_assignment PIN_N11 -to QSFP0_LED_LINK[2] +set_location_assignment PIN_D13 -to QSFP0_LED_LINK[3] +set_location_assignment PIN_M1 -to QSFP1_LED_ACTIVE[0] +set_location_assignment PIN_N3 -to QSFP1_LED_ACTIVE[1] +set_location_assignment PIN_L3 -to QSFP1_LED_ACTIVE[2] +set_location_assignment PIN_K2 -to QSFP1_LED_ACTIVE[3] +set_location_assignment PIN_M2 -to QSFP1_LED_LINK[0] +set_location_assignment PIN_M3 -to QSFP1_LED_LINK[1] +set_location_assignment PIN_K1 -to QSFP1_LED_LINK[2] +set_location_assignment PIN_L1 -to QSFP1_LED_LINK[3] +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to QSFP0_LED_ACTIVE[0] +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to QSFP0_LED_ACTIVE[1] +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to QSFP0_LED_ACTIVE[2] +set_instance_assignment -name IO_STANDARD "2.5 V" -to QSFP0_LED_ACTIVE[3] +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to QSFP0_LED_LINK[0] +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to QSFP0_LED_LINK[1] +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to QSFP0_LED_LINK[2] +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to QSFP0_LED_LINK[3] +set_instance_assignment -name IO_STANDARD "2.5 V" -to QSFP1_LED_ACTIVE[0] +set_instance_assignment -name IO_STANDARD "2.5 V" -to QSFP1_LED_ACTIVE[1] +set_instance_assignment -name IO_STANDARD "2.5 V" -to QSFP1_LED_ACTIVE[2] +set_instance_assignment -name IO_STANDARD "2.5 V" -to QSFP1_LED_ACTIVE[3] +set_instance_assignment -name IO_STANDARD "2.5 V" -to QSFP1_LED_LINK[0] +set_instance_assignment -name IO_STANDARD "2.5 V" -to QSFP1_LED_LINK[1] +set_instance_assignment -name IO_STANDARD "2.5 V" -to QSFP1_LED_LINK[2] +set_instance_assignment -name IO_STANDARD "2.5 V" -to QSFP1_LED_LINK[3] + +# DIO direction control. +set_location_assignment PIN_N12 -to DIO_DIRECTION_A[0] +set_location_assignment PIN_N10 -to DIO_DIRECTION_A[1] +set_location_assignment PIN_N9 -to DIO_DIRECTION_A[2] +set_location_assignment PIN_M4 -to DIO_DIRECTION_A[3] +set_location_assignment PIN_M5 -to DIO_DIRECTION_A[4] +set_location_assignment PIN_N4 -to DIO_DIRECTION_A[5] +set_location_assignment PIN_N5 -to DIO_DIRECTION_A[6] +set_location_assignment PIN_N7 -to DIO_DIRECTION_A[7] +set_location_assignment PIN_N8 -to DIO_DIRECTION_A[8] +set_location_assignment PIN_M8 -to DIO_DIRECTION_A[9] +set_location_assignment PIN_M9 -to DIO_DIRECTION_A[10] +set_location_assignment PIN_M13 -to DIO_DIRECTION_A[11] +set_location_assignment PIN_L5 -to DIO_DIRECTION_B[0] +set_location_assignment PIN_L4 -to DIO_DIRECTION_B[1] +set_location_assignment PIN_K5 -to DIO_DIRECTION_B[2] +set_location_assignment PIN_J5 -to DIO_DIRECTION_B[3] +set_location_assignment PIN_N6 -to DIO_DIRECTION_B[4] +set_location_assignment PIN_M7 -to DIO_DIRECTION_B[5] +set_location_assignment PIN_J6 -to DIO_DIRECTION_B[6] +set_location_assignment PIN_K6 -to DIO_DIRECTION_B[7] +set_location_assignment PIN_J7 -to DIO_DIRECTION_B[8] +set_location_assignment PIN_K7 -to DIO_DIRECTION_B[9] +set_location_assignment PIN_M12 -to DIO_DIRECTION_B[10] +set_location_assignment PIN_M11 -to DIO_DIRECTION_B[11] +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_A[0] +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_A[1] +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_A[2] +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_A[3] +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_A[4] +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_A[5] +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_A[6] +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_A[7] +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_A[8] +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_A[9] +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_A[10] +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_A[11] +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_B[0] +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_B[1] +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_B[2] +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_B[3] +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_B[4] +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_B[5] +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_B[6] +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_B[7] +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_B[8] +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_B[9] +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_B[10] +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_B[11] + + +# PS Interfaces to/from motherboard. +#------------------------------------------ + +# LMK04832 SPI master interface. +set_location_assignment PIN_J9 -to LMK32_SCLK +set_location_assignment PIN_H13 -to LMK32_MOSI +set_location_assignment PIN_L11 -to LMK32_MISO +set_location_assignment PIN_J13 -to LMK32_CS_N +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to LMK32_SCLK +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to LMK32_MOSI +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to LMK32_MISO +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to LMK32_CS_N + +# TPM 2.0 SPI master interface. +set_location_assignment PIN_D11 -to TPM_SCLK +set_location_assignment PIN_E10 -to TPM_MOSI +set_location_assignment PIN_C13 -to TPM_MISO +set_location_assignment PIN_L10 -to TPM_CS_N +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to TPM_SCLK +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to TPM_MOSI +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to TPM_MISO +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to TPM_CS_N + +# Phase DAC SPI master interface. +set_location_assignment PIN_K8 -to PHASE_DAC_SCLK +set_location_assignment PIN_J8 -to PHASE_DAC_MOSI +set_location_assignment PIN_M10 -to PHASE_DAC_CS_N +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to PHASE_DAC_SCLK +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to PHASE_DAC_MOSI +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to PHASE_DAC_CS_N + +# Daughterboards' JTAG master interfaces. +set_location_assignment PIN_J12 -to DB_JTAG_TCK[0] +set_location_assignment PIN_G9 -to DB_JTAG_TCK[1] +set_location_assignment PIN_K12 -to DB_JTAG_TDI[0] +set_location_assignment PIN_E13 -to DB_JTAG_TDI[1] +set_location_assignment PIN_H10 -to DB_JTAG_TDO[0] +set_location_assignment PIN_F13 -to DB_JTAG_TDO[1] +set_location_assignment PIN_K11 -to DB_JTAG_TMS[0] +set_location_assignment PIN_G10 -to DB_JTAG_TMS[1] +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DB_JTAG_TCK[0] +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DB_JTAG_TCK[1] +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DB_JTAG_TDI[0] +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DB_JTAG_TDI[1] +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DB_JTAG_TDO[0] +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DB_JTAG_TDO[1] +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DB_JTAG_TMS[0] +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DB_JTAG_TMS[1] + +# Daughterboards' Calibration EEPROM SPI interfaces. +set_location_assignment PIN_C9 -to DB_CALEEPROM_CS_N[0] +set_location_assignment PIN_B9 -to DB_CALEEPROM_MISO[0] +set_location_assignment PIN_B10 -to DB_CALEEPROM_MOSI[0] +set_location_assignment PIN_A10 -to DB_CALEEPROM_SCLK[0] + +set_location_assignment PIN_B5 -to DB_CALEEPROM_MOSI[1] +set_location_assignment PIN_B6 -to DB_CALEEPROM_SCLK[1] +set_location_assignment PIN_B4 -to DB_CALEEPROM_MISO[1] +set_location_assignment PIN_B3 -to DB_CALEEPROM_CS_N[1] + +set_instance_assignment -name IO_STANDARD "1.8 V" -to DB_CALEEPROM_CS_N[0] +set_instance_assignment -name IO_STANDARD "1.8 V" -to DB_CALEEPROM_MISO[0] +set_instance_assignment -name IO_STANDARD "1.8 V" -to DB_CALEEPROM_MOSI[0] +set_instance_assignment -name IO_STANDARD "1.8 V" -to DB_CALEEPROM_SCLK[0] + +set_instance_assignment -name IO_STANDARD "1.8 V" -to DB_CALEEPROM_MOSI[1] +set_instance_assignment -name IO_STANDARD "1.8 V" -to DB_CALEEPROM_SCLK[1] +set_instance_assignment -name IO_STANDARD "1.8 V" -to DB_CALEEPROM_MISO[1] +set_instance_assignment -name IO_STANDARD "1.8 V" -to DB_CALEEPROM_CS_N[1] + +# Daughterboards' Control interfaces. +set_location_assignment PIN_C10 -to DB_CTRL_SCLK[0] +set_location_assignment PIN_A9 -to DB_CTRL_MISO[0] +set_location_assignment PIN_A8 -to DB_ARST[0] +set_location_assignment PIN_A11 -to DB_CTRL_CS_N[0] +set_location_assignment PIN_E8 -to DB_CTRL_MOSI[0] +set_location_assignment PIN_D8 -to DB_REF_CLK[0] + +set_location_assignment PIN_A3 -to DB_REF_CLK[1] +set_location_assignment PIN_A4 -to DB_CTRL_MISO[1] +set_location_assignment PIN_D6 -to DB_CTRL_CS_N[1] +set_location_assignment PIN_E6 -to DB_CTRL_SCLK[1] +set_location_assignment PIN_A5 -to DB_CTRL_MOSI[1] +set_location_assignment PIN_B2 -to DB_ARST[1] + +set_instance_assignment -name IO_STANDARD "1.8 V" -to DB_CTRL_SCLK[0] +set_instance_assignment -name IO_STANDARD "1.8 V" -to DB_CTRL_MISO[0] +set_instance_assignment -name IO_STANDARD "1.8 V" -to DB_ARST[0] +set_instance_assignment -name IO_STANDARD "1.8 V" -to DB_CTRL_CS_N[0] +set_instance_assignment -name IO_STANDARD "1.8 V" -to DB_CTRL_MOSI[0] +set_instance_assignment -name IO_STANDARD "1.8 V" -to DB_REF_CLK[0] + +set_instance_assignment -name IO_STANDARD "1.8 V" -to DB_REF_CLK[1] +set_instance_assignment -name IO_STANDARD "1.8 V" -to DB_CTRL_MISO[1] +set_instance_assignment -name IO_STANDARD "1.8 V" -to DB_CTRL_CS_N[1] +set_instance_assignment -name IO_STANDARD "1.8 V" -to DB_CTRL_SCLK[1] +set_instance_assignment -name IO_STANDARD "1.8 V" -to DB_CTRL_MOSI[1] +set_instance_assignment -name IO_STANDARD "1.8 V" -to DB_ARST[1] + + +# Miscellaneous. +#------------------------------------------ + +# Power supply clocks switch. +set_location_assignment PIN_J2 -to PS_CLK_ON_CPLD +set_instance_assignment -name IO_STANDARD "2.5 V" -to PS_CLK_ON_CPLD + +# iPASS misc. +set_location_assignment PIN_B12 -to IPASS_POWER_DISABLE +set_location_assignment PIN_C11 -to IPASS_POWER_EN_FAULT[0] +set_location_assignment PIN_C12 -to IPASS_POWER_EN_FAULT[1] +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to IPASS_POWER_DISABLE +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to IPASS_POWER_EN_FAULT[0] +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to IPASS_POWER_EN_FAULT[1] + +# PCIe reset to FPGA. +set_location_assignment PIN_A2 -to PCIE_RESET +set_instance_assignment -name IO_STANDARD "1.8 V" -to PCIE_RESET + +# TPM reset. +set_location_assignment PIN_K13 -to TPM_RESET_n +set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to TPM_RESET_n + +# File list. +set_global_assignment -name EXTERNAL_FLASH_FALLBACK_ADDRESS 00000000 +set_global_assignment -name INTERNAL_FLASH_UPDATE_MODE "SINGLE COMP IMAGE" +set_global_assignment -name EN_USER_IO_WEAK_PULLUP OFF +set_global_assignment -name EN_SPI_IO_WEAK_PULLUP OFF + +set_global_assignment -name VHDL_FILE ip/cmi/PcieCmiWrapper.vhd +set_global_assignment -name VHDL_FILE ip/cmi/PcieCmi.vhd +set_global_assignment -name QSYS_FILE ip/clkctrl/clkctrl.qsys +set_global_assignment -name QSYS_FILE ip/flash/on_chip_flash.qsys +set_global_assignment -name SDC_FILE db_spi_shared_constants.sdc +set_global_assignment -name SDC_FILE mb_cpld.sdc +set_global_assignment -name VERILOG_FILE reconfig_engine.v +set_global_assignment -name VERILOG_FILE mb_cpld.v +set_global_assignment -name VERILOG_FILE ctrlport_to_spi.v +set_global_assignment -name VERILOG_FILE ctrlport_to_jtag.v +set_global_assignment -name VERILOG_FILE pl_cpld_regs.v +set_global_assignment -name VERILOG_FILE pwr_supply_clk_gen.v +set_global_assignment -name VERILOG_FILE ps_cpld_regs.v +set_global_assignment -name VERILOG_FILE reset_generator.v +set_global_assignment -name VERILOG_FILE spi_slave_to_ctrlport_master.v +set_global_assignment -name VERILOG_FILE spi_slave.v +set_global_assignment -name QIP_FILE ip/pll/pll.qip +set_global_assignment -name VERILOG_FILE ../../../lib/control/synchronizer_impl.v +set_global_assignment -name VERILOG_FILE ../../../lib/control/synchronizer.v +set_global_assignment -name VERILOG_FILE ../../../lib/rfnoc/utils/ctrlport_splitter.v +set_global_assignment -name VERILOG_FILE ../../../lib/rfnoc/utils/ctrlport_terminator.v +set_global_assignment -name VERILOG_FILE ../../../lib/wb_spi/rtl/verilog/spi_top.v +set_global_assignment -name VERILOG_FILE ../../../lib/wb_spi/rtl/verilog/spi_shift.v +set_global_assignment -name VERILOG_FILE ../../../lib/wb_spi/rtl/verilog/spi_defines.v +set_global_assignment -name VERILOG_FILE ../../../lib/wb_spi/rtl/verilog/spi_clgen.v +set_global_assignment -name VERILOG_FILE ../../../lib/control/pulse_synchronizer.v +set_global_assignment -name VERILOG_FILE ../../../lib/control/handshake.v +set_global_assignment -name VHDL_FILE ../../../lib/vivado_ipi/axi_bitq/bitq_fsm.vhd +set_global_assignment -name VHDL_FILE ../../../lib/vivado_ipi/axi_bitq/axi_bitq.vhd +set_global_assignment -name QIP_FILE ip/oddr/oddr.qip +set_global_assignment -name SOURCE_FILE db/mb_cpld.cmp.rdb +set_global_assignment -name PARTITION_NETLIST_TYPE POST_FIT -section_id "PcieCmi:PcieCmix" +set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id "PcieCmi:PcieCmix" +set_global_assignment -name PARTITION_COLOR 52377 -section_id "PcieCmi:PcieCmix" +set_global_assignment -name PARTITION_IMPORT_FILE ip/cmi/PcieCmi.qxp -section_id "PcieCmi:PcieCmix" +set_global_assignment -name PARTITION_LAST_IMPORTED_FILE ip/cmi/PcieCmi.qxp -section_id "PcieCmi:PcieCmix" +set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top +set_instance_assignment -name PARTITION_HIERARCHY pciec_5b6b1 -to "PcieCmiWrapper:pcie_cmi_inst|PcieCmi:PcieCmix" -section_id "PcieCmi:PcieCmix"
\ No newline at end of file diff --git a/fpga/usrp3/top/x400/cpld/mb_cpld.sdc b/fpga/usrp3/top/x400/cpld/mb_cpld.sdc new file mode 100644 index 000000000..af291a994 --- /dev/null +++ b/fpga/usrp3/top/x400/cpld/mb_cpld.sdc @@ -0,0 +1,689 @@ +# +# Copyright 2021 Ettus Research, a National Instruments Brand +# +# SPDX-License-Identifier: LGPL-3.0-or-later +# +# Description: +# +# Timing constraints for the X4xx's motherboard CPLD. +# + +set_time_format -unit ns -decimal_places 3 + +##################################################################### +# General +##################################################################### +# For a couple of 3.3V interfaces the buffer SN74AVC4T774RSVR is used to +# increase the drive strength. For reuse we define the timings constants here. +# For direction A to B and B to A the maximum timing varies by 0.1 ns. Taking +# the maximum of both. +set buffer_prop_min 0.100 +set buffer_prop_max 2.400 + +##################################################################### +# Main Clocks +##################################################################### +## Input clocks. +# Reliable clock: 100.0 MHz +set CLK_100_period 10.000 +create_clock -name CLK_100 -period $CLK_100_period [get_ports CLK_100] + +# internal PLL derived clock +derive_pll_clocks +# provide name for derived clocks +set CLK_250 [get_clocks {*clk[1]}] + +# PLL output pins of the generated 50 MHz clock for internal processing +set clk50_period 20.000 +set pll_clk_out_pin [get_pins {pll_inst|altpll_component|auto_generated|pll1|clk[0]}] + +set clk250_period 4.000 + +# PLL reference clock: 64 MHz (maximum) +set prc_clock_period 15.625 +create_clock -name PLL_REF_CLK -period $prc_clock_period [get_ports PLL_REF_CLK] + +##################################################################### +# Timing exceptions +##################################################################### +## SPI slaves +# Delay path for all synchronizers is based on the period of the +# faster clock domain (50 MHz derived by the PLL from 100 MHz reliable clock). +set clk50_period [expr {$CLK_100_period * 2}] + +set_max_delay -to [get_registers *synchronizer_false_path\|value\[0\]\[*\]] \ + $clk50_period + +# sclk data to CLK_100 +set_max_delay -from [get_registers *spi_slave_async\|received_word\[*\]] \ + -to [get_registers *spi_slave_async\|data_out\[*\]] \ + $clk50_period +# PLL driven data to sclk +set_max_delay -from [get_clocks {pll_inst*}] \ + -to [get_registers *spi_slave_async\|transmit_bits\[*\]] \ + $clk50_period + +##################################################################### +# JTAG to daughterboards +##################################################################### +# Use the worst-case board propagation delays. +# Assuming 170.0 ps/in and usage of X410 DB. +# Longest trace | Trace length | Trace delay +# TDI to DB 0 | 7.625 in | 1.296 ns +# -------------------------------------------- + +# JTAG parameters +# see https://www.intel.com/content/www/us/en/programmable/documentation/mcn1397700832153.html#mcn1399899915639 +set db_jtag_board_delay 1.296 +set db_jtag_setup 3.000 +set db_jtag_hold 10.000 +set db_jtag_clk_to_out 20.000 + +set db0_jtag_outputs [get_ports {DB_JTAG_TDI[0] DB_JTAG_TMS[0]}] +set db0_jtag_inputs [get_ports {DB_JTAG_TDO[0]}] +set db1_jtag_outputs [get_ports {DB_JTAG_TDI[1] DB_JTAG_TMS[1]}] +set db1_jtag_inputs [get_ports {DB_JTAG_TDO[1]}] + +##### DB 0 ##### +# generated jtag clock is at least divided by 4 +# max JTAG clock rate = 20 MHz +# source clock rate = 50 MHz +# only even dividers -> minimum value = 4 +set db0_jtag_clk_register [get_registers {ctrlport_to_jtag:db0_jtag|bitq_fsm:jtag_master|bitq_state.HIGH}] +create_generated_clock -source $pll_clk_out_pin \ + -name db0_jtag_clk $db0_jtag_clk_register \ + -divide_by 4 + +# see White Rabbit DAC for futher explanation +set_false_path -from $db0_jtag_clk_register -to $db0_jtag_clk_register + +create_generated_clock \ + -source $db0_jtag_clk_register \ + -name db0_jtag_out_clk [get_ports {DB_JTAG_TCK[0]}] + +set_output_delay -clock db0_jtag_out_clk \ + -max [expr {$db_jtag_setup + $db_jtag_board_delay + $buffer_prop_max}] \ + $db0_jtag_outputs +set_output_delay -clock db0_jtag_out_clk \ + -min [expr {-$db_jtag_hold - $db_jtag_board_delay - $buffer_prop_min}] \ + $db0_jtag_outputs +# data is driven on CPLD on falling edge, which is 2 clock cycles ahead +# of the latch edge +set_multicycle_path -setup -start -to $db0_jtag_outputs 2 +set_multicycle_path -hold -start -to $db0_jtag_outputs 3 + +# maximum delay accounts for slow clock and data propagation as +# well as clock to out time +set_input_delay -clock_fall -clock db0_jtag_out_clk \ + -max [expr {$db_jtag_clk_to_out + 2*$db_jtag_board_delay + 2*$buffer_prop_max}] \ + $db0_jtag_inputs +# worst-case everything changes immediatelly +set_input_delay -clock_fall -clock db0_jtag_out_clk \ + -min [expr {2*$buffer_prop_min}] \ + $db0_jtag_inputs +set_multicycle_path -setup -end -from $db0_jtag_inputs 2 +set_multicycle_path -hold -end -from $db0_jtag_inputs 3 + +##### DB 1 ##### +# generated jtag clock is at least divided by 4 +set db1_jtag_clk_register [get_registers {ctrlport_to_jtag:db1_jtag|bitq_fsm:jtag_master|bitq_state.HIGH}] +create_generated_clock -source $pll_clk_out_pin \ + -name db1_jtag_clk $db1_jtag_clk_register \ + -divide_by 4 +# see White Rabbit DAC for futher explanation +set_false_path -from $db1_jtag_clk_register -to $db1_jtag_clk_register +create_generated_clock \ + -source $db1_jtag_clk_register \ + -name db1_jtag_out_clk [get_ports {DB_JTAG_TCK[1]}] + +set_output_delay -clock db1_jtag_out_clk \ + -max [expr {$db_jtag_setup + $db_jtag_board_delay + $buffer_prop_max}] \ + $db1_jtag_outputs +set_output_delay -clock db1_jtag_out_clk \ + -min [expr {-$db_jtag_hold - $db_jtag_board_delay - $buffer_prop_min}] \ + $db1_jtag_outputs +set_multicycle_path -setup -start -to $db1_jtag_outputs 2 +set_multicycle_path -hold -start -to $db1_jtag_outputs 3 + +# maximum delay accounts for slow clock and data propagation as +# well as clock to out time +set_input_delay -clock_fall -clock db1_jtag_out_clk \ + -max [expr {$db_jtag_clk_to_out + 2*$db_jtag_board_delay + 2*$buffer_prop_max}] \ + $db1_jtag_inputs +# ideally everything changes immediatelly +set_input_delay -clock_fall -clock db1_jtag_out_clk \ + -min [expr {2*$buffer_prop_min}] \ + $db1_jtag_inputs +set_multicycle_path -setup -end -from $db1_jtag_inputs 2 +set_multicycle_path -hold -end -from $db1_jtag_inputs 3 + +##################################################################### +# FPGA <-> MB CPLD PL SPI interface +##################################################################### +# Create clock for the PL's SPI interface. +# PRC at least divided by 2 by the SPI Master on FPGA +set pl_sclk_period [expr {2 * $prc_clock_period}] +create_clock -name pl_sclk -period $pl_sclk_period [get_registers mb_cpld_sclk] + +# The SPI PL master (on the FPGA) is designed as a system synchronous +# interface using PLL_REF_CLK. +# The FPGA output constraints are required to calculate the windows +# at CPLD of valid data +# They are derived iteratively from the FPGA design ensuring a large +# valid data period. +set pl_spi_fpga_min_out 0.000 +set pl_spi_fpga_max_out 11.000 + +# The longest trace on the PL SPI interface is (sssuming 170.0 ps/in) +# Longest trace | Trace length | Trace delay +# CS_0 | 7.143 in | 1.215 ns +set pl_spi_board_delay 1.215 + +# This path also contains a level translator which has a typical +# switching time of 2.7 ns. Let's add a margin of 1 ns as worst +# case estimation +set pl_level_trans_delay 3.700 + +# CPLD and FPGA both use PLL reference clock from a common clock chip. +# The traces from that clock chip to the ICs are not length matched +# Assume a worst case clock difference of 0.5 ns at the IC inputs. +# There is no direction defined. The clock can arrive faster or slower +# on one IC. +set pl_clock_diff 0.500 + +set pl_slave_inputs [get_ports {PL_CPLD_SCLK PL_CPLD_MOSI PL_CPLD_CS_N[*]}] +# calculate output delays back from capturing edge, add board delay, level translator and clock difference +set_input_delay -clock PLL_REF_CLK \ + -max [expr {$prc_clock_period - $pl_spi_fpga_max_out + $pl_spi_board_delay + $pl_level_trans_delay + $pl_clock_diff}] \ + $pl_slave_inputs +# Assuming data is going without any delay, clock is arriving early at CPLD. +# Negate minimum output delay as it is defined from the change to the start clock edge. +set_input_delay -clock PLL_REF_CLK \ + -min [expr {- $pl_spi_fpga_min_out - $pl_clock_diff}] \ + $pl_slave_inputs + +# ensure large data valid window for the FPGA +# those values are used in the FPGA / DB CPLDs +# to calculate the input delay +# those values are maximum integer values to still meet timing +set pl_spi_cpld_min_out -1.000 +set pl_spi_cpld_max_out 8.000 + +set pl_slave_outputs [get_ports {PL_CPLD_MISO}] +set_output_delay -clock PLL_REF_CLK -max $pl_spi_cpld_max_out $pl_slave_outputs +set_output_delay -clock PLL_REF_CLK -min $pl_spi_cpld_min_out $pl_slave_outputs + +##################################################################### +# DB clock and reset +##################################################################### +# Output clocks for the daughterboards (SPI control) +create_generated_clock -source $pll_clk_out_pin \ + -name db0_ref_clk [get_ports {DB_REF_CLK[0]}] +create_generated_clock -source $pll_clk_out_pin \ + -name db1_ref_clk [get_ports {DB_REF_CLK[1]}] + +# output reset within one clock period +set_max_delay -to [get_ports {DB_ARST[0] DB_ARST[1]}] $CLK_100_period +set_min_delay -to [get_ports {DB_ARST[0] DB_ARST[1]}] 0 + +##################################################################### +# DB SPI interfaces +##################################################################### +# --------- ----------------- ----------------- +# FPGA | CS/SCLK/ | MB CPLD | | DB | +# |-- MOSI ->|--------> R1 ->|--------->| | +# SPI | | | | SPI | +# master |<- MISO --|<- R2 <--------|<---------| slave | +# --------- ----------------- ----------------- +# +# The output clocks are derived from the PLL reference clock (PRC). The SCLK +# edges are aligned with the rising edge of PLL reference clock. There are two +# registers R1 and R2 in the SPI path between FPGA and DB. +# For the transmission of data from master to slave those registers are +# transparent. The overall reception is just delayed by 1 PLL reference clock +# cycle. In the other direction the MISO timing is different. The falling edge +# of SCLK is used for changing the data signals. The propagation of this signal +# to the DB is delayed by 1 PLL reference clock period because of register R1. +# The MISO signal is captured on the rising edge of SCLK on the FPGA. Register +# R2 in the MB CPLD changes the timing in a way that MISO has to be stable on +# the rising edge of PLL reference clock before the SCLK rising edge. +# Additionally a minimum of two PLL reference clock cycles are required for +# processing in the SPI slave. The number of processing cycles is denoted by n. + +# Here is an example for n=2 and SPI bus with CPHA=0 and CPOL=0. +# Data is driven on the falling edge and captured on the rising edge of the +# clock signal. The falling edge of the SCLK@DB is delayed by a clock cycle +# because of R1. The FPGA as SPI master is capturing the data on the rising edge +# of SCLK. The register R2 on the MB CPLD is capturing the data one clock cycle +# earlier. Therefore MISO has to be stable one clock cycle earlier then the +# original SCLK at the MB CPLD input. The effective SCLK signal to use for the +# timing constraints of the DB therefore has a low period which is reduced by 2 +# clock cycles (R1 + R2) of PLL reference clock. It still has the same period as +# SCLK. In this example the low period would be 2 PRC cycles and the high period +# would be 6 PRC cycles. +# The following waveform illustrates the timing for n=2. Based on the defined +# delays <XXXX> denotes the time when the signal is not stable. +# +# <--- R1 --->|<-------- n=2 -------->|<--- R2 ---> +# PRC ___/-----\_____/-----\_____/-----\_____/-----\_____/---- +# SCLK ---\_______________________________________________/---- +# SCLK @ DB (ideal) ---------------\________________________________________ +# SCLK @ DB (effective) ---------------\_______________________/---------------- +# MOSI output @ MB CPLD --------------<XXXX>------------------------------------ +# MISO input @ MB CPLD -------------------------<XXXX>------------------------- +# DB propagation and processing <---------> +# MOSI change @ FPGA ^ +# MOSI change @ MB CPLD ^ +# MISO capture @ MB CPLD ^ +# MISO capture @ FPGA ^ +# +# Although the delays are defined based on PLL reference clock the SPI bus clock +# must be divided by at least n+2, where n>1 to be functional. Increase n in +# case the DB propagation and processing time does not fit into n PLL reference +# clock cycles taking the delays from below into account (see waveform above). +# Make sure you defined the SPI bus clock frequency for the slave to n*PLL clock +# period (effective SPI clock). Set the required SPI DB clock divider on the +# FPGA before starting data transfer. +# +# The constants for this interface are defined in db_spi_shared_constants.sdc + +#### DB 0 #### +create_generated_clock -source [get_ports {PLL_REF_CLK}] \ + -name db0_ctrl_clk_int [get_registers {DB_CTRL_SCLK[0]~reg0}] +create_generated_clock -source [get_registers {DB_CTRL_SCLK[0]~reg0}] \ + -name db0_ctrl_clk [get_ports {DB_CTRL_SCLK[0]}] + +set db0_ctrl_outputs [get_ports {DB_CTRL_MOSI[0] DB_CTRL_CS_N[0]}] +set_output_delay -clock db0_ctrl_clk -max $db_cpld_spi_max_out $db0_ctrl_outputs +set_output_delay -clock db0_ctrl_clk -min $db_cpld_spi_min_out $db0_ctrl_outputs + +set db0_ctrl_inputs [get_ports {DB_CTRL_MISO[0]}] +set_input_delay -clock db0_ctrl_clk -max $db_cpld_spi_max_in $db0_ctrl_inputs +set_input_delay -clock db0_ctrl_clk -min $db_cpld_spi_min_in $db0_ctrl_inputs + +#### DB 1 #### +create_generated_clock -source [get_ports {PLL_REF_CLK}] \ + -name db1_ctrl_clk_int [get_registers {DB_CTRL_SCLK[1]~reg0}] +create_generated_clock -source [get_registers {DB_CTRL_SCLK[1]~reg0}] \ + -name db1_ctrl_clk [get_ports DB_CTRL_SCLK[1]] + +set db1_ctrl_outputs [get_ports {DB_CTRL_MOSI[1] DB_CTRL_CS_N[1]}] +set_output_delay -clock db1_ctrl_clk -max $db_cpld_spi_max_out $db1_ctrl_outputs +set_output_delay -clock db1_ctrl_clk -min $db_cpld_spi_min_out $db1_ctrl_outputs + +set db1_ctrl_inputs [get_ports {DB_CTRL_MISO[1]}] +set_input_delay -clock db1_ctrl_clk -max $db_cpld_spi_max_in $db1_ctrl_inputs +set_input_delay -clock db1_ctrl_clk -min $db_cpld_spi_min_in $db1_ctrl_inputs + +##################################################################### +# Power supply clocks, LEDs, DIO direction +##################################################################### +# Change all output signals in this section within one clock period of the +# driving clocks. + +# Power supply clocks +set power_supply_clocks_outputs [get_ports {PWR_SUPPLY_CLK_*}] +set_min_delay -to $power_supply_clocks_outputs 0 +set_max_delay -to $power_supply_clocks_outputs $CLK_100_period + +# LED signals +set led_outputs [get_ports {QSFP0_LED_ACTIVE[*] QSFP0_LED_LINK[*] \ + QSFP1_LED_ACTIVE[*] QSFP1_LED_LINK[*]}] +set_min_delay -to $led_outputs 0 +set_max_delay -to $led_outputs $prc_clock_period + +# DIO direction +set dio_outputs [get_ports {DIO_DIRECTION_A[*] DIO_DIRECTION_B[*]}] +set_min_delay -to $dio_outputs 0 +set_max_delay -to $dio_outputs $clk50_period + +# Power control +set pwr_ctrl_outputs [get_ports {IPASS_POWER_DISABLE PWR_EN_5V_OSC_100 PWR_EN_5V_OSC_122_88}] +set_min_delay -to $pwr_ctrl_outputs 0 +set_max_delay -to $pwr_ctrl_outputs $clk50_period + +# Power fault inputs +# Virtual clocks for constraining inputs. Using an odd clock period to +# make sure any uncovered paths will result in timing errors due to short setup +# or hold path. +set power_fault_inputs [get_ports {IPASS_POWER_EN_FAULT[*]}] +create_clock -name virtual_async_in_clk -period 4.567 +set_input_delay -clock virtual_async_in_clk 0 $power_fault_inputs + +##################################################################### +# FPGA <-> MB CPLD PS SPI interface +##################################################################### +# Assume the PS SPI clock is maximum 5 MHz. +# It is driven from another source and provided with the data. +set ps_sclk_period 200.000 +create_clock -name ps_sclk -period $ps_sclk_period [get_ports PS_CPLD_SCLK] + +# The SPI PS master (on the FPGA) is wired through the MIO (Multiplexed I/O) +# pins, meaning that the timing characteristics of the interface come from +# the controller itself (i.e. no timed routing through PL). +# Based on the SPI master controller specification (DS925: Table 48), +# one may define the min/max input/output delay constraints. +set ps_spi_tco_min -2.000 +set ps_spi_tco_max 5.000 +set ps_spi_miso_setup -2.000 +set ps_spi_miso_hold [expr {0.3 * $ps_sclk_period}] + +# Use the worst-case board propagation delays. +# Assuming 170.0 ps/in. +# Longest trace | Trace length | Trace delay +# CS0_n | 4.735 in | 0.805 ns +# -------------------------------------------- +set ps_spi_board_delay 0.805 + +set ps_slave_inputs [get_ports {PS_CPLD_MOSI PS_CPLD_CS_N[*]}] +# clock is immediately available, data is taking maximum time +# SPI data in CPOL=CPHA=1 is driven on the falling sclk edge +set ps_sclk_max_in_delay [expr {$ps_spi_tco_max + $ps_spi_board_delay}] +set_input_delay -clock ps_sclk -clock_fall \ + -max $ps_sclk_max_in_delay \ + $ps_slave_inputs +# fast data and clock delayed (reducing data delay) +set_input_delay -clock ps_sclk -clock_fall \ + -min [expr {$ps_spi_tco_min - $ps_spi_board_delay}] \ + $ps_slave_inputs + +set ps_slave_outputs [get_ports {PS_CPLD_MISO}] +# use only half the frequency because falling edge is driving data +set_output_delay -clock ps_sclk \ + -max [expr {$ps_spi_miso_setup + 2*$ps_spi_board_delay}] \ + $ps_slave_outputs +# use hold requirement only as clock and data propagation further +# delay the signal +set_output_delay -clock ps_sclk \ + -min [expr {-$ps_spi_miso_hold}] \ + $ps_slave_outputs + +# Chip select signals are captured for binary decoding in 250 MHz clock domain. +# To be able to specify a maximum delay for the data path only a second set of +# input delays is added to the root clock of the 250 MHz domain. +set_input_delay -add_delay -clock CLK_100 0 [get_ports {PS_CPLD_CS_N[*]}] +# Declare paths between the 2 clock domains as false paths +set_false_path -from [get_clocks {CLK_100}] -to [get_ports {PS_CPLD_MISO}] +set_false_path -from [get_clocks {ps_sclk}] -to [get_registers {synchronizer:ps_spi_input_sync_inst*}] +# Specify maximum data path delay +set_max_delay -from [get_ports {PS_CPLD_CS_N[*]}] -to $CLK_250 $clk250_period + +##################################################################### +# MB CPLD PS SPI passthrough +##################################################################### +###### Binary CS decoding ###### +# The CS outputs for the external SPI slaves are driven from a 250 MHz clock to +# ensure glitch free switching after binary encoding. Additionally those signals +# have to meet the setup and hold requirements of the SPI slaves operating at +# ps_sclk (5 MHz). CS lines typically are asserted half a clock period of sclk +# before any active edge of sclk. The constraints below are using multi-cycle +# paths to provide the placer with information about the clock multiplier from +# ps_sclk to 250 MHz. Furthermore they incorporate the time required for +# decoding by lowering the clock multiplier as shown in the waveform below +# (multiplier is not shown correctly). +# +# ps_sclk -\__________________________________________________/-------- +# 250 MHz _/-\_/-\_/-\_/-\_/-\_/-\_/-\_/-\_/-\_/-\_/-\_/-\_/-\_/-\_/-\- +# CS @ CPLD input X>--------------- stable ------------------------------------ +# CS @ CPLD output ---------<XXXXXXX>-------------- stable --------------------- +# |<----->| min decoding delay +# |<----->| change window +# --------------->| SPI slave hold requirement +# SPI slave setup requirement |<-------------------------------->| +# +# Get port to apply the multi-cycle constraint. +set binary_cs_ports [get_ports {LMK32_CS_N TPM_CS_N PHASE_DAC_CS_N DB_CALEEPROM_CS_N[*] CLK_DB_CS_N}] +# Determine number of full 250 MHz periods within half a period of ps_sclk. +set ps_spi_clock_divider [expr {int($ps_sclk_period/$clk250_period/2)}] +# Setup multi-cycle accounts for +# - one clock cycle data path delay from port to first register stage +# - one clock cycle to resolve meta-stability +# - up to 3 register stages internally (port to ps_cpld_cs_n_shift3) +# - one output register stage (registers on each $binary_cs_ports) +# Static timing analysis will take the data path from register to output port +# into account. +# The number of 250 MHz periods is reduced by a total of 7 clock cycles (listed +# above) to match the SPI slave setup requirement time shown in the waveform +# above. The slave's setup time in ps_sclk domain is specified below for each +# individual slave. +set ps_spi_setup_multicycle [expr {$ps_spi_clock_divider - 7}] +set_multicycle_path -setup -start -to $binary_cs_ports $ps_spi_setup_multicycle +# Hold multicycle accounts for +# - min 2 synchronization register stages internally (ps_cpld_cs_n_shift2) +# (= min one clock cycle delay as data could arrive just before setup +# requirement of first register stages assuming no data delay) +# - one output register stage +# Static timing analysis will take the data path from register to output port +# into account. +# As the clock edge for hold analysis is shifted with the setup edge the number +# of multi cycles has to be increased by this amount of cycles to get back to +# the falling edge of ps_sclk. Furthermore CS lines are released one half +# ps_sclk period after the last data transfer. So hold delay is increased by an +# additional half clock cycle. +set ps_spi_hold_multicycle [expr {$ps_spi_clock_divider + $ps_spi_setup_multicycle - 2}] +set_multicycle_path -hold -start -to $binary_cs_ports $ps_spi_hold_multicycle + +###### local SPI slave ###### +# The chip select path for the MB CPLD itself is driven in the 250 MHz clock +# domain and captured by registers operating at ps_sclk. Therefore setting the +# path as false path preventing the placer from adding additional routing delay +# to ensure hold timing. The setup path is limited to a maximum extend of one +# clock period. As this path crosses clock domains clock propagation is included +# in this path during static timing analysis. The TCL analysis in +# scripts/ps_cs_analysis.tcl ensures a maximum value for data excluding the +# clocking network. +set_false_path -from [get_registers {ps_spi_cs_n_decoded[0]}] -hold +set_max_delay -from [get_registers {ps_spi_cs_n_decoded[0]}] $clk250_period + +###### LMK04832 ###### +create_generated_clock -source [get_ports PS_CPLD_SCLK] \ + -name lmk_spi_sclk [get_ports LMK32_SCLK] + +# Use the worst-case board propagation delays. +# Assuming 170.0 ps/in. +# Longest trace | Trace length | Trace delay +# LMK32_SCLK | 8.259 in | 1.404 ns +# -------------------------------------------- +set lmk_board_delay 1.404 + +# setup and hold dominated by CS <-> SCK relationship +set lmk_setup 20.000 +set lmk_hold 20.000 +set lmk_tco_max 60.000 + +set lmk_outputs [get_ports {LMK32_MOSI LMK32_CS_N}] +set_output_delay -clock lmk_spi_sclk \ + -max [expr {$lmk_setup + $lmk_board_delay + $buffer_prop_max}] \ + $lmk_outputs +set_output_delay -clock lmk_spi_sclk \ + -min [expr {-$lmk_hold - $lmk_board_delay - $buffer_prop_min}] \ + $lmk_outputs + +set lmk_inputs [get_ports {LMK32_MISO}] +set_input_delay -clock lmk_spi_sclk -clock_fall \ + -max [expr {$lmk_tco_max + 2*$lmk_board_delay + 2*$buffer_prop_max}] \ + $lmk_inputs +set_input_delay -clock lmk_spi_sclk -clock_fall \ + -min [expr {2*$buffer_prop_min}] \ + $lmk_inputs + +###### Phase DAC ###### +create_generated_clock -source [get_ports PS_CPLD_SCLK] \ + -name phase_dac_spi_sclk [get_ports PHASE_DAC_SCLK] + +# Use the worst-case board propagation delays. +# Assuming 170.0 ps/in. +# Longest trace | Trace length | Trace delay +# SpiDCs3v3_n | 8.322 in | 1.415 ns +# -------------------------------------------- +set phase_dac_board_delay 1.415 + +#setup dominated by SYNC signal +set phase_dac_setup 13.000 +set phase_dac_hold 5.000 + +# device captures data on falling clock edge (CPOL = 1) +# constraining it as it would be like all the other SPI modules +# PS SPI master is responsible for changing SPI mode when talking +# to this device +set phase_dac_outputs [get_ports {PHASE_DAC_MOSI PHASE_DAC_CS_N}] +set_output_delay -clock phase_dac_spi_sclk -clock_fall \ + -max [expr {$phase_dac_setup + $phase_dac_board_delay}] \ + $phase_dac_outputs +set_output_delay -clock phase_dac_spi_sclk -clock_fall \ + -min [expr {-$phase_dac_hold - $phase_dac_board_delay}] \ + $phase_dac_outputs + +###### TPM ###### +create_generated_clock -source [get_ports PS_CPLD_SCLK] \ + -name tpm_spi_sclk [get_ports TPM_SCLK] + +# Use the worst-case board propagation delays. +# Assuming 170.0 ps/in. +# Longest trace | Trace length | Trace delay +# TPM_CS_n | 1.128 in | 0.196 ns +# -------------------------------------------- +set tpm_board_delay 0.196 + +#tco dominated by NSS signal +set tpm_setup 5.000 +set tpm_hold 5.000 +set tpm_tco_max 25.000 + +set tpm_outputs [get_ports {TPM_MOSI TPM_CS_N}] +set_output_delay -clock tpm_spi_sclk \ + -max [expr {$tpm_setup + $tpm_board_delay}] \ + $tpm_outputs +set_output_delay -clock tpm_spi_sclk \ + -min [expr {-$tpm_hold - $tpm_board_delay}] \ + $tpm_outputs + +set tpm_inputs [get_ports {TPM_MISO}] +set_input_delay -clock tpm_spi_sclk -clock_fall \ + -max [expr {$tpm_tco_max + 2*$tpm_board_delay}] \ + $tpm_inputs +set_input_delay -clock tpm_spi_sclk -clock_fall \ + -min 0 \ + $tpm_inputs + +###### DB Calibration EEPROM ###### +# Use worst case board propagation delays to estimate input and output +# timing. The longest path assuming 170 ps/in is: +# db0_caleeprom_spi_cs_n | 4.387 in | 0.746 ns +set eeprom_board_prop_delay 0.746 +# Within the path to the EEPROM on the DB there is a level-transistor. +# The maximum propagation delays are 0.1..3.3 ns to the DB and 3.7 ns from the DB. +set eeprom_lvl_trans_to_db_delay_min 0.1 +set eeprom_lvl_trans_to_db_delay_max 3.3 +set eeprom_lvl_trans_from_db_delay_max 3.7 +# Data in setup and hold times of the EEPROM are 5ns (based on the +# CS_N setup and hold times). +set db_eeprom_setup 5 +set db_eeprom_hold 5 +# Ouput valid from SCK is min 0 ns and max 8 ns. +set db_eeprom_output_valid 8 + +# max out path assuming clock delay is 0 and data delay is maximum value +set eeprom_max_out [expr {$eeprom_board_prop_delay + $eeprom_lvl_trans_to_db_delay_max + $db_eeprom_setup}] +# min out path assuming clock delay is maximal and data delay is 0 +set eeprom_min_out [expr {-($eeprom_board_prop_delay + $eeprom_lvl_trans_to_db_delay_min + $db_eeprom_hold)}] +# board propagation to eeprom and back + lvl_translator back and forth + clock to data on eeprom +set eeprom_max_in [expr {$eeprom_board_prop_delay*2 + $eeprom_lvl_trans_to_db_delay_max + $eeprom_lvl_trans_from_db_delay_max + $db_eeprom_output_valid}] +# assuming no delay for everything +set eeprom_min_in 0 + +### DB 0 +create_generated_clock -source [get_ports PS_CPLD_SCLK] \ + -name db0_eeprom_clk [get_ports {DB_CALEEPROM_SCLK[0]}] + +set db0_eeprom_outputs [get_ports {DB_CALEEPROM_MOSI[0] DB_CALEEPROM_CS_N[0]}] +set_output_delay -clock db0_eeprom_clk -max $eeprom_max_out $db0_eeprom_outputs +set_output_delay -clock db0_eeprom_clk -min $eeprom_min_out $db0_eeprom_outputs + +set db0_eeprom_inputs [get_ports {DB_CALEEPROM_MISO[0]}] +# data is changed on the falling edge +set_input_delay -clock db0_eeprom_clk -clock_fall -max $eeprom_max_in $db0_eeprom_inputs +set_input_delay -clock db0_eeprom_clk -clock_fall -min $eeprom_min_in $db0_eeprom_inputs + +### DB 1 +create_generated_clock -source [get_ports PS_CPLD_SCLK] \ + -name db1_eeprom_clk [get_ports {DB_CALEEPROM_SCLK[1]}] + +set db1_eeprom_outputs [get_ports {DB_CALEEPROM_MOSI[1] DB_CALEEPROM_CS_N[1]}] +set_output_delay -clock db1_eeprom_clk -max $eeprom_max_out $db1_eeprom_outputs +set_output_delay -clock db1_eeprom_clk -min $eeprom_min_out $db1_eeprom_outputs + +set db1_eeprom_inputs [get_ports {DB_CALEEPROM_MISO[1]}] +# data is changed on the falling edge +set_input_delay -clock db1_eeprom_clk -clock_fall -max $eeprom_max_in $db1_eeprom_inputs +set_input_delay -clock db1_eeprom_clk -clock_fall -min $eeprom_min_in $db1_eeprom_inputs + +#### Clocking AUX board SPI interface #### +# Rev B clocking aux board uses a LMK05318 connected to this interface +# Using its timing for this interface. +create_generated_clock -source [get_ports PS_CPLD_SCLK] \ + -name clk_db_clk_out [get_ports CLK_DB_SCLK] +set clk_db_setup 10.000 +set clk_db_hold 10.000 +set clk_db_tco_max 20.000 +# Just a worst case assumption based on 2 times the MB trace length CLK_DB_MOSI. +# The multiplier 2 accounts for any traces on the CLK AUX board. +set clk_db_board_delay 4.000 + +set clk_db_outputs [get_ports {CLK_DB_CS_N CLK_DB_MOSI}] +# Output signals have to stable for max setup and propagation time. Clock delay +# to device is expected to be 0 in this equation. +set_output_delay -clock clk_db_clk_out \ + -max [expr {$clk_db_setup + $clk_db_board_delay + $buffer_prop_max}] $clk_db_outputs +# The min output delay is comprised of: +# - device required hold time ($clk_db_hold) +# - max clock propagation delay ($clk_db_board_delay) +# - min data propagation time (0) +# All terms have to be negated as min output delay is defined in opposite +# direction (positive into the past). +set_output_delay -clock clk_db_clk_out \ + -min [expr {-$clk_db_hold - $clk_db_board_delay - $buffer_prop_min}] $clk_db_outputs + +set clk_db_inputs [get_ports {CLK_DB_MISO}] +# Max delay calculated is based on +# - max clock delay ($clk_db_board_delay) +# - max clock to out LMK ($clk_db_tco_max) +# - max data path delay ($clk_db_board_delay) +set_input_delay -clock clk_db_clk_out -clock_fall \ + -max [expr {$clk_db_tco_max + $clk_db_board_delay*2 + 2*$buffer_prop_max}] $clk_db_inputs +# Min delay assumes clock propagates to device and data propagates to CPLD +# without any delays. +set_input_delay -clock clk_db_clk_out -clock_fall \ + -min [expr {2*$buffer_prop_min}] $clk_db_inputs + +##################################################################### +# PCIe signals +##################################################################### +# I²C bus is operated at 100kHz. Constraints would not improve timing +# significantly (typically in the order of nanoseconds, which is negligible +# given the SCL period of 10 us). +# PCI-Express reset signal is not timing critical as it is received +# asynchronously by the FPGA. +set_false_path -to [get_ports {IPASS_SDA[0] IPASS_SCL[0] PCIE_RESET}] +# I²C inputs are only consumed by synchronizers. +# Add exceptions for all known consumers. +set_false_path -to [get_registers {PcieCmiWrapper:pcie_cmi_inst|PcieCmi:PcieCmix|UsfCablePort:UsfCablePortx|CablePort:CablePortx|I2cTop:CableI2cx|I2cMonitor:I2cMonitorx|I2cFilter:I2cFilterx|I2cSigFilter:SclFilterx|fSig_ms}] +set_false_path -to [get_registers {PcieCmiWrapper:pcie_cmi_inst|PcieCmi:PcieCmix|UsfCablePort:UsfCablePortx|CablePort:CablePortx|I2cTop:CableI2cx|I2cMonitor:I2cMonitorx|I2cFilter:I2cFilterx|I2cSigFilter:SdaFilterx|fSig_ms}] +set_false_path -to [get_registers {PcieCmiWrapper:pcie_cmi_inst|PcieCmi:PcieCmix|UsfCablePort:UsfCablePortx|CablePort:CablePortx|StuckBusFixer:StuckBusFixerx|DoubleSyncSlAsyncIn:DoubleSclkx|DoubleSyncAsyncInBase:DoubleSyncAsyncInBasex|DFlopAsync:oSig_msx|lpm_ff:LPM_FFx|dffs[0]}] +set_false_path -to [get_registers {PcieCmiWrapper:pcie_cmi_inst|PcieCmi:PcieCmix|UsfCablePort:UsfCablePortx|CablePort:CablePortx|StuckBusFixer:StuckBusFixerx|DoubleSyncSlAsyncIn:DoubleSdax|DoubleSyncAsyncInBase:DoubleSyncAsyncInBasex|DFlopAsync:oSig_msx|lpm_ff:LPM_FFx|dffs[0]}] + +##################################################################### +# Known Issue of On-Chip Flash +##################################################################### +# see https://www.intel.com/content/www/us/en/programmable/support/support-resources/knowledge-base/tools/2016/warning--332060---node---alteraonchipflash-onchipflash-alteraonc.html +create_generated_clock -name flash_se_neg_reg \ + -source [get_pins { on_chip_flash:flash_inst|altera_onchip_flash:onchip_flash_0|altera_onchip_flash_avmm_data_controller:avmm_data_controller|flash_se_neg_reg|clk }] \ + -divide_by 2 [get_pins { on_chip_flash:flash_inst|altera_onchip_flash:onchip_flash_0|altera_onchip_flash_avmm_data_controller:avmm_data_controller|flash_se_neg_reg|q } ] + +##################################################################### +# Clock uncertainty +##################################################################### +# Assign some uncertainty to all clocks +set clock_uncertainty 0.150 +set_clock_uncertainty -to [get_clocks *] $clock_uncertainty +derive_clock_uncertainty diff --git a/fpga/usrp3/top/x400/cpld/mb_cpld.v b/fpga/usrp3/top/x400/cpld/mb_cpld.v new file mode 100644 index 000000000..4ea5dc574 --- /dev/null +++ b/fpga/usrp3/top/x400/cpld/mb_cpld.v @@ -0,0 +1,1033 @@ +// +// Copyright 2021 Ettus Research, A National Instruments Brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: mb_cpld +// +// Description: +// +// Top level file for the X4xx motherboard CPLD. +// +// Parameters: +// +// SIMULATION : Set to 1 to speed up simulation. +// + +`default_nettype none + + +module mb_cpld #( + parameter SIMULATION = 0 +) ( + //--------------------------------------------------------------------------- + // Clocking + //--------------------------------------------------------------------------- + + // CPLD's PLL reference clock (differential input; abbreviation: pclk) + input wire PLL_REF_CLK, + + // Reliable clock (100 MHz; differential input) + input wire CLK_100, + + //--------------------------------------------------------------------------- + // Power Supplies + //--------------------------------------------------------------------------- + + // Power supply clocks + output wire PWR_SUPPLY_CLK_CORE, + output wire PWR_SUPPLY_CLK_DDR4_S, + output wire PWR_SUPPLY_CLK_DDR4_N, + output wire PWR_SUPPLY_CLK_0P9V, + output wire PWR_SUPPLY_CLK_1P8V, + output wire PWR_SUPPLY_CLK_2P5V, + output wire PWR_SUPPLY_CLK_3P3V, + output wire PWR_SUPPLY_CLK_3P6V, + + // Power supply control + output wire PWR_EN_5V_OSC_100, + output wire PWR_EN_5V_OSC_122_88, + output wire IPASS_POWER_DISABLE, + input wire [1:0] IPASS_POWER_EN_FAULT, + + //--------------------------------------------------------------------------- + // Interfaces from/to RFSoC + //--------------------------------------------------------------------------- + + // PL SPI slave interface + input wire PL_CPLD_SCLK, + input wire PL_CPLD_MOSI, + output reg PL_CPLD_MISO, + input wire [1:0] PL_CPLD_CS_N, + + // IRQ to PL + output wire PL_CPLD_IRQ, + + // PS SPI slave interface + // Chip Selects: + // PS_CPLD_CS_N(2:0) -> binary encoded chip select + // PS_CPLD_CS_N(3) -> chip select "enable" + input wire PS_CPLD_SCLK, + input wire PS_CPLD_MOSI, + output wire PS_CPLD_MISO, + input wire [3:0] PS_CPLD_CS_N, + + //--------------------------------------------------------------------------- + // PL Interfaces to/from Motherboard + //--------------------------------------------------------------------------- + + // Clocking AUX board SPI master interface + output wire CLK_DB_SCLK, + output wire CLK_DB_MOSI, + input wire CLK_DB_MISO, + output wire CLK_DB_CS_N, + + // QSFP LEDs + // Port 0 + output wire [3:0] QSFP0_LED_ACTIVE, + output wire [3:0] QSFP0_LED_LINK, + // Port 1 + output wire [3:0] QSFP1_LED_ACTIVE, + output wire [3:0] QSFP1_LED_LINK, + + // Daughterboard control interface + // 1 -> DB1 / 0 -> DB0 + output reg [1:0] DB_CTRL_SCLK, + output reg [1:0] DB_CTRL_MOSI, + input wire [1:0] DB_CTRL_MISO, + output reg [1:0] DB_CTRL_CS_N, + output wire [1:0] DB_REF_CLK, + output wire [1:0] DB_ARST, + + // Daughterboards' JTAG master interfaces. + // 1 -> DB1 / 0 -> DB0 + output wire [1:0] DB_JTAG_TCK, + output wire [1:0] DB_JTAG_TDI, // from CPLD to DB + input wire [1:0] DB_JTAG_TDO, // from DB to CPLD + output wire [1:0] DB_JTAG_TMS, + + //--------------------------------------------------------------------------- + // PS Interfaces to/from Motherboard + //--------------------------------------------------------------------------- + + // LMK04832 SPI master interface + output wire LMK32_SCLK, + output wire LMK32_MOSI, + input wire LMK32_MISO, + output wire LMK32_CS_N, + + // TPM 2.0 SPI master interface + // Note: TPM is not currently supported + output wire TPM_SCLK, + output wire TPM_MOSI, + input wire TPM_MISO, + output wire TPM_CS_N, + + // Phase DAC SPI master interface + output wire PHASE_DAC_SCLK, + output wire PHASE_DAC_MOSI, + output wire PHASE_DAC_CS_N, + + // DIO direction control + output wire [11:0] DIO_DIRECTION_A, + output wire [11:0] DIO_DIRECTION_B, + + // Daughterboard calibration EEPROM SPI + // 1 -> DB1 / 0 -> DB0 + output wire [1:0] DB_CALEEPROM_SCLK, + output wire [1:0] DB_CALEEPROM_MOSI, + input wire [1:0] DB_CALEEPROM_MISO, + output wire [1:0] DB_CALEEPROM_CS_N, + + //--------------------------------------------------------------------------- + // Miscellaneous + //--------------------------------------------------------------------------- + + // This signal enables the 1.8 V and 3.3 V power supply clocks. + output wire PS_CLK_ON_CPLD, + + // iPASS control interface + input wire [1:0] IPASS_PRESENT_N, + inout wire [1:0] IPASS_SCL, + inout wire [1:0] IPASS_SDA, + + // PCIe reset to FPGA + output wire PCIE_RESET, + + // TPM reset + output wire TPM_RESET_n +); + + // SPI masters (spi_top) are limited to 64 bit transmission length + `define SPI_MAX_CHAR_64 + + `include "../../../lib/rfnoc/core/ctrlport.vh" + `include "regmap/mb_cpld_ps_regmap_utils.vh" + `include "regmap/mb_cpld_pl_regmap_utils.vh" + + //--------------------------------------------------------------------------- + // Clocks and Resets + //--------------------------------------------------------------------------- + + wire clk40, clk50, clk250; + wire pll_ref_clk_int; + + wire reset_clk50; + wire reset_clk40; + wire power_on_reset_clk100; + + wire [0:0] pll_locked_async; + wire [0:0] pll_locked_clk50; + wire [0:0] pll_locked_clk40; + + wire pll_ref_clk_en_clk50; + wire pll_ref_clk_en_pclk; + + reset_generator reliable_reset_gen_inst ( + .clk (CLK_100), + .power_on_reset (power_on_reset_clk100) + ); + + // Divide reliable clock by 2 since the design is not capable of running at + // 100 MHz. Multiple by 2.5 to get a fast clock to handle PS SPI chip select + // decoding. + pll pll_inst ( + .inclk0 (CLK_100), + .c0 (clk50), + .c1 (clk250), + .c2 (clk40), + .locked (pll_locked_async) + ); + + // Bring pll_ref_clk enable signal to the same clock domain. + synchronizer #( + .WIDTH (1), + .STAGES (2), + .INITIAL_VAL (1'b0), + .FALSE_PATH_TO_IN (1) + ) pll_ref_clk_en_sync ( + .clk (PLL_REF_CLK), + .rst (1'b0), + .in (pll_ref_clk_en_clk50), + .out (pll_ref_clk_en_pclk) + ); + + // Enable clock using ALTCLKCTRL IP. + clkctrl pll_ref_clk_ctrl_inst ( + .inclk (PLL_REF_CLK), + .ena (pll_ref_clk_en_pclk), + .outclk (pll_ref_clk_int) + ); + + // Use locked signal as reset for clk50 and clk40 clock domain + synchronizer #( + .WIDTH (1), + .STAGES (2), + .INITIAL_VAL (1'b0), + .FALSE_PATH_TO_IN (1) + ) clk50_reset_sync ( + .clk (clk50), + .rst (1'b0), + .in (pll_locked_async), + .out (pll_locked_clk50) + ); + + assign reset_clk50 = ~pll_locked_clk50; + + synchronizer #( + .WIDTH (1), + .STAGES (2), + .INITIAL_VAL (1'b0), + .FALSE_PATH_TO_IN (1) + ) clk40_reset_sync ( + .clk (clk40), + .rst (1'b0), + .in (pll_locked_async), + .out (pll_locked_clk40) + ); + + assign reset_clk40 = ~pll_locked_clk40; + + //--------------------------------------------------------------------------- + // Power Supply Clock + //--------------------------------------------------------------------------- + + // Frequency definitions + localparam SOUCE_CLOCK_FREQUENCY = 100_000_000; + localparam TARGET_FREQUENCY_350k = 350_000; + localparam TARGET_FREQUENCY_450k = 450_000; + localparam TARGET_FREQUENCY_500k = 500_000; + localparam TARGET_FREQUENCY_600k = 600_000; + localparam TARGET_FREQUENCY_800k = 800_000; + localparam TARGET_FREQUENCY_1M = 1_000_000; + + pwr_supply_clk_gen #( + .SOURCE_CLK_FREQ (SOUCE_CLOCK_FREQUENCY), + .TARGET_CLK_FREQ (TARGET_FREQUENCY_350k) + ) freq_gen_350k ( + .clk (CLK_100), + .rst (power_on_reset_clk100), + .pwr_supply_clk (PWR_SUPPLY_CLK_0P9V) + ); + + wire pwr_supply_clk_450k; + pwr_supply_clk_gen #( + .SOURCE_CLK_FREQ (SOUCE_CLOCK_FREQUENCY), + .TARGET_CLK_FREQ (TARGET_FREQUENCY_450k) + ) freq_gen_450k ( + .clk (CLK_100), + .rst (power_on_reset_clk100), + .pwr_supply_clk (pwr_supply_clk_450k) + ); + + assign PWR_SUPPLY_CLK_DDR4_S = pwr_supply_clk_450k; + assign PWR_SUPPLY_CLK_DDR4_N = pwr_supply_clk_450k; + + pwr_supply_clk_gen #( + .SOURCE_CLK_FREQ (SOUCE_CLOCK_FREQUENCY), + .TARGET_CLK_FREQ (TARGET_FREQUENCY_500k) + ) freq_gen_500k ( + .clk (CLK_100), + .rst (power_on_reset_clk100), + .pwr_supply_clk (PWR_SUPPLY_CLK_CORE) + ); + + pwr_supply_clk_gen #( + .SOURCE_CLK_FREQ (SOUCE_CLOCK_FREQUENCY), + .TARGET_CLK_FREQ (TARGET_FREQUENCY_600k) + ) freq_gen_600k ( + .clk (CLK_100), + .rst (power_on_reset_clk100), + .pwr_supply_clk (PWR_SUPPLY_CLK_1P8V) + ); + + pwr_supply_clk_gen #( + .SOURCE_CLK_FREQ (SOUCE_CLOCK_FREQUENCY), + .TARGET_CLK_FREQ (TARGET_FREQUENCY_800k) + ) freq_gen_800k ( + .clk (CLK_100), + .rst (power_on_reset_clk100), + .pwr_supply_clk (PWR_SUPPLY_CLK_2P5V) + ); + + wire pwr_supply_clk_1M; + pwr_supply_clk_gen #( + .SOURCE_CLK_FREQ (SOUCE_CLOCK_FREQUENCY), + .TARGET_CLK_FREQ (TARGET_FREQUENCY_1M) + ) freq_gen_1M ( + .clk (CLK_100), + .rst (power_on_reset_clk100), + .pwr_supply_clk (pwr_supply_clk_1M) + ); + + assign PWR_SUPPLY_CLK_3P3V = pwr_supply_clk_1M; + assign PWR_SUPPLY_CLK_3P6V = pwr_supply_clk_1M; + + //--------------------------------------------------------------------------- + // PL Interfaces + //--------------------------------------------------------------------------- + + wire [1:0] db_clk_enable; + wire [1:0] db_reset; + wire [1:0] ipass_cable_present; + + // Clocks and reset + oddr db0_clk_out ( + .outclock (clk50), + .din ({1'b0, db_clk_enable[0]}), + .pad_out (DB_REF_CLK[0]), + .aclr (reset_clk50) + ); + + oddr db1_clk_out ( + .outclock (clk50), + .din ({1'b0, db_clk_enable[1]}), + .pad_out (DB_REF_CLK[1]), + .aclr (reset_clk50) + ); + + assign DB_ARST[0] = db_reset[0]; + assign DB_ARST[1] = db_reset[1]; + + // PL SPI FPGA -> DB CPLD + reg mb_cpld_sclk, mb_cpld_mosi, mb_cpld_cs_n; + wire mb_cpld_miso; + + // PL SPI chip select decoding + localparam PL_CS_MB_CPLD = 2'b00; + localparam PL_CS_DB0 = 2'b10; + localparam PL_CS_DB1 = 2'b01; + localparam PL_CS_IDLE = 2'b11; + + // PL SPI registers do not have a separate reset. + // SW is expected to properly setup the DBs before issuing SPI transactions. + always @(posedge pll_ref_clk_int) begin : to_db + // Default chip selects + DB_CTRL_CS_N[0] <= 1'b1; + DB_CTRL_CS_N[1] <= 1'b1; + mb_cpld_cs_n <= 1'b1; + + // DB 0 + DB_CTRL_SCLK[0] <= PL_CPLD_SCLK; + DB_CTRL_MOSI[0] <= PL_CPLD_MOSI; + if (PL_CPLD_CS_N == PL_CS_DB0) begin + DB_CTRL_CS_N[0] <= 1'b0; + end + + // DB 1 + DB_CTRL_SCLK[1] <= PL_CPLD_SCLK; + DB_CTRL_MOSI[1] <= PL_CPLD_MOSI; + if (PL_CPLD_CS_N == PL_CS_DB1) begin + DB_CTRL_CS_N[1] <= 1'b0; + end + + // MB CPLD + mb_cpld_sclk <= PL_CPLD_SCLK; + mb_cpld_mosi <= PL_CPLD_MOSI; + if (PL_CPLD_CS_N == PL_CS_MB_CPLD) begin + mb_cpld_cs_n <= 1'b0; + end + end + + // SPI DB CPLD -> FPGA + always @(posedge pll_ref_clk_int) begin : from_db + case (PL_CPLD_CS_N) + PL_CS_MB_CPLD : PL_CPLD_MISO <= mb_cpld_miso; // MB CPLD + PL_CS_DB1 : PL_CPLD_MISO <= DB_CTRL_MISO[1]; // DB 1 + PL_CS_DB0 : PL_CPLD_MISO <= DB_CTRL_MISO[0]; // DB 0 + PL_CS_IDLE : PL_CPLD_MISO <= 1'bz; // Inactive + endcase + end + + // Local PL SPI target + wire [19:0] pl_ctrlport_req_addr; + wire [31:0] pl_ctrlport_req_data; + wire pl_ctrlport_req_rd; + wire pl_ctrlport_req_wr; + wire pl_ctrlport_resp_ack; + wire [31:0] pl_ctrlport_resp_data; + wire [ 1:0] pl_ctrlport_resp_status; + spi_slave_to_ctrlport_master #( + .CLK_FREQUENCY (50_000_000), + .SPI_FREQUENCY (10_666_667) + ) pl_spi_endpoint ( + .ctrlport_clk (clk50), + .ctrlport_rst (reset_clk50), + .m_ctrlport_req_wr (pl_ctrlport_req_wr), + .m_ctrlport_req_rd (pl_ctrlport_req_rd), + .m_ctrlport_req_addr (pl_ctrlport_req_addr), + .m_ctrlport_req_data (pl_ctrlport_req_data), + .m_ctrlport_resp_ack (pl_ctrlport_resp_ack), + .m_ctrlport_resp_status (pl_ctrlport_resp_status), + .m_ctrlport_resp_data (pl_ctrlport_resp_data), + .sclk (mb_cpld_sclk), + .cs_n (mb_cpld_cs_n), + .mosi (mb_cpld_mosi), + .miso (mb_cpld_miso) + ); + + // Split up the PL control port + wire [19:0] pl_regs_ctrlport_req_addr; + wire [31:0] pl_regs_ctrlport_req_data; + wire pl_regs_ctrlport_req_rd; + wire pl_regs_ctrlport_req_wr; + wire pl_regs_ctrlport_resp_ack; + wire [31:0] pl_regs_ctrlport_resp_data; + wire [ 1:0] pl_regs_ctrlport_resp_status; + + wire [19:0] pl_term_ctrlport_req_addr; + wire [31:0] pl_term_ctrlport_req_data; + wire pl_term_ctrlport_req_rd; + wire pl_term_ctrlport_req_wr; + wire pl_term_ctrlport_resp_ack; + wire [31:0] pl_term_ctrlport_resp_data; + wire [ 1:0] pl_term_ctrlport_resp_status; + + wire pl_jtag0_ctrlport_req_rd; + wire pl_jtag0_ctrlport_req_wr; + wire pl_jtag0_ctrlport_resp_ack; + wire [31:0] pl_jtag0_ctrlport_resp_data; + wire [ 1:0] pl_jtag0_ctrlport_resp_status; + wire [19:0] pl_jtag0_ctrlport_req_addr; + wire [31:0] pl_jtag0_ctrlport_req_data; + + wire [19:0] pl_jtag1_ctrlport_req_addr; + wire [31:0] pl_jtag1_ctrlport_req_data; + wire pl_jtag1_ctrlport_req_rd; + wire pl_jtag1_ctrlport_req_wr; + wire pl_jtag1_ctrlport_resp_ack; + wire [31:0] pl_jtag1_ctrlport_resp_data; + wire [1:0] pl_jtag1_ctrlport_resp_status; + + ctrlport_splitter #( + .NUM_SLAVES (4) + ) pl_ctrlport_splitter ( + .ctrlport_clk (clk50), + .ctrlport_rst (reset_clk50), + .s_ctrlport_req_wr (pl_ctrlport_req_wr), + .s_ctrlport_req_rd (pl_ctrlport_req_rd), + .s_ctrlport_req_addr (pl_ctrlport_req_addr), + .s_ctrlport_req_data (pl_ctrlport_req_data), + .s_ctrlport_req_byte_en (), + .s_ctrlport_req_has_time (), + .s_ctrlport_req_time (), + .s_ctrlport_resp_ack (pl_ctrlport_resp_ack), + .s_ctrlport_resp_status (pl_ctrlport_resp_status), + .s_ctrlport_resp_data (pl_ctrlport_resp_data), + .m_ctrlport_req_wr ({pl_regs_ctrlport_req_wr, pl_term_ctrlport_req_wr, pl_jtag0_ctrlport_req_wr, pl_jtag1_ctrlport_req_wr}), + .m_ctrlport_req_rd ({pl_regs_ctrlport_req_rd, pl_term_ctrlport_req_rd, pl_jtag0_ctrlport_req_rd, pl_jtag1_ctrlport_req_rd}), + .m_ctrlport_req_addr ({pl_regs_ctrlport_req_addr, pl_term_ctrlport_req_addr, pl_jtag0_ctrlport_req_addr, pl_jtag1_ctrlport_req_addr}), + .m_ctrlport_req_data ({pl_regs_ctrlport_req_data, pl_term_ctrlport_req_data, pl_jtag0_ctrlport_req_data, pl_jtag1_ctrlport_req_data}), + .m_ctrlport_req_byte_en (), + .m_ctrlport_req_has_time (), + .m_ctrlport_req_time (), + .m_ctrlport_resp_ack ({pl_regs_ctrlport_resp_ack, pl_term_ctrlport_resp_ack, pl_jtag0_ctrlport_resp_ack, pl_jtag1_ctrlport_resp_ack}), + .m_ctrlport_resp_status ({pl_regs_ctrlport_resp_status, pl_term_ctrlport_resp_status, pl_jtag0_ctrlport_resp_status, pl_jtag1_ctrlport_resp_status}), + .m_ctrlport_resp_data ({pl_regs_ctrlport_resp_data, pl_term_ctrlport_resp_data, pl_jtag0_ctrlport_resp_data, pl_jtag1_ctrlport_resp_data}) + ); + + pl_cpld_regs #( + .BASE_ADDRESS (PL_REGISTERS) + ) pl_regs ( + .ctrlport_clk (clk50), + .ctrlport_rst (reset_clk50), + .s_ctrlport_req_wr (pl_regs_ctrlport_req_wr), + .s_ctrlport_req_rd (pl_regs_ctrlport_req_rd), + .s_ctrlport_req_addr (pl_regs_ctrlport_req_addr), + .s_ctrlport_req_data (pl_regs_ctrlport_req_data), + .s_ctrlport_resp_ack (pl_regs_ctrlport_resp_ack), + .s_ctrlport_resp_status (pl_regs_ctrlport_resp_status), + .s_ctrlport_resp_data (pl_regs_ctrlport_resp_data), + .qsfp0_led_active (QSFP0_LED_ACTIVE), + .qsfp0_led_link (QSFP0_LED_LINK), + .qsfp1_led_active (QSFP1_LED_ACTIVE), + .qsfp1_led_link (QSFP1_LED_LINK), + .ipass_cable_present (ipass_cable_present) + ); + + ctrlport_to_jtag #( + .BASE_ADDRESS (JTAG_DB0), + .DEFAULT_PRESCALAR (1) + ) db0_jtag ( + .ctrlport_clk (clk50), + .ctrlport_rst (reset_clk50), + .s_ctrlport_req_wr (pl_jtag0_ctrlport_req_wr), + .s_ctrlport_req_rd (pl_jtag0_ctrlport_req_rd), + .s_ctrlport_req_addr (pl_jtag0_ctrlport_req_addr), + .s_ctrlport_req_data (pl_jtag0_ctrlport_req_data), + .s_ctrlport_resp_ack (pl_jtag0_ctrlport_resp_ack), + .s_ctrlport_resp_status (pl_jtag0_ctrlport_resp_status), + .s_ctrlport_resp_data (pl_jtag0_ctrlport_resp_data), + .tck (DB_JTAG_TCK[0]), + .tdi (DB_JTAG_TDI[0]), + .tdo (DB_JTAG_TDO[0]), + .tms (DB_JTAG_TMS[0]) + ); + + ctrlport_to_jtag #( + .BASE_ADDRESS (JTAG_DB1), + .DEFAULT_PRESCALAR (1) + ) db1_jtag ( + .ctrlport_clk (clk50), + .ctrlport_rst (reset_clk50), + .s_ctrlport_req_wr (pl_jtag1_ctrlport_req_wr), + .s_ctrlport_req_rd (pl_jtag1_ctrlport_req_rd), + .s_ctrlport_req_addr (pl_jtag1_ctrlport_req_addr), + .s_ctrlport_req_data (pl_jtag1_ctrlport_req_data), + .s_ctrlport_resp_ack (pl_jtag1_ctrlport_resp_ack), + .s_ctrlport_resp_status (pl_jtag1_ctrlport_resp_status), + .s_ctrlport_resp_data (pl_jtag1_ctrlport_resp_data), + .tck (DB_JTAG_TCK[1]), + .tdi (DB_JTAG_TDI[1]), + .tdo (DB_JTAG_TDO[1]), + .tms (DB_JTAG_TMS[1]) + ); + + // Termination of ctrlport request + ctrlport_terminator #( + .START_ADDRESS (JTAG_DB1 + JTAG_DB1_SIZE), + .LAST_ADDRESS (2**CTRLPORT_ADDR_W-1) + ) pl_terminator ( + .ctrlport_clk (clk50), + .ctrlport_rst (reset_clk50), + .s_ctrlport_req_wr (pl_term_ctrlport_req_wr), + .s_ctrlport_req_rd (pl_term_ctrlport_req_rd), + .s_ctrlport_req_addr (pl_term_ctrlport_req_addr), + .s_ctrlport_req_data (pl_term_ctrlport_req_data), + .s_ctrlport_resp_ack (pl_term_ctrlport_resp_ack), + .s_ctrlport_resp_status (pl_term_ctrlport_resp_status), + .s_ctrlport_resp_data (pl_term_ctrlport_resp_data) + ); + + //--------------------------------------------------------------------------- + // PS Interfaces + //--------------------------------------------------------------------------- + + // Local PS SPI target + wire [19:0] ps_ctrlport_req_addr; + wire [31:0] ps_ctrlport_req_data; + wire ps_ctrlport_req_rd; + wire ps_ctrlport_req_wr; + wire ps_ctrlport_resp_ack; + wire [31:0] ps_ctrlport_resp_data; + wire [ 1:0] ps_ctrlport_resp_status; + + wire ps_spi_endpoint_sclk; + wire ps_spi_endpoint_mosi; + wire ps_spi_endpoint_miso; + wire ps_spi_endpoint_cs_n; + spi_slave_to_ctrlport_master #( + .CLK_FREQUENCY (50_000_000), + .SPI_FREQUENCY (5_000_000) + ) ps_spi_endpoint ( + .ctrlport_clk (clk50), + .ctrlport_rst (reset_clk50), + .m_ctrlport_req_wr (ps_ctrlport_req_wr), + .m_ctrlport_req_rd (ps_ctrlport_req_rd), + .m_ctrlport_req_addr (ps_ctrlport_req_addr), + .m_ctrlport_req_data (ps_ctrlport_req_data), + .m_ctrlport_resp_ack (ps_ctrlport_resp_ack), + .m_ctrlport_resp_status (ps_ctrlport_resp_status), + .m_ctrlport_resp_data (ps_ctrlport_resp_data), + .sclk (ps_spi_endpoint_sclk), + .cs_n (ps_spi_endpoint_cs_n), + .mosi (ps_spi_endpoint_mosi), + .miso (ps_spi_endpoint_miso) + ); + + // The PS SPI chip select signals are binary encoded. + // + // The internal SPI slaves as well as external slaves like the LMK04832 + // trigger actions or resets based on edges of the chip select signal. + // Therefore this implementation has to avoid glitches on the chip select + // signal although the SPI protocol is synchronous. + // + // The chip signals are double synchronized to make sure there is no + // meta-stability. Due to different traces lengths there is no guarantee for + // the chip select signals to change at the same time. To overcome this issue + // register stage 2 and 3 are compared. Only in case of matching values the + // change is propagated to the slaves' chip select lines. Once the IDLE state + // (all ones) is detected in register stage 2 the slaves' chip select lines + // will be deasserted. + + // Input sync registers (3 stages) + wire [3:0] ps_cpld_cs_n_shift2; // Resolving meta-stability, reset on IDLE + reg [3:0] ps_cpld_cs_n_shift3 = {4 {1'b1}}; // Stable state detection + synchronizer #( + .WIDTH (4), + .STAGES (2), + .INITIAL_VAL (4'b1111), + .FALSE_PATH_TO_IN (0) + ) ps_spi_input_sync_inst ( + .clk (clk250), + .rst (1'b0), + .in (PS_CPLD_CS_N), + .out (ps_cpld_cs_n_shift2) + ); + always @(posedge clk250) begin + ps_cpld_cs_n_shift3 <= ps_cpld_cs_n_shift2; + end + + // SPI binary decoding + reg [SPI_ENDPOINT_SIZE-2:0] ps_spi_cs_n_decoded = {SPI_ENDPOINT_SIZE-1 {1'b1}}; + always @(posedge clk250) begin + // reset in case of IDLE state + if (ps_cpld_cs_n_shift2[2:0] == PS_CS_IDLE) begin + ps_spi_cs_n_decoded <= {SPI_ENDPOINT_SIZE-1 {1'b1}}; + // only apply changes when stable state is detected + end else if (ps_cpld_cs_n_shift3[2:0] == ps_cpld_cs_n_shift2[2:0]) begin + ps_spi_cs_n_decoded[PS_CS_MB_CPLD] <= ps_cpld_cs_n_shift3[2:0] != PS_CS_MB_CPLD; + ps_spi_cs_n_decoded[PS_CS_LMK32] <= ps_cpld_cs_n_shift3[2:0] != PS_CS_LMK32; + ps_spi_cs_n_decoded[PS_CS_TPM] <= ps_cpld_cs_n_shift3[2:0] != PS_CS_TPM; + ps_spi_cs_n_decoded[PS_CS_PHASE_DAC] <= ps_cpld_cs_n_shift3[2:0] != PS_CS_PHASE_DAC; + ps_spi_cs_n_decoded[PS_CS_DB0_CAL_EEPROM] <= ps_cpld_cs_n_shift3[2:0] != PS_CS_DB0_CAL_EEPROM; + ps_spi_cs_n_decoded[PS_CS_DB1_CAL_EEPROM] <= ps_cpld_cs_n_shift3[2:0] != PS_CS_DB1_CAL_EEPROM; + ps_spi_cs_n_decoded[PS_CS_CLK_AUX_DB] <= ps_cpld_cs_n_shift3[2:0] != PS_CS_CLK_AUX_DB; + end + end + + // Local SPI slave + assign ps_spi_endpoint_sclk = PS_CPLD_SCLK; + assign ps_spi_endpoint_mosi = PS_CPLD_MOSI; + assign ps_spi_endpoint_cs_n = ps_spi_cs_n_decoded[PS_CS_MB_CPLD]; + + // LMK04832 SPI signals + assign LMK32_SCLK = PS_CPLD_SCLK; + assign LMK32_MOSI = PS_CPLD_MOSI; + assign LMK32_CS_N = ps_spi_cs_n_decoded[PS_CS_LMK32]; + + // TPM SPI signals + // Note: TPM is not currently supported + assign TPM_SCLK = PS_CPLD_SCLK; + assign TPM_MOSI = PS_CPLD_MOSI; + assign TPM_CS_N = ps_spi_cs_n_decoded[PS_CS_TPM]; + + // Phase DAC SPI signals + assign PHASE_DAC_SCLK = PS_CPLD_SCLK; + assign PHASE_DAC_MOSI = PS_CPLD_MOSI; + assign PHASE_DAC_CS_N = ps_spi_cs_n_decoded[PS_CS_PHASE_DAC]; + + // DB EEPROM 0 SPI signals + assign DB_CALEEPROM_SCLK[0] = PS_CPLD_SCLK; + assign DB_CALEEPROM_MOSI[0] = PS_CPLD_MOSI; + assign DB_CALEEPROM_CS_N[0] = ps_spi_cs_n_decoded[PS_CS_DB0_CAL_EEPROM]; + + // DB EEPROM 1 SPI signals + assign DB_CALEEPROM_SCLK[1] = PS_CPLD_SCLK; + assign DB_CALEEPROM_MOSI[1] = PS_CPLD_MOSI; + assign DB_CALEEPROM_CS_N[1] = ps_spi_cs_n_decoded[PS_CS_DB1_CAL_EEPROM]; + + // CLK AUX DB SPI signals + assign CLK_DB_SCLK = PS_CPLD_SCLK; + assign CLK_DB_MOSI = PS_CPLD_MOSI; + assign CLK_DB_CS_N = ps_spi_cs_n_decoded[PS_CS_CLK_AUX_DB]; + + // Combine SPI responses based on inputs only as this path is captured + // synchronously to PS_CPLD_SCLK by the SPI master. + assign PS_CPLD_MISO = (PS_CPLD_CS_N[2:0] == PS_CS_MB_CPLD) ? ps_spi_endpoint_miso : + (PS_CPLD_CS_N[2:0] == PS_CS_LMK32) ? LMK32_MISO : + (PS_CPLD_CS_N[2:0] == PS_CS_TPM) ? TPM_MISO : + (PS_CPLD_CS_N[2:0] == PS_CS_DB0_CAL_EEPROM) ? DB_CALEEPROM_MISO[0] : + (PS_CPLD_CS_N[2:0] == PS_CS_DB1_CAL_EEPROM) ? DB_CALEEPROM_MISO[1] : + (PS_CPLD_CS_N[2:0] == PS_CS_CLK_AUX_DB) ? CLK_DB_MISO : + 1'bz; // Default case and PHASE_DAC + + // Split up the PS control port + wire [19:0] ps_regs_ctrlport_req_addr; + wire [31:0] ps_regs_ctrlport_req_data; + wire ps_regs_ctrlport_req_rd; + wire ps_regs_ctrlport_req_wr; + wire ps_regs_ctrlport_resp_ack; + wire [31:0] ps_regs_ctrlport_resp_data; + wire [ 1:0] ps_regs_ctrlport_resp_status; + + wire [19:0] ps_term_ctrlport_req_addr; + wire [31:0] ps_term_ctrlport_req_data; + wire ps_term_ctrlport_req_rd; + wire ps_term_ctrlport_req_wr; + wire ps_term_ctrlport_resp_ack; + wire [31:0] ps_term_ctrlport_resp_data; + wire [ 1:0] ps_term_ctrlport_resp_status; + + wire [19:0] ps_reconfig_ctrlport_req_addr; + wire [31:0] ps_reconfig_ctrlport_req_data; + wire ps_reconfig_ctrlport_req_rd; + wire ps_reconfig_ctrlport_req_wr; + wire ps_reconfig_ctrlport_resp_ack; + wire [31:0] ps_reconfig_ctrlport_resp_data; + wire [ 1:0] ps_reconfig_ctrlport_resp_status; + + wire [19:0] ps_power_ctrlport_req_addr; + wire [31:0] ps_power_ctrlport_req_data; + wire ps_power_ctrlport_req_rd; + wire ps_power_ctrlport_req_wr; + wire ps_power_ctrlport_resp_ack; + wire [31:0] ps_power_ctrlport_resp_data; + wire [ 1:0] ps_power_ctrlport_resp_status; + + ctrlport_splitter #( + .NUM_SLAVES (4) + ) ps_ctrlport_splitter ( + .ctrlport_clk (clk50), + .ctrlport_rst (reset_clk50), + .s_ctrlport_req_wr (ps_ctrlport_req_wr), + .s_ctrlport_req_rd (ps_ctrlport_req_rd), + .s_ctrlport_req_addr (ps_ctrlport_req_addr), + .s_ctrlport_req_data (ps_ctrlport_req_data), + .s_ctrlport_req_byte_en (), + .s_ctrlport_req_has_time (), + .s_ctrlport_req_time (), + .s_ctrlport_resp_ack (ps_ctrlport_resp_ack), + .s_ctrlport_resp_status (ps_ctrlport_resp_status), + .s_ctrlport_resp_data (ps_ctrlport_resp_data), + .m_ctrlport_req_wr ({ps_power_ctrlport_req_wr, ps_regs_ctrlport_req_wr, ps_term_ctrlport_req_wr, ps_reconfig_ctrlport_req_wr}), + .m_ctrlport_req_rd ({ps_power_ctrlport_req_rd, ps_regs_ctrlport_req_rd, ps_term_ctrlport_req_rd, ps_reconfig_ctrlport_req_rd}), + .m_ctrlport_req_addr ({ps_power_ctrlport_req_addr, ps_regs_ctrlport_req_addr, ps_term_ctrlport_req_addr, ps_reconfig_ctrlport_req_addr}), + .m_ctrlport_req_data ({ps_power_ctrlport_req_data, ps_regs_ctrlport_req_data, ps_term_ctrlport_req_data, ps_reconfig_ctrlport_req_data}), + .m_ctrlport_req_byte_en (), + .m_ctrlport_req_has_time (), + .m_ctrlport_req_time (), + .m_ctrlport_resp_ack ({ps_power_ctrlport_resp_ack, ps_regs_ctrlport_resp_ack, ps_term_ctrlport_resp_ack, ps_reconfig_ctrlport_resp_ack}), + .m_ctrlport_resp_status ({ps_power_ctrlport_resp_status, ps_regs_ctrlport_resp_status, ps_term_ctrlport_resp_status, ps_reconfig_ctrlport_resp_status}), + .m_ctrlport_resp_data ({ps_power_ctrlport_resp_data, ps_regs_ctrlport_resp_data, ps_term_ctrlport_resp_data, ps_reconfig_ctrlport_resp_data}) + ); + + wire [39:0] serial_num_clk50; + wire cmi_ready_clk50; + wire cmi_other_side_detected_clk50; + ps_cpld_regs #( + .BASE_ADDRESS (PS_REGISTERS) + ) ps_regs ( + .ctrlport_clk (clk50), + .ctrlport_rst (reset_clk50), + .s_ctrlport_req_wr (ps_regs_ctrlport_req_wr), + .s_ctrlport_req_rd (ps_regs_ctrlport_req_rd), + .s_ctrlport_req_addr (ps_regs_ctrlport_req_addr), + .s_ctrlport_req_data (ps_regs_ctrlport_req_data), + .s_ctrlport_resp_ack (ps_regs_ctrlport_resp_ack), + .s_ctrlport_resp_status (ps_regs_ctrlport_resp_status), + .s_ctrlport_resp_data (ps_regs_ctrlport_resp_data), + .db_clk_enable (db_clk_enable), + .db_reset (db_reset), + .pll_ref_clk_enable (pll_ref_clk_en_clk50), + .dio_direction_a (DIO_DIRECTION_A), + .dio_direction_b (DIO_DIRECTION_B), + .serial_num (serial_num_clk50), + .cmi_ready (cmi_ready_clk50), + .cmi_other_side_detected (cmi_other_side_detected_clk50) + ); + + ps_power_regs #( + .BASE_ADDRESS (POWER_REGISTERS), + .NUM_ADDRESSES (POWER_REGISTERS_SIZE) + ) ps_power_regs_inst ( + .ctrlport_clk (clk50), + .ctrlport_rst (reset_clk50), + .s_ctrlport_req_wr (ps_power_ctrlport_req_wr), + .s_ctrlport_req_rd (ps_power_ctrlport_req_rd), + .s_ctrlport_req_addr (ps_power_ctrlport_req_addr), + .s_ctrlport_req_data (ps_power_ctrlport_req_data), + .s_ctrlport_resp_ack (ps_power_ctrlport_resp_ack), + .s_ctrlport_resp_status (ps_power_ctrlport_resp_status), + .s_ctrlport_resp_data (ps_power_ctrlport_resp_data), + .ipass_power_disable (IPASS_POWER_DISABLE), + .ipass_power_fault_n (IPASS_POWER_EN_FAULT), + .osc_100_en (PWR_EN_5V_OSC_100), + .osc_122_88_en (PWR_EN_5V_OSC_122_88) + ); + + // Termination of ctrlport request + ctrlport_terminator #( + .START_ADDRESS (POWER_REGISTERS + POWER_REGISTERS_SIZE), + .LAST_ADDRESS (2**CTRLPORT_ADDR_W-1) + ) ps_terminator ( + .ctrlport_clk (clk50), + .ctrlport_rst (reset_clk50), + .s_ctrlport_req_wr (ps_term_ctrlport_req_wr), + .s_ctrlport_req_rd (ps_term_ctrlport_req_rd), + .s_ctrlport_req_addr (ps_term_ctrlport_req_addr), + .s_ctrlport_req_data (ps_term_ctrlport_req_data), + .s_ctrlport_resp_ack (ps_term_ctrlport_resp_ack), + .s_ctrlport_resp_status (ps_term_ctrlport_resp_status), + .s_ctrlport_resp_data (ps_term_ctrlport_resp_data) + ); + + + //--------------------------------------------------------------------------- + // Reconfiguration + //--------------------------------------------------------------------------- + // On-chip flash interface + // + // Naming is according to Avalon Memory-Mapped Interfaces: + // https://www.intel.com/content/dam/www/programmable/us/en/pdfs/literature/manual/mnl_avalon_spec.pdf + + wire csr_addr; + wire csr_read; + wire [31:0] csr_readdata; + wire csr_write; + wire [31:0] csr_writedata; + wire [16:0] data_addr; + wire data_read; + wire [31:0] data_readdata; + wire data_readdatavalid; + wire data_waitrequest; + wire data_write; + wire [31:0] data_writedata; + wire reset_clk50_n; + + assign reset_clk50_n = ~reset_clk50; + on_chip_flash flash_inst ( + .clock (clk50), + .avmm_csr_addr (csr_addr), + .avmm_csr_read (csr_read), + .avmm_csr_writedata (csr_writedata), + .avmm_csr_write (csr_write), + .avmm_csr_readdata (csr_readdata), + .avmm_data_addr (data_addr), + .avmm_data_read (data_read), + .avmm_data_writedata (data_writedata), + .avmm_data_write (data_write), + .avmm_data_readdata (data_readdata), + .avmm_data_waitrequest (data_waitrequest), + .avmm_data_readdatavalid (data_readdatavalid), + .avmm_data_burstcount (4'b0001), + .reset_n (reset_clk50_n) + ); + + reconfig_engine #( + .BASE_ADDRESS (RECONFIG), + .NUM_ADDRESSES (RECONFIG_SIZE), + .MEM_INIT (0) + ) reconfig_engine_inst ( + .ctrlport_clk (clk50), + .ctrlport_rst (reset_clk50), + .s_ctrlport_req_wr (ps_reconfig_ctrlport_req_wr), + .s_ctrlport_req_rd (ps_reconfig_ctrlport_req_rd), + .s_ctrlport_req_addr (ps_reconfig_ctrlport_req_addr), + .s_ctrlport_req_data (ps_reconfig_ctrlport_req_data), + .s_ctrlport_resp_ack (ps_reconfig_ctrlport_resp_ack), + .s_ctrlport_resp_status (ps_reconfig_ctrlport_resp_status), + .s_ctrlport_resp_data (ps_reconfig_ctrlport_resp_data), + .csr_addr (csr_addr), + .csr_read (csr_read), + .csr_writedata (csr_writedata), + .csr_write (csr_write), + .csr_readdata (csr_readdata), + .data_addr (data_addr), + .data_read (data_read), + .data_writedata (data_writedata), + .data_write (data_write), + .data_readdata (data_readdata), + .data_waitrequest (data_waitrequest), + .data_readdatavalid (data_readdatavalid) + ); + + //--------------------------------------------------------------------------- + // CMI Interface + //--------------------------------------------------------------------------- + + // Control and status information clock transition + wire [39:0] serial_num_clk40; + wire cmi_ready_clk40; + wire cmi_other_side_detected_clk40; + + handshake #( + .WIDTH (41) + ) cmi_control_hs ( + .clk_a (clk50), + .rst_a (reset_clk50), + .valid_a (1'b1), + .data_a ({cmi_ready_clk50, serial_num_clk50}), + .busy_a (), + .clk_b (clk40), + .valid_b (), + .data_b ({cmi_ready_clk40, serial_num_clk40}) + ); + + synchronizer #( + .WIDTH (1), + .STAGES (2), + .INITIAL_VAL (1'b0), + .FALSE_PATH_TO_IN (1) + ) cmi_status_sync ( + .clk (clk50), + .rst (reset_clk50), + .in (cmi_other_side_detected_clk40), + .out (cmi_other_side_detected_clk50) + ); + + wire scl_out; + wire sda_out; + wire [1:0] ipass_cable_present_n = ~ipass_cable_present; + + PcieCmiWrapper #( + .kSimulation (SIMULATION) + ) pcie_cmi_inst ( + .Clk (clk40), + .acReset (reset_clk40), + .cSerialNumber (serial_num_clk40), + .cBoardIsReady (cmi_ready_clk40), + .cCmiReset (PCIE_RESET), + .cOtherSideDetected (cmi_other_side_detected_clk40), + .aCblPrsnt_n (ipass_cable_present_n[0]), + .aSdaIn (IPASS_SDA[0]), + .aSdaOut (sda_out), + .aSclIn (IPASS_SCL[0]), + .aSclOut (scl_out) + ); + + // External pull-ups are used to drive the signal high + assign IPASS_SDA[0] = sda_out ? 1'bz : 1'b0; + assign IPASS_SCL[0] = scl_out ? 1'bz : 1'b0; + + // No CMI controller for second interface + assign IPASS_SCL[1] = 1'bz; + assign IPASS_SDA[1] = 1'bz; + + //--------------------------------------------------------------------------- + // Miscellaneous + //--------------------------------------------------------------------------- + + // Constants + assign PS_CLK_ON_CPLD = 1'b0; // Active-low driving of PS clocks + assign TPM_RESET_n = 1'b1; + + // Currently unused ports + assign PL_CPLD_IRQ = 1'b0; + +endmodule + + +`default_nettype wire + + +//XmlParse xml_on +//<top name="X4XX_MB_CPLD"> +// <regmapcfg readablestrobes="false"> +// <map name="MB_CPLD_PS_REGMAP"/> +// <map name="MB_CPLD_PL_REGMAP"/> +// </regmapcfg> +//</top> +//<regmap name="MB_CPLD_PS_REGMAP" readablestrobes="false" markdown="true" generatevhdl="true" ettusguidelines="true"> +// <info> +// This register map is available using the PS CPLD SPI interface. +// </info> +// <group name="MB_CPLD_PS_WINDOWS"> +// <window name="PS_REGISTERS" offset="0x00" size="0x40" targetregmap="PS_CPLD_BASE_REGMAP"/> +// <window name="RECONFIG" offset="0x40" size="0x20" targetregmap="RECONFIG_REGMAP"/> +// <window name="POWER_REGISTERS" offset="0x60" size="0x20" targetregmap="PS_POWER_REGMAP"/> +// </group> +// <group name="PS_SPI_ENDPOINTS"> +// <enumeratedtype name="SPI_ENDPOINT"> +// <value name="PS_CS_MB_CPLD" integer="0"/> +// <value name="PS_CS_LMK32" integer="1"/> +// <value name="PS_CS_TPM" integer="2"/> +// <value name="PS_CS_PHASE_DAC" integer="3"/> +// <value name="PS_CS_DB0_CAL_EEPROM" integer="4"/> +// <value name="PS_CS_DB1_CAL_EEPROM" integer="5"/> +// <value name="PS_CS_CLK_AUX_DB" integer="6"/> +// <value name="PS_CS_IDLE" integer="7"/> +// </enumeratedtype> +// </group> +//</regmap> +//<regmap name="MB_CPLD_PL_REGMAP" readablestrobes="false" markdown="true" generatevhdl="true" ettusguidelines="true"> +// <info> +// This register map is available using the PL CPLD SPI interface. +// All protocol masters controller by this register map are running with a clock frequency of 50 MHz. +// </info> +// <group name="MB_CPLD_PL_WINDOWS"> +// <window name="PL_REGISTERS" offset="0x0" size="0x40" targetregmap="PL_CPLD_BASE_REGMAP"/> +// <window name="JTAG_DB0" offset="0x60" size="0x20" targetregmap="JTAG_REGMAP"> +// <info> +// JTAG Master connected to first daugherboard's CPLD JTAG interface. +// +// **Use minimum value of 1 for @.JTAG_REGMAP.prescalar because the DB CPLD JTAG interface maximum clock frequency is 20 MHz.** +// </info> +// </window> +// <window name="JTAG_DB1" offset="0x80" size="0x20" targetregmap="JTAG_REGMAP"> +// <info> +// JTAG Master connected to second daugherboard's CPLD JTAG interface. +// +// **Use minimum value of 1 for @.JTAG_REGMAP.prescalar because the DB CPLD JTAG interface maximum clock frequency is 20 MHz.** +// </info> +// </window> +// </group> +//</regmap> +//<regmap name="CONSTANTS_REGMAP" readablestrobes="false" generatevhdl="true" ettusguidelines="true"> +// <group name="CONSTANTS_GROUP"> +// <info> +// Basic registers containing version and capabilities information. +// </info> + +// <enumeratedtype name="CONSTANTS_ENUM" showhexvalue="true"> +// <info> +// This enumeration is used to create the constants held in the basic registers. +// </info> +// <value name="PS_CPLD_SIGNATURE" integer="0x0A522D27"/> +// <value name="PL_CPLD_SIGNATURE" integer="0x3FDC5C47"/> +// <value name="CPLD_REVISION" integer="0x21012015"/> +// <value name="OLDEST_CPLD_REVISION" integer="0x20122114"/> +// </enumeratedtype> +// </group> +//</regmap> +//XmlParse xml_off diff --git a/fpga/usrp3/top/x400/cpld/pl_cpld_regs.v b/fpga/usrp3/top/x400/cpld/pl_cpld_regs.v new file mode 100644 index 000000000..19acdea67 --- /dev/null +++ b/fpga/usrp3/top/x400/cpld/pl_cpld_regs.v @@ -0,0 +1,297 @@ +// +// Copyright 2021 Ettus Research, A National Instruments Brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: pl_cpld_regs +// +// Description: +// +// Basic Registers to inform software about version and capabilities. +// +// Parameters: +// +// BASE_ADDRESS : Base address for CtrlPort registers +// + +`default_nettype none + + +module pl_cpld_regs #( + parameter BASE_ADDRESS = 0 +) ( + 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, + + // QSFP LEDs + // Port 0 + output wire [ 3:0] qsfp0_led_active, + output wire [ 3:0] qsfp0_led_link, + // Port 1 + output wire [ 3:0] qsfp1_led_active, + output wire [ 3:0] qsfp1_led_link, + + // iPass status + output wire [ 1:0] ipass_cable_present +); + + `include "regmap/constants_regmap_utils.vh" + `include "regmap/pl_cpld_base_regmap_utils.vh" + `include "../../../lib/rfnoc/core/ctrlport.vh" + + //--------------------------------------------------------------------------- + // Address Calculation + //--------------------------------------------------------------------------- + + localparam NUM_ADDRESSES = 64; + wire address_in_range = (s_ctrlport_req_addr >= BASE_ADDRESS) && + (s_ctrlport_req_addr < BASE_ADDRESS + NUM_ADDRESSES); + + //--------------------------------------------------------------------------- + // Internal Registers + //--------------------------------------------------------------------------- + + reg [SCRATCH_REGISTER_SIZE-1:0] scratch_reg; + reg [LED_REGISTER_SIZE-1:0] led_reg; + reg [CABLE_PRESENT_REG_SIZE-1:0] ipass_reg; + + //--------------------------------------------------------------------------- + // Assign Outputs + //--------------------------------------------------------------------------- + + assign qsfp0_led_active = led_reg[QSFP0_LED_ACTIVE+:QSFP0_LED_ACTIVE_SIZE]; + assign qsfp0_led_link = led_reg[QSFP0_LED_LINK+:QSFP0_LED_LINK_SIZE]; + + assign qsfp1_led_active = led_reg[QSFP1_LED_ACTIVE+:QSFP1_LED_ACTIVE_SIZE]; + assign qsfp1_led_link = led_reg[QSFP1_LED_LINK+:QSFP1_LED_LINK_SIZE]; + + assign ipass_cable_present = ipass_reg; + + //--------------------------------------------------------------------------- + // Handling of ControlPort Requests + //--------------------------------------------------------------------------- + + always @(posedge ctrlport_clk) begin + // Reset internal registers and responses + if (ctrlport_rst) begin + scratch_reg <= 0; + led_reg <= 0; + ipass_reg <= 0; + s_ctrlport_resp_ack <= 1'b0; + + // Write requests + end else if (s_ctrlport_req_wr) begin + // Always issue an ack and no data + s_ctrlport_resp_ack <= 1'b1; + s_ctrlport_resp_data <= {CTRLPORT_DATA_W {1'bx}}; + s_ctrlport_resp_status <= CTRL_STS_OKAY; + + case (s_ctrlport_req_addr) + BASE_ADDRESS + SCRATCH_REGISTER: + scratch_reg <= s_ctrlport_req_data; + + BASE_ADDRESS + LED_REGISTER: + led_reg <= s_ctrlport_req_data[LED_REGISTER_SIZE-1:0]; + + BASE_ADDRESS + CABLE_PRESENT_REG: begin + ipass_reg[0] <= s_ctrlport_req_data[IPASS0_CABLE_PRESENT]; + ipass_reg[1] <= s_ctrlport_req_data[IPASS1_CABLE_PRESENT]; + 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 request + 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; + + case (s_ctrlport_req_addr) + BASE_ADDRESS + SIGNATURE_REGISTER: + s_ctrlport_resp_data <= PL_CPLD_SIGNATURE; + + BASE_ADDRESS + REVISION_REGISTER: + s_ctrlport_resp_data <= CPLD_REVISION; + + BASE_ADDRESS + OLDEST_COMPATIBLE_REVISION_REGISTER: + s_ctrlport_resp_data <= OLDEST_CPLD_REVISION; + + BASE_ADDRESS + SCRATCH_REGISTER: + s_ctrlport_resp_data <= scratch_reg; + + BASE_ADDRESS + GIT_HASH_REGISTER: + `ifdef GIT_HASH + s_ctrlport_resp_data <= `GIT_HASH; + `else + s_ctrlport_resp_data <= 32'hDEADBEEF; + `endif + + BASE_ADDRESS + LED_REGISTER: + s_ctrlport_resp_data <= {{(CTRLPORT_DATA_W - LED_REGISTER_SIZE){1'b0}}, led_reg}; + + BASE_ADDRESS + CABLE_PRESENT_REG: begin + s_ctrlport_resp_data <= {CTRLPORT_DATA_W {1'b0}}; + s_ctrlport_resp_data[IPASS0_CABLE_PRESENT] <= ipass_reg[0]; + s_ctrlport_resp_data[IPASS1_CABLE_PRESENT] <= ipass_reg[1]; + end + + // Error on undefined address + default: begin + s_ctrlport_resp_data <= {CTRLPORT_DATA_W {1'bx}}; + 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 + +endmodule + + +`default_nettype wire + + +//XmlParse xml_on +//<regmap name="PL_CPLD_BASE_REGMAP" readablestrobes="false" generatevhdl="true" ettusguidelines="true"> +// <group name="PL_CPLD_BASE_REGS"> +// <info> +// Basic registers containing version and capabilities information. +// </info> +// +// <register name="SIGNATURE_REGISTER" offset="0x00" writable="false" size="32"> +// <info>Contains the product's signature.</info> +// <bitfield name="PRODUCT_SIGNATURE" range="31..0"> +// <info>Fixed value PL_CPLD_SIGNATURE of @.CONSTANTS_REGMAP</info> +// </bitfield> +// </register> +// +// <register name="REVISION_REGISTER" offset="0x04" writable="false" size="32"> +// <info>Contains the CPLD revision (see CPLD_REVISION of @.CONSTANTS_REGMAP)</info> +// <bitfield name="REVISION_HH" range="7..0"> +// <info>Contains revision hour code.</info> +// </bitfield> +// <bitfield name="REVISION_DD" range="15..8"> +// <info>Contains revision day code.</info> +// </bitfield> +// <bitfield name="REVISION_MM" range="23..16"> +// <info>Contains revision month code.</info> +// </bitfield> +// <bitfield name="REVISION_YY" range="31..24"> +// <info>Contains revision year code.</info> +// </bitfield> +// </register> +// +// <register name="OLDEST_COMPATIBLE_REVISION_REGISTER" offset="0x08" writable="false" size="32"> +// <info> +// This register returns (in YYMMDDHH format) the oldest revision +// that is still compatible with this one. Compatible means that +// registers or register bits may have been added, but not +// modified or deleted (see OLDEST_CPLD_REVISION of @.CONSTANTS_REGMAP). +// </info> +// <bitfield name="OLD_REVISION_HH" range="7..0"> +// <info>Contains revision hour code.</info> +// </bitfield> +// <bitfield name="OLD_REVISION_DD" range="15..8"> +// <info>Contains revision day code.</info> +// </bitfield> +// <bitfield name="OLD_REVISION_MM" range="23..16"> +// <info>Contains revision month code.</info> +// </bitfield> +// <bitfield name="OLD_REVISION_YY" range="31..24"> +// <info>Contains revision year code.</info> +// </bitfield> +// </register> +// +// <register name="SCRATCH_REGISTER" offset="0x0C" size="32"> +// <info>Read/write register for general software use.</info> +// </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> +// +// <group name="MB_CPLD_LED_REGS"> +// <info> +// Register Map to control QSFP LEDs. +// </info> +// <register name="LED_REGISTER" offset="0x20" size="16"> +// <info> +// Provides to the LEDs of the QSFP ports. +// Write access will directly change the LED status. +// The LED lights up if the corresponding bit is set. +// </info> +// <bitfield name="QSFP0_LED_LINK" range="3..0"> +// <info>Link LEDs of QSFP port 0</info> +// </bitfield> +// <bitfield name="QSFP0_LED_ACTIVE" range="7..4"> +// <info>Active LEDs of QSFP port 0</info> +// </bitfield> +// <bitfield name="QSFP1_LED_LINK" range="11..8"> +// <info>Link LEDs of QSFP port 1</info> +// </bitfield> +// <bitfield name="QSFP1_LED_ACTIVE" range="15..12"> +// <info>Active LEDs of QSFP port 1</info> +// </bitfield> +// </register> +// </group> +// +// <group name="PL_CMI_REGS"> +// <info> +// Cable present status register. +// </info> +// <register name="CABLE_PRESENT_REG" offset="0x30" size="2"> +// <info> +// Information from FPGA about the cable present status. +// </info> +// <bitfield name="IPASS0_CABLE_PRESENT" range="0"> +// <info>Set to 1 if cable present in iPass 0 connector.</info> +// </bitfield> +// <bitfield name="IPASS1_CABLE_PRESENT" range="1"> +// <info>Set to 1 if cable present in iPass 1 connector.</info> +// </bitfield> +// </register> +// </group> +//</regmap> +//XmlParse xml_off diff --git a/fpga/usrp3/top/x400/cpld/ps_cpld_regs.v b/fpga/usrp3/top/x400/cpld/ps_cpld_regs.v new file mode 100644 index 000000000..d5f9b1d5f --- /dev/null +++ b/fpga/usrp3/top/x400/cpld/ps_cpld_regs.v @@ -0,0 +1,404 @@ +// +// Copyright 2021 Ettus Research, A National Instruments Brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: ps_cpld_regs +// +// Description: +// +// Basic registers to inform software about version and capabilities. +// +// Parameters: +// +// BASE_ADDRESS : Base address for CtrlPort registers +// + +`default_nettype none + + +module ps_cpld_regs #( + parameter BASE_ADDRESS = 0 +) ( + 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, + + // Configuration outputs + output reg [ 1:0] db_clk_enable = 2'b00, + output reg [ 1:0] db_reset = 2'b11, + output reg pll_ref_clk_enable = 1'b0, + + output reg [11:0] dio_direction_a = 12'b0, + output reg [11:0] dio_direction_b = 12'b0, + + output reg [39:0] serial_num = 40'b0, + output reg cmi_ready = 1'b0, + input wire cmi_other_side_detected +); + +`include "regmap/constants_regmap_utils.vh" +`include "regmap/ps_cpld_base_regmap_utils.vh" +`include "../../../lib/rfnoc/core/ctrlport.vh" + +//----------------------------------------------------------------------------- +// Address Calculation +//----------------------------------------------------------------------------- + +localparam NUM_ADDRESSES = 64; +wire address_in_range = (s_ctrlport_req_addr >= BASE_ADDRESS) && + (s_ctrlport_req_addr < BASE_ADDRESS + NUM_ADDRESSES); + +//----------------------------------------------------------------------------- +// Internal Registers +//----------------------------------------------------------------------------- + +reg [SCRATCH_REGISTER_SIZE-1:0] scratch_reg; + +//----------------------------------------------------------------------------- +// Handling of ControlPort Requests +//----------------------------------------------------------------------------- + +always @(posedge ctrlport_clk) begin + // Reset internal registers and responses + if (ctrlport_rst) begin + scratch_reg <= 0; + db_clk_enable <= 2'b00; + db_reset <= 2'b11; + pll_ref_clk_enable <= 1'b0; + dio_direction_a <= {DIO_DIRECTION_A_SIZE{1'b0}}; + dio_direction_b <= {DIO_DIRECTION_B_SIZE{1'b0}}; + s_ctrlport_resp_ack <= 1'b0; + s_ctrlport_resp_data <= {CTRLPORT_ADDR_W {1'bx}}; + s_ctrlport_resp_status <= CTRL_STS_OKAY; + + // Write requests + end else begin + if (s_ctrlport_req_wr) begin + // Always issue an ack and no data + s_ctrlport_resp_ack <= 1'b1; + s_ctrlport_resp_data <= {CTRLPORT_ADDR_W {1'bx}}; + s_ctrlport_resp_status <= CTRL_STS_OKAY; + + case (s_ctrlport_req_addr) + BASE_ADDRESS + SCRATCH_REGISTER: + scratch_reg <= s_ctrlport_req_data; + + BASE_ADDRESS + PL_DB_REGISTER: begin + if (s_ctrlport_req_data[DISABLE_CLOCK_DB0]) begin + db_clk_enable[0] <= 1'b0; + end else if (s_ctrlport_req_data[ENABLE_CLOCK_DB0]) begin + db_clk_enable[0] <= 1'b1; + end + if (s_ctrlport_req_data[DISABLE_CLOCK_DB1]) begin + db_clk_enable[1] <= 1'b0; + end else if (s_ctrlport_req_data[ENABLE_CLOCK_DB1]) begin + db_clk_enable[1] <= 1'b1; + end + if (s_ctrlport_req_data[DISABLE_PLL_REF_CLOCK]) begin + pll_ref_clk_enable <= 1'b0; + end else if (s_ctrlport_req_data[ENABLE_PLL_REF_CLOCK]) begin + pll_ref_clk_enable <= 1'b1; + end + if (s_ctrlport_req_data[ASSERT_RESET_DB0]) begin + db_reset[0] <= 1'b1; + end else if (s_ctrlport_req_data[RELEASE_RESET_DB0]) begin + db_reset[0] <= 1'b0; + end + if (s_ctrlport_req_data[ASSERT_RESET_DB1]) begin + db_reset[1] <= 1'b1; + end else if (s_ctrlport_req_data[RELEASE_RESET_DB1]) begin + db_reset[1] <= 1'b0; + end + end + + BASE_ADDRESS + DIO_DIRECTION_REGISTER: begin + dio_direction_a <= s_ctrlport_req_data[DIO_DIRECTION_A_MSB:DIO_DIRECTION_A]; + dio_direction_b <= s_ctrlport_req_data[DIO_DIRECTION_B_MSB:DIO_DIRECTION_B]; + end + + BASE_ADDRESS + SERIAL_NUM_LOW_REG: begin + serial_num[31:0] <= s_ctrlport_req_data; + end + + BASE_ADDRESS + SERIAL_NUM_HIGH_REG: begin + serial_num[39:32] <= s_ctrlport_req_data[SERIAL_NUM_HIGH_REG_SIZE-1:0]; + end + + BASE_ADDRESS + CMI_CONTROL_STATUS: begin + cmi_ready <= s_ctrlport_req_data[CMI_READY]; + 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 request + 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 <= {CTRLPORT_DATA_W {1'b0}}; + + case (s_ctrlport_req_addr) + BASE_ADDRESS + SIGNATURE_REGISTER: + s_ctrlport_resp_data <= PS_CPLD_SIGNATURE; + + BASE_ADDRESS + REVISION_REGISTER: + s_ctrlport_resp_data <= CPLD_REVISION; + + BASE_ADDRESS + OLDEST_COMPATIBLE_REVISION_REGISTER: + s_ctrlport_resp_data <= OLDEST_CPLD_REVISION; + + BASE_ADDRESS + SCRATCH_REGISTER: + s_ctrlport_resp_data <= scratch_reg; + + BASE_ADDRESS + GIT_HASH_REGISTER: + `ifdef GIT_HASH + s_ctrlport_resp_data <= `GIT_HASH; + `else + s_ctrlport_resp_data <= 32'hDEADBEEF; + `endif + + BASE_ADDRESS + PL_DB_REGISTER: begin + s_ctrlport_resp_data[DB0_CLOCK_ENABLED] <= db_clk_enable[0]; + s_ctrlport_resp_data[DB1_CLOCK_ENABLED] <= db_clk_enable[1]; + s_ctrlport_resp_data[PLL_REF_CLOCK_ENABLED] <= pll_ref_clk_enable; + s_ctrlport_resp_data[DB0_RESET_ASSERTED] <= db_reset[0]; + s_ctrlport_resp_data[DB1_RESET_ASSERTED] <= db_reset[1]; + end + + BASE_ADDRESS + DIO_DIRECTION_REGISTER: begin + s_ctrlport_resp_data[DIO_DIRECTION_A_MSB:DIO_DIRECTION_A] <= dio_direction_a; + s_ctrlport_resp_data[DIO_DIRECTION_B_MSB:DIO_DIRECTION_B] <= dio_direction_b; + end + + BASE_ADDRESS + SERIAL_NUM_LOW_REG: begin + s_ctrlport_resp_data <= serial_num[31:0]; + end + + BASE_ADDRESS + SERIAL_NUM_HIGH_REG: begin + s_ctrlport_resp_data[SERIAL_NUM_HIGH_REG_SIZE-1:0] <= serial_num[39:32]; + end + + BASE_ADDRESS + CMI_CONTROL_STATUS: begin + s_ctrlport_resp_data[CMI_READY] <= cmi_ready; + s_ctrlport_resp_data[OTHER_SIDE_DETECTED] <= cmi_other_side_detected; + end + + // Error on undefined address + default: begin + s_ctrlport_resp_data <= {CTRLPORT_DATA_W {1'bx}}; + 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="PS_CPLD_BASE_REGMAP" readablestrobes="false" generatevhdl="true" ettusguidelines="true"> +// <group name="PS_CPLD_BASE_REGS"> +// <info> +// Basic registers containing version and capabilites information. +// </info> +// +// <register name="SIGNATURE_REGISTER" offset="0x00" writable="false" size="32"> +// <info>Contains the product's signature.</info> +// <bitfield name="PRODUCT_SIGNATURE" range="31..0"> +// <info>Fixed value PS_CPLD_SIGNATURE of @.CONSTANTS_REGMAP</info> +// </bitfield> +// </register> +// +// <register name="REVISION_REGISTER" offset="0x04" writable="false" size="32"> +// <info>Contains the CPLD revision (see CPLD_REVISION of @.CONSTANTS_REGMAP).</info> +// <bitfield name="REVISION_HH" range="7..0"> +// <info>Contains revision hour code.</info> +// </bitfield> +// <bitfield name="REVISION_DD" range="15..8"> +// <info>Contains revision day code.</info> +// </bitfield> +// <bitfield name="REVISION_MM" range="23..16"> +// <info>Contains revision month code.</info> +// </bitfield> +// <bitfield name="REVISION_YY" range="31..24"> +// <info>Contains revision year code.</info> +// </bitfield> +// </register> +// +// <register name="OLDEST_COMPATIBLE_REVISION_REGISTER" offset="0x08" writable="false" size="32"> +// <info> +// This register returns (in YYMMDDHH format) the oldest revision +// that is still compatible with this one. Compatible means that +// registers or register bits may have been added, but not +// modified or deleted (see OLDEST_CPLD_REVISION of @.CONSTANTS_REGMAP). +// </info> +// <bitfield name="OLD_REVISION_HH" range="7..0"> +// <info>Contains revision hour code.</info> +// </bitfield> +// <bitfield name="OLD_REVISION_DD" range="15..8"> +// <info>Contains revision day code.</info> +// </bitfield> +// <bitfield name="OLD_REVISION_MM" range="23..16"> +// <info>Contains revision month code.</info> +// </bitfield> +// <bitfield name="OLD_REVISION_YY" range="31..24"> +// <info>Contains revision year code.</info> +// </bitfield> +// </register> +// +// <register name="SCRATCH_REGISTER" offset="0x0C" size="32"> +// <info>Read/write register for general software use.</info> +// </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> +// +// <group name="PS_CONTROL_REGS"> +// <info> +// Register Map to control MB CPLD functions. +// </info> +// <register name="PL_DB_REGISTER" offset="0x20" size="32"> +// <info> +// Register to control the PL part DB SPI connection and reset generation. +// The DB connection is clocked with PLL reference clock. Ensure this clock is stable +// and enabled before starting any SPI request. +// The PLL reference clock can be disabled if both DB connections are disabled or inactive. +// To enable the DB connection, enable clock with one write access and release +// reset with the next write access. +// To disable the DB connection, assert reset with one write access and +// disable clocks with the next write access. +// </info> +// <bitfield name="DB0_CLOCK_ENABLED" range="0" writable="false"> +// <info>Indicates if a clock is forwarded to DB 0.</info> +// </bitfield> +// <bitfield name="DB1_CLOCK_ENABLED" range="1" writable="false"> +// <info>Indicates if a clock is forwarded to DB 1.</info> +// </bitfield> +// <bitfield name="PLL_REF_CLOCK_ENABLED" range="2" writable="false"> +// <info>Indicates if the PLL reference clock for the PL interface is enabled.</info> +// </bitfield> +// <bitfield name="DB0_RESET_ASSERTED" range="4" writable="false"> +// <info>Indicates that reset is asserted for DB 0.</info> +// </bitfield> +// <bitfield name="DB1_RESET_ASSERTED" range="5" writable="false"> +// <info>Indicates that reset is asserted for DB 1.</info> +// </bitfield> +// <bitfield name="ENABLE_CLOCK_DB0" range="8" readable="false"> +// <info>Writing with this flag set enables DB 0 clock forwarding. (may be overwritten by @.DISABLE_CLOCK_DB0)</info> +// </bitfield> +// <bitfield name="ENABLE_CLOCK_DB1" range="9" readable="false"> +// <info>Writing with this flag set enables DB 1 clock forwarding. (may be overwritten by @.DISABLE_CLOCK_DB1)</info> +// </bitfield> +// <bitfield name="ENABLE_PLL_REF_CLOCK" range="10" readable="false"> +// <info>Writing with this flag set enables the PLL reference clock. Assert this flag after PLL reference clock is stable. (may be overwritten by @.DISABLE_PLL_REF_CLOCK)</info> +// </bitfield> +// <bitfield name="DISABLE_CLOCK_DB0" range="12" readable="false"> +// <info>Writing with this flag set disables DB 0 clock forwarding (overrides @.ENABLE_CLOCK_DB0)</info> +// </bitfield> +// <bitfield name="DISABLE_CLOCK_DB1" range="13" readable="false"> +// <info>Writing with this flag set disables DB 1 clock forwarding (overrides @.ENABLE_CLOCK_DB1)</info> +// </bitfield> +// <bitfield name="DISABLE_PLL_REF_CLOCK" range="14" readable="false"> +// <info>Writing with this flag set disables the PLL reference clock (overrides @.ENABLE_PLL_REF_CLOCK). Assert this flag to reconfigure the clock.</info> +// </bitfield> +// <bitfield name="RELEASE_RESET_DB0" range="16" readable="false"> +// <info>Writing with this flag set releases DB 0 reset. (may be overwritten by @.ASSERT_RESET_DB0)</info> +// </bitfield> +// <bitfield name="RELEASE_RESET_DB1" range="17" readable="false"> +// <info>Writing with this flag set releases DB 1 reset. (may be overwritten by @.ASSERT_RESET_DB1)</info> +// </bitfield> +// <bitfield name="ASSERT_RESET_DB0" range="20" readable="false"> +// <info>Writing with this flag set asserts reset for DB 0 (overrides @.RELEASE_RESET_DB0)</info> +// </bitfield> +// <bitfield name="ASSERT_RESET_DB1" range="21" readable="false"> +// <info>Writing with this flag set asserts reset for DB 1 (overrides @.RELEASE_RESET_DB1)</info> +// </bitfield> +// </register> +// </group> +// +// <group name="DIO_REGS"> +// <info> +// Registers to control the GPIO buffer direction on the DIO board connected to the FPGA. +// Make sure the GPIO lines between FPGA and GPIO board are not driven by two drivers. +// Set the direction in the FPGA's DIO register appropriately. +// </info> +// <register name="DIO_DIRECTION_REGISTER" offset="0x30" size="32"> +// <info> +// Set the direction of FPGA buffer connected to DIO ports on the DIO board.{br/} +// Each bit represents one signal line. 0 = line is an input to the FPGA, 1 = line is an output driven by the FPGA. +// </info> +// <bitfield name="DIO_DIRECTION_A" range="11..0" initialvalue="0"/> +// <bitfield name="DIO_DIRECTION_B" range="27..16" initialvalue="0"/> +// </register> +// </group> +// +// <group name="PS_CMI_REGS"> +// <info> +// Cable present status register. +// </info> +// <register name="SERIAL_NUM_LOW_REG" offset="0x34" size="32"> +// <info>Least significant bytes of 5 byte serial number.</info> +// </register> +// <register name="SERIAL_NUM_HIGH_REG" offset="0x38" size="8"> +// <info>Most significant byte of 5 byte serial number.</info> +// </register> +// <register name="CMI_CONTROL_STATUS" offset="0x3C" size="32"> +// <info>Control CMI communication and delivers information on the CMI link status.</info> +// <bitfield name="CMI_READY" range="0"> +// <info>Set if the device is ready to establish a PCI-Express link (affects CMI_CLP_READY bit).</info> +// </bitfield> +// <bitfield name="OTHER_SIDE_DETECTED" range="31" writable="false"> +// <info>1 if an upstream CMI device has been detected.</info> +// </bitfield> +// </register> +// </group> +//</regmap> +//XmlParse xml_off diff --git a/fpga/usrp3/top/x400/cpld/ps_power_regs.v b/fpga/usrp3/top/x400/cpld/ps_power_regs.v new file mode 100644 index 000000000..3e1a25206 --- /dev/null +++ b/fpga/usrp3/top/x400/cpld/ps_power_regs.v @@ -0,0 +1,231 @@ +// +// Copyright 2021 Ettus Research, A National Instruments Brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: ps_power_regs +// +// Description: +// +// Registers to control power supplies on the motherboard. +// +// Parameters: +// +// BASE_ADDRESS : Base address for CtrlPort registers. +// NUM_ADDRESSES : Number of bytes of address space to use. +// + +`default_nettype none + + +module ps_power_regs #( + parameter BASE_ADDRESS = 0, + parameter NUM_ADDRESSES = 32 +) ( + 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, + + // iPass + output reg ipass_power_disable = 1'b0, + input wire [ 1:0] ipass_power_fault_n, + + // Oscillators + output reg osc_100_en, + output reg osc_122_88_en +); + + `include "regmap/ps_power_regmap_utils.vh" + `include "../../../lib/rfnoc/core/ctrlport.vh" + + //---------------------------------------------------------- + // Address Calculation + //---------------------------------------------------------- + + wire address_in_range = (s_ctrlport_req_addr >= BASE_ADDRESS) && + (s_ctrlport_req_addr < BASE_ADDRESS + NUM_ADDRESSES); + + //---------------------------------------------------------- + // Internal Registers + //---------------------------------------------------------- + + reg [1:0] ipass_power_sticky = 2'b00; + reg [1:0] ipass_clear_sticky = 2'b00; + + //---------------------------------------------------------- + // Handling of ControlPort Requests + //---------------------------------------------------------- + + always @(posedge ctrlport_clk) begin + // Reset internal registers and responses + if (ctrlport_rst) begin + ipass_power_disable <= 1'b0; + s_ctrlport_resp_ack <= 1'b0; + s_ctrlport_resp_status <= CTRL_STS_OKAY; + s_ctrlport_resp_data <= {CTRLPORT_ADDR_W {1'bx}}; + + osc_100_en <= 1'b0; + osc_122_88_en <= 1'b0; + + end else begin + // Default assignments + ipass_clear_sticky <= 2'b00; + + // Write requests + if (s_ctrlport_req_wr) begin + // Always issue an ack and no data + s_ctrlport_resp_ack <= 1'b1; + s_ctrlport_resp_status <= CTRL_STS_OKAY; + s_ctrlport_resp_data <= {CTRLPORT_ADDR_W {1'bx}}; + + case (s_ctrlport_req_addr) + BASE_ADDRESS + IPASS_POWER_REG: begin + ipass_power_disable <= s_ctrlport_req_data[IPASS_DISABLE_POWER_BIT]; + ipass_clear_sticky[0] <= s_ctrlport_req_data[IPASS_CLEAR_POWER_FAULT0]; + ipass_clear_sticky[1] <= s_ctrlport_req_data[IPASS_CLEAR_POWER_FAULT1]; + end + + BASE_ADDRESS + OSC_POWER_REG: begin + osc_100_en <= s_ctrlport_req_data[OSC_100]; + osc_122_88_en <= s_ctrlport_req_data[OSC_122_88]; + 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 request + 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 <= {CTRLPORT_DATA_W {1'b0}}; + + case (s_ctrlport_req_addr) + BASE_ADDRESS + IPASS_POWER_REG: begin + s_ctrlport_resp_data[IPASS_DISABLE_POWER_BIT] <= ipass_power_disable; + s_ctrlport_resp_data[IPASS_POWER_FAULT0] <= ipass_power_sticky[0]; + s_ctrlport_resp_data[IPASS_POWER_FAULT1] <= ipass_power_sticky[1]; + end + + BASE_ADDRESS + OSC_POWER_REG: begin + s_ctrlport_resp_data[OSC_100] <= osc_100_en; + s_ctrlport_resp_data[OSC_122_88] <= osc_122_88_en; + end + + // Error on undefined address + default: begin + s_ctrlport_resp_data <= {CTRLPORT_DATA_W {1'bx}}; + 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 + + //---------------------------------------------------------- + // Sticky Logic of Power Registers + //---------------------------------------------------------- + + // Synchronize asynchronous inputs + wire [1:0] ipass_power_fault_lcl_n; + synchronizer #( + .WIDTH (2), + .STAGES (2), + .INITIAL_VAL (1'b0), + .FALSE_PATH_TO_IN (1) + ) power_fault_sync ( + .clk (ctrlport_clk), + .rst (ctrlport_rst), + .in (ipass_power_fault_n), + .out (ipass_power_fault_lcl_n) + ); + + always @(posedge ctrlport_clk) begin + if (ctrlport_rst) begin + ipass_power_sticky <= 2'b00; + end else begin + // Keep value if not cleared or set in case of fault + ipass_power_sticky <= (ipass_power_sticky & ~ipass_clear_sticky) | ~ipass_power_fault_lcl_n; + end + end + +endmodule + + +`default_nettype wire + + +//XmlParse xml_on +//<regmap name="PS_POWER_REGMAP" readablestrobes="false" generatevhdl="true" ettusguidelines="true"> +// <group name="PS_POWER_REGS"> +// <info> +// Registers to control power supplies on the motherboard. +// </info> +// +// <register name="IPASS_POWER_REG" offset="0x00" size="32"> +// <info>Controls the power supplies for the iPass connectors.</info> +// <bitfield name="IPASS_DISABLE_POWER_BIT" range="0"> +// <info>Set to 1 to disable power for both iPass connectors.</info> +// </bitfield> +// <bitfield name="IPASS_CLEAR_POWER_FAULT0" range="30" readable="false"> +// <info>Clear @.IPASS_POWER_FAULT0.</info> +// </bitfield> +// <bitfield name="IPASS_CLEAR_POWER_FAULT1" range="31" readable="false"> +// <info>Clear @.IPASS_POWER_FAULT1.</info> +// </bitfield> +// <bitfield name="IPASS_POWER_FAULT0" range="30" writable="false"> +// <info> +// Asserted signal indicates a power fault in power switch for iPass +// connector 0. Sticky bit. Asserted on occurrence. Reset using +// @.IPASS_CLEAR_POWER_FAULT0. +// </info> +// </bitfield> +// <bitfield name="IPASS_POWER_FAULT1" range="31" writable="false"> +// <info> +// Asserted signal indicates a power fault in power switch for iPass +// connector 1. Sticky bit. Asserted on occurrence. Reset using +// @.IPASS_CLEAR_POWER_FAULT1. +// </info> +// </bitfield> +// </register> +// +// <register name="OSC_POWER_REG" offset="0x04" size="32"> +// <info>Controls the power supplies for the oscillators.</info> +// <bitfield name="OSC_100" range="0"> +// <info>Enables 5V power switch for the 100 MHz oscillator.</info> +// </bitfield> +// <bitfield name="OSC_122_88" range="1"> +// <info>Enables 5V power switch for the 122.88 MHz oscillator.</info> +// </bitfield> +// </register> +// </group> +//</regmap> +//XmlParse xml_off diff --git a/fpga/usrp3/top/x400/cpld/pwr_supply_clk_gen.v b/fpga/usrp3/top/x400/cpld/pwr_supply_clk_gen.v new file mode 100644 index 000000000..e69db9dfc --- /dev/null +++ b/fpga/usrp3/top/x400/cpld/pwr_supply_clk_gen.v @@ -0,0 +1,73 @@ +// +// Copyright 2021 Ettus Research, A National Instruments Brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: pwr_supply_clk_gen +// +// Description: +// +// Generates a clock for one motherboard power supply. +// +// Parameters: +// +// BASE_ADDRESS : Base address for CtrlPort registers. +// NUM_ADDRESSES : Number of bytes of address space to use. +// + +`default_nettype none + + +module pwr_supply_clk_gen#( + parameter SOURCE_CLK_FREQ = 100_000_000, + parameter TARGET_CLK_FREQ = 100_000 +) ( + // Base clock and reset + input wire clk, + input wire rst, + + // Power supply clocks + output reg pwr_supply_clk +); + +//----------------------------------------------------------------------------- +// Counter Calculation / Definition +//----------------------------------------------------------------------------- +// Counter to generate the power supply switching clock + +// Assumption: the ratio between the generated clock and the source clock is +// even, therefore we can produce a 50% DC clock output. +localparam MAX_COUNT = SOURCE_CLK_FREQ / TARGET_CLK_FREQ / 2; +localparam COUNTER_W = $clog2(MAX_COUNT); +reg [COUNTER_W-1:0] counter = 0; + +//----------------------------------------------------------------------------- +// Clock Generation +//----------------------------------------------------------------------------- +// This process implements a simple clock divider for the power supply +// switcher. + +// SAFE COUNTER START! rst is a synchronous reset generated in the +// clk domain; therefore, inherently safe. +always @(posedge clk) begin + if (rst) begin + counter <= 0; + pwr_supply_clk <= 1'b0; + end + else begin + // Add one every cycle to the counter + counter <= counter + 1'b1; + + // When the counter reaches its mid value, it is reset and the output clock + // output is toggled. + if (counter == MAX_COUNT-1) begin + counter <= 0; + pwr_supply_clk <= ~pwr_supply_clk; + end + end +end + +endmodule + + +`default_nettype wire diff --git a/fpga/usrp3/top/x400/cpld/raw_conversion.cof b/fpga/usrp3/top/x400/cpld/raw_conversion.cof new file mode 100644 index 000000000..87ecb15d8 --- /dev/null +++ b/fpga/usrp3/top/x400/cpld/raw_conversion.cof @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="US-ASCII" standalone="yes"?> +<cof> + <output_filename>output_files/mb_cpld_converted.pof</output_filename> + <n_pages>1</n_pages> + <width>1</width> + <mode>14</mode> + <sof_data> + <user_name>Page_0</user_name> + <page_flags>1</page_flags> + <bit0> + <sof_filename>output_files/mb_cpld.sof<compress_bitstream>1</compress_bitstream></sof_filename> + </bit0> + </sof_data> + <version>10</version> + <create_cvp_file>0</create_cvp_file> + <create_hps_iocsr>0</create_hps_iocsr> + <auto_create_rpd>1</auto_create_rpd> + <rpd_little_endian>1</rpd_little_endian> + <options> + <map_file>1</map_file> + </options> + <MAX10_device_options> + <por>0</por> + <io_pullup>1</io_pullup> + <config_from_cfm0_only>0</config_from_cfm0_only> + <isp_source>0</isp_source> + <verify_protect>0</verify_protect> + <epof>0</epof> + <ufm_source>0</ufm_source> + </MAX10_device_options> + <advanced_options> + <ignore_epcs_id_check>1</ignore_epcs_id_check> + <ignore_condone_check>2</ignore_condone_check> + <plc_adjustment>0</plc_adjustment> + <post_chain_bitstream_pad_bytes>-1</post_chain_bitstream_pad_bytes> + <post_device_bitstream_pad_bytes>-1</post_device_bitstream_pad_bytes> + <bitslice_pre_padding>1</bitslice_pre_padding> + </advanced_options> +</cof>
\ No newline at end of file diff --git a/fpga/usrp3/top/x400/cpld/reconfig_engine.v b/fpga/usrp3/top/x400/cpld/reconfig_engine.v new file mode 100644 index 000000000..a7c94b4a2 --- /dev/null +++ b/fpga/usrp3/top/x400/cpld/reconfig_engine.v @@ -0,0 +1,1024 @@ +// +// Copyright 2021 Ettus Research, A National Instruments Brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: reconfig_engine +// +// Description: +// +// This file implements the registers and the state machine to interface with +// Intel's IP for the Max 10 FPGA that allows in-field updates to the primary +// FPGA image. This state machine has been designed to provide a level of +// abstraction between the register interface provided to user and the +// details of interfacing with Intel's On-Chip Flash IP block. The user +// simply needs to instruct this state machine to enable/disable write +// protection and perform read/write/erase operations accordingly to load and +// verify a new primary FPGA image. Since the purpose of this file is to +// allow modification to an FPGA image care has been taken to mitigate data +// corruption. +// +// The interface to Intel's On-Chip Flash IP block implemented in this file +// is based on the information found in the Max 10 User Flash Memory User +// Guide found at the link below. +// +// https://www.intel.com/content/dam/www/programmable/us/en/pdfs/literature/hb/max-10/ug_m10_ufm.pdf +// +// Parameters: +// +// BASE_ADDRESS : Base address for CtrlPort registers. +// NUM_ADDRESSES : Number of bytes of address space to use. +// MEM_INIT : Memory initialization enabled. Set to 0 if MAX10 internal +// configuration set to single compressed image. Set to 1 if +// MAX10 internal configuration set to single compressed +// image with memory initialization. +// + +`default_nettype none + + +module reconfig_engine #( + parameter BASE_ADDRESS = 0, + parameter NUM_ADDRESSES = 32, + parameter MEM_INIT = 0 +) ( + 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, + + // Interface to On-Chip Flash IP + output reg csr_addr, + output reg csr_read, + output reg [31:0] csr_writedata, + output reg csr_write, + input wire [31:0] csr_readdata, + output reg [16:0] data_addr, + output reg data_read, + output reg [31:0] data_writedata, + output reg data_write, + input wire [31:0] data_readdata, + input wire data_waitrequest, + input wire data_readdatavalid +); + + `include "regmap/reconfig_regmap_utils.vh" + `include "../../../lib/rfnoc/core/ctrlport.vh" + + //---------------------------------------------------------- + // Flash Interface between Registers and State Machine + //---------------------------------------------------------- + + // Flash Data Interface + reg [16:0] flash_addr = 0; + reg [31:0] flash_write_data = 0; + reg [31:0] flash_read_data; + + // Flash Control Interface - Control + reg flash_read_stb = 1'b0; + reg flash_write_stb = 1'b0; + reg flash_erase_stb = 1'b0; + reg flash_enable_wp_stb = 1'b0; + reg flash_disable_wp_stb = 1'b0; + reg [2:0] flash_sector = 3'b0; + + // Flash Control Interface - Status + reg flash_wp_enabled; + reg flash_read_idle; + reg flash_write_idle; + reg flash_erase_idle; + reg flash_read_err; + reg flash_write_err; + reg flash_erase_err; + reg clear_flash_read_err_stb = 1'b0; + reg clear_flash_write_err_stb = 1'b0; + reg clear_flash_erase_err_stb = 1'b0; + + //---------------------------------------------------------- + // Address Calculation + //---------------------------------------------------------- + + wire address_in_range = (s_ctrlport_req_addr >= BASE_ADDRESS) && + (s_ctrlport_req_addr < BASE_ADDRESS + NUM_ADDRESSES); + + //---------------------------------------------------------- + // Handling of ControlPort Requests + //---------------------------------------------------------- + + always @(posedge ctrlport_clk) begin + // Default assignments + s_ctrlport_resp_ack <= 1'b0; + + flash_read_stb <= 1'b0; + flash_write_stb <= 1'b0; + flash_erase_stb <= 1'b0; + flash_enable_wp_stb <= 1'b0; + flash_disable_wp_stb <= 1'b0; + clear_flash_read_err_stb <= 1'b0; + clear_flash_write_err_stb <= 1'b0; + clear_flash_erase_err_stb <= 1'b0; + + // Do not acknowledge on reset + if (ctrlport_rst) begin + s_ctrlport_resp_ack <= 1'b0; + s_ctrlport_resp_data <= {32{1'bx}}; + s_ctrlport_resp_status <= CTRL_STS_OKAY; + + // Write requests + end else begin + 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 + FLASH_CONTROL_REG: begin + flash_read_stb <= s_ctrlport_req_data[FLASH_READ_STB]; + flash_write_stb <= s_ctrlport_req_data[FLASH_WRITE_STB]; + flash_erase_stb <= s_ctrlport_req_data[FLASH_ERASE_STB]; + flash_enable_wp_stb <= s_ctrlport_req_data[FLASH_ENABLE_WP_STB]; + flash_disable_wp_stb <= s_ctrlport_req_data[FLASH_DISABLE_WP_STB]; + clear_flash_read_err_stb <= s_ctrlport_req_data[CLEAR_FLASH_READ_ERROR_STB]; + clear_flash_write_err_stb <= s_ctrlport_req_data[CLEAR_FLASH_WRITE_ERROR_STB]; + clear_flash_erase_err_stb <= s_ctrlport_req_data[CLEAR_FLASH_ERASE_ERROR_STB]; + flash_sector <= s_ctrlport_req_data[FLASH_ERASE_SECTOR_MSB:FLASH_ERASE_SECTOR]; + end + + BASE_ADDRESS + FLASH_ADDR_REG: begin + flash_addr <= s_ctrlport_req_data[FLASH_ADDR_MSB:FLASH_ADDR]; + end + + BASE_ADDRESS + FLASH_WRITE_DATA_REG: begin + flash_write_data <= s_ctrlport_req_data[FLASH_WRITE_DATA_MSB:FLASH_WRITE_DATA]; + end + + // Error on undefined address + default: begin + if (address_in_range) begin + s_ctrlport_resp_status <= CTRL_STS_CMDERR; + + // No response if out of range + end else begin + s_ctrlport_resp_ack <= 1'b0; + end + end + endcase + + // Read request + 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; + + case (s_ctrlport_req_addr) + BASE_ADDRESS + FLASH_STATUS_REG: begin + s_ctrlport_resp_data <= {CTRLPORT_DATA_W {1'b0}}; + s_ctrlport_resp_data[FLASH_WP_ENABLED] <= flash_wp_enabled; + s_ctrlport_resp_data[FLASH_READ_IDLE] <= flash_read_idle; + s_ctrlport_resp_data[FLASH_READ_ERR] <= flash_read_err; + s_ctrlport_resp_data[FLASH_ERASE_IDLE] <= flash_erase_idle; + s_ctrlport_resp_data[FLASH_ERASE_ERR] <= flash_erase_err; + s_ctrlport_resp_data[FLASH_WRITE_IDLE] <= flash_write_idle; + s_ctrlport_resp_data[FLASH_WRITE_ERR] <= flash_write_err; + s_ctrlport_resp_data[FLASH_MEM_INIT_ENABLED] <= MEM_INIT ? 1'b1 : 1'b0; + end + + BASE_ADDRESS + FLASH_ADDR_REG: begin + s_ctrlport_resp_data <= {CTRLPORT_DATA_W {1'b0}}; + s_ctrlport_resp_data[FLASH_ADDR_MSB:FLASH_ADDR] <= flash_addr; + end + + BASE_ADDRESS + FLASH_READ_DATA_REG: begin + s_ctrlport_resp_data <= flash_read_data; + end + + BASE_ADDRESS + FLASH_CFM0_START_ADDR_REG: begin + s_ctrlport_resp_data <= MEM_INIT ? FLASH_PRIMARY_IMAGE_START_ADDR_MEM_INIT : + FLASH_PRIMARY_IMAGE_START_ADDR; + end + + BASE_ADDRESS + FLASH_CFM0_END_ADDR_REG: begin + s_ctrlport_resp_data <= FLASH_PRIMARY_IMAGE_END_ADDR; + end + + // Error on undefined address + default: begin + s_ctrlport_resp_data <= {32{1'bx}}; + if (address_in_range) begin + s_ctrlport_resp_status <= CTRL_STS_CMDERR; + + // No response if out of range + end else begin + s_ctrlport_resp_ack <= 1'b0; + end + end + endcase + end + end + end + + //---------------------------------------------------------- + // State Machine Constants + //---------------------------------------------------------- + + // Local state + localparam IDLE = 4'h0; + localparam WP_DISABLED = 4'h1; + localparam WAIT_FOR_READ_DATA_VALID = 4'h2; + localparam GET_READ_STATUS = 4'h3; + localparam CHECK_READ_STATUS = 4'h4; + localparam WAIT_FOR_WRITE_COMPLETE = 4'h5; + localparam GET_WRITE_STATUS = 4'h6; + localparam CHECK_WRITE_STATUS = 4'h7; + localparam ERASE_SECTOR = 4'h8; + localparam GET_ERASE_BUSY = 4'h9; + localparam CHECK_ERASE_BUSY = 4'hA; + localparam GET_ERASE_IDLE = 4'hB; + localparam CHECK_ERASE_IDLE = 4'hC; + + // The Intel on-chip flash control interface has two registers, a Status + // Register at address 0 and a Control Register at address 1. The constants + // defined below identify fields and values of interest in each register. + // These are taken directly from the Max 10 Flash Memory User Guide. + localparam STATUS_REG_ADDR = 1'b0; + localparam STATUS_REG_BUSY_STATUS_MSB = 1; + localparam STATUS_REG_BUSY_STATUS_LSB = 0; + localparam STATUS_REG_IDLE = 2'b00; + localparam STATUS_REG_ERASE_BUSY = 2'b01; + localparam STATUS_REG_WRITE_BUSY = 2'b10; + localparam STATUS_REG_READ_BUSY = 2'b11; + localparam STATUS_REG_READ_STATUS = 2; + localparam STATUS_REG_WRITE_STATUS = 3; + localparam STATUS_REG_ERASE_STATUS = 4; + localparam OPERATION_FAILED = 0; + + localparam CONTROL_REG_ADDR = 1'b1; + localparam SECTOR_ERASE_ADDR_MSB = 22; + localparam SECTOR_ERASE_ADDR_LSB = 20; + localparam CFM0_WP_OFFSET_MSB = 26; + localparam CFM0_WP_OFFSET_LSB = 24; + localparam ENABLE_WP = MEM_INIT ? 3'b111 : 3'b100; + localparam DISABLE_WP = 3'b000; + + //---------------------------------------------------------- + // State Machine + //---------------------------------------------------------- + + reg [3:0] state = IDLE; + wire flash_no_errors_detected; + + assign flash_no_errors_detected = ~(flash_read_err | flash_write_err | flash_erase_err); + + always @(posedge ctrlport_clk) begin + if (ctrlport_rst) begin + state <= IDLE; + + // Signals to config registers + flash_wp_enabled <= 1'b1; + flash_read_idle <= 1'b1; + flash_write_idle <= 1'b1; + flash_erase_idle <= 1'b1; + flash_read_err <= 1'b0; + flash_write_err <= 1'b0; + flash_erase_err <= 1'b0; + flash_read_data <= 32'b0; + + // Signals to flash control interface + csr_addr <= 1'b0; + csr_writedata <= {32 {1'b1}}; + csr_read <= 1'b0; + csr_write <= 1'b0; + + // Signals to flash data interface + data_addr <= 17'b0; + data_writedata <= 32'b0; + data_read <= 1'b0; + data_write <= 1'b0; + end + // Rising edge clock + else begin + // Default values + csr_read <= 1'b0; + csr_write <= 1'b0; + csr_addr <= STATUS_REG_ADDR; + csr_writedata <= {32 {1'b1}}; + + data_read <= 1'b0; + data_write <= 1'b0; + + // State handling + case(state) + + // When in IDLE: + // * No operations are in progress and write protection is enabled. + // * Allowed transitions are to either read data from flash or + // disable write protection. + // * Transitions are only allowed if no error bits are asserted. + // * In the event both the *read_stb and *disable_wp_stb bits are + // asserted read operations take priority as these do not open the + // flash to modification. + // * Attempts to both enable and disable write protection + // simultaneously result in the state machine remaining in IDLE + // write protection enabled. + IDLE: begin + flash_wp_enabled <= 1'b1; + + if (flash_read_stb && flash_no_errors_detected) begin + state <= WAIT_FOR_READ_DATA_VALID; + flash_read_idle <= 1'b0; + data_read <= 1'b1; + data_addr <= flash_addr; + end else if (flash_disable_wp_stb && ~flash_enable_wp_stb && flash_no_errors_detected) begin + state <= WP_DISABLED; + csr_write <= 1'b1; + csr_addr <= CONTROL_REG_ADDR; + csr_writedata[CFM0_WP_OFFSET_MSB:CFM0_WP_OFFSET_LSB] <= DISABLE_WP; + end + end + + // Transition from WP_DISABLED when write protection is enabled or when + // write/erase operations are initiated. A few things to note: + // * Enabling write protection takes priority, regardless of what + // other control bits may be asserted simultaneously, followed by + // writes, and lastly erases. + // * The user should not strobe both the *write_stb and *erase_stb + // bits simultaneously, but if they do the state machine returns to + // IDLE (thereby enabling write protection) and the *write_err and + // *erase_err bits are asserted. + // * Performing a write or erase operation is only allowed from + // WP_DISABLED. This allows some mitigation against data corruption + // as multiple steps are required to change the data in the flash. + // First write protection must be disabled, and only then can the + // flash be erased or written. + WP_DISABLED: begin + flash_wp_enabled <= 1'b0; + + if (flash_erase_stb && flash_write_stb) begin + flash_erase_err <= 1'b1; + flash_write_err <= 1'b1; + end + + if (flash_enable_wp_stb || (flash_erase_stb && flash_write_stb)) begin + state <= IDLE; + csr_write <= 1'b1; + csr_addr <= CONTROL_REG_ADDR; + csr_writedata[CFM0_WP_OFFSET_MSB:CFM0_WP_OFFSET_LSB] <= ENABLE_WP; + end else if (flash_write_stb) begin + state <= WAIT_FOR_WRITE_COMPLETE; + flash_write_idle <= 1'b0; + data_write <= 1'b1; + data_writedata <= flash_write_data; + data_addr <= flash_addr; + end else if (flash_erase_stb) begin + state <= ERASE_SECTOR; + flash_erase_idle <= 1'b0; + csr_write <= 1'b1; + csr_addr <= CONTROL_REG_ADDR; + csr_writedata[CFM0_WP_OFFSET_MSB:CFM0_WP_OFFSET_LSB] <= DISABLE_WP; + csr_writedata[SECTOR_ERASE_ADDR_MSB:SECTOR_ERASE_ADDR_LSB] <= flash_sector; + end + end + + + // Read Flash + // -------------- + // Per Intel's Max 10 User Flash Memory User Guide, the Read bit of the + // flash data interface should be pulsed for one clock cycle to start + // the read process from flash. This pulse occurs upon transition from + // IDLE to WAIT_FOR_READ_DATA_VALID. The state machine then waits in + // WAIT_FOR_READ_DATA_VALID until the flash data interface + // data_readdatavalid signal asserts, indicating the data is now valid. + // Intel's documentation does not provide guidance on the expected time + // for data_readdatavalid to assert. From simulation, however, + // data_readdatavalid asserts four clock cycles after the Read pulse + // ends. The data_readdatavalid signal from the flash data interface + // pulses for one clock cycle. Only during this pulse is the data valid. + WAIT_FOR_READ_DATA_VALID: begin + if (data_readdatavalid) begin + state <= GET_READ_STATUS; + flash_read_data <= data_readdata; + csr_read <= 1'b1; + end + end + + // The data_readdatavalid signal determines when the read operation has + // completed in the flash data interface, but Intel's documentation + // does not indicate the relation of this bit to the 'busy' field in + // the flash control interface Status Register. To verify that the read + // operation is complete, the StatusRegister is polled until the 'busy' + // field indicates the flash is idle. This polling operation is + // implemented with CHECK_READ_STATUS below. GET_READ_STATUS exists to + // set the address of the flash control interface to the Status + // Register and pulse the read bit of the flash control interface. + // CHECK_READ_STATUS evaluates the resulting Status Register data and + // steer the state machine accordingly. See Figure 6 in Intel's Max 10 + // User Flash Memory User Guide for a waveform on this request and + // check mechanism. Successful read operations result in the state + // machine returning to IDLE. Failing read operations assert the + // flash_read_err bit before returning to IDLE. From simulation, the + // 'busy' field returns to IDLE on the third read. + GET_READ_STATUS: begin + state <= CHECK_READ_STATUS; + // csr_read set in transactions into this state + // CSR address set as default assignment + end + CHECK_READ_STATUS: begin + if (csr_readdata[STATUS_REG_BUSY_STATUS_MSB:STATUS_REG_BUSY_STATUS_LSB] == STATUS_REG_IDLE) begin + state <= IDLE; + flash_read_idle <= 1'b1; + flash_read_err <= (csr_readdata[STATUS_REG_READ_STATUS] == OPERATION_FAILED) ? 1'b1 : 1'b0; + end else if (csr_readdata[STATUS_REG_BUSY_STATUS_MSB:STATUS_REG_BUSY_STATUS_LSB] == STATUS_REG_READ_BUSY) begin + state <= GET_READ_STATUS; + csr_read <= 1'b1; + end + end + + + // Write Flash + //--------------- + // Per Intel's Max 10 User Flash Memory User Guide, the Write bit of + // the flash data interface should be asserted while maintaining + // address and data until the flash interface deasserts the + // data_waitrequest bit. Transition from WP_DISABLED to + // WAIT_FOR_WRITE_COMPLETE causes the write bit to assert and address + // and data to be set. The state machine remains in this state until + // the data_waitrequest bit deasserts. Per Intel's Max 10 User Flash + // Memory User Guide, the data_waitrequest signal is expected to + // deassert within 555 usec. + WAIT_FOR_WRITE_COMPLETE: begin + if (~data_waitrequest) begin + state <= GET_WRITE_STATUS; + csr_read <= 1'b1; + end else begin + // Flash writes require asserting the Write bit of the flash data + // interface until the write is complete. + data_write <= 1'b1; + end + end + + // The data_waitrequest signal determines when the write operation has + // completed in the flash data interface, but Intel's documentation does + // not indicate the relation of this bit to the 'busy' field in the flash + // control interface Status Register. To verify that the write operation + // is complete the StatusRegister is polled until the 'busy' field + // indicates the flash is idle. This polling operation is implemented with + // GET_WRITE_STATUS and CHECK_WRITE_STATUS below, and follows the same + // methodology as the polling operation for reads described above with the + // following two changes: + // * Upon successful completion of a write operation the state + // machine returns to WP_DISABLED. This allows repeated writes of + // new data without having to disable/enable for each write. + // * When a failure is detected the state machine transitions to to + // IDLE thereby enabling write protection. Failure of a write is + // not expected. Write protection is enabled in the event of a + // failure to mitigate further data corruption. + GET_WRITE_STATUS: begin + state <= CHECK_WRITE_STATUS; + // csr_read set in transactions into this state + // CSR address set as default assignment + end + CHECK_WRITE_STATUS: begin + if (csr_readdata[STATUS_REG_BUSY_STATUS_MSB:STATUS_REG_BUSY_STATUS_LSB] == STATUS_REG_IDLE) begin + if (csr_readdata[STATUS_REG_WRITE_STATUS] == OPERATION_FAILED) begin + state <= IDLE; + csr_write <= 1'b1; + csr_addr <= CONTROL_REG_ADDR; + csr_writedata[CFM0_WP_OFFSET_MSB:CFM0_WP_OFFSET_LSB] <= ENABLE_WP; + end else begin // SUCCESS + state <= WP_DISABLED; + end + flash_write_idle <= 1'b1; + flash_write_err <= (csr_readdata[STATUS_REG_WRITE_STATUS] == OPERATION_FAILED) ? 1'b1 : 1'b0; + end else if (csr_readdata[STATUS_REG_BUSY_STATUS_MSB:STATUS_REG_BUSY_STATUS_LSB] == STATUS_REG_WRITE_BUSY) begin + state <= GET_WRITE_STATUS; + csr_read <= 1'b1; + end + end + + // Erase Flash + //------------- + // Erasing the primary configuration image requires a single write to + // the flash control interface Control Register. Only one sector needs + // to be erased to erase the entire primary configuration image. + // Transition from WP_DISABLED to ERASE_SECTOR causes data to be + // written to the Control Register to erase this sector and pulse the + // flash control interface write bit. + ERASE_SECTOR: begin + state <= GET_ERASE_BUSY; + csr_read <= 1'b1; + end + + // There is some latency between writing the Control Register and the + // 'busy' field of the flash control interface Status Register + // indicating the erase operation is in progress. After initiating the + // erase operation, GET_ERASE_BUSY and CHECK_ERASE_BUSY implement a + // polling operation to determine when the erase operation has started. + // GET_ERASE_BUSY exists to set the address of the flash control + // interface to the Status Register and pulse the read bit of the flash + // control interface. CHECK_ERASE_BUSY exists to evaluate the resulting + // Status Register data and steer the state machine accordingly. The + // polling operation continues until the 'busy' field indicates the + // erase operation is in progress. Intel's documentation does not + // indicate how long it takes for the Status Register to indicate the + // erase is in progress, but simulation shows the erase is in progress + // after the second read. + GET_ERASE_BUSY: begin + state <= CHECK_ERASE_BUSY; + // csr_read set in transactions into this state + // CSR address set as default assignment + end + CHECK_ERASE_BUSY: begin + if (csr_readdata[STATUS_REG_BUSY_STATUS_MSB:STATUS_REG_BUSY_STATUS_LSB] == STATUS_REG_ERASE_BUSY) begin + state <= GET_ERASE_IDLE; + csr_read <= 1'b1; + end else if (csr_readdata[STATUS_REG_BUSY_STATUS_MSB:STATUS_REG_BUSY_STATUS_LSB] == STATUS_REG_IDLE) begin + state <= GET_ERASE_BUSY; + csr_read <= 1'b1; + end + end + + // Once the erase operation is in progress a second polling operation + // defined by GET_ERASE_IDLE and CHECK_ERASE_IDLE is implemented to + // determine when the operation has completed. This polling operation + // follows the same methodology as the polling operation for erase busy + // described above. Intel's documentation indicates that erase + // operations take a maximum of 350 msec. + GET_ERASE_IDLE: begin + state <= CHECK_ERASE_IDLE; + // csr_read set in transactions into this state + // CSR address set as default assignment + end + CHECK_ERASE_IDLE: begin + if (csr_readdata[STATUS_REG_BUSY_STATUS_MSB:STATUS_REG_BUSY_STATUS_LSB] == STATUS_REG_IDLE) begin + if (csr_readdata[STATUS_REG_ERASE_STATUS] == OPERATION_FAILED) begin + state <= IDLE; + csr_write <= 1'b1; + csr_addr <= CONTROL_REG_ADDR; + csr_writedata[CFM0_WP_OFFSET_MSB:CFM0_WP_OFFSET_LSB] <= ENABLE_WP; + end else begin // SUCCESS + state <= WP_DISABLED; + end + flash_erase_idle <= 1'b1; + flash_erase_err <= (csr_readdata[STATUS_REG_ERASE_STATUS] == OPERATION_FAILED) ? 1'b1 : 1'b0; + end else if (csr_readdata[STATUS_REG_BUSY_STATUS_MSB:STATUS_REG_BUSY_STATUS_LSB] == STATUS_REG_ERASE_BUSY) begin + state <= GET_ERASE_IDLE; + csr_read <= 1'b1; + end + end + + // Default to IDLE in other cases + default: begin + state <= IDLE; + end + endcase + + // Reset errors + if (clear_flash_read_err_stb) begin + flash_read_err <= 1'b0; + end + if (clear_flash_write_err_stb) begin + flash_write_err <= 1'b0; + end + if (clear_flash_erase_err_stb) begin + flash_erase_err <= 1'b0; + end + end + end + +endmodule + + +`default_nettype wire + + +//XmlParse xml_on +//<regmap name="RECONFIG_REGMAP" readablestrobes="false" generatevhdl="true" ettusguidelines="true"> +// <group name="RECONFIG_REGS"> +// <info> +// These registers are used to upload and verify a new primary image to the +// Max 10 FPGA on-chip flash when configured to support dual configuration +// images. The steps below outline the process of verifying/preparing the +// new image to be written, erasing the current image, writing the new +// image, and verifying the new image was successfully written. +// {p}{b}Prepare the data...{/b} +// {ol}{li}{p}The Max 10 FPGA build should generate a *cfm0_auto.rpd +// file The *.rpd file is a "raw programming +// data" file holding all data related to the +// configuration image (CFM0). There are two +// important items to note regarding the addresses. +// First the *rpd data uses {b}byte{/b} addresses. +// Second, the start/end addresses defined by +// FLASH_PRIMARY_IMAGE_ADDR_ENUM are 32-bit word addresses{/p}{/li} +// {li}{p}As a sanity check, verify the size of the raw +// programming data for CFM0 correspond to the address +// range of FLASH_PRIMARY_IMAGE_ADDR_ENUM. Do this by +// reading the values from FLASH_CFM0_START_ADDR_REG and +// FLASH_CFM0_END_ADDR, subtract both values, add one and +// multiply by four. +// {/p}{/li} +// {li}{p}Having passed the sanity check the *.rpd data must +// now be manipulated into the form required by Altera's +// on-chip flash IP. Two operations must be performed. +// First the data must be converted from bytes to 32-bit +// words. Second the bit order must be reversed. This is +// illustrated in in the following table which shows byte +// address and data from the *.rpd file compared to the +// word address and data to be written to the on-chip +// flash. +// {table border=1} +// {tr}{td}.Map Addr{/td}{td}.Map Data{/td}{td}Flash Addr{/td}{td}Flash Data{/td}{/tr} +// {tr}{td}0x2B800{/td}{td}0x01{/td}{td rowspan=4}0xAC00{/td}{td rowspan=4}0x8040C020{/td}{/tr} +// {tr}{td}0x2B801{/td}{td}0x02{/td}{/tr} +// {tr}{td}0x2B802{/td}{td}0x03{/td}{/tr} +// {tr}{td}0x2B803{/td}{td}0x04{/td}{/tr} +// {tr}{td}0x2B804{/td}{td}0x05{/td}{td rowspan=4}0xAC01{/td}{td rowspan=4}0xA060E010{/td}{/tr} +// {tr}{td}0x2B805{/td}{td}0x06{/td}{/tr} +// {tr}{td}0x2B806{/td}{td}0x07{/td}{/tr} +// {tr}{td}0x2B807{/td}{td}0x08{/td}{/tr} +// {/table} +// {/p}{/li} +// {li}{p}The resulting set of flash address data pairs should +// be used when writing FLASH_ADDR_REG and +// FLASH_WRITE_DATA_REG to update the CFM0 image. +// However, prior to writing the new image the old image +// must be erased. +// {/p}{/li} +// {/ol} +// {/p} +// {p}{b}Erase the current primary flash image...{/b} +// {ol}{p}{li}Read FLASH_STATUS_REG and verify no error bits are +// asserted and that all read, write, and erase operations +// are idle.{/p}{/li} +// {p}{li}Disable write protection of the flash by strobing the +// FLASH_DISABLE_WP_STB bit of FLASH_CONTROL_REG. +// {/p}{/li} +// {p}{li}Verify write protection is disabled and no errors are +// present by reading FLASH_STATUS_REG.{/p}{/li} +// {p}{li}Initiate the erase operation by setting +// @.FLASH_ERASE_SECTOR and strobing FLASH_ERASE_STB of +// FLASH_CONTROL_REG.{/p}{/li} +// {p}{li}Poll the FLASH_ERASE_IDLE bit of +// FLASH_STATUS_REG until it de-asserts indicating the +// erase operation is complete, then verify the operation +// was successful by checking that the FLASH_ERASE_ERR +// bit is de-asserted. Erase operations are expected to +// take a maximum of 350 msec. Upon completion of the erase +// operation write protection will remain disabled. +// {/p}{/li} +// {p}{li}Erase additional sectors as required (see +// @.FLASH_ERASE_SECTOR for details) by restarting with first +// step.{/p}{/li} +// {/ol} +// {/p} +// {p}{b}Write the new primary flash image...{/b} +// {ol}{p}{li}Read FLASH_STATUS_REG and verify no error bits are +// asserted, all read, write, and erase operations are +// idle, and write protection is disabled.{/li} +// {p}{li}Set the target address for the write to the Max 10 +// on-chip flash by writing value from +// FLASH_CFM0_START_ADDR_REG to FLASH_ADDR_REG.{/li}{/p} +// {p}{li}Set the data to be written to this address by writing +// the new 32-bit word of the new image to +// FLASH_WRITE_DATA_REG.{/li}{/p} +// {p}{li}Initiate the write by strobing FLASH_WRITE_STB of +// FLASH_CONTROL_REG.{/li}{/p} +// {p}{li}Poll the FLASH_WRITE_IDLE bit of +// FLASH_STATUS_REG until it de-asserts indicating the +// write operation is complete, then verify the operation +// was successful by checking that the FLASH_WRITE_ERR +// bit is de-asserted. Write operations are expected to +// take a maximum of 550 usec.{/li}{/p} +// {p}{li}Upon completion of the write operation return to step +// 2, incrementing the target address by one, and writing +// the next 32-bit word to Max10FlashWriteDatReg. If this +// was the last write, indicated by writing to +// FLASH_PRIMARY_IMAGE_END_ADDR, proceed to the next step +// to enable write protection.{/li}{/p} +// {p}{li}After writing the new image enable write protection +// by strobing the FLASH_ENABLE_WP_STB bit of +// FLASH_CONTROL_REG.{/li}{/p} +// {/ol} +// {/p} +// {p}{b}Verify the new primary flash image...{/b} +// {ol}{p}{li}Read FLASH_STATUS_REG and verify no error bits are +// asserted and that all read, write, and erase operations +// are idle.{/li}{/p} +// {p}{li}Set the target address for the read in the Max 10 +// on-chip flash by writing value from +// FLASH_CFM0_START_ADDR_REG to FLASH_ADDR_REG.{/li}{/p} +// {p}{li}Initiate the read by strobing FLASH_READ_STB of +// FLASH_CONTROL_REG.{/li}{/p} +// {p}{li}Poll the FLASH_READ_IDLE bit of +// FLASH_STATUS_REG until it de-asserts indicating the +// read operation is complete, then verify the operation +// was successful by checking that the FLASH_READ_ERR +// bit is de-asserted. There is no guidance on exactly how +// long reads take to complete, but they are expected to be +// fairly quick. A very conservative timeout on this +// polling would be similar to that used for write +// operations.{/li}{/p} +// {p}{li}Upon completion of the read operation the resulting +// data returned by the on-chip flash will be available in +// Max10FlashReadDatReg. Read this register, compare to +// expected value previously written, and ensure they +// match.{/li}{/p} +// {p}{li}Return to step 2, incrementing the target +// address by one. If this was the last read verification +// is complete and no further action is required.{/li}{/p} +// {/ol} +// {/p} +// {p}After the flash has been erased, programmed, and verified, a power +// cycle is required for the new image to become active. +// {/p} +// </info> +// <enumeratedtype name="FLASH_PRIMARY_IMAGE_ADDR_ENUM" showhexvalue="true"> +// <info> +// Those values are the start and end address of the CFM image flash +// sector from Intel's On-Chip Flash IP Generator. Note that the values +// given in the IP generator are byte based where the values of this enum +// are U32 based (divided by 4). +// </info> +// <value name="FLASH_PRIMARY_IMAGE_START_ADDR_MEM_INIT" +// integer="4096"/> +// <value name="FLASH_PRIMARY_IMAGE_START_ADDR" +// integer="39936"/> +// <value name="FLASH_PRIMARY_IMAGE_END_ADDR" +// integer="75775"/> +// </enumeratedtype> +// <register name="FLASH_STATUS_REG" offset="0x000" size="32" +// attributes="Readable"> +// <bitfield name="FLASH_WP_ENABLED" range="0"> +// <info> +// This bit is asserted when the flash is write protected and +// de-asserted when write protection is disabled. +// {li}Write protection must be enabled prior to performing read +// operations.{/li} +// {li}Write protection must be disabled prior to performing write and +// erase operations.{/li} +// </info> +// </bitfield> +// <bitfield name="FLASH_READ_IDLE" range="4"> +// <info> +// This bit is de-asserted when a read operation is in progress. Poll +// this bit after strobing the FLASH_READ_STB bit of +// FLASH_CONTROL_REG to determine when the read operation has +// completed, then check the FLASH_READ_ERR bit to verify the +// operation was successful. +// </info> +// </bitfield> +// <bitfield name="FLASH_READ_ERR" range="5"> +// <info> +// This bit is asserted when a read operation fails. Clear this error +// by strobing the CLEAR_FLASH_READ_ERROR_STB of this register. In the +// event of a read error... +// {li}the data in FLASH_READ_DATA_REG is invalid.{/li} +// {li}attempts to disable write protection will be ignored.{/li} +// {li}attempts to read/write/erase the flash will be ignored.{/li} +// </info> +// </bitfield> +// <bitfield name="FLASH_ERASE_IDLE" range="8"> +// <info> +// This bit is de-asserted when an erase operation is in progress. Poll +// this bit after strobing the FLASH_ERASE_STB bit of +// FLASH_CONTROL_REG to determine when the erase operation has +// completed, then check the FLASH_ERASE_ERR bit to verify the +// operation was successful. +// </info> +// </bitfield> +// <bitfield name="FLASH_ERASE_ERR" range="9"> +// <info> +// This bit is asserted when an erase operation fails. Clear this +// error by strobing CLEAR_FLASH_ERASE_ERROR_STB of this register. In +// the event of an erase error... +// {li}{b}the primary configuration image may be corrupted,{/b} and +// power cycling the board may result in unknown behavior.{/li} +// {li}write protection of the flash will automatically be +// re-enabled.{/li} +// {li}attempts to disable write protection will be ignored.{/li} +// {li}attempts to read/write/erase the flash will be ignored.{/li} +// </info> +// </bitfield> +// <bitfield name="FLASH_WRITE_IDLE" range="12"> +// <info> +// This bit is de-asserted when a write operation is in progress. Poll +// this bit after strobing the FLASH_WRITE_STB bit of +// FLASH_CONTROL_REG to determine when the write operation has +// completed, then check the FLASH_WRITE_ERR bit to verify the +// operation was successful. +// </info> +// </bitfield> +// <bitfield name="FLASH_WRITE_ERR" range="13"> +// <info> +// This bit is asserted when write operation fails. Clear this error +// by strobing the CLEAR_FLASH_WRITE_ERROR_STB bit of this register. In +// the event of a write error... +// {li}{b}the primary configuration image may be corrupted,{/b} and +// power cycling the board may result unknown behavior.{/li} +// {li}write protection of the flash will automatically be +// re-enabled.{/li} +// {li}attempts to disable write protection will be ignored.{/li} +// {li}attempts to read/write/erase the flash will be ignored.{/li} +// </info> +// </bitfield> +// <bitfield name="FLASH_MEM_INIT_ENABLED" range="16"> +// <info> +// This bit is asserted when the flash can hold an image with memory +// initialization. +// </info> +// </bitfield> +// </register> +// <register name="FLASH_CONTROL_REG" offset="0x04" size="32" +// attributes="Writable"> +// <bitfield name="FLASH_ENABLE_WP_STB" range="0" +// attributes="strobe"> +// <info> +// Strobe this bit to enable write protection to the section of the +// Max 10 on-chip flash storing the primary configuration image +// (CFM0). +// {li}Read the FLASH_WP_ENABLED bit of FLASH_STATUS_REG to +// determine the current state of write protection.{/li} +// {li}Prior to strobing this bit verify no write or erase operations +// are in progress and no error bits are asserted by reading +// FLASH_STATUS_REG.{/li} +// {li}Attempts to enable write protection while erase or write +// operations are in progress will be ignored.{/li} +// {li}Write protection must be enabled prior to performing +// read operations.{/li} +// {li}Write protection should be enabled after completing +// write or erase operations to prevent data corruption.{/li} +// </info> +// </bitfield> +// <bitfield name="FLASH_DISABLE_WP_STB" range="1" +// attributes="strobe"> +// <info> +// Strobe this bit to disable write protection to the section of the +// Max 10 on-chip flash storing the primary configuration image +// (CFM0). +// {li}Read the FLASH_WP_ENABLED bit of FLASH_STATUS_REG to +// determine the current state of write protection.{/li} +// {li}Prior to strobing this bit verify no read operations are in +// progress and no error bits are asserted by reading +// FLASH_STATUS_REG.{/li} +// {li}Attempts to disable write protection while a read is in +// progress will be ignored.{/li} +// {li}Attempts to disable write protection will be ignored if +// this bit is strobed simultaneously with either FLASH_READ_STB +// or FLASH_ENABLE_WP_STB.{/li} +// {li}Write protection must be disabled prior to performing erase or +// write operations.{/li} +// {li}Upon completion of erase/write operations write protection +// will remain disabled. When not actively erasing or writing a new +// image write protection should be enabled to avoid data +// corruption.{/li} +// </info> +// </bitfield> +// <bitfield name="FLASH_READ_STB" range="2" +// attributes="strobe"> +// <info> +// Strobe this bit to read data from the flash address identified in +// FLASH_ADDR_REG. +// {li}Prior to strobing this bit verify no read, write, or erase +// operations are in progress, no error bits are asserted, and +// write protection is enabled by reading FLASH_STATUS_REG.{/li} +// {li}Attempts to read data while other operations are in progress +// or while write protection is disabled will be ignored.{/li} +// {li}After strobing this bit poll the FLASH_READ_IDLE and +// FLASH_READ_ERR bits of FLASH_STATUS_REG to determine when +// the read operation is complete and if it was successful.{/li} +// {li}Upon successful completion the data read from flash will be +// available in FLASH_READ_DATA_REG.{/li} +// </info> +// </bitfield> +// <bitfield name="FLASH_WRITE_STB" range="3" +// attributes="strobe"> +// <info> +// Strobe this bit to write the data contained in +// FLASH_WRITE_DATA_REG to the flash address identified in +// FLASH_ADDR_REG. +// {li}The flash must be erased before writing new data.{/li} +// {li}Prior to strobing this bit verify write protection is +// disabled, no other write or erase operations are in progress, and +// no error bits are asserted by reading FLASH_STATUS_REG.{/li} +// {li}Attempts to write data while other write or erase operations +// are in progress will be ignored.{/li} +// {li}Attempts to write data with write protection enabled will be +// ignored.{/li} +// {li}Strobing this bit and FLASH_ERASE_STB simultaneously will +// result in both the write and erase operation being ignored, +// both corresponding error bits being set, and write protection +// being re-enabled.{/li} +// {li}After strobing this bit poll theMax10FlashWriteIdle and +// FLASH_WRITE_ERR bits of FLASH_STATUS_REG to determine when +// the write operation is complete and if it was successful.{/li} +// </info> +// </bitfield> +// <bitfield name="FLASH_ERASE_STB" range="4" +// attributes="strobe"> +// <info> +// Strobe this bit to erase the primary Max10 configuration image +// (CFM0). +// {li}Prior to strobing this bit verify no other write or erase +// operations are in progress, write protection is disabled, and no +// error bits are asserted by reading FLASH_STATUS_REG.{/li} +// {li}Attempts to erase the primary image while other write or erase +// operations are in progress will be ignored. +// {li}Attempts to erase the primary image when write protection is +// enabled will be ignored.{/li} +// {li}Strobing this bit and FLASH_WRITE_STB simultaneously will +// result both the erase and the write operation being ignored, both +// corresponding error bits being set, and write protection being +// re-enabled.{/li} +// {li}After strobing this bit poll the FLASH_ERASE_IDLE and +// FLASH_ERASE_ERR bits of FLASH_STATUS_REG to determine when +// the erase operation is complete and if it was successful.{/li} +// </info> +// </bitfield> +// <bitfield name="FLASH_ERASE_SECTOR" range="7..5" +// attributes="strobe"> +// <info> +// Defines the sector to be erased. Has to be set latest with the +// write access which starts the erase operation by strobing +// @.FLASH_ERASE_STB.{br} +// If the flash is configured to support memory initialization (see +// @.FLASH_MEM_INIT_ENABLED flag) the sectors 2 to 4 have to be erased. +// If the flag is not asserted only sector 4 has to be erased. +// </info> +// </bitfield> +// <bitfield name="CLEAR_FLASH_READ_ERROR_STB" range="8" +// attributes="strobe"> +// <info> +// Strobe this bit to clear a read error. +// </info> +// </bitfield> +// <bitfield name="CLEAR_FLASH_WRITE_ERROR_STB" range="9" +// attributes="strobe"> +// <info> +// Strobe this bit to clear a write error. +// </info> +// </bitfield> +// <bitfield name="CLEAR_FLASH_ERASE_ERROR_STB" range="10" +// attributes="strobe"> +// <info> +// Strobe this bit to clear an erase error. +// </info> +// </bitfield> +// </register> +// <register name="FLASH_ADDR_REG" offset="0x08" size="32" +// attributes="Readable|Writable"> +// <bitfield name="FLASH_ADDR" range="16..0"> +// <info> +// This field holds the target address for the next read or +// write operation. Set this field prior to strobing the +// FLASH_WRITE_STB and FLASH_READ_STB bits of +// FLASH_CONTROL_REG. Valid addresses are defined by the +// FLASH_PRIMARY_IMAGE_ADDR_ENUM enumeration. +// </info> +// </bitfield> +// </register> +// <register name="FLASH_WRITE_DATA_REG" offset="0x0C" size="32" +// attributes="Writable"> +// <bitfield name="FLASH_WRITE_DATA" range="31..0"> +// <info> +// Data in this register will be written to the flash at the address +// identified in FLASH_ADDR_REG when a successful write operation +// is executed. +// </info> +// </bitfield> +// </register> +// <register name="FLASH_READ_DATA_REG" offset="0x10" size="32" +// attributes="Readable"> +// <bitfield name="FLASH_READ_DATA" range="31..0"> +// <info> +// This register contains data read from the flash address identified +// in FLASH_ADDR_REG after a successful read operation is executed. +// </info> +// </bitfield> +// </register> +// <register name="FLASH_CFM0_START_ADDR_REG" offset="0x14" size="32" +// attributes="Readable"> +// <bitfield name="FLASH_CFM0_START_ADDR" range="31..0"> +// <info> +// Start address of CFM0 image within flash memory (as defined in FLASH_PRIMARY_IMAGE_ADDR_ENUM). +// </info> +// </bitfield> +// </register> +// <register name="FLASH_CFM0_END_ADDR_REG" offset="0x18" size="32" +// attributes="Readable"> +// <bitfield name="FLASH_CFM0_END_ADDR" range="31..0"> +// <info> +// Last address of CFM0 image within flash memory (as defined in FLASH_PRIMARY_IMAGE_ADDR_ENUM). +// </info> +// </bitfield> +// </register> +// </group> +//</regmap> +//XmlParse xml_off diff --git a/fpga/usrp3/top/x400/cpld/regmap/constants_regmap_utils.vh b/fpga/usrp3/top/x400/cpld/regmap/constants_regmap_utils.vh new file mode 100644 index 000000000..4e5921f4c --- /dev/null +++ b/fpga/usrp3/top/x400/cpld/regmap/constants_regmap_utils.vh @@ -0,0 +1,28 @@ +// +// Copyright 2021 Ettus Research, A National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: constants_regmap_utils.vh +// Description: +// The constants in this file are autogenerated by XmlParse. + +//=============================================================================== +// A numerically ordered list of registers and their HDL source files +//=============================================================================== + + +//=============================================================================== +// RegTypes +//=============================================================================== + +//=============================================================================== +// Register Group CONSTANTS_GROUP +//=============================================================================== + + // Enumerated type CONSTANTS_ENUM + localparam CONSTANTS_ENUM_SIZE = 4; + localparam PS_CPLD_SIGNATURE = 'hA522D27; // CONSTANTS_ENUM:PS_CPLD_SIGNATURE + localparam OLDEST_CPLD_REVISION = 'h20122114; // CONSTANTS_ENUM:OLDEST_CPLD_REVISION + localparam CPLD_REVISION = 'h21012015; // CONSTANTS_ENUM:CPLD_REVISION + localparam PL_CPLD_SIGNATURE = 'h3FDC5C47; // CONSTANTS_ENUM:PL_CPLD_SIGNATURE diff --git a/fpga/usrp3/top/x400/cpld/regmap/jtag_regmap_utils.vh b/fpga/usrp3/top/x400/cpld/regmap/jtag_regmap_utils.vh new file mode 100644 index 000000000..f57e28ea9 --- /dev/null +++ b/fpga/usrp3/top/x400/cpld/regmap/jtag_regmap_utils.vh @@ -0,0 +1,57 @@ +// +// Copyright 2021 Ettus Research, A National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: jtag_regmap_utils.vh +// Description: +// The constants in this file are autogenerated by XmlParse. + +//=============================================================================== +// A numerically ordered list of registers and their HDL source files +//=============================================================================== + + // TX_DATA : 0x0 (ctrlport_to_jtag.v) + // STB_DATA : 0x4 (ctrlport_to_jtag.v) + // CONTROL : 0x8 (ctrlport_to_jtag.v) + // RX_DATA : 0xC (ctrlport_to_jtag.v) + +//=============================================================================== +// RegTypes +//=============================================================================== + +//=============================================================================== +// Register Group JTAG_REGS +//=============================================================================== + + // TX_DATA Register (from ctrlport_to_jtag.v) + localparam TX_DATA = 'h0; // Register Offset + localparam TX_DATA_SIZE = 32; // register width in bits + localparam TX_DATA_MASK = 32'h0; + + // STB_DATA Register (from ctrlport_to_jtag.v) + localparam STB_DATA = 'h4; // Register Offset + localparam STB_DATA_SIZE = 32; // register width in bits + localparam STB_DATA_MASK = 32'h0; + + // CONTROL Register (from ctrlport_to_jtag.v) + localparam CONTROL = 'h8; // Register Offset + localparam CONTROL_SIZE = 32; // register width in bits + localparam CONTROL_MASK = 32'h80001FFF; + localparam PRESCALAR_SIZE = 8; //CONTROL:prescalar + localparam PRESCALAR_MSB = 7; //CONTROL:prescalar + localparam PRESCALAR = 0; //CONTROL:prescalar + localparam LENGTH_SIZE = 5; //CONTROL:length + localparam LENGTH_MSB = 12; //CONTROL:length + localparam LENGTH = 8; //CONTROL:length + localparam RESET_SIZE = 1; //CONTROL:reset + localparam RESET_MSB = 31; //CONTROL:reset + localparam RESET = 31; //CONTROL:reset + localparam READY_SIZE = 1; //CONTROL:ready + localparam READY_MSB = 31; //CONTROL:ready + localparam READY = 31; //CONTROL:ready + + // RX_DATA Register (from ctrlport_to_jtag.v) + localparam RX_DATA = 'hC; // Register Offset + localparam RX_DATA_SIZE = 32; // register width in bits + localparam RX_DATA_MASK = 32'h0; diff --git a/fpga/usrp3/top/x400/cpld/regmap/mb_cpld_pl_regmap_utils.vh b/fpga/usrp3/top/x400/cpld/regmap/mb_cpld_pl_regmap_utils.vh new file mode 100644 index 000000000..d70590690 --- /dev/null +++ b/fpga/usrp3/top/x400/cpld/regmap/mb_cpld_pl_regmap_utils.vh @@ -0,0 +1,36 @@ +// +// Copyright 2021 Ettus Research, A National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: mb_cpld_pl_regmap_utils.vh +// Description: +// The constants in this file are autogenerated by XmlParse. + +//=============================================================================== +// A numerically ordered list of registers and their HDL source files +//=============================================================================== + + // PL_REGISTERS : 0x0 (mb_cpld.v) + // JTAG_DB0 : 0x60 (mb_cpld.v) + // JTAG_DB1 : 0x80 (mb_cpld.v) + +//=============================================================================== +// RegTypes +//=============================================================================== + +//=============================================================================== +// Register Group MB_CPLD_PL_WINDOWS +//=============================================================================== + + // PL_REGISTERS Window (from mb_cpld.v) + localparam PL_REGISTERS = 'h0; // Window Offset + localparam PL_REGISTERS_SIZE = 'h40; // size in bytes + + // JTAG_DB0 Window (from mb_cpld.v) + localparam JTAG_DB0 = 'h60; // Window Offset + localparam JTAG_DB0_SIZE = 'h20; // size in bytes + + // JTAG_DB1 Window (from mb_cpld.v) + localparam JTAG_DB1 = 'h80; // Window Offset + localparam JTAG_DB1_SIZE = 'h20; // size in bytes diff --git a/fpga/usrp3/top/x400/cpld/regmap/mb_cpld_ps_regmap_utils.vh b/fpga/usrp3/top/x400/cpld/regmap/mb_cpld_ps_regmap_utils.vh new file mode 100644 index 000000000..9eb044c10 --- /dev/null +++ b/fpga/usrp3/top/x400/cpld/regmap/mb_cpld_ps_regmap_utils.vh @@ -0,0 +1,51 @@ +// +// Copyright 2021 Ettus Research, A National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: mb_cpld_ps_regmap_utils.vh +// Description: +// The constants in this file are autogenerated by XmlParse. + +//=============================================================================== +// A numerically ordered list of registers and their HDL source files +//=============================================================================== + + // PS_REGISTERS : 0x0 (mb_cpld.v) + // RECONFIG : 0x40 (mb_cpld.v) + // POWER_REGISTERS : 0x60 (mb_cpld.v) + +//=============================================================================== +// RegTypes +//=============================================================================== + +//=============================================================================== +// Register Group MB_CPLD_PS_WINDOWS +//=============================================================================== + + // PS_REGISTERS Window (from mb_cpld.v) + localparam PS_REGISTERS = 'h0; // Window Offset + localparam PS_REGISTERS_SIZE = 'h40; // size in bytes + + // RECONFIG Window (from mb_cpld.v) + localparam RECONFIG = 'h40; // Window Offset + localparam RECONFIG_SIZE = 'h20; // size in bytes + + // POWER_REGISTERS Window (from mb_cpld.v) + localparam POWER_REGISTERS = 'h60; // Window Offset + localparam POWER_REGISTERS_SIZE = 'h20; // size in bytes + +//=============================================================================== +// Register Group PS_SPI_ENDPOINTS +//=============================================================================== + + // Enumerated type SPI_ENDPOINT + localparam SPI_ENDPOINT_SIZE = 8; + localparam PS_CS_MB_CPLD = 'h0; // SPI_ENDPOINT:PS_CS_MB_CPLD + localparam PS_CS_LMK32 = 'h1; // SPI_ENDPOINT:PS_CS_LMK32 + localparam PS_CS_TPM = 'h2; // SPI_ENDPOINT:PS_CS_TPM + localparam PS_CS_PHASE_DAC = 'h3; // SPI_ENDPOINT:PS_CS_PHASE_DAC + localparam PS_CS_DB0_CAL_EEPROM = 'h4; // SPI_ENDPOINT:PS_CS_DB0_CAL_EEPROM + localparam PS_CS_DB1_CAL_EEPROM = 'h5; // SPI_ENDPOINT:PS_CS_DB1_CAL_EEPROM + localparam PS_CS_CLK_AUX_DB = 'h6; // SPI_ENDPOINT:PS_CS_CLK_AUX_DB + localparam PS_CS_IDLE = 'h7; // SPI_ENDPOINT:PS_CS_IDLE diff --git a/fpga/usrp3/top/x400/cpld/regmap/pl_cpld_base_regmap_utils.vh b/fpga/usrp3/top/x400/cpld/regmap/pl_cpld_base_regmap_utils.vh new file mode 100644 index 000000000..820216d71 --- /dev/null +++ b/fpga/usrp3/top/x400/cpld/regmap/pl_cpld_base_regmap_utils.vh @@ -0,0 +1,122 @@ +// +// Copyright 2021 Ettus Research, A National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: pl_cpld_base_regmap_utils.vh +// Description: +// The constants in this file are autogenerated by XmlParse. + +//=============================================================================== +// A numerically ordered list of registers and their HDL source files +//=============================================================================== + + // SIGNATURE_REGISTER : 0x0 (pl_cpld_regs.v) + // REVISION_REGISTER : 0x4 (pl_cpld_regs.v) + // OLDEST_COMPATIBLE_REVISION_REGISTER : 0x8 (pl_cpld_regs.v) + // SCRATCH_REGISTER : 0xC (pl_cpld_regs.v) + // GIT_HASH_REGISTER : 0x10 (pl_cpld_regs.v) + // LED_REGISTER : 0x20 (pl_cpld_regs.v) + // CABLE_PRESENT_REG : 0x30 (pl_cpld_regs.v) + +//=============================================================================== +// RegTypes +//=============================================================================== + +//=============================================================================== +// Register Group MB_CPLD_LED_REGS +//=============================================================================== + + // LED_REGISTER Register (from pl_cpld_regs.v) + localparam LED_REGISTER = 'h20; // Register Offset + localparam LED_REGISTER_SIZE = 16; // register width in bits + localparam LED_REGISTER_MASK = 16'hFFFF; + localparam QSFP0_LED_LINK_SIZE = 4; //LED_REGISTER:QSFP0_LED_LINK + localparam QSFP0_LED_LINK_MSB = 3; //LED_REGISTER:QSFP0_LED_LINK + localparam QSFP0_LED_LINK = 0; //LED_REGISTER:QSFP0_LED_LINK + localparam QSFP0_LED_ACTIVE_SIZE = 4; //LED_REGISTER:QSFP0_LED_ACTIVE + localparam QSFP0_LED_ACTIVE_MSB = 7; //LED_REGISTER:QSFP0_LED_ACTIVE + localparam QSFP0_LED_ACTIVE = 4; //LED_REGISTER:QSFP0_LED_ACTIVE + localparam QSFP1_LED_LINK_SIZE = 4; //LED_REGISTER:QSFP1_LED_LINK + localparam QSFP1_LED_LINK_MSB = 11; //LED_REGISTER:QSFP1_LED_LINK + localparam QSFP1_LED_LINK = 8; //LED_REGISTER:QSFP1_LED_LINK + localparam QSFP1_LED_ACTIVE_SIZE = 4; //LED_REGISTER:QSFP1_LED_ACTIVE + localparam QSFP1_LED_ACTIVE_MSB = 15; //LED_REGISTER:QSFP1_LED_ACTIVE + localparam QSFP1_LED_ACTIVE = 12; //LED_REGISTER:QSFP1_LED_ACTIVE + +//=============================================================================== +// Register Group PL_CMI_REGS +//=============================================================================== + + // CABLE_PRESENT_REG Register (from pl_cpld_regs.v) + localparam CABLE_PRESENT_REG = 'h30; // Register Offset + localparam CABLE_PRESENT_REG_SIZE = 2; // register width in bits + localparam CABLE_PRESENT_REG_MASK = 2'h3; + localparam IPASS0_CABLE_PRESENT_SIZE = 1; //CABLE_PRESENT_REG:IPASS0_CABLE_PRESENT + localparam IPASS0_CABLE_PRESENT_MSB = 0; //CABLE_PRESENT_REG:IPASS0_CABLE_PRESENT + localparam IPASS0_CABLE_PRESENT = 0; //CABLE_PRESENT_REG:IPASS0_CABLE_PRESENT + localparam IPASS1_CABLE_PRESENT_SIZE = 1; //CABLE_PRESENT_REG:IPASS1_CABLE_PRESENT + localparam IPASS1_CABLE_PRESENT_MSB = 1; //CABLE_PRESENT_REG:IPASS1_CABLE_PRESENT + localparam IPASS1_CABLE_PRESENT = 1; //CABLE_PRESENT_REG:IPASS1_CABLE_PRESENT + +//=============================================================================== +// Register Group PL_CPLD_BASE_REGS +//=============================================================================== + + // SIGNATURE_REGISTER Register (from pl_cpld_regs.v) + localparam SIGNATURE_REGISTER = 'h0; // Register Offset + localparam SIGNATURE_REGISTER_SIZE = 32; // register width in bits + localparam SIGNATURE_REGISTER_MASK = 32'hFFFFFFFF; + localparam PRODUCT_SIGNATURE_SIZE = 32; //SIGNATURE_REGISTER:PRODUCT_SIGNATURE + localparam PRODUCT_SIGNATURE_MSB = 31; //SIGNATURE_REGISTER:PRODUCT_SIGNATURE + localparam PRODUCT_SIGNATURE = 0; //SIGNATURE_REGISTER:PRODUCT_SIGNATURE + + // REVISION_REGISTER Register (from pl_cpld_regs.v) + localparam REVISION_REGISTER = 'h4; // Register Offset + localparam REVISION_REGISTER_SIZE = 32; // register width in bits + localparam REVISION_REGISTER_MASK = 32'hFFFFFFFF; + localparam REVISION_HH_SIZE = 8; //REVISION_REGISTER:REVISION_HH + localparam REVISION_HH_MSB = 7; //REVISION_REGISTER:REVISION_HH + localparam REVISION_HH = 0; //REVISION_REGISTER:REVISION_HH + localparam REVISION_DD_SIZE = 8; //REVISION_REGISTER:REVISION_DD + localparam REVISION_DD_MSB = 15; //REVISION_REGISTER:REVISION_DD + localparam REVISION_DD = 8; //REVISION_REGISTER:REVISION_DD + localparam REVISION_MM_SIZE = 8; //REVISION_REGISTER:REVISION_MM + localparam REVISION_MM_MSB = 23; //REVISION_REGISTER:REVISION_MM + localparam REVISION_MM = 16; //REVISION_REGISTER:REVISION_MM + localparam REVISION_YY_SIZE = 8; //REVISION_REGISTER:REVISION_YY + localparam REVISION_YY_MSB = 31; //REVISION_REGISTER:REVISION_YY + localparam REVISION_YY = 24; //REVISION_REGISTER:REVISION_YY + + // OLDEST_COMPATIBLE_REVISION_REGISTER Register (from pl_cpld_regs.v) + localparam OLDEST_COMPATIBLE_REVISION_REGISTER = 'h8; // Register Offset + localparam OLDEST_COMPATIBLE_REVISION_REGISTER_SIZE = 32; // register width in bits + localparam OLDEST_COMPATIBLE_REVISION_REGISTER_MASK = 32'hFFFFFFFF; + localparam OLD_REVISION_HH_SIZE = 8; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_HH + localparam OLD_REVISION_HH_MSB = 7; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_HH + localparam OLD_REVISION_HH = 0; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_HH + localparam OLD_REVISION_DD_SIZE = 8; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_DD + localparam OLD_REVISION_DD_MSB = 15; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_DD + localparam OLD_REVISION_DD = 8; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_DD + localparam OLD_REVISION_MM_SIZE = 8; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_MM + localparam OLD_REVISION_MM_MSB = 23; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_MM + localparam OLD_REVISION_MM = 16; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_MM + localparam OLD_REVISION_YY_SIZE = 8; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_YY + localparam OLD_REVISION_YY_MSB = 31; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_YY + localparam OLD_REVISION_YY = 24; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_YY + + // SCRATCH_REGISTER Register (from pl_cpld_regs.v) + localparam SCRATCH_REGISTER = 'hC; // Register Offset + localparam SCRATCH_REGISTER_SIZE = 32; // register width in bits + localparam SCRATCH_REGISTER_MASK = 32'h0; + + // GIT_HASH_REGISTER Register (from pl_cpld_regs.v) + localparam GIT_HASH_REGISTER = 'h10; // Register Offset + localparam GIT_HASH_REGISTER_SIZE = 32; // register width in bits + localparam GIT_HASH_REGISTER_MASK = 32'hFFFFFFFF; + localparam GIT_HASH_SIZE = 28; //GIT_HASH_REGISTER:GIT_HASH + localparam GIT_HASH_MSB = 27; //GIT_HASH_REGISTER:GIT_HASH + localparam GIT_HASH = 0; //GIT_HASH_REGISTER:GIT_HASH + localparam GIT_CLEAN_SIZE = 4; //GIT_HASH_REGISTER:GIT_CLEAN + localparam GIT_CLEAN_MSB = 31; //GIT_HASH_REGISTER:GIT_CLEAN + localparam GIT_CLEAN = 28; //GIT_HASH_REGISTER:GIT_CLEAN diff --git a/fpga/usrp3/top/x400/cpld/regmap/ps_cpld_base_regmap_utils.vh b/fpga/usrp3/top/x400/cpld/regmap/ps_cpld_base_regmap_utils.vh new file mode 100644 index 000000000..a5a067bb4 --- /dev/null +++ b/fpga/usrp3/top/x400/cpld/regmap/ps_cpld_base_regmap_utils.vh @@ -0,0 +1,183 @@ +// +// Copyright 2021 Ettus Research, A National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: ps_cpld_base_regmap_utils.vh +// Description: +// The constants in this file are autogenerated by XmlParse. + +//=============================================================================== +// A numerically ordered list of registers and their HDL source files +//=============================================================================== + + // SIGNATURE_REGISTER : 0x0 (ps_cpld_regs.v) + // REVISION_REGISTER : 0x4 (ps_cpld_regs.v) + // OLDEST_COMPATIBLE_REVISION_REGISTER : 0x8 (ps_cpld_regs.v) + // SCRATCH_REGISTER : 0xC (ps_cpld_regs.v) + // GIT_HASH_REGISTER : 0x10 (ps_cpld_regs.v) + // PL_DB_REGISTER : 0x20 (ps_cpld_regs.v) + // DIO_DIRECTION_REGISTER : 0x30 (ps_cpld_regs.v) + // SERIAL_NUM_LOW_REG : 0x34 (ps_cpld_regs.v) + // SERIAL_NUM_HIGH_REG : 0x38 (ps_cpld_regs.v) + // CMI_CONTROL_STATUS : 0x3C (ps_cpld_regs.v) + +//=============================================================================== +// RegTypes +//=============================================================================== + +//=============================================================================== +// Register Group DIO_REGS +//=============================================================================== + + // DIO_DIRECTION_REGISTER Register (from ps_cpld_regs.v) + localparam DIO_DIRECTION_REGISTER = 'h30; // Register Offset + localparam DIO_DIRECTION_REGISTER_SIZE = 32; // register width in bits + localparam DIO_DIRECTION_REGISTER_MASK = 32'hFFF0FFF; + localparam DIO_DIRECTION_A_SIZE = 12; //DIO_DIRECTION_REGISTER:DIO_DIRECTION_A + localparam DIO_DIRECTION_A_MSB = 11; //DIO_DIRECTION_REGISTER:DIO_DIRECTION_A + localparam DIO_DIRECTION_A = 0; //DIO_DIRECTION_REGISTER:DIO_DIRECTION_A + localparam DIO_DIRECTION_B_SIZE = 12; //DIO_DIRECTION_REGISTER:DIO_DIRECTION_B + localparam DIO_DIRECTION_B_MSB = 27; //DIO_DIRECTION_REGISTER:DIO_DIRECTION_B + localparam DIO_DIRECTION_B = 16; //DIO_DIRECTION_REGISTER:DIO_DIRECTION_B + +//=============================================================================== +// Register Group PS_CMI_REGS +//=============================================================================== + + // SERIAL_NUM_LOW_REG Register (from ps_cpld_regs.v) + localparam SERIAL_NUM_LOW_REG = 'h34; // Register Offset + localparam SERIAL_NUM_LOW_REG_SIZE = 32; // register width in bits + localparam SERIAL_NUM_LOW_REG_MASK = 32'h0; + + // SERIAL_NUM_HIGH_REG Register (from ps_cpld_regs.v) + localparam SERIAL_NUM_HIGH_REG = 'h38; // Register Offset + localparam SERIAL_NUM_HIGH_REG_SIZE = 8; // register width in bits + localparam SERIAL_NUM_HIGH_REG_MASK = 8'h0; + + // CMI_CONTROL_STATUS Register (from ps_cpld_regs.v) + localparam CMI_CONTROL_STATUS = 'h3C; // Register Offset + localparam CMI_CONTROL_STATUS_SIZE = 32; // register width in bits + localparam CMI_CONTROL_STATUS_MASK = 32'h80000001; + localparam CMI_READY_SIZE = 1; //CMI_CONTROL_STATUS:CMI_READY + localparam CMI_READY_MSB = 0; //CMI_CONTROL_STATUS:CMI_READY + localparam CMI_READY = 0; //CMI_CONTROL_STATUS:CMI_READY + localparam OTHER_SIDE_DETECTED_SIZE = 1; //CMI_CONTROL_STATUS:OTHER_SIDE_DETECTED + localparam OTHER_SIDE_DETECTED_MSB = 31; //CMI_CONTROL_STATUS:OTHER_SIDE_DETECTED + localparam OTHER_SIDE_DETECTED = 31; //CMI_CONTROL_STATUS:OTHER_SIDE_DETECTED + +//=============================================================================== +// Register Group PS_CONTROL_REGS +//=============================================================================== + + // PL_DB_REGISTER Register (from ps_cpld_regs.v) + localparam PL_DB_REGISTER = 'h20; // Register Offset + localparam PL_DB_REGISTER_SIZE = 32; // register width in bits + localparam PL_DB_REGISTER_MASK = 32'h337737; + localparam DB0_CLOCK_ENABLED_SIZE = 1; //PL_DB_REGISTER:DB0_CLOCK_ENABLED + localparam DB0_CLOCK_ENABLED_MSB = 0; //PL_DB_REGISTER:DB0_CLOCK_ENABLED + localparam DB0_CLOCK_ENABLED = 0; //PL_DB_REGISTER:DB0_CLOCK_ENABLED + localparam DB1_CLOCK_ENABLED_SIZE = 1; //PL_DB_REGISTER:DB1_CLOCK_ENABLED + localparam DB1_CLOCK_ENABLED_MSB = 1; //PL_DB_REGISTER:DB1_CLOCK_ENABLED + localparam DB1_CLOCK_ENABLED = 1; //PL_DB_REGISTER:DB1_CLOCK_ENABLED + localparam PLL_REF_CLOCK_ENABLED_SIZE = 1; //PL_DB_REGISTER:PLL_REF_CLOCK_ENABLED + localparam PLL_REF_CLOCK_ENABLED_MSB = 2; //PL_DB_REGISTER:PLL_REF_CLOCK_ENABLED + localparam PLL_REF_CLOCK_ENABLED = 2; //PL_DB_REGISTER:PLL_REF_CLOCK_ENABLED + localparam DB0_RESET_ASSERTED_SIZE = 1; //PL_DB_REGISTER:DB0_RESET_ASSERTED + localparam DB0_RESET_ASSERTED_MSB = 4; //PL_DB_REGISTER:DB0_RESET_ASSERTED + localparam DB0_RESET_ASSERTED = 4; //PL_DB_REGISTER:DB0_RESET_ASSERTED + localparam DB1_RESET_ASSERTED_SIZE = 1; //PL_DB_REGISTER:DB1_RESET_ASSERTED + localparam DB1_RESET_ASSERTED_MSB = 5; //PL_DB_REGISTER:DB1_RESET_ASSERTED + localparam DB1_RESET_ASSERTED = 5; //PL_DB_REGISTER:DB1_RESET_ASSERTED + localparam ENABLE_CLOCK_DB0_SIZE = 1; //PL_DB_REGISTER:ENABLE_CLOCK_DB0 + localparam ENABLE_CLOCK_DB0_MSB = 8; //PL_DB_REGISTER:ENABLE_CLOCK_DB0 + localparam ENABLE_CLOCK_DB0 = 8; //PL_DB_REGISTER:ENABLE_CLOCK_DB0 + localparam ENABLE_CLOCK_DB1_SIZE = 1; //PL_DB_REGISTER:ENABLE_CLOCK_DB1 + localparam ENABLE_CLOCK_DB1_MSB = 9; //PL_DB_REGISTER:ENABLE_CLOCK_DB1 + localparam ENABLE_CLOCK_DB1 = 9; //PL_DB_REGISTER:ENABLE_CLOCK_DB1 + localparam ENABLE_PLL_REF_CLOCK_SIZE = 1; //PL_DB_REGISTER:ENABLE_PLL_REF_CLOCK + localparam ENABLE_PLL_REF_CLOCK_MSB = 10; //PL_DB_REGISTER:ENABLE_PLL_REF_CLOCK + localparam ENABLE_PLL_REF_CLOCK = 10; //PL_DB_REGISTER:ENABLE_PLL_REF_CLOCK + localparam DISABLE_CLOCK_DB0_SIZE = 1; //PL_DB_REGISTER:DISABLE_CLOCK_DB0 + localparam DISABLE_CLOCK_DB0_MSB = 12; //PL_DB_REGISTER:DISABLE_CLOCK_DB0 + localparam DISABLE_CLOCK_DB0 = 12; //PL_DB_REGISTER:DISABLE_CLOCK_DB0 + localparam DISABLE_CLOCK_DB1_SIZE = 1; //PL_DB_REGISTER:DISABLE_CLOCK_DB1 + localparam DISABLE_CLOCK_DB1_MSB = 13; //PL_DB_REGISTER:DISABLE_CLOCK_DB1 + localparam DISABLE_CLOCK_DB1 = 13; //PL_DB_REGISTER:DISABLE_CLOCK_DB1 + localparam DISABLE_PLL_REF_CLOCK_SIZE = 1; //PL_DB_REGISTER:DISABLE_PLL_REF_CLOCK + localparam DISABLE_PLL_REF_CLOCK_MSB = 14; //PL_DB_REGISTER:DISABLE_PLL_REF_CLOCK + localparam DISABLE_PLL_REF_CLOCK = 14; //PL_DB_REGISTER:DISABLE_PLL_REF_CLOCK + localparam RELEASE_RESET_DB0_SIZE = 1; //PL_DB_REGISTER:RELEASE_RESET_DB0 + localparam RELEASE_RESET_DB0_MSB = 16; //PL_DB_REGISTER:RELEASE_RESET_DB0 + localparam RELEASE_RESET_DB0 = 16; //PL_DB_REGISTER:RELEASE_RESET_DB0 + localparam RELEASE_RESET_DB1_SIZE = 1; //PL_DB_REGISTER:RELEASE_RESET_DB1 + localparam RELEASE_RESET_DB1_MSB = 17; //PL_DB_REGISTER:RELEASE_RESET_DB1 + localparam RELEASE_RESET_DB1 = 17; //PL_DB_REGISTER:RELEASE_RESET_DB1 + localparam ASSERT_RESET_DB0_SIZE = 1; //PL_DB_REGISTER:ASSERT_RESET_DB0 + localparam ASSERT_RESET_DB0_MSB = 20; //PL_DB_REGISTER:ASSERT_RESET_DB0 + localparam ASSERT_RESET_DB0 = 20; //PL_DB_REGISTER:ASSERT_RESET_DB0 + localparam ASSERT_RESET_DB1_SIZE = 1; //PL_DB_REGISTER:ASSERT_RESET_DB1 + localparam ASSERT_RESET_DB1_MSB = 21; //PL_DB_REGISTER:ASSERT_RESET_DB1 + localparam ASSERT_RESET_DB1 = 21; //PL_DB_REGISTER:ASSERT_RESET_DB1 + +//=============================================================================== +// Register Group PS_CPLD_BASE_REGS +//=============================================================================== + + // SIGNATURE_REGISTER Register (from ps_cpld_regs.v) + localparam SIGNATURE_REGISTER = 'h0; // Register Offset + localparam SIGNATURE_REGISTER_SIZE = 32; // register width in bits + localparam SIGNATURE_REGISTER_MASK = 32'hFFFFFFFF; + localparam PRODUCT_SIGNATURE_SIZE = 32; //SIGNATURE_REGISTER:PRODUCT_SIGNATURE + localparam PRODUCT_SIGNATURE_MSB = 31; //SIGNATURE_REGISTER:PRODUCT_SIGNATURE + localparam PRODUCT_SIGNATURE = 0; //SIGNATURE_REGISTER:PRODUCT_SIGNATURE + + // REVISION_REGISTER Register (from ps_cpld_regs.v) + localparam REVISION_REGISTER = 'h4; // Register Offset + localparam REVISION_REGISTER_SIZE = 32; // register width in bits + localparam REVISION_REGISTER_MASK = 32'hFFFFFFFF; + localparam REVISION_HH_SIZE = 8; //REVISION_REGISTER:REVISION_HH + localparam REVISION_HH_MSB = 7; //REVISION_REGISTER:REVISION_HH + localparam REVISION_HH = 0; //REVISION_REGISTER:REVISION_HH + localparam REVISION_DD_SIZE = 8; //REVISION_REGISTER:REVISION_DD + localparam REVISION_DD_MSB = 15; //REVISION_REGISTER:REVISION_DD + localparam REVISION_DD = 8; //REVISION_REGISTER:REVISION_DD + localparam REVISION_MM_SIZE = 8; //REVISION_REGISTER:REVISION_MM + localparam REVISION_MM_MSB = 23; //REVISION_REGISTER:REVISION_MM + localparam REVISION_MM = 16; //REVISION_REGISTER:REVISION_MM + localparam REVISION_YY_SIZE = 8; //REVISION_REGISTER:REVISION_YY + localparam REVISION_YY_MSB = 31; //REVISION_REGISTER:REVISION_YY + localparam REVISION_YY = 24; //REVISION_REGISTER:REVISION_YY + + // OLDEST_COMPATIBLE_REVISION_REGISTER Register (from ps_cpld_regs.v) + localparam OLDEST_COMPATIBLE_REVISION_REGISTER = 'h8; // Register Offset + localparam OLDEST_COMPATIBLE_REVISION_REGISTER_SIZE = 32; // register width in bits + localparam OLDEST_COMPATIBLE_REVISION_REGISTER_MASK = 32'hFFFFFFFF; + localparam OLD_REVISION_HH_SIZE = 8; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_HH + localparam OLD_REVISION_HH_MSB = 7; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_HH + localparam OLD_REVISION_HH = 0; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_HH + localparam OLD_REVISION_DD_SIZE = 8; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_DD + localparam OLD_REVISION_DD_MSB = 15; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_DD + localparam OLD_REVISION_DD = 8; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_DD + localparam OLD_REVISION_MM_SIZE = 8; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_MM + localparam OLD_REVISION_MM_MSB = 23; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_MM + localparam OLD_REVISION_MM = 16; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_MM + localparam OLD_REVISION_YY_SIZE = 8; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_YY + localparam OLD_REVISION_YY_MSB = 31; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_YY + localparam OLD_REVISION_YY = 24; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_YY + + // SCRATCH_REGISTER Register (from ps_cpld_regs.v) + localparam SCRATCH_REGISTER = 'hC; // Register Offset + localparam SCRATCH_REGISTER_SIZE = 32; // register width in bits + localparam SCRATCH_REGISTER_MASK = 32'h0; + + // GIT_HASH_REGISTER Register (from ps_cpld_regs.v) + localparam GIT_HASH_REGISTER = 'h10; // Register Offset + localparam GIT_HASH_REGISTER_SIZE = 32; // register width in bits + localparam GIT_HASH_REGISTER_MASK = 32'hFFFFFFFF; + localparam GIT_HASH_SIZE = 28; //GIT_HASH_REGISTER:GIT_HASH + localparam GIT_HASH_MSB = 27; //GIT_HASH_REGISTER:GIT_HASH + localparam GIT_HASH = 0; //GIT_HASH_REGISTER:GIT_HASH + localparam GIT_CLEAN_SIZE = 4; //GIT_HASH_REGISTER:GIT_CLEAN + localparam GIT_CLEAN_MSB = 31; //GIT_HASH_REGISTER:GIT_CLEAN + localparam GIT_CLEAN = 28; //GIT_HASH_REGISTER:GIT_CLEAN diff --git a/fpga/usrp3/top/x400/cpld/regmap/ps_power_regmap_utils.vh b/fpga/usrp3/top/x400/cpld/regmap/ps_power_regmap_utils.vh new file mode 100644 index 000000000..e4021b29e --- /dev/null +++ b/fpga/usrp3/top/x400/cpld/regmap/ps_power_regmap_utils.vh @@ -0,0 +1,54 @@ +// +// Copyright 2021 Ettus Research, A National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: ps_power_regmap_utils.vh +// Description: +// The constants in this file are autogenerated by XmlParse. + +//=============================================================================== +// A numerically ordered list of registers and their HDL source files +//=============================================================================== + + // IPASS_POWER_REG : 0x0 (ps_power_regs.v) + // OSC_POWER_REG : 0x4 (ps_power_regs.v) + +//=============================================================================== +// RegTypes +//=============================================================================== + +//=============================================================================== +// Register Group PS_POWER_REGS +//=============================================================================== + + // IPASS_POWER_REG Register (from ps_power_regs.v) + localparam IPASS_POWER_REG = 'h0; // Register Offset + localparam IPASS_POWER_REG_SIZE = 32; // register width in bits + localparam IPASS_POWER_REG_MASK = 32'hC0000001; + localparam IPASS_DISABLE_POWER_BIT_SIZE = 1; //IPASS_POWER_REG:IPASS_DISABLE_POWER_BIT + localparam IPASS_DISABLE_POWER_BIT_MSB = 0; //IPASS_POWER_REG:IPASS_DISABLE_POWER_BIT + localparam IPASS_DISABLE_POWER_BIT = 0; //IPASS_POWER_REG:IPASS_DISABLE_POWER_BIT + localparam IPASS_CLEAR_POWER_FAULT0_SIZE = 1; //IPASS_POWER_REG:IPASS_CLEAR_POWER_FAULT0 + localparam IPASS_CLEAR_POWER_FAULT0_MSB = 30; //IPASS_POWER_REG:IPASS_CLEAR_POWER_FAULT0 + localparam IPASS_CLEAR_POWER_FAULT0 = 30; //IPASS_POWER_REG:IPASS_CLEAR_POWER_FAULT0 + localparam IPASS_POWER_FAULT0_SIZE = 1; //IPASS_POWER_REG:IPASS_POWER_FAULT0 + localparam IPASS_POWER_FAULT0_MSB = 30; //IPASS_POWER_REG:IPASS_POWER_FAULT0 + localparam IPASS_POWER_FAULT0 = 30; //IPASS_POWER_REG:IPASS_POWER_FAULT0 + localparam IPASS_CLEAR_POWER_FAULT1_SIZE = 1; //IPASS_POWER_REG:IPASS_CLEAR_POWER_FAULT1 + localparam IPASS_CLEAR_POWER_FAULT1_MSB = 31; //IPASS_POWER_REG:IPASS_CLEAR_POWER_FAULT1 + localparam IPASS_CLEAR_POWER_FAULT1 = 31; //IPASS_POWER_REG:IPASS_CLEAR_POWER_FAULT1 + localparam IPASS_POWER_FAULT1_SIZE = 1; //IPASS_POWER_REG:IPASS_POWER_FAULT1 + localparam IPASS_POWER_FAULT1_MSB = 31; //IPASS_POWER_REG:IPASS_POWER_FAULT1 + localparam IPASS_POWER_FAULT1 = 31; //IPASS_POWER_REG:IPASS_POWER_FAULT1 + + // OSC_POWER_REG Register (from ps_power_regs.v) + localparam OSC_POWER_REG = 'h4; // Register Offset + localparam OSC_POWER_REG_SIZE = 32; // register width in bits + localparam OSC_POWER_REG_MASK = 32'h3; + localparam OSC_100_SIZE = 1; //OSC_POWER_REG:OSC_100 + localparam OSC_100_MSB = 0; //OSC_POWER_REG:OSC_100 + localparam OSC_100 = 0; //OSC_POWER_REG:OSC_100 + localparam OSC_122_88_SIZE = 1; //OSC_POWER_REG:OSC_122_88 + localparam OSC_122_88_MSB = 1; //OSC_POWER_REG:OSC_122_88 + localparam OSC_122_88 = 1; //OSC_POWER_REG:OSC_122_88 diff --git a/fpga/usrp3/top/x400/cpld/regmap/reconfig_regmap_utils.vh b/fpga/usrp3/top/x400/cpld/regmap/reconfig_regmap_utils.vh new file mode 100644 index 000000000..2ddc6a8b9 --- /dev/null +++ b/fpga/usrp3/top/x400/cpld/regmap/reconfig_regmap_utils.vh @@ -0,0 +1,135 @@ +// +// Copyright 2021 Ettus Research, A National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: reconfig_regmap_utils.vh +// Description: +// The constants in this file are autogenerated by XmlParse. + +//=============================================================================== +// A numerically ordered list of registers and their HDL source files +//=============================================================================== + + // FLASH_STATUS_REG : 0x0 (reconfig_engine.v) + // FLASH_CONTROL_REG : 0x4 (reconfig_engine.v) + // FLASH_ADDR_REG : 0x8 (reconfig_engine.v) + // FLASH_WRITE_DATA_REG : 0xC (reconfig_engine.v) + // FLASH_READ_DATA_REG : 0x10 (reconfig_engine.v) + // FLASH_CFM0_START_ADDR_REG : 0x14 (reconfig_engine.v) + // FLASH_CFM0_END_ADDR_REG : 0x18 (reconfig_engine.v) + +//=============================================================================== +// RegTypes +//=============================================================================== + +//=============================================================================== +// Register Group RECONFIG_REGS +//=============================================================================== + + // Enumerated type FLASH_PRIMARY_IMAGE_ADDR_ENUM + localparam FLASH_PRIMARY_IMAGE_ADDR_ENUM_SIZE = 3; + localparam FLASH_PRIMARY_IMAGE_START_ADDR_MEM_INIT = 'h1000; // FLASH_PRIMARY_IMAGE_ADDR_ENUM:FLASH_PRIMARY_IMAGE_START_ADDR_MEM_INIT + localparam FLASH_PRIMARY_IMAGE_START_ADDR = 'h9C00; // FLASH_PRIMARY_IMAGE_ADDR_ENUM:FLASH_PRIMARY_IMAGE_START_ADDR + localparam FLASH_PRIMARY_IMAGE_END_ADDR = 'h127FF; // FLASH_PRIMARY_IMAGE_ADDR_ENUM:FLASH_PRIMARY_IMAGE_END_ADDR + + // FLASH_STATUS_REG Register (from reconfig_engine.v) + localparam FLASH_STATUS_REG = 'h0; // Register Offset + localparam FLASH_STATUS_REG_SIZE = 32; // register width in bits + localparam FLASH_STATUS_REG_MASK = 32'h13331; + localparam FLASH_WP_ENABLED_SIZE = 1; //FLASH_STATUS_REG:FLASH_WP_ENABLED + localparam FLASH_WP_ENABLED_MSB = 0; //FLASH_STATUS_REG:FLASH_WP_ENABLED + localparam FLASH_WP_ENABLED = 0; //FLASH_STATUS_REG:FLASH_WP_ENABLED + localparam FLASH_READ_IDLE_SIZE = 1; //FLASH_STATUS_REG:FLASH_READ_IDLE + localparam FLASH_READ_IDLE_MSB = 4; //FLASH_STATUS_REG:FLASH_READ_IDLE + localparam FLASH_READ_IDLE = 4; //FLASH_STATUS_REG:FLASH_READ_IDLE + localparam FLASH_READ_ERR_SIZE = 1; //FLASH_STATUS_REG:FLASH_READ_ERR + localparam FLASH_READ_ERR_MSB = 5; //FLASH_STATUS_REG:FLASH_READ_ERR + localparam FLASH_READ_ERR = 5; //FLASH_STATUS_REG:FLASH_READ_ERR + localparam FLASH_ERASE_IDLE_SIZE = 1; //FLASH_STATUS_REG:FLASH_ERASE_IDLE + localparam FLASH_ERASE_IDLE_MSB = 8; //FLASH_STATUS_REG:FLASH_ERASE_IDLE + localparam FLASH_ERASE_IDLE = 8; //FLASH_STATUS_REG:FLASH_ERASE_IDLE + localparam FLASH_ERASE_ERR_SIZE = 1; //FLASH_STATUS_REG:FLASH_ERASE_ERR + localparam FLASH_ERASE_ERR_MSB = 9; //FLASH_STATUS_REG:FLASH_ERASE_ERR + localparam FLASH_ERASE_ERR = 9; //FLASH_STATUS_REG:FLASH_ERASE_ERR + localparam FLASH_WRITE_IDLE_SIZE = 1; //FLASH_STATUS_REG:FLASH_WRITE_IDLE + localparam FLASH_WRITE_IDLE_MSB = 12; //FLASH_STATUS_REG:FLASH_WRITE_IDLE + localparam FLASH_WRITE_IDLE = 12; //FLASH_STATUS_REG:FLASH_WRITE_IDLE + localparam FLASH_WRITE_ERR_SIZE = 1; //FLASH_STATUS_REG:FLASH_WRITE_ERR + localparam FLASH_WRITE_ERR_MSB = 13; //FLASH_STATUS_REG:FLASH_WRITE_ERR + localparam FLASH_WRITE_ERR = 13; //FLASH_STATUS_REG:FLASH_WRITE_ERR + localparam FLASH_MEM_INIT_ENABLED_SIZE = 1; //FLASH_STATUS_REG:FLASH_MEM_INIT_ENABLED + localparam FLASH_MEM_INIT_ENABLED_MSB = 16; //FLASH_STATUS_REG:FLASH_MEM_INIT_ENABLED + localparam FLASH_MEM_INIT_ENABLED = 16; //FLASH_STATUS_REG:FLASH_MEM_INIT_ENABLED + + // FLASH_CONTROL_REG Register (from reconfig_engine.v) + localparam FLASH_CONTROL_REG = 'h4; // Register Offset + localparam FLASH_CONTROL_REG_SIZE = 32; // register width in bits + localparam FLASH_CONTROL_REG_MASK = 32'h7FF; + localparam FLASH_ENABLE_WP_STB_SIZE = 1; //FLASH_CONTROL_REG:FLASH_ENABLE_WP_STB + localparam FLASH_ENABLE_WP_STB_MSB = 0; //FLASH_CONTROL_REG:FLASH_ENABLE_WP_STB + localparam FLASH_ENABLE_WP_STB = 0; //FLASH_CONTROL_REG:FLASH_ENABLE_WP_STB + localparam FLASH_DISABLE_WP_STB_SIZE = 1; //FLASH_CONTROL_REG:FLASH_DISABLE_WP_STB + localparam FLASH_DISABLE_WP_STB_MSB = 1; //FLASH_CONTROL_REG:FLASH_DISABLE_WP_STB + localparam FLASH_DISABLE_WP_STB = 1; //FLASH_CONTROL_REG:FLASH_DISABLE_WP_STB + localparam FLASH_READ_STB_SIZE = 1; //FLASH_CONTROL_REG:FLASH_READ_STB + localparam FLASH_READ_STB_MSB = 2; //FLASH_CONTROL_REG:FLASH_READ_STB + localparam FLASH_READ_STB = 2; //FLASH_CONTROL_REG:FLASH_READ_STB + localparam FLASH_WRITE_STB_SIZE = 1; //FLASH_CONTROL_REG:FLASH_WRITE_STB + localparam FLASH_WRITE_STB_MSB = 3; //FLASH_CONTROL_REG:FLASH_WRITE_STB + localparam FLASH_WRITE_STB = 3; //FLASH_CONTROL_REG:FLASH_WRITE_STB + localparam FLASH_ERASE_STB_SIZE = 1; //FLASH_CONTROL_REG:FLASH_ERASE_STB + localparam FLASH_ERASE_STB_MSB = 4; //FLASH_CONTROL_REG:FLASH_ERASE_STB + localparam FLASH_ERASE_STB = 4; //FLASH_CONTROL_REG:FLASH_ERASE_STB + localparam FLASH_ERASE_SECTOR_SIZE = 3; //FLASH_CONTROL_REG:FLASH_ERASE_SECTOR + localparam FLASH_ERASE_SECTOR_MSB = 7; //FLASH_CONTROL_REG:FLASH_ERASE_SECTOR + localparam FLASH_ERASE_SECTOR = 5; //FLASH_CONTROL_REG:FLASH_ERASE_SECTOR + localparam CLEAR_FLASH_READ_ERROR_STB_SIZE = 1; //FLASH_CONTROL_REG:CLEAR_FLASH_READ_ERROR_STB + localparam CLEAR_FLASH_READ_ERROR_STB_MSB = 8; //FLASH_CONTROL_REG:CLEAR_FLASH_READ_ERROR_STB + localparam CLEAR_FLASH_READ_ERROR_STB = 8; //FLASH_CONTROL_REG:CLEAR_FLASH_READ_ERROR_STB + localparam CLEAR_FLASH_WRITE_ERROR_STB_SIZE = 1; //FLASH_CONTROL_REG:CLEAR_FLASH_WRITE_ERROR_STB + localparam CLEAR_FLASH_WRITE_ERROR_STB_MSB = 9; //FLASH_CONTROL_REG:CLEAR_FLASH_WRITE_ERROR_STB + localparam CLEAR_FLASH_WRITE_ERROR_STB = 9; //FLASH_CONTROL_REG:CLEAR_FLASH_WRITE_ERROR_STB + localparam CLEAR_FLASH_ERASE_ERROR_STB_SIZE = 1; //FLASH_CONTROL_REG:CLEAR_FLASH_ERASE_ERROR_STB + localparam CLEAR_FLASH_ERASE_ERROR_STB_MSB = 10; //FLASH_CONTROL_REG:CLEAR_FLASH_ERASE_ERROR_STB + localparam CLEAR_FLASH_ERASE_ERROR_STB = 10; //FLASH_CONTROL_REG:CLEAR_FLASH_ERASE_ERROR_STB + + // FLASH_ADDR_REG Register (from reconfig_engine.v) + localparam FLASH_ADDR_REG = 'h8; // Register Offset + localparam FLASH_ADDR_REG_SIZE = 32; // register width in bits + localparam FLASH_ADDR_REG_MASK = 32'h1FFFF; + localparam FLASH_ADDR_SIZE = 17; //FLASH_ADDR_REG:FLASH_ADDR + localparam FLASH_ADDR_MSB = 16; //FLASH_ADDR_REG:FLASH_ADDR + localparam FLASH_ADDR = 0; //FLASH_ADDR_REG:FLASH_ADDR + + // FLASH_WRITE_DATA_REG Register (from reconfig_engine.v) + localparam FLASH_WRITE_DATA_REG = 'hC; // Register Offset + localparam FLASH_WRITE_DATA_REG_SIZE = 32; // register width in bits + localparam FLASH_WRITE_DATA_REG_MASK = 32'hFFFFFFFF; + localparam FLASH_WRITE_DATA_SIZE = 32; //FLASH_WRITE_DATA_REG:FLASH_WRITE_DATA + localparam FLASH_WRITE_DATA_MSB = 31; //FLASH_WRITE_DATA_REG:FLASH_WRITE_DATA + localparam FLASH_WRITE_DATA = 0; //FLASH_WRITE_DATA_REG:FLASH_WRITE_DATA + + // FLASH_READ_DATA_REG Register (from reconfig_engine.v) + localparam FLASH_READ_DATA_REG = 'h10; // Register Offset + localparam FLASH_READ_DATA_REG_SIZE = 32; // register width in bits + localparam FLASH_READ_DATA_REG_MASK = 32'hFFFFFFFF; + localparam FLASH_READ_DATA_SIZE = 32; //FLASH_READ_DATA_REG:FLASH_READ_DATA + localparam FLASH_READ_DATA_MSB = 31; //FLASH_READ_DATA_REG:FLASH_READ_DATA + localparam FLASH_READ_DATA = 0; //FLASH_READ_DATA_REG:FLASH_READ_DATA + + // FLASH_CFM0_START_ADDR_REG Register (from reconfig_engine.v) + localparam FLASH_CFM0_START_ADDR_REG = 'h14; // Register Offset + localparam FLASH_CFM0_START_ADDR_REG_SIZE = 32; // register width in bits + localparam FLASH_CFM0_START_ADDR_REG_MASK = 32'hFFFFFFFF; + localparam FLASH_CFM0_START_ADDR_SIZE = 32; //FLASH_CFM0_START_ADDR_REG:FLASH_CFM0_START_ADDR + localparam FLASH_CFM0_START_ADDR_MSB = 31; //FLASH_CFM0_START_ADDR_REG:FLASH_CFM0_START_ADDR + localparam FLASH_CFM0_START_ADDR = 0; //FLASH_CFM0_START_ADDR_REG:FLASH_CFM0_START_ADDR + + // FLASH_CFM0_END_ADDR_REG Register (from reconfig_engine.v) + localparam FLASH_CFM0_END_ADDR_REG = 'h18; // Register Offset + localparam FLASH_CFM0_END_ADDR_REG_SIZE = 32; // register width in bits + localparam FLASH_CFM0_END_ADDR_REG_MASK = 32'hFFFFFFFF; + localparam FLASH_CFM0_END_ADDR_SIZE = 32; //FLASH_CFM0_END_ADDR_REG:FLASH_CFM0_END_ADDR + localparam FLASH_CFM0_END_ADDR_MSB = 31; //FLASH_CFM0_END_ADDR_REG:FLASH_CFM0_END_ADDR + localparam FLASH_CFM0_END_ADDR = 0; //FLASH_CFM0_END_ADDR_REG:FLASH_CFM0_END_ADDR diff --git a/fpga/usrp3/top/x400/cpld/regmap/spi_regmap_utils.vh b/fpga/usrp3/top/x400/cpld/regmap/spi_regmap_utils.vh new file mode 100644 index 000000000..bf25b6fd3 --- /dev/null +++ b/fpga/usrp3/top/x400/cpld/regmap/spi_regmap_utils.vh @@ -0,0 +1,69 @@ +// +// Copyright 2021 Ettus Research, A National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: spi_regmap_utils.vh +// Description: +// The constants in this file are autogenerated by XmlParse. + +//=============================================================================== +// A numerically ordered list of registers and their HDL source files +//=============================================================================== + + // RX_DATA_LOW : 0x0 (ctrlport_to_spi.v) + // RX_DATA_HIGH : 0x4 (ctrlport_to_spi.v) + // TX_DATA_LOW : 0x8 (ctrlport_to_spi.v) + // TX_DATA_HIGH : 0xC (ctrlport_to_spi.v) + // CONTROL : 0x10 (ctrlport_to_spi.v) + // CLOCK_DIVIDER : 0x14 (ctrlport_to_spi.v) + // SLAVE_SELECT : 0x18 (ctrlport_to_spi.v) + +//=============================================================================== +// RegTypes +//=============================================================================== + +//=============================================================================== +// Register Group SPI_REGS +//=============================================================================== + + // RX_DATA_LOW Register (from ctrlport_to_spi.v) + localparam RX_DATA_LOW = 'h0; // Register Offset + localparam RX_DATA_LOW_SIZE = 32; // register width in bits + localparam RX_DATA_LOW_MASK = 32'h0; + + // RX_DATA_HIGH Register (from ctrlport_to_spi.v) + localparam RX_DATA_HIGH = 'h4; // Register Offset + localparam RX_DATA_HIGH_SIZE = 32; // register width in bits + localparam RX_DATA_HIGH_MASK = 32'h0; + + // TX_DATA_LOW Register (from ctrlport_to_spi.v) + localparam TX_DATA_LOW = 'h8; // Register Offset + localparam TX_DATA_LOW_SIZE = 32; // register width in bits + localparam TX_DATA_LOW_MASK = 32'h0; + + // TX_DATA_HIGH Register (from ctrlport_to_spi.v) + localparam TX_DATA_HIGH = 'hC; // Register Offset + localparam TX_DATA_HIGH_SIZE = 32; // register width in bits + localparam TX_DATA_HIGH_MASK = 32'h0; + + // CONTROL Register (from ctrlport_to_spi.v) + localparam CONTROL = 'h10; // Register Offset + localparam CONTROL_SIZE = 32; // register width in bits + localparam CONTROL_MASK = 32'h0; + + // CLOCK_DIVIDER Register (from ctrlport_to_spi.v) + localparam CLOCK_DIVIDER = 'h14; // Register Offset + localparam CLOCK_DIVIDER_SIZE = 8; // register width in bits + localparam CLOCK_DIVIDER_MASK = 8'hFF; + localparam DIVIDER_SIZE = 8; //CLOCK_DIVIDER:Divider + localparam DIVIDER_MSB = 7; //CLOCK_DIVIDER:Divider + localparam DIVIDER = 0; //CLOCK_DIVIDER:Divider + + // SLAVE_SELECT Register (from ctrlport_to_spi.v) + localparam SLAVE_SELECT = 'h18; // Register Offset + localparam SLAVE_SELECT_SIZE = 16; // register width in bits + localparam SLAVE_SELECT_MASK = 16'hFFFF; + localparam SS_SIZE = 16; //SLAVE_SELECT:SS + localparam SS_MSB = 15; //SLAVE_SELECT:SS + localparam SS = 0; //SLAVE_SELECT:SS diff --git a/fpga/usrp3/top/x400/cpld/reset_generator.v b/fpga/usrp3/top/x400/cpld/reset_generator.v new file mode 100644 index 000000000..dd3a56022 --- /dev/null +++ b/fpga/usrp3/top/x400/cpld/reset_generator.v @@ -0,0 +1,93 @@ +// +// Copyright 2021 Ettus Research, A National Instruments Brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: reset_generator +// +// Description: +// +// Generates a power-on reset signal that is asserted at startup and stays +// asserted for at least CYCLES_IN_RESET clock cycles. +// +// Internally, it generates a 1-bit synchronous signal (initialize) to safely +// initialize the power_on_reset_counter incremental counter to 0's. +// +// A delayed version of the initializing signal is also generated +// (counter_enable) to start counting. +// +// 1_ 2_ 3_ 4_ 5_ 6_ 7_ 8_ 9_ +// clk _| |_| |_| |_| |_| |_| |_| |_| |_| +// _____________________ +// initialize _____________| +// _________ +// counter_enable _________________________| +// + +`default_nettype none + + +module reset_generator ( + input wire clk, + output reg power_on_reset = 1'b1 +); + + wire [0:0] counter_enable; + wire [0:0] initialize; + + synchronizer #( + .WIDTH (1), + .STAGES (3), + .INITIAL_VAL (1'b0), + .FALSE_PATH_TO_IN (0) + ) init_sync_inst ( + .clk (clk), + .rst (1'b0), + .in (1'b1), + .out (initialize) + ); + + synchronizer #( + .WIDTH (1), + .STAGES (3), + .INITIAL_VAL (1'b0), + .FALSE_PATH_TO_IN (0) + ) counter_en_sync_inst ( + .clk (clk), + .rst (1'b0), + .in (initialize), + .out (counter_enable) + ); + + // Internal synchronous reset generator. + localparam CYCLES_IN_RESET = 20; + reg [7:0] power_on_reset_counter = 8'b0; + + // This block generates a synchronous reset in the clk domain that can be + // used by downstream logic. + // + // power_on_reset_counter is first initialized to 0's upon assertion of + // initialize. Some cycles later (3), upon assertion if counter_enable, + // power_on_reset_counter starts to increment. + // + // power_on_reset will remain asserted until power_on_reset_counter reaches + // cycles_in_reset, resulting in the deassertion of power_on_reset. + always @(posedge clk) begin : power_on_reset_gen + if (counter_enable) begin + if (power_on_reset_counter == CYCLES_IN_RESET-1) begin + power_on_reset <= 1'b0; + end else begin + power_on_reset_counter <= power_on_reset_counter + 1'b1; + power_on_reset <= 1'b1; + end + end + else if (initialize) begin + power_on_reset_counter <= 8'b0; + power_on_reset <= 1'b1; + end + end + +endmodule + + +`default_nettype wire diff --git a/fpga/usrp3/top/x400/cpld/scripts/ps_cs_analysis.tcl b/fpga/usrp3/top/x400/cpld/scripts/ps_cs_analysis.tcl new file mode 100644 index 000000000..03ff77d2c --- /dev/null +++ b/fpga/usrp3/top/x400/cpld/scripts/ps_cs_analysis.tcl @@ -0,0 +1,32 @@ +# +# Copyright 2021 Ettus Research, a National Instruments Brand +# +# SPDX-License-Identifier: LGPL-3.0-or-later +# +# Module: ps_cs_analysis +# +# Description: +# +# Analyze false path in PS SPI logic to ensure an upper delay boundary. +# + +# get project to a working state +project_open -force "mb_cpld.qpf" +create_timing_netlist +update_timing_netlist + +# Determine data path delay from MB CPLD chip select signal to MB CPLD internal +# SPI slave +set paths [report_path -from [get_registers {ps_spi_cs_n_decoded[0]}] -multi_corner] +set spiSlaveCsPathDelay [lindex $paths 1] + +# clock period at 250 MHz (clock driving the decoding registers) +set maxDelay 4 + +# compare path from above with maximum delay +if ([expr {$maxDelay < $spiSlaveCsPathDelay}]) { + puts "MB CPLD SPI CS line longer than expected." + exit 1 +} + +exit 0 diff --git a/fpga/usrp3/top/x400/cpld/spi_slave.v b/fpga/usrp3/top/x400/cpld/spi_slave.v new file mode 100644 index 000000000..ab2f16fea --- /dev/null +++ b/fpga/usrp3/top/x400/cpld/spi_slave.v @@ -0,0 +1,288 @@ +// +// Copyright 2021 Ettus Research, A National Instruments Brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: spi_slave +// +// Description: +// +// SPI slave for configuration CPOL = CPHA = 0. +// Transfers 8 bit = 1 byte MSB first. Parallel data has to be +// provided and consumed immediately when flags are asserted. +// +// Limitation: clk frequency <= 2*sclk frequency +// +// Data request from sclk domain is triggered towards the clk domain ahead of +// time. This is due to the clock domain crossing using the synchronizer and +// processing pipeline stages. +// +// The worst case propagation delay of the used synchronizer is: +// +// 4 'clk' clock cycles: +// 1 clock cycle of signal propagation to synchronizer +// (data_request_sclk assertion) +// 1 clock cycle to capture data with instability in first stage +// 1 clock cycle to stabilize first stage +// 1 clock cycle to capture data in second stage +// (data_request_clk available in 'clk' domain) +// +// Once synchronized in 'clk' domain, there is one additional clock cycle to +// derive data_out_valid and data_in_required. To ensure that transmit data +// is registered a 'clk' cycle ahead of the actual transmission we need 2 +// more 'clk' clock cycles. This ensures that transmit_word has changed and +// is stable for at least one 'clk' cycle before 'sclk' asserts again. Any +// additional time required externally to respond to the control port +// requests should be considered in this crossing as well. This is a total of +// 7 clock cycles (+ctrlport response margin) @ clk domain. The minimum +// required time in sclk domain to issue the request is calculated based on +// the clock frequencies. +// +// Parameters: +// +// CLK_FREQUENCY : Frequency of "clk" +// SPI_FREQUENCY : Frequency of "sclk" +// + +`default_nettype none + + +module spi_slave #( + parameter CLK_FREQUENCY = 50000000, + parameter SPI_FREQUENCY = 10000000 +) ( + //--------------------------------------------------------------- + // SPI Interface + //--------------------------------------------------------------- + + input wire sclk, + input wire cs_n, + input wire mosi, + output wire miso, + + //--------------------------------------------------------------- + // Parallel Interface + //--------------------------------------------------------------- + + input wire clk, + input wire rst, + + output reg data_in_required, + input wire data_in_valid, + input wire [7:0] data_in, + + output reg data_out_valid, + output reg [7:0] data_out, + + output wire active +); + + wire [0:0] data_request_clk; + wire [0:0] reception_complete_clk; + + //--------------------------------------------------------------- + // SPI Receiver @ sclk + //--------------------------------------------------------------- + + reg [7:0] receiver_reg; + reg [2:0] current_bit_index; + reg reception_complete_sclk = 1'b0; + reg [7:0] received_word; + + always @(posedge sclk or posedge cs_n) begin + // Reset logic on positive cs_n edge = slave idle + if (cs_n) begin + receiver_reg <= 8'b0; + end + // Rising edge of sclk + else begin + // Capture bits into shift register MSBs first + receiver_reg <= {receiver_reg[6:0], mosi}; + end + end + + // Reset with cs_n might occur too early during clk sync. + // Reset half way through the reception. + always @(posedge sclk) begin + // Complete word was received + if (current_bit_index == 7) begin + reception_complete_sclk <= 1'b1; + received_word <= {receiver_reg[6:0], mosi}; + + // Reset after half transaction + end else if (current_bit_index == 3) begin + reception_complete_sclk <= 1'b0; + end + end + + //--------------------------------------------------------------- + // Handover of data sclk -> clk + //--------------------------------------------------------------- + + synchronizer #( + .WIDTH (1), + .STAGES (2), + .INITIAL_VAL (1'b0), + .FALSE_PATH_TO_IN (1) + ) data_sync_inst ( + .clk (clk), + .rst (1'b0), + .in (reception_complete_sclk), + .out (reception_complete_clk) + ); + + //--------------------------------------------------------------- + // Parallel interface data output @ clk + //--------------------------------------------------------------- + + reg reception_complete_clk_delayed = 1'b0; + + // Propagate toggling signal without reset to ensure stability on reset + always @(posedge clk) begin + // Capture last state of reception + reception_complete_clk_delayed <= reception_complete_clk; + end + + // Derive data and control signal + always @(posedge clk) begin + if (rst) begin + data_out_valid <= 1'b0; + data_out <= 8'b0; + end + else begin + // Default assignment + data_out_valid <= 1'b0; + + // Provide data to output on rising_edge + if (reception_complete_clk & ~reception_complete_clk_delayed) begin + // Data can simply be captured as the reception complete signal + // indicates stable values in received_word. + data_out <= received_word; + data_out_valid <= 1'b1; + end + end + end + + //--------------------------------------------------------------- + // SPI Transmitter @ sclk + //--------------------------------------------------------------- + + // Data request calculation: + // SCLK_CYCLES_DURING_DATA_REQ = 8 clk period / sclk period + // Clock periods are expressed by reciprocal of frequencies. + // Term "+CLK_FREQUENCY-1" is used to round up the result in integer logic. + localparam SCLK_CYCLES_DURING_DATA_REQ = (8*SPI_FREQUENCY + CLK_FREQUENCY-1)/CLK_FREQUENCY; + // subtract from 8 bits per transfer to get target index + localparam DATA_REQ_BIT_INDEX = 8 - SCLK_CYCLES_DURING_DATA_REQ; + + reg [7:0] transmit_bits; + reg [7:0] transmit_word; + reg data_request_sclk = 1'b0; + + always @(negedge sclk or posedge cs_n) begin + // Reset logic on positive cs_n edge = slave idle + if (cs_n) begin + current_bit_index <= 3'b0; + data_request_sclk <= 1'b0; + transmit_bits <= 8'b0; + end + // Falling edge of sclk + else begin + // Fill or move shift register for byte transmissions + if (current_bit_index == 7) begin + transmit_bits <= transmit_word; + end else begin + transmit_bits <= {transmit_bits[6:0], 1'b0}; + end + + // Update bit index + current_bit_index <= current_bit_index + 1'b1; + + // Trigger request for new word at start of calculated index + if (current_bit_index == DATA_REQ_BIT_INDEX-1) begin + data_request_sclk <= 1'b1; + // Reset after half the reception in case cs_n is not changed in between + // two transactions. + end else if (current_bit_index == (DATA_REQ_BIT_INDEX+4-1)%8) begin + data_request_sclk <= 1'b0; + end + end + end + + // Drive miso output with data when cs_n low + assign miso = cs_n ? 1'bz : transmit_bits[7]; + + //--------------------------------------------------------------- + // Handover of Data Request sclk -> clk + //--------------------------------------------------------------- + + synchronizer #( + .WIDTH (1), + .STAGES (2), + .INITIAL_VAL (1'b0), + .FALSE_PATH_TO_IN (1) + ) request_sync_inst ( + .clk (clk), + .rst (rst), + .in (data_request_sclk), + .out (data_request_clk) + ); + + //--------------------------------------------------------------- + // Parallel Interface Data Input Control + //--------------------------------------------------------------- + + reg data_request_clk_delayed; + + always @(posedge clk) begin + if (rst) begin + data_request_clk_delayed <= 1'b0; + data_in_required <= 1'b0; + transmit_word <= 8'b0; + end + else begin + // Default assignment + data_in_required <= 1'b0; + + // Capture last state of data request + data_request_clk_delayed <= data_request_clk; + + // Request data from input + if (~data_request_clk_delayed & data_request_clk) begin + data_in_required <= 1'b1; + end + + // Capture new data if valid data available, 0 otherwise. + if (data_in_required) begin + if (data_in_valid) begin + transmit_word <= data_in; + end else begin + transmit_word <= 8'b0; + end + end + end + end + + //--------------------------------------------------------------- + // Chip Select + //--------------------------------------------------------------- + // Driven as active signal in parallel clock domain + + wire cs_n_clk; + assign active = ~cs_n_clk; + synchronizer #( + .WIDTH (1), + .STAGES (2), + .INITIAL_VAL (1'b1), + .FALSE_PATH_TO_IN (1) + ) active_sync_inst ( + .clk (clk), + .rst (rst), + .in (cs_n), + .out (cs_n_clk) + ); + +endmodule + + +`default_nettype wire diff --git a/fpga/usrp3/top/x400/cpld/spi_slave_to_ctrlport_master.v b/fpga/usrp3/top/x400/cpld/spi_slave_to_ctrlport_master.v new file mode 100644 index 000000000..6f624fe17 --- /dev/null +++ b/fpga/usrp3/top/x400/cpld/spi_slave_to_ctrlport_master.v @@ -0,0 +1,238 @@ +// +// Copyright 2021 Ettus Research, A National Instruments Brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: spi_slave_to_ctrlport_master +// +// Description: +// +// SPI slave to ContolPort master conversion in order to tunnel control port +// request through an SPI bus. +// +// The request format on SPI is defined as: +// +// Write request: +// 1'b1 = write, 15 bit address, 32 bit data (MOSI), 8 bit processing gap, +// 5 bit padding, 1 bit ack, 2 bit status +// +// Read request: +// 1'b0 = read, 15 bit address, 8 bit processing gap, 32 bit data (MISO), +// 5 bit padding, 1 bit ack, 2 bit status +// +// Parameters: +// +// CLK_FREQUENCY : Frequency of "clk" +// SPI_FREQUENCY : Frequency of "sclk" +// + +`default_nettype none + + +module spi_slave_to_ctrlport_master #( + parameter CLK_FREQUENCY = 50000000, + parameter SPI_FREQUENCY = 10000000 +) ( + //--------------------------------------------------------------- + // ControlPort Master + //--------------------------------------------------------------- + + input wire ctrlport_clk, + input wire ctrlport_rst, + + output wire m_ctrlport_req_wr, + output wire m_ctrlport_req_rd, + output wire [19:0] m_ctrlport_req_addr, + output wire [31:0] m_ctrlport_req_data, + + input wire m_ctrlport_resp_ack, + input wire [ 1:0] m_ctrlport_resp_status, + input wire [31:0] m_ctrlport_resp_data, + + //--------------------------------------------------------------- + // SPI Slave + //--------------------------------------------------------------- + + input wire sclk, + input wire cs_n, + input wire mosi, + output wire miso +); + + `include "../../../lib/rfnoc/core/ctrlport.vh" + + //--------------------------------------------------------------- + // SPI Slave + //--------------------------------------------------------------- + + wire [7:0] data_in; + wire [7:0] data_out; + wire data_in_valid; + wire data_out_valid; + wire data_in_required; + wire spi_slave_active; + + spi_slave #( + .CLK_FREQUENCY (CLK_FREQUENCY), + .SPI_FREQUENCY (SPI_FREQUENCY) + ) spi_slave_async ( + .sclk (sclk), + .cs_n (cs_n), + .mosi (mosi), + .miso (miso), + .clk (ctrlport_clk), + .rst (ctrlport_rst), + .data_in_required (data_in_required), + .data_in_valid (data_in_valid), + .data_in (data_in), + .data_out_valid (data_out_valid), + .data_out (data_out), + .active (spi_slave_active) + ); + + //--------------------------------------------------------------- + // Reset Generation from SPI Slave + //--------------------------------------------------------------- + + reg spi_slave_active_delayed = 1'b0; + always @(posedge ctrlport_clk) begin + if (ctrlport_rst) begin + spi_slave_active_delayed <= 1'b0; + end + else begin + spi_slave_active_delayed <= spi_slave_active; + end + end + + // Trigger reset on falling edge of active signal (rising edge of cs_n) + wire spi_slave_reset; + assign spi_slave_reset = spi_slave_active_delayed & (~spi_slave_active); + + //--------------------------------------------------------------- + // Transfer Constants + //--------------------------------------------------------------- + + localparam NUM_BYTES_TRANSACTION = 8; + localparam NUM_BYTES_WRITE_REQUEST_PAYLOAD = 6; + localparam NUM_BYTES_READ_REQUEST_PAYLOAD = 2; + localparam MAX_BYTES_RESPONSE_PAYLOAD = 5; + + //--------------------------------------------------------------- + // Data Receiver + //--------------------------------------------------------------- + + reg [3:0] num_bytes_received; + reg request_received; + reg write_request; + reg provide_response; + reg [NUM_BYTES_WRITE_REQUEST_PAYLOAD*8-1:0] request_reg = {NUM_BYTES_WRITE_REQUEST_PAYLOAD*8 {1'b0}}; + + always @(posedge ctrlport_clk) begin + if (ctrlport_rst || spi_slave_reset) begin + num_bytes_received <= 4'b0; + request_received <= 1'b0; + write_request <= 1'b0; + provide_response <= 1'b0; + end + else begin + // Counter number of received bytes + if (data_out_valid) begin + // Increment counter + num_bytes_received <= num_bytes_received + 1'b1; + + if (num_bytes_received == NUM_BYTES_TRANSACTION-1) begin + num_bytes_received <= 4'b0; + end + end + + // Check for read / write on first received byte's MSB + if (data_out_valid && (num_bytes_received == 0)) begin + write_request <= data_out[7]; + end + + // Detect complete request + request_received <= 1'b0; + if (data_out_valid) begin + if (write_request && (num_bytes_received == NUM_BYTES_WRITE_REQUEST_PAYLOAD-1)) begin + request_received <= 1'b1; + provide_response <= 1'b1; + end else if (~write_request && (num_bytes_received == NUM_BYTES_READ_REQUEST_PAYLOAD-1)) begin + request_received <= 1'b1; + provide_response <= 1'b1; + end + end + + // Detect end of response on last received byte + if (num_bytes_received == NUM_BYTES_TRANSACTION-1) begin + provide_response <= 1'b0; + end + + // Capture data into shift register + if (data_out_valid) begin + request_reg <= {request_reg[NUM_BYTES_WRITE_REQUEST_PAYLOAD*8-8-1:0], data_out}; + end + end + end + + // Drive ControlPort + localparam SPI_TRANSFER_ADDRESS_WIDTH = 15; + assign m_ctrlport_req_wr = request_received && write_request; + assign m_ctrlport_req_rd = request_received && ~write_request; + assign m_ctrlport_req_data = request_reg[CTRLPORT_DATA_W-1:0]; + assign m_ctrlport_req_addr = (write_request) ? + {5'b0, request_reg[CTRLPORT_DATA_W+:SPI_TRANSFER_ADDRESS_WIDTH]} : + {5'b0, request_reg[0+:SPI_TRANSFER_ADDRESS_WIDTH]}; + + //--------------------------------------------------------------- + // Response Handling + //--------------------------------------------------------------- + + reg [MAX_BYTES_RESPONSE_PAYLOAD*8-1:0] response_reg; + reg ready_for_response; // active during processing gap + wire write_response_byte; + + always @(posedge ctrlport_clk) begin + if (ctrlport_rst || spi_slave_reset) begin + response_reg <= {8*MAX_BYTES_RESPONSE_PAYLOAD {1'b0}}; + ready_for_response <= 1'b0; + end + else begin + // Reset response on new request + if (request_received) begin + ready_for_response <= 1'b1; + if (write_request) begin + // Just last byte -> padding, ack flag, CMDERR, padding (data length) + response_reg <= {5'b0, 1'b1, CTRL_STS_CMDERR, {CTRLPORT_DATA_W{1'b0}}}; + end else begin + // Last 5 bytes -> data = 0, Padding, ack flag, CMDERR + response_reg <= {{CTRLPORT_DATA_W{1'b0}}, 5'b0, 1'b1, CTRL_STS_CMDERR}; + end + + // Capture response within processing gap, leave default response from above otherwise + end else if (m_ctrlport_resp_ack && ready_for_response) begin + if (write_request) begin + response_reg <= {5'b0, m_ctrlport_resp_ack, m_ctrlport_resp_status, {CTRLPORT_DATA_W{1'b0}}}; + end else begin + response_reg <= {m_ctrlport_resp_data, 5'b0, m_ctrlport_resp_ack, m_ctrlport_resp_status}; + end + end + + // Shift data after writing to slave + if (write_response_byte) begin + response_reg <= {response_reg[0+:(MAX_BYTES_RESPONSE_PAYLOAD-1)*8], 8'b0}; + ready_for_response <= 1'b0; + end + end + end + + // Response is written after request part has been transferred + assign write_response_byte = data_in_required && provide_response; + + // Assign SPI slave inputs + assign data_in = response_reg[(MAX_BYTES_RESPONSE_PAYLOAD-1)*8+:8]; + assign data_in_valid = write_response_byte; + +endmodule + + +`default_nettype wire |