diff options
| author | Wade Fife <wade.fife@ettus.com> | 2021-06-08 19:40:46 -0500 |
|---|---|---|
| committer | Aaron Rossetto <aaron.rossetto@ni.com> | 2021-06-10 11:56:58 -0500 |
| commit | 6d3765605262016a80f71e36357f749ea35cbe5a (patch) | |
| tree | 7d62d6622befd4132ac1ee085effa1426f7f53e5 /fpga/usrp3/top/x400/ctrlport_spi_master.v | |
| parent | f706b89e6974e28ce76aadeeb06169becc86acba (diff) | |
| download | uhd-6d3765605262016a80f71e36357f749ea35cbe5a.tar.gz uhd-6d3765605262016a80f71e36357f749ea35cbe5a.tar.bz2 uhd-6d3765605262016a80f71e36357f749ea35cbe5a.zip | |
fpga: x400: Add support for X410 motherboard FPGA
Co-authored-by: Andrew Moch <Andrew.Moch@ni.com>
Co-authored-by: Daniel Jepson <daniel.jepson@ni.com>
Co-authored-by: Javier Valenzuela <javier.valenzuela@ni.com>
Co-authored-by: Joerg Hofrichter <joerg.hofrichter@ni.com>
Co-authored-by: Kumaran Subramoniam <kumaran.subramoniam@ni.com>
Co-authored-by: Max Köhler <max.koehler@ni.com>
Co-authored-by: Michael Auchter <michael.auchter@ni.com>
Co-authored-by: Paul Butler <paul.butler@ni.com>
Co-authored-by: Wade Fife <wade.fife@ettus.com>
Co-authored-by: Hector Rubio <hrubio@ni.com>
Diffstat (limited to 'fpga/usrp3/top/x400/ctrlport_spi_master.v')
| -rw-r--r-- | fpga/usrp3/top/x400/ctrlport_spi_master.v | 243 |
1 files changed, 243 insertions, 0 deletions
diff --git a/fpga/usrp3/top/x400/ctrlport_spi_master.v b/fpga/usrp3/top/x400/ctrlport_spi_master.v new file mode 100644 index 000000000..0279dbd29 --- /dev/null +++ b/fpga/usrp3/top/x400/ctrlport_spi_master.v @@ -0,0 +1,243 @@ +// +// Copyright 2021 Ettus Research, A National Instruments Brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: ctrlport_spi_master +// +// Description: +// +// This block transfers a control port request via SPI. 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: +// +// CPLD_ADDRESS_WIDTH : Number of address bits to allocate to one CPLD +// register map. +// MB_CPLD_BASE_ADDRESS : Base address for the motherboard CPLD. +// DB_0_CPLD_BASE_ADDRESS : Base address for the first daughterboard CPLD. +// DB_1_CPLD_BASE_ADDRESS : Base address for the second daughterboard CPLD. +// + +`default_nettype none + + +module ctrlport_spi_master #( + parameter CPLD_ADDRESS_WIDTH = 15, + parameter MB_CPLD_BASE_ADDRESS = 20'h8000, + parameter DB_0_CPLD_BASE_ADDRESS = 20'h10000, + parameter DB_1_CPLD_BASE_ADDRESS = 20'h18000 +) ( + 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 = 1'b0, + output reg [ 1:0] s_ctrlport_resp_status = 2'b0, + output reg [31:0] s_ctrlport_resp_data = 32'b0, + + // SPI + output wire [1:0] ss, + output wire sclk, + output wire mosi, + input wire miso, + + // Configuration from register interface + input wire [15:0] mb_clock_divider, + input wire [15:0] db_clock_divider +); + + `include "../../lib/rfnoc/core/ctrlport.vh" + + // Registers / wires for SPI core communication + reg [31:0] set_data = 0; + reg [ 7:0] set_addr = 0; + reg set_stb = 1'b0; + + wire [63:0] readback; + wire readback_stb; + + //--------------------------------------------------------------------------- + // Address calculation + //--------------------------------------------------------------------------- + + // Define configuration for the address calculation + localparam [19:0] BASE_ADDRESS_MASK = {20{1'b1}} << CPLD_ADDRESS_WIDTH; + + // Wires for saving access + wire mb_cpld_access = (s_ctrlport_req_addr & BASE_ADDRESS_MASK) == MB_CPLD_BASE_ADDRESS; + wire db_0_cpld_access = (s_ctrlport_req_addr & BASE_ADDRESS_MASK) == DB_0_CPLD_BASE_ADDRESS; + wire db_1_cpld_access = (s_ctrlport_req_addr & BASE_ADDRESS_MASK) == DB_1_CPLD_BASE_ADDRESS; + + //--------------------------------------------------------------------------- + // FSM to handle transfers + //--------------------------------------------------------------------------- + + localparam IDLE = 3'd0; + localparam SET_DIVIDER = 3'd1; + localparam WRITE_SPI_MSB = 3'd2; + localparam WRITE_SPI_LSB = 3'd3; + localparam CONFIG_TRANSFER = 3'd4; + localparam WAIT_SPI = 3'd5; + + localparam DIVIDER_ADDRESS = 8'd0; + localparam CTRL_ADDRESS = 8'd1; + localparam DATA_UPPER_ADDRESS = 8'd2; + localparam DATA_LOWER_ADDRESS = 8'd3; + + // Combined static configuration consisting of + // 0x4000 = in data bit latched on rising edge of sclk + // - out data launched on falling edge + // - num bits = 64 + localparam CTRL_VALUE = 32'h40000000; + + reg [ 2:0] state = IDLE; + reg [31:0] data_cache; + reg [19:0] address_cache; + reg wr_cache; + reg [15:0] divider; + reg [ 1:0] cs; + + always @ (posedge ctrlport_clk) begin + // Moving reset to the end of the block to reduce fanout of ctrlport_rst + + // Default assignments + s_ctrlport_resp_ack <= 1'b0; + set_stb <= 1'b0; + + case (state) + IDLE: begin + // Requests appear + if (s_ctrlport_req_wr | s_ctrlport_req_rd) begin + // Any CPLD targeted + if (mb_cpld_access | db_0_cpld_access | db_1_cpld_access) begin + state <= CONFIG_TRANSFER; + end + end + + // Select chip select and divider value + if (mb_cpld_access) begin + divider <= mb_clock_divider; + cs <= 2'b00; + end else begin + divider <= db_clock_divider; + if (db_0_cpld_access) begin + cs <= 2'b10; + end else begin + cs <= 2'b01; + end + end + + // Save data and address for further steps + data_cache <= s_ctrlport_req_data; + address_cache <= s_ctrlport_req_addr; + wr_cache <= s_ctrlport_req_wr; + end + + // Set slave select + CONFIG_TRANSFER: begin + state <= SET_DIVIDER; + + set_stb <= 1'b1; + set_addr <= CTRL_ADDRESS; + // Slave select located in LSBs. Inverted against the desired value in + // cs register as 1 represents slave enabled in combination with + // generic IDLE value. + set_data <= CTRL_VALUE | {30'b0, ~cs}; + end + + // Write divider to SPI core + SET_DIVIDER: begin + state <= WRITE_SPI_LSB; + + set_stb <= 1'b1; + set_addr <= DIVIDER_ADDRESS; + set_data <= {16'b0, divider}; + end + + // Write lower bits to SPI core (aligned to MSB) + WRITE_SPI_LSB: begin + state <= WRITE_SPI_MSB; + + set_stb <= 1'b1; + set_addr <= DATA_LOWER_ADDRESS; + set_data <= {data_cache[15:0], 16'bx}; + end + + // Write upper bits, which triggers transaction to start + WRITE_SPI_MSB: begin + state <= WAIT_SPI; + + set_stb <= 1'b1; + set_addr <= DATA_UPPER_ADDRESS; + set_data <= {wr_cache, address_cache[14:0], data_cache[31:16]}; + end + + // Wait for transaction to complete and translate to ctrlport response + WAIT_SPI: begin + s_ctrlport_resp_status <= readback[2] ? readback[1:0] : CTRL_STS_CMDERR; + s_ctrlport_resp_data <= wr_cache ? {CTRLPORT_DATA_W {1'b0}} : readback[39:8]; + s_ctrlport_resp_ack <= readback_stb; + + if (readback_stb) begin + state <= IDLE; + end + end + + default: begin + state <= IDLE; + end + endcase + + // Reset control registers only + if (ctrlport_rst) begin + state <= IDLE; + s_ctrlport_resp_ack <= 1'b0; + set_stb <= 1'b0; + end + end + + //--------------------------------------------------------------------------- + // SPI master + //--------------------------------------------------------------------------- + + simple_spi_core_64bit #( + .BASE (0), + .WIDTH (2), + .CLK_IDLE (0), + .SEN_IDLE (2'b11), + .MAX_BITS (64) + ) simple_spi_core_64bit_i ( + .clock (ctrlport_clk), + .reset (ctrlport_rst), + .set_stb (set_stb), + .set_addr (set_addr), + .set_data (set_data), + .readback (readback), + .readback_stb (readback_stb), + .ready (), + .sen (ss), + .sclk (sclk), + .mosi (mosi), + .miso (miso), + .debug () + ); + +endmodule + + +`default_nettype wire |
