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>


Original-commit: 6d3765605262016a80f71e36357f749ea35cbe5a
This commit is contained in:
Wade Fife
2021-06-10 11:56:58 -05:00
committed by Aaron Rossetto
co-authored by Andrew Moch Daniel Jepson Javier Valenzuela Joerg Hofrichter Kumaran Subramoniam Max Köhler Michael Auchter Paul Butler Hector Rubio
parent bfef20ea45
commit 61782b02d7
205 changed files with 299634 additions and 0 deletions
@@ -0,0 +1,186 @@
//
// Copyright 2021 Ettus Research, a National Instruments Brand
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: ctrlport_byte_deserializer
//
// Description:
// Slave interface of CtrlPort interface serialized as byte stream.
// See description in ctrlport_byte_serializer module for more details.
//
`default_nettype none
module ctrlport_byte_deserializer (
input wire ctrlport_clk,
input wire ctrlport_rst,
// Request
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,
// Response
input wire m_ctrlport_resp_ack,
input wire [ 1:0] m_ctrlport_resp_status,
input wire [31:0] m_ctrlport_resp_data,
// byte interface
input wire [ 7:0] bytestream_data_in,
input wire bytestream_valid_in,
input wire bytestream_direction,
output reg [ 7:0] bytestream_data_out = 8'b0,
output reg bytestream_valid_out = 1'b0,
output reg bytestream_output_enable = 1'b0
);
`include "../../../lib/rfnoc/core/ctrlport.vh"
//---------------------------------------------------------------
// transfer constants
//---------------------------------------------------------------
// derived from transaction specification
localparam NUM_BYTES_RX_READ = 2;
localparam NUM_BYTES_TX_READ = 5;
localparam NUM_BYTES_RX_WRITE = 6;
localparam NUM_BYTES_TX_WRITE = 1;
localparam SPI_TRANSFER_ADDRESS_WIDTH = 15;
//----------------------------------------------------------
// handle transfer
//----------------------------------------------------------
localparam INIT_RX = 2'd0;
localparam RECEIVE = 2'd1;
localparam WAIT_RESPONSE = 2'd2;
localparam SENDING = 2'd3;
// internal registers
reg [ 1:0] state = INIT_RX;
reg [NUM_BYTES_RX_WRITE*8-1:0] request_cache = {NUM_BYTES_RX_WRITE*8 {1'b0}};
reg [ NUM_BYTES_TX_READ*8-1:0] response_cache = {NUM_BYTES_TX_READ*8 {1'b0}};
reg [ 2:0] byte_counter = 3'b0;
reg transfer_complete = 1'b0;
reg write_transfer = 1'b0;
// input registers to relax input timing
reg [7:0] bytestream_data_in_reg = 8'b0;
reg bytestream_valid_in_reg = 1'b0;
reg bytestream_direction_reg = 1'b0;
always @ (posedge ctrlport_clk) begin
bytestream_data_in_reg <= bytestream_data_in;
bytestream_valid_in_reg <= bytestream_valid_in;
bytestream_direction_reg <= bytestream_direction;
end
// state machine
always @ (posedge ctrlport_clk) begin
if (ctrlport_rst) begin
state <= INIT_RX;
byte_counter <= 3'b0;
transfer_complete <= 1'b0;
bytestream_output_enable <= 1'b0;
end else begin
// default assignments
transfer_complete <= 1'b0;
// direction defined by master
bytestream_output_enable <= bytestream_direction;
bytestream_valid_out <= 1'b0;
case (state)
// additional cycle for switching to make sure valid signal is driven
// from master when being in RECEIVE state
INIT_RX: begin
byte_counter <= 3'b0;
if (bytestream_direction_reg == 0) begin
state <= RECEIVE;
end
end
// wait for reception of request from master
RECEIVE: begin
if (bytestream_valid_in_reg) begin
byte_counter <= byte_counter + 1'b1;
request_cache <= {request_cache[NUM_BYTES_RX_WRITE*8-9:0], bytestream_data_in_reg};
// capture write or read
if (byte_counter == 0) begin
write_transfer <= bytestream_data_in_reg[7];
end
// wait until request completes
if ((write_transfer && byte_counter == NUM_BYTES_RX_WRITE-1) ||
(~write_transfer && byte_counter == NUM_BYTES_RX_READ-1)) begin
transfer_complete <= 1'b1;
state <= WAIT_RESPONSE;
end
end
// Workaround for missing pull down resistor:
// Use pull up and schmitt trigger to detect FPGA reload by line going high unexpectedly
if (bytestream_direction_reg == 1) begin
state <= INIT_RX;
end
end
WAIT_RESPONSE: begin
byte_counter <= 3'b0;
if (m_ctrlport_resp_ack) begin
state <= SENDING;
if (write_transfer) begin
response_cache <= {5'b0, 1'b1, m_ctrlport_resp_status, 32'b0};
end else begin
response_cache <= {m_ctrlport_resp_data, 5'b0, 1'b1, m_ctrlport_resp_status};
end
end
//abort by host
if (bytestream_direction_reg == 0) begin
state <= INIT_RX;
end
end
SENDING: begin
bytestream_valid_out <= 1'b1;
bytestream_data_out <= response_cache[NUM_BYTES_TX_READ*8-8+:8];
response_cache <= {response_cache[NUM_BYTES_TX_READ*8-9:0], 8'b0};
byte_counter <= byte_counter + 1'b1;
// wait until request completes
if ((write_transfer && byte_counter == NUM_BYTES_TX_WRITE-1) ||
(~write_transfer && byte_counter == NUM_BYTES_TX_READ-1)) begin
state <= INIT_RX;
end
//abort by host
if (bytestream_direction_reg == 0) begin
state <= INIT_RX;
end
end
default: begin
state <= INIT_RX;
end
endcase
end
end
//----------------------------------------------------------
// assign request to ctrlport
//----------------------------------------------------------
assign m_ctrlport_req_wr = write_transfer & transfer_complete;
assign m_ctrlport_req_rd = ~write_transfer & transfer_complete;
assign m_ctrlport_req_data = request_cache[0+:CTRLPORT_DATA_W];
assign m_ctrlport_req_addr = (write_transfer) ?
// Skipping data in LSBs to get to the address for writes.
{5'b0, request_cache[CTRLPORT_DATA_W+:SPI_TRANSFER_ADDRESS_WIDTH]} :
// Full request = address of 2 bytes in LSBs.
{5'b0, request_cache[0+:SPI_TRANSFER_ADDRESS_WIDTH]};
endmodule
`default_nettype wire