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 /fpga/usrp3/top/x400/cpld/ctrlport_to_spi.v | |
| 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>
Diffstat (limited to 'fpga/usrp3/top/x400/cpld/ctrlport_to_spi.v')
| -rw-r--r-- | fpga/usrp3/top/x400/cpld/ctrlport_to_spi.v | 276 |
1 files changed, 276 insertions, 0 deletions
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 |
