Files
b210-k7-fpga/top/x400/dboards/ctrlport_byte_deserializer.v
T
Javier Valenzuela a6fc53b4e6 fpga: x400: zbx: Add support for XO3 CPLD variant.
The main changes included are:
- Variant-dependent pin-out instantiation.
- Update clocking scheme in top level file
  to include XO3 PLL
- Add ability to shift outgoing data for
  the GPIO communication interface with
  the X410 FPGA.
- Include project files required to build
  the XO3 variant of the ZBX CPLD.
- Add build flow for Lattice Diamond designs.
- Add ability to build XO3 variant of ZBX CPLD.


Original-commit: 2c7813acb21383f302353a1b6cf57f0946fa0b6b
2022-06-28 16:33:05 -05:00

220 lines
7.1 KiB
Verilog

//
// 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.
// Input and output data may be driven/registered using clocks with
// different phases (but same frequency), this allows the capability
// to facilitate meeting timing on this interface.
//
`default_nettype none
module ctrlport_byte_deserializer (
// clock domain used to register input data
input wire ctrlport_clk,
// clock domain used to drive output data
input wire ctrlport_clk_adjusted,
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] request_byte_counter = 3'b0;
reg [ 2:0] response_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;
request_byte_counter <= 3'b0;
transfer_complete <= 1'b0;
response_byte_counter <= 3'b0;
end else begin
// default assignments
transfer_complete <= 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
request_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
request_byte_counter <= request_byte_counter + 1'b1;
request_cache <= {request_cache[NUM_BYTES_RX_WRITE*8-9:0], bytestream_data_in_reg};
// capture write or read
if (request_byte_counter == 0) begin
write_transfer <= bytestream_data_in_reg[7];
end
// wait until request completes
if ((write_transfer && request_byte_counter == NUM_BYTES_RX_WRITE-1) ||
(~write_transfer && request_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
request_byte_counter <= 3'b0;
response_byte_counter <= 3'b0;
if (m_ctrlport_resp_ack) begin
state <= SENDING;
end
//abort by host
if (bytestream_direction_reg == 0) begin
state <= INIT_RX;
end
end
SENDING: begin
response_byte_counter <= response_byte_counter + 1'b1;
// wait until request completes
if ((write_transfer && response_byte_counter == NUM_BYTES_TX_WRITE-1) ||
(~write_transfer && response_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
// Output data control
always @ (posedge ctrlport_clk_adjusted) begin
if (ctrlport_rst) begin
bytestream_valid_out <= 1'b0;
bytestream_output_enable <= 1'b0;
end else begin
bytestream_valid_out <= 1'b0;
// direction defined by master
bytestream_output_enable <= bytestream_direction;
case (state)
WAIT_RESPONSE: begin
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
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};
end
default: begin
// NOP
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