422 lines
18 KiB
Verilog
422 lines
18 KiB
Verilog
// (C) 2001-2019 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.
|
|
|
|
|
|
/*
|
|
This block is responsible for accepting 128/256 bit descriptors and
|
|
buffering them in descriptor FIFOs. Each bytelane of the descriptor
|
|
can be written to individually and writing ot the descriptor 'go' bit
|
|
commits the data into the FIFO. Reading that data out of the FIFO
|
|
occurs two cycles after the read is asserted as the FIFOs do not support
|
|
lookahead mode.
|
|
|
|
This block must keep local copies of per descriptor information like
|
|
the optional sequence number or interrupt masks. When parked mode
|
|
is set in the descriptor the same will transfer multiple times when
|
|
the descriptor FIFO only contains one descriptor (and this descriptor
|
|
will not be popped). Parked mode is useful for video frame buffering.
|
|
|
|
|
|
|
|
1.0 - The on-chip memory in the FIFOs are not inferred so there may
|
|
be some extra unused bits. In a later Quartus II release the
|
|
on-chip memory will be replaced with inferred memory.
|
|
|
|
1.1 - Shifted all descriptor registers into this block (from the dispatcher
|
|
block). Added breakout blocks responsible for re-packing the
|
|
information for use by each master.
|
|
|
|
1.2 - Added the read_early_done_enable bit to the breakout (for debug)
|
|
|
|
1.3 - Made the read_address and write_address widths 64-bit (for debug)
|
|
*/
|
|
|
|
|
|
|
|
// synthesis translate_off
|
|
`timescale 1ns / 1ps
|
|
// synthesis translate_on
|
|
|
|
// turn off superfluous verilog processor warnings
|
|
// altera message_level Level1
|
|
// altera message_off 10034 10035 10036 10037 10230 10240 10030
|
|
|
|
|
|
module descriptor_buffers (
|
|
clk,
|
|
reset,
|
|
|
|
writedata,
|
|
write,
|
|
byteenable,
|
|
waitrequest,
|
|
|
|
read_command_valid,
|
|
read_command_ready,
|
|
read_command_data,
|
|
read_command_empty,
|
|
read_command_full,
|
|
read_command_used,
|
|
|
|
write_command_valid,
|
|
write_command_ready,
|
|
write_command_data,
|
|
write_command_empty,
|
|
write_command_full,
|
|
write_command_used,
|
|
|
|
stop_issuing_commands,
|
|
stop,
|
|
sw_reset,
|
|
sequence_number,
|
|
transfer_complete_IRQ_mask,
|
|
early_termination_IRQ_mask,
|
|
error_IRQ_mask
|
|
);
|
|
|
|
parameter MODE = 0;
|
|
parameter DATA_WIDTH = 256;
|
|
parameter BYTE_ENABLE_WIDTH = 32;
|
|
parameter FIFO_DEPTH = 128;
|
|
parameter FIFO_DEPTH_LOG2 = 7; // top level module can figure this out
|
|
|
|
input clk;
|
|
input reset;
|
|
|
|
input [DATA_WIDTH-1:0] writedata;
|
|
input write;
|
|
input [BYTE_ENABLE_WIDTH-1:0] byteenable;
|
|
output wire waitrequest;
|
|
|
|
output wire read_command_valid;
|
|
input read_command_ready;
|
|
output wire [255:0] read_command_data;
|
|
output wire read_command_empty;
|
|
output wire read_command_full;
|
|
output wire [FIFO_DEPTH_LOG2:0] read_command_used;
|
|
|
|
output wire write_command_valid;
|
|
input write_command_ready;
|
|
output wire [255:0] write_command_data;
|
|
output wire write_command_empty;
|
|
output wire write_command_full;
|
|
output wire [FIFO_DEPTH_LOG2:0] write_command_used;
|
|
|
|
input stop_issuing_commands;
|
|
input stop;
|
|
input sw_reset;
|
|
output wire [31:0] sequence_number;
|
|
output wire transfer_complete_IRQ_mask;
|
|
output wire early_termination_IRQ_mask;
|
|
output wire [7:0] error_IRQ_mask;
|
|
|
|
|
|
/* Internal wires and registers */
|
|
reg write_command_empty_d1;
|
|
reg write_command_empty_d2;
|
|
reg read_command_empty_d1;
|
|
reg read_command_empty_d2;
|
|
wire push_write_fifo;
|
|
wire pop_write_fifo;
|
|
wire push_read_fifo;
|
|
wire pop_read_fifo;
|
|
wire go_bit;
|
|
wire read_park;
|
|
wire read_park_enable; // park is enabled when read_park is enabled and the read FIFO is empty
|
|
wire write_park;
|
|
wire write_park_enable; // park is enabled when write_park is enabled and the write FIFO is empty
|
|
wire [DATA_WIDTH-1:0] write_fifo_output;
|
|
wire [DATA_WIDTH-1:0] read_fifo_output;
|
|
wire [15:0] write_sequence_number;
|
|
reg [15:0] write_sequence_number_d1;
|
|
wire [15:0] read_sequence_number;
|
|
reg [15:0] read_sequence_number_d1;
|
|
wire read_transfer_complete_IRQ_mask;
|
|
reg read_transfer_complete_IRQ_mask_d1;
|
|
wire write_transfer_complete_IRQ_mask;
|
|
reg write_transfer_complete_IRQ_mask_d1;
|
|
wire write_early_termination_IRQ_mask;
|
|
reg write_early_termination_IRQ_mask_d1;
|
|
wire [7:0] write_error_IRQ_mask;
|
|
reg [7:0] write_error_IRQ_mask_d1;
|
|
wire issue_write_descriptor; // one cycle strobe used to indicate when there is a valid write descriptor ready to be sent to the write master
|
|
wire issue_read_descriptor; // one cycle strobe used to indicate when there is a valid write descriptor ready to be sent to the write master
|
|
wire write_en; // Qualified fifo write with waitrequest to prevent fifo overflow when descriptor slave port is being back pressured
|
|
|
|
|
|
/* Unused signals that are provided for debug convenience */
|
|
wire [63:0] read_address;
|
|
wire [31:0] read_length;
|
|
wire [7:0] read_transmit_channel;
|
|
wire read_generate_sop;
|
|
wire read_generate_eop;
|
|
wire [7:0] read_burst_count;
|
|
wire [15:0] read_stride;
|
|
wire [7:0] read_transmit_error;
|
|
wire read_early_done_enable;
|
|
wire [63:0] write_address;
|
|
wire [31:0] write_length;
|
|
wire write_end_on_eop;
|
|
wire [7:0] write_burst_count;
|
|
wire [15:0] write_stride;
|
|
|
|
|
|
|
|
/************************************************* Registers *******************************************************/
|
|
always @ (posedge clk or posedge reset)
|
|
begin
|
|
if (reset)
|
|
begin
|
|
write_sequence_number_d1 <= 0;
|
|
write_transfer_complete_IRQ_mask_d1 <= 0;
|
|
write_early_termination_IRQ_mask_d1 <= 0;
|
|
write_error_IRQ_mask_d1 <= 0;
|
|
end
|
|
else if (issue_write_descriptor) // if parked mode is enabled and there are no more descriptors buffered then this will not fire when the command is sent out
|
|
begin
|
|
write_sequence_number_d1 <= write_sequence_number;
|
|
write_transfer_complete_IRQ_mask_d1 <= write_transfer_complete_IRQ_mask;
|
|
write_early_termination_IRQ_mask_d1 <= write_early_termination_IRQ_mask;
|
|
write_error_IRQ_mask_d1 <= write_error_IRQ_mask;
|
|
end
|
|
end
|
|
|
|
|
|
always @ (posedge clk or posedge reset)
|
|
begin
|
|
if (reset)
|
|
begin
|
|
read_sequence_number_d1 <= 0;
|
|
read_transfer_complete_IRQ_mask_d1 <= 0;
|
|
end
|
|
else if (issue_read_descriptor) // if parked mode is enabled and there are no more descriptors buffered then this will not fire when the command is sent out
|
|
begin
|
|
read_sequence_number_d1 <= read_sequence_number;
|
|
read_transfer_complete_IRQ_mask_d1 <= read_transfer_complete_IRQ_mask;
|
|
end
|
|
end
|
|
|
|
|
|
// need to use a delayed valid signal since the commmand buffers have two cycles of latency
|
|
always @ (posedge clk or posedge reset)
|
|
begin
|
|
if (reset)
|
|
begin
|
|
write_command_empty_d1 <= 0;
|
|
write_command_empty_d2 <= 0;
|
|
read_command_empty_d1 <= 0;
|
|
read_command_empty_d2 <= 0;
|
|
end
|
|
else
|
|
begin
|
|
write_command_empty_d1 <= write_command_empty;
|
|
write_command_empty_d2 <= write_command_empty_d1;
|
|
read_command_empty_d1 <= read_command_empty;
|
|
read_command_empty_d2 <= read_command_empty_d1;
|
|
end
|
|
end
|
|
/*********************************************** End Registers *****************************************************/
|
|
|
|
|
|
/****************************************** Module Instantiations **************************************************/
|
|
/* the write_signal_break module simply takes the output of the descriptor buffer and reformats the data
|
|
* to be sent in the command format needed by the master command port. If new features are added to the
|
|
* descriptor format then add it to this block. This block also provides the descriptor information
|
|
* using a naming convention isn't of bit indexes in a 256 bit wide command signal.
|
|
*/
|
|
write_signal_breakout the_write_signal_breakout (
|
|
.write_command_data_in (write_fifo_output),
|
|
.write_command_data_out (write_command_data),
|
|
.write_address (write_address),
|
|
.write_length (write_length),
|
|
.write_park (write_park),
|
|
.write_end_on_eop (write_end_on_eop),
|
|
.write_transfer_complete_IRQ_mask (write_transfer_complete_IRQ_mask),
|
|
.write_early_termination_IRQ_mask (write_early_termination_IRQ_mask),
|
|
.write_error_IRQ_mask (write_error_IRQ_mask),
|
|
.write_burst_count (write_burst_count),
|
|
.write_stride (write_stride),
|
|
.write_sequence_number (write_sequence_number),
|
|
.write_stop (stop),
|
|
.write_sw_reset (sw_reset)
|
|
);
|
|
defparam the_write_signal_breakout.DATA_WIDTH = DATA_WIDTH;
|
|
|
|
|
|
/* the read_signal_break module simply takes the output of the descriptor buffer and reformats the data
|
|
* to be sent in the command format needed by the master command port. If new features are added to the
|
|
* descriptor format then add it to this block. This block also provides the descriptor information
|
|
* using a naming convention isn't of bit indexes in a 256 bit wide command signal.
|
|
*/
|
|
read_signal_breakout the_read_signal_breakout (
|
|
.read_command_data_in (read_fifo_output),
|
|
.read_command_data_out (read_command_data),
|
|
.read_address (read_address),
|
|
.read_length (read_length),
|
|
.read_transmit_channel (read_transmit_channel),
|
|
.read_generate_sop (read_generate_sop),
|
|
.read_generate_eop (read_generate_eop),
|
|
.read_park (read_park),
|
|
.read_transfer_complete_IRQ_mask (read_transfer_complete_IRQ_mask),
|
|
.read_burst_count (read_burst_count),
|
|
.read_stride (read_stride),
|
|
.read_sequence_number (read_sequence_number),
|
|
.read_transmit_error (read_transmit_error),
|
|
.read_early_done_enable (read_early_done_enable),
|
|
.read_stop (stop),
|
|
.read_sw_reset (sw_reset)
|
|
);
|
|
defparam the_read_signal_breakout.DATA_WIDTH = DATA_WIDTH;
|
|
|
|
|
|
// Descriptor FIFO allows for each byte lane to be written to and the data is not committed to the FIFO until the 'push' signal is asserted.
|
|
// This differs from scfifo which commits the data any time the write signal is asserted.
|
|
fifo_with_byteenables the_read_command_FIFO (
|
|
.clk (clk),
|
|
.areset (reset),
|
|
.sreset (sw_reset),
|
|
.write_data (writedata),
|
|
.write_byteenables (byteenable),
|
|
.write (write_en),
|
|
.push (push_read_fifo),
|
|
.read_data (read_fifo_output),
|
|
.pop (pop_read_fifo),
|
|
.used (read_command_used), // this is a 'true used' signal with the full bit accounted for
|
|
.full (read_command_full),
|
|
.empty (read_command_empty)
|
|
);
|
|
defparam the_read_command_FIFO.DATA_WIDTH = DATA_WIDTH; // we are not actually going to use all these bits and byte lanes left unconnected at the output will get optimized away
|
|
defparam the_read_command_FIFO.FIFO_DEPTH = FIFO_DEPTH;
|
|
defparam the_read_command_FIFO.FIFO_DEPTH_LOG2 = FIFO_DEPTH_LOG2;
|
|
defparam the_read_command_FIFO.LATENCY = 2;
|
|
|
|
|
|
// Descriptor FIFO allows for each byte lane to be written to and the data is not committed to the FIFO until the 'push' signal is asserted.
|
|
// This differs from scfifo which commits the data any time the write signal is asserted.
|
|
fifo_with_byteenables the_write_command_FIFO (
|
|
.clk (clk),
|
|
.areset (reset),
|
|
.sreset (sw_reset),
|
|
.write_data (writedata),
|
|
.write_byteenables (byteenable),
|
|
.write (write_en),
|
|
.push (push_write_fifo),
|
|
.read_data (write_fifo_output),
|
|
.pop (pop_write_fifo),
|
|
.used (write_command_used), // this is a 'true used' signal with the full bit accounted for
|
|
.full (write_command_full),
|
|
.empty (write_command_empty)
|
|
);
|
|
defparam the_write_command_FIFO.DATA_WIDTH = DATA_WIDTH; // we are not actually going to use all these bits and byte lanes left unconnected at the output will get optimized away
|
|
defparam the_write_command_FIFO.FIFO_DEPTH = FIFO_DEPTH;
|
|
defparam the_write_command_FIFO.FIFO_DEPTH_LOG2 = FIFO_DEPTH_LOG2;
|
|
defparam the_write_command_FIFO.LATENCY = 2;
|
|
/**************************************** End Module Instantiations ************************************************/
|
|
|
|
|
|
/****************************************** Combinational Signals **************************************************/
|
|
generate // all unnecessary signals and drivers will be optimized away
|
|
if (MODE == 0) // MM-->MM
|
|
begin
|
|
assign waitrequest = (read_command_full == 1) | (write_command_full == 1) | (sw_reset == 1);
|
|
|
|
// information for the CSR or response blocks to use
|
|
assign sequence_number = {write_sequence_number_d1, read_sequence_number_d1};
|
|
assign transfer_complete_IRQ_mask = write_transfer_complete_IRQ_mask_d1;
|
|
assign early_termination_IRQ_mask = 1'b0;
|
|
assign error_IRQ_mask = 8'h00;
|
|
|
|
// read buffer flow control
|
|
assign push_read_fifo = go_bit;
|
|
assign read_park_enable = (read_park == 1) & (read_command_used == 1); // we want to keep the descriptor in the FIFO when the park bit is set
|
|
assign read_command_valid = (stop == 0) & (sw_reset == 0) & (stop_issuing_commands == 0) &
|
|
(read_command_empty == 0) & (read_command_empty_d1 == 0) & (read_command_empty_d2 == 0); // command buffer has two cycles of latency so the empty deassertion need to delayed two cycles but asserted in zero cycles, the time between commands will be at least 2 cycles so this delay is only needed coming out of the empty condition
|
|
assign issue_read_descriptor = (read_command_valid == 1) & (read_command_ready == 1);
|
|
assign pop_read_fifo = (issue_read_descriptor == 1) & (read_park_enable == 0); // don't want to pop the fifo if we are in parked mode
|
|
|
|
// write buffer flow control
|
|
assign push_write_fifo = go_bit;
|
|
assign write_park_enable = (write_park == 1) & (write_command_used == 1); // we want to keep the descriptor in the FIFO when the park bit is set
|
|
assign write_command_valid = (stop == 0) & (sw_reset == 0) & (stop_issuing_commands == 0) &
|
|
(write_command_empty == 0) & (write_command_empty_d1 == 0) & (write_command_empty_d2 == 0); // command buffer has two cycles of latency so the empty deassertion need to delayed two cycles but asserted in zero cycles, the time between commands will be at least 2 cycles so this delay is only needed coming out of the empty condition
|
|
assign issue_write_descriptor = (write_command_valid == 1) & (write_command_ready == 1);
|
|
assign pop_write_fifo = (issue_write_descriptor == 1) & (write_park_enable == 0); // don't want to pop the fifo if we are in parked mode
|
|
end
|
|
else if (MODE == 1) // MM-->ST
|
|
begin
|
|
// information for the CSR or response blocks to use
|
|
assign sequence_number = {16'h0000, read_sequence_number_d1};
|
|
assign transfer_complete_IRQ_mask = read_transfer_complete_IRQ_mask_d1;
|
|
assign early_termination_IRQ_mask = 1'b0;
|
|
assign error_IRQ_mask = 8'h00;
|
|
|
|
assign waitrequest = (read_command_full == 1) | (sw_reset == 1);
|
|
|
|
// read buffer flow control
|
|
assign push_read_fifo = go_bit;
|
|
assign read_park_enable = (read_park == 1) & (read_command_used == 1); // we want to keep the descriptor in the FIFO when the park bit is set
|
|
assign read_command_valid = (stop == 0) & (sw_reset == 0) & (stop_issuing_commands == 0) &
|
|
(read_command_empty == 0) & (read_command_empty_d1 == 0) & (read_command_empty_d2 == 0); // command buffer has two cycles of latency so the empty deassertion need to delayed two cycles but asserted in zero cycles, the time between commands will be at least 2 cycles so this delay is only needed coming out of the empty condition
|
|
assign issue_read_descriptor = (read_command_valid == 1) & (read_command_ready == 1);
|
|
assign pop_read_fifo = (issue_read_descriptor == 1) & (read_park_enable == 0); // don't want to pop the fifo if we are in parked mode
|
|
|
|
// write buffer flow control
|
|
assign push_write_fifo = 0;
|
|
assign write_park_enable = 0;
|
|
assign write_command_valid = 0;
|
|
assign issue_write_descriptor = 0;
|
|
assign pop_write_fifo = 0;
|
|
end
|
|
else // ST-->MM
|
|
begin
|
|
// information for the CSR or response blocks to use
|
|
assign sequence_number = {write_sequence_number_d1, 16'h0000};
|
|
assign transfer_complete_IRQ_mask = write_transfer_complete_IRQ_mask_d1;
|
|
assign early_termination_IRQ_mask = write_early_termination_IRQ_mask_d1;
|
|
assign error_IRQ_mask = write_error_IRQ_mask_d1;
|
|
|
|
assign waitrequest = (write_command_full == 1) | (sw_reset == 1);
|
|
|
|
// read buffer flow control
|
|
assign push_read_fifo = 0;
|
|
assign read_park_enable = 0;
|
|
assign read_command_valid = 0;
|
|
assign issue_read_descriptor = 0;
|
|
assign pop_read_fifo = 0;
|
|
|
|
// write buffer flow control
|
|
assign push_write_fifo = go_bit;
|
|
assign write_park_enable = (write_park == 1) & (write_command_used == 1); // we want to keep the descriptor in the FIFO when the park bit is set
|
|
assign write_command_valid = (stop == 0) & (sw_reset == 0) & (stop_issuing_commands == 0) &
|
|
(write_command_empty == 0) & (write_command_empty_d1 == 0) & (write_command_empty_d2 == 0); // command buffer has two cycles of latency so the empty deassertion need to delayed two cycles but asserted in zero cycles, the time between commands will be at least 2 cycles so this delay is only needed coming out of the empty condition
|
|
assign issue_write_descriptor = (write_command_valid == 1) & (write_command_ready == 1);
|
|
assign pop_write_fifo = (issue_write_descriptor == 1) & (write_park_enable == 0); // don't want to pop the fifo if we are in parked mode
|
|
end
|
|
endgenerate
|
|
|
|
|
|
generate // go bit is in a different location depending on the width of the slave port
|
|
if (DATA_WIDTH == 256)
|
|
begin
|
|
assign go_bit = (writedata[255] == 1) & (write == 1) & (byteenable[31] == 1) & (waitrequest == 0);
|
|
end
|
|
else
|
|
begin
|
|
assign go_bit = (writedata[127] == 1) & (write == 1) & (byteenable[15] == 1) & (waitrequest == 0);
|
|
end
|
|
endgenerate
|
|
|
|
assign write_en = (write == 1) & (waitrequest == 0);
|
|
/**************************************** End Combinational Signals ************************************************/
|
|
|
|
endmodule
|