Initial commit: retroDE_ps2 — first-of-its-kind PS2 GS FPGA core (DE25-Nano / Agilex 5)
RTL (GS rasterizer, EE core stub, platform bridge, LPDDR4B path), sim regression (272 TBs), docs, and tooling. Copyrighted PS2 content (BIOS, game code, GS dumps, and all dump-derived textures/traces) is excluded via .gitignore and stays local. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,383 @@
|
||||
// (C) 2001-2026 Altera Corporation. All rights reserved.
|
||||
// Your use of Altera 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 Altera Program License Subscription
|
||||
// Agreement, Altera 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 Altera and sold by
|
||||
// Altera or its authorized distributors. Please refer to the applicable
|
||||
// agreement for further details.
|
||||
|
||||
|
||||
// (C) 2001-2017 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.
|
||||
|
||||
|
||||
// (C) 2001-2012 Altera Corporation. All rights reserved.
|
||||
// Your use of Altera Corporation's design tools, logic functions and other
|
||||
// software and tools, and its AMPP partner logic functions, and any output
|
||||
// files 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 Altera Program License Subscription
|
||||
// Agreement, Altera MegaCore Function License Agreement, or other applicable
|
||||
// license agreement, including, without limitation, that your use is for the
|
||||
// sole purpose of programming logic devices manufactured by Altera and sold by
|
||||
// Altera or its authorized distributors. Please refer to the applicable
|
||||
// agreement for further details.
|
||||
|
||||
|
||||
// $Id: //acds/rel/26.1/ip/iconnect/merlin/altera_merlin_slave_agent/altera_merlin_burst_uncompressor.sv#1 $
|
||||
// $Revision: #1 $
|
||||
// $Date: 2026/02/05 $
|
||||
|
||||
// ------------------------------------------
|
||||
// Merlin Burst Uncompressor
|
||||
//
|
||||
// Compressed read bursts -> uncompressed
|
||||
// ------------------------------------------
|
||||
|
||||
`timescale 1 ns / 1 ns
|
||||
|
||||
module altera_merlin_burst_uncompressor
|
||||
#(
|
||||
parameter ADDR_W = 16,
|
||||
parameter BURSTWRAP_W = 3,
|
||||
parameter BYTE_CNT_W = 4,
|
||||
parameter PKT_SYMBOLS = 4,
|
||||
parameter BURST_SIZE_W = 3,
|
||||
parameter SYNC_RESET = 0,
|
||||
parameter USED_IN_WIDTH_ADAPTER = 0
|
||||
)
|
||||
(
|
||||
input clk,
|
||||
input reset,
|
||||
|
||||
// sink ST signals
|
||||
input sink_startofpacket,
|
||||
input sink_endofpacket,
|
||||
input sink_valid,
|
||||
output sink_ready,
|
||||
|
||||
// sink ST "data"
|
||||
input [ADDR_W - 1: 0] sink_addr,
|
||||
input [BURSTWRAP_W - 1 : 0] sink_burstwrap,
|
||||
input [BYTE_CNT_W - 1 : 0] sink_byte_cnt,
|
||||
input sink_is_compressed,
|
||||
input [BURST_SIZE_W-1 : 0] sink_burstsize,
|
||||
|
||||
// source ST signals
|
||||
output source_startofpacket,
|
||||
output source_endofpacket,
|
||||
output source_valid,
|
||||
input source_ready,
|
||||
|
||||
// source ST "data"
|
||||
output [ADDR_W - 1: 0] source_addr,
|
||||
output [BURSTWRAP_W - 1 : 0] source_burstwrap,
|
||||
output [BYTE_CNT_W - 1 : 0] source_byte_cnt,
|
||||
|
||||
// Note: in the slave agent, the output should always be uncompressed. In
|
||||
// other applications, it may be required to leave-compressed or not. How to
|
||||
// control? Seems like a simple mux - pass-through if no uncompression is
|
||||
// required.
|
||||
output source_is_compressed,
|
||||
output [BURST_SIZE_W-1 : 0] source_burstsize
|
||||
);
|
||||
|
||||
//----------------------------------------------------
|
||||
// AXSIZE decoding
|
||||
//
|
||||
// Turns the axsize value into the actual number of bytes
|
||||
// being transferred.
|
||||
// ---------------------------------------------------
|
||||
function reg[63:0] bytes_in_transfer;
|
||||
input [BURST_SIZE_W-1:0] axsize;
|
||||
case (axsize)
|
||||
4'b0000: bytes_in_transfer = 64'b0000000000000000000000000000000000000000000000000000000000000001;
|
||||
4'b0001: bytes_in_transfer = 64'b0000000000000000000000000000000000000000000000000000000000000010;
|
||||
4'b0010: bytes_in_transfer = 64'b0000000000000000000000000000000000000000000000000000000000000100;
|
||||
4'b0011: bytes_in_transfer = 64'b0000000000000000000000000000000000000000000000000000000000001000;
|
||||
4'b0100: bytes_in_transfer = 64'b0000000000000000000000000000000000000000000000000000000000010000;
|
||||
4'b0101: bytes_in_transfer = 64'b0000000000000000000000000000000000000000000000000000000000100000;
|
||||
4'b0110: bytes_in_transfer = 64'b0000000000000000000000000000000000000000000000000000000001000000;
|
||||
4'b0111: bytes_in_transfer = 64'b0000000000000000000000000000000000000000000000000000000010000000;
|
||||
4'b1000: bytes_in_transfer = 64'b0000000000000000000000000000000000000000000000000000000100000000;
|
||||
4'b1001: bytes_in_transfer = 64'b0000000000000000000000000000000000000000000000000000001000000000;
|
||||
default:bytes_in_transfer = 64'b0000000000000000000000000000000000000000000000000000000000000001;
|
||||
endcase
|
||||
|
||||
endfunction
|
||||
|
||||
localparam LG_PKT_SYMBOLS = $clog2(PKT_SYMBOLS);
|
||||
|
||||
// num_symbols is PKT_SYMBOLS, appropriately sized.
|
||||
wire [31:0] int_num_symbols;
|
||||
if(USED_IN_WIDTH_ADAPTER)
|
||||
assign int_num_symbols = (|sink_burstsize) ? PKT_SYMBOLS:1;
|
||||
else
|
||||
assign int_num_symbols = PKT_SYMBOLS;
|
||||
wire [BYTE_CNT_W-1:0] num_symbols = int_num_symbols[BYTE_CNT_W-1:0];
|
||||
|
||||
// def: Burst Compression. In a merlin network, a compressed burst is one
|
||||
// which is transmitted in a single beat. Example: read burst. In
|
||||
// constrast, an uncompressed burst (example: write burst) is transmitted in
|
||||
// one beat per writedata item.
|
||||
//
|
||||
// For compressed bursts which require response packets, burst
|
||||
// uncompression is required. Concrete example: a read burst of size 8
|
||||
// occupies one response-fifo position. When that fifo position reaches the
|
||||
// front of the FIFO, the slave starts providing the required 8 readdatavalid
|
||||
// pulses. The 8 return response beats must be provided in a single packet,
|
||||
// with incrementing address and decrementing byte_cnt fields. Upon receipt
|
||||
// of the final readdata item of the burst, the response FIFO item is
|
||||
// retired.
|
||||
// Burst uncompression logic provides:
|
||||
// a) 2-state FSM (idle, busy)
|
||||
// reset to idle state
|
||||
// transition to busy state for 2nd and subsequent rdv pulses
|
||||
// - a single-cycle burst (aka non-burst read) causes no transition to
|
||||
// busy state.
|
||||
// b) response startofpacket/endofpacket logic. The response FIFO item
|
||||
// will have sop asserted, and may have eop asserted. (In the case of
|
||||
// multiple read bursts transmit in the command fabric in a single packet,
|
||||
// the eop assertion will come in a later FIFO item.) To support packet
|
||||
// conservation, and emit a well-formed packet on the response fabric,
|
||||
// i) response fabric startofpacket is asserted only for the first resp.
|
||||
// beat;
|
||||
// ii) response fabric endofpacket is asserted only for the last resp.
|
||||
// beat.
|
||||
// c) response address field. The response address field contains an
|
||||
// incrementing sequence, such that each readdata item is associated with
|
||||
// its slave-map location. N.b. a) computing the address correctly requires
|
||||
// knowledge of burstwrap behavior b) there may be no clients of the address
|
||||
// field, which makes this field a good target for optimization. See
|
||||
// burst_uncompress_address_counter below.
|
||||
// d) response byte_cnt field. The response byte_cnt field contains a
|
||||
// decrementing sequence, such that each beat of the response contains the
|
||||
// count of bytes to follow. In the case of sub-bursts in a single packet,
|
||||
// the byte_cnt field may decrement down to num_symbols, then back up to
|
||||
// some value, multiple times in the packet.
|
||||
|
||||
reg burst_uncompress_busy;
|
||||
reg [BYTE_CNT_W-1:0] burst_uncompress_byte_counter_lint;
|
||||
wire first_packet_beat;
|
||||
wire last_packet_beat;
|
||||
|
||||
assign first_packet_beat = sink_valid & ~burst_uncompress_busy;
|
||||
|
||||
always @ (posedge clk) begin
|
||||
if (source_valid & source_ready & sink_valid) begin
|
||||
if(burst_uncompress_busy) begin
|
||||
burst_uncompress_byte_counter_lint <= burst_uncompress_byte_counter_lint-num_symbols;
|
||||
end else begin
|
||||
burst_uncompress_byte_counter_lint <= sink_byte_cnt - num_symbols;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
// First cycle: burst_uncompress_byte_counter isn't ready yet, mux the input to
|
||||
// the output.
|
||||
assign source_byte_cnt =
|
||||
first_packet_beat ? sink_byte_cnt : burst_uncompress_byte_counter_lint;
|
||||
assign source_valid = sink_valid;
|
||||
|
||||
// Last packet beat is set throughout receipt of an uncompressed read burst
|
||||
// from the response FIFO - this forces all the burst uncompression machinery
|
||||
// idle.
|
||||
assign last_packet_beat = ~sink_is_compressed |
|
||||
(
|
||||
burst_uncompress_busy ?
|
||||
(sink_valid & (burst_uncompress_byte_counter_lint == num_symbols)) :
|
||||
sink_valid & (sink_byte_cnt == num_symbols)
|
||||
);
|
||||
|
||||
|
||||
// Generation of internal reset synchronization
|
||||
reg internal_sclr;
|
||||
generate if (SYNC_RESET == 1) begin : rst_syncronizer
|
||||
always @ (posedge clk) begin
|
||||
internal_sclr <= reset;
|
||||
end
|
||||
end
|
||||
endgenerate
|
||||
|
||||
generate
|
||||
if (SYNC_RESET == 0) begin : async_rst0
|
||||
always @(posedge clk or posedge reset) begin
|
||||
if (reset) begin
|
||||
burst_uncompress_busy <= '0;
|
||||
end
|
||||
else begin
|
||||
if (source_valid & source_ready & sink_valid) begin
|
||||
// No matter what the current state, last_packet_beat leads to
|
||||
// idle.
|
||||
if (last_packet_beat) begin
|
||||
burst_uncompress_busy <= '0;
|
||||
end
|
||||
else begin
|
||||
burst_uncompress_busy <= 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end // async_rst0
|
||||
else begin // sync_rst0
|
||||
always @(posedge clk ) begin
|
||||
if (internal_sclr) begin
|
||||
burst_uncompress_busy <= '0;
|
||||
end
|
||||
else begin
|
||||
if (source_valid & source_ready & sink_valid) begin
|
||||
// No matter what the current state, last_packet_beat leads to
|
||||
// idle.
|
||||
if (last_packet_beat) begin
|
||||
burst_uncompress_busy <= '0;
|
||||
end
|
||||
else begin
|
||||
burst_uncompress_busy <= 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end // sync_rst0
|
||||
endgenerate
|
||||
//always @ (posedge clk) begin
|
||||
// if (source_valid & source_ready & sink_valid) begin
|
||||
// // No matter what the current state, last_packet_beat leads to
|
||||
// // idle.
|
||||
// if (last_packet_beat) begin
|
||||
// burst_uncompress_byte_counter <= '0;
|
||||
// end
|
||||
// else begin
|
||||
// if (burst_uncompress_busy) begin
|
||||
// burst_uncompress_byte_counter <= (burst_uncompress_byte_counter > 0) ?
|
||||
// (burst_uncompress_byte_counter_lint[BYTE_CNT_W-1:LG_PKT_SYMBOLS] - num_symbols[BYTE_CNT_W-1:LG_PKT_SYMBOLS]) :
|
||||
// (sink_byte_cnt[BYTE_CNT_W-1:LG_PKT_SYMBOLS] - num_symbols[BYTE_CNT_W-1:LG_PKT_SYMBOLS]);
|
||||
// end
|
||||
// else begin // not busy, at least one more beat to go
|
||||
// burst_uncompress_byte_counter <= sink_byte_cnt[BYTE_CNT_W-1:LG_PKT_SYMBOLS] - num_symbols[BYTE_CNT_W-1:LG_PKT_SYMBOLS];
|
||||
// // To do: should busy go true for numsymbols-size compressed
|
||||
// // bursts?
|
||||
// end
|
||||
// end
|
||||
// end
|
||||
//end
|
||||
|
||||
|
||||
reg [ADDR_W - 1 : 0 ] burst_uncompress_address_base;
|
||||
reg [ADDR_W - 1 : 0] burst_uncompress_address_offset;
|
||||
|
||||
wire [63:0] decoded_burstsize_wire;
|
||||
wire [ADDR_W-1:0] decoded_burstsize;
|
||||
|
||||
|
||||
localparam ADD_BURSTWRAP_W = (ADDR_W > BURSTWRAP_W) ? ADDR_W : BURSTWRAP_W;
|
||||
wire [ADD_BURSTWRAP_W-1:0] addr_width_burstwrap;
|
||||
// The input burstwrap value can be used as a mask against address values,
|
||||
// but with one caveat: the address width may be (probably is) wider than
|
||||
// the burstwrap width. The spec says: extend the msb of the burstwrap
|
||||
// value out over the entire address width (but only if the address width
|
||||
// actually is wider than the burstwrap width; otherwise it's a 0-width or
|
||||
// negative range and concatenation multiplier).
|
||||
generate
|
||||
if (ADDR_W > BURSTWRAP_W) begin : addr_sign_extend
|
||||
// Sign-extend, just wires:
|
||||
assign addr_width_burstwrap[ADDR_W - 1 : BURSTWRAP_W] =
|
||||
{(ADDR_W - BURSTWRAP_W) {sink_burstwrap[BURSTWRAP_W - 1]}};
|
||||
assign addr_width_burstwrap[BURSTWRAP_W-1:0] = sink_burstwrap [BURSTWRAP_W-1:0];
|
||||
end
|
||||
else begin
|
||||
assign addr_width_burstwrap[BURSTWRAP_W-1 : 0] = sink_burstwrap;
|
||||
end
|
||||
endgenerate
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (first_packet_beat & source_ready) begin
|
||||
burst_uncompress_address_base <= sink_addr & ~addr_width_burstwrap[ADDR_W-1:0];
|
||||
end
|
||||
end
|
||||
|
||||
//always @(posedge clk or posedge reset) begin
|
||||
// if (reset) begin
|
||||
// burst_uncompress_address_base <= '0;
|
||||
// end
|
||||
// else if (first_packet_beat & source_ready) begin
|
||||
// burst_uncompress_address_base <= sink_addr & ~addr_width_burstwrap[ADDR_W-1:0];
|
||||
// end
|
||||
//end
|
||||
|
||||
assign decoded_burstsize_wire = bytes_in_transfer(sink_burstsize); //expand it to 64 bits
|
||||
assign decoded_burstsize = decoded_burstsize_wire[ADDR_W-1:0]; //then take the width that is needed
|
||||
|
||||
wire [ADDR_W : 0] p1_burst_uncompress_address_offset =
|
||||
(
|
||||
(first_packet_beat ?
|
||||
sink_addr :
|
||||
burst_uncompress_address_offset) + decoded_burstsize
|
||||
) &
|
||||
addr_width_burstwrap[ADDR_W-1:0];
|
||||
wire [ADDR_W-1:0] p1_burst_uncompress_address_offset_lint = p1_burst_uncompress_address_offset [ADDR_W-1:0];
|
||||
|
||||
always @ (posedge clk) begin
|
||||
if (source_ready & source_valid) begin
|
||||
burst_uncompress_address_offset <= p1_burst_uncompress_address_offset_lint;
|
||||
end
|
||||
end
|
||||
|
||||
//always @(posedge clk or posedge reset) begin
|
||||
// if (reset) begin
|
||||
// burst_uncompress_address_offset <= '0;
|
||||
// end
|
||||
// else begin
|
||||
// if (source_ready & source_valid) begin
|
||||
// burst_uncompress_address_offset <= p1_burst_uncompress_address_offset_lint;
|
||||
// // if (first_packet_beat) begin
|
||||
// // burst_uncompress_address_offset <=
|
||||
// // (sink_addr + num_symbols) & addr_width_burstwrap;
|
||||
// // end
|
||||
// // else begin
|
||||
// // burst_uncompress_address_offset <=
|
||||
// // (burst_uncompress_address_offset + num_symbols) & addr_width_burstwrap;
|
||||
// // end
|
||||
// end
|
||||
// end
|
||||
//end
|
||||
|
||||
// On the first packet beat, send the input address out unchanged,
|
||||
// while values are computed/registered for 2nd and subsequent beats.
|
||||
assign source_addr = first_packet_beat ? sink_addr :
|
||||
burst_uncompress_address_base | burst_uncompress_address_offset;
|
||||
assign source_burstwrap = sink_burstwrap;
|
||||
assign source_burstsize = sink_burstsize;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// A single (compressed) read burst will have sop/eop in the same beat.
|
||||
// A sequence of read sub-bursts emitted by a burst adapter in response to a
|
||||
// single read burst will have sop on the first sub-burst, eop on the last.
|
||||
// Assert eop only upon (sink_endofpacket & last_packet_beat) to preserve
|
||||
// packet conservation.
|
||||
assign source_startofpacket = sink_startofpacket & ~burst_uncompress_busy;
|
||||
assign source_endofpacket = sink_endofpacket & last_packet_beat;
|
||||
assign sink_ready = source_valid & source_ready & last_packet_beat;
|
||||
|
||||
// This is correct for the slave agent usage, but won't always be true in the
|
||||
// width adapter. To do: add an "please uncompress" input, and use it to
|
||||
// pass-through or modify, and set source_is_compressed accordingly.
|
||||
assign source_is_compressed = 1'b0;
|
||||
endmodule
|
||||
|
||||
`ifdef QUESTA_INTEL_OEM
|
||||
`pragma questa_oem_00 "mfufSZOYfNPxmSfS+FkCl32e9bHGnpakqHX1nHXvrhE4J6x8qGVCEAJRqHIBXSp/FcyWPq9/UmljeMey51E9VTMH3OCNEvZdEUSPU4/Vf6DgtU26zIfR3Ws2AtmUBXEHD5yEeHuHpEMedz5PLIdzFsBxJ/9OiyM+8A3UVG3icM2FQlZPfaXli71zX1obNH4Hi4tyLUZvYQoJv7xSQMqW1lxant16XP5C2V2aZfTOCZlTuVjbs7t2AvXR8qtB5hlO4OP16VPo84MCPLx2rVhD1zQQWJ7B8d/ZQxcAh23irlYM5PRXVl1hzM1E9XBSwTHX4GiaPXc8KI87MAd2OBRsTVzQ3ploJyDTJ/5iLBZk4lL6RD0/o7jVPAsAA+iYoLIntesrKlzmNSO+ripXoEhypWMwRKSzgZZBPMMElLmdGOVkBpdGTg8XYKHFaxXioKDrffXWH12N3vtI6NzFHQfH/h77pcm8kqSxGEZzefHKCpgRsohq+zmawBPnqIEaklf3w9TR8wCComgJoehSxSSU/SoZucGVczKi/zpxAaV1C3ZvnYRs6KS3lwnftursubOcnVc54fiBCNX0o2tUlOGUN0MZVEhCByjyP7/tDDYHyz9Dyh5CcvlQ1SlPiN2bmCdVaKBDuFQGfnNX4iqkFXbtpf7KyNk9EwAzMRwGegjRDAqiYGeKBW/CfOtS6SxSn5LnfJyo1DRPBwBMYeT9gTB/CrgMTgZ+I0tO5pLPCNfpzFfaADXjL2aK7Oohy9lgFxUbDj3q5P1aPR2PeEeAnnBI1Cr9zvzuR1DljqKvMOVADEKuTYRh0CnptFzPRonyrUW0ISqpzVm4wrGeiVIWDlOU8I0E1VOdTB5G/FOYL7Ebbu+trxrk1HrXg+BTlfLX2HGtuX4biBJX3qBsyXItz0GnbOPIyN3bm3ZPkveSN7/nVnoPqYgXI5x9ilgczDHvSqU9mbmxiKhhU+AFIaVHUSBECnzRd5E6E34UW/Cxs92veqD6Z3nxWZyIP4Xab517bXhz"
|
||||
`endif
|
||||
+841
@@ -0,0 +1,841 @@
|
||||
// (C) 2001-2026 Altera Corporation. All rights reserved.
|
||||
// Your use of Altera 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 Altera Program License Subscription
|
||||
// Agreement, Altera 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 Altera and sold by
|
||||
// Altera or its authorized distributors. Please refer to the applicable
|
||||
// agreement for further details.
|
||||
|
||||
|
||||
// (C) 2001-2011 Altera Corporation. All rights reserved.
|
||||
// Your use of Altera Corporation's design tools, logic functions and other
|
||||
// software and tools, and its AMPP partner logic functions, and any output
|
||||
// files 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 Altera Program License Subscription
|
||||
// Agreement, Altera MegaCore Function License Agreement, or other applicable
|
||||
// license agreement, including, without limitation, that your use is for the
|
||||
// sole purpose of programming logic devices manufactured by Altera and sold by
|
||||
// Altera or its authorized distributors. Please refer to the applicable
|
||||
// agreement for further details.
|
||||
|
||||
`timescale 1 ns / 1 ns
|
||||
|
||||
module qsys_top_altera_merlin_slave_agent_1930_jxauz3i
|
||||
#(
|
||||
// Packet parameters
|
||||
parameter PKT_BEGIN_BURST = 81,
|
||||
parameter PKT_DATA_H = 31,
|
||||
parameter PKT_DATA_L = 0,
|
||||
parameter PKT_SYMBOL_W = 8,
|
||||
parameter PKT_BYTEEN_H = 71,
|
||||
parameter PKT_BYTEEN_L = 68,
|
||||
parameter PKT_ADDR_H = 63,
|
||||
parameter PKT_ADDR_L = 32,
|
||||
parameter PKT_TRANS_LOCK = 87,
|
||||
parameter PKT_TRANS_COMPRESSED_READ = 67,
|
||||
parameter PKT_TRANS_POSTED = 66,
|
||||
parameter PKT_TRANS_WRITE = 65,
|
||||
parameter PKT_TRANS_READ = 64,
|
||||
parameter PKT_SRC_ID_H = 74,
|
||||
parameter PKT_SRC_ID_L = 72,
|
||||
parameter PKT_DEST_ID_H = 77,
|
||||
parameter PKT_DEST_ID_L = 75,
|
||||
parameter PKT_BURSTWRAP_H = 85,
|
||||
parameter PKT_BURSTWRAP_L = 82,
|
||||
parameter PKT_BYTE_CNT_H = 81,
|
||||
parameter PKT_BYTE_CNT_L = 78,
|
||||
parameter PKT_PROTECTION_H = 86,
|
||||
parameter PKT_PROTECTION_L = 86,
|
||||
parameter PKT_RESPONSE_STATUS_H = 89,
|
||||
parameter PKT_RESPONSE_STATUS_L = 88,
|
||||
parameter PKT_BURST_SIZE_H = 92,
|
||||
parameter PKT_BURST_SIZE_L = 90,
|
||||
parameter PKT_ORI_BURST_SIZE_L = 93,
|
||||
parameter PKT_ORI_BURST_SIZE_H = 95,
|
||||
parameter PKT_POISON_L = 97,
|
||||
parameter PKT_POISON_H = 97,
|
||||
parameter PKT_DATACHK_L = 98,
|
||||
parameter PKT_DATACHK_H = 98,
|
||||
parameter PKT_SAI_L = 99,
|
||||
parameter PKT_SAI_H = 99,
|
||||
parameter PKT_ADDRCHK_L = 100,
|
||||
parameter PKT_ADDRCHK_H = 100,
|
||||
parameter PKT_USER_DATA_L = 101,
|
||||
parameter PKT_USER_DATA_H = 101,
|
||||
parameter PKT_ATRACE = 102,
|
||||
parameter PKT_TRACE = 103,
|
||||
parameter PKT_AWAKEUP = 104,
|
||||
|
||||
//ACE5-Lite signals
|
||||
parameter PKT_AWATOP_L = 154,
|
||||
parameter PKT_AWATOP_H = 159,
|
||||
parameter PKT_AWSTASHNID_L = 160,
|
||||
parameter PKT_AWSTASHNID_H = 170,
|
||||
parameter PKT_AWSTASHNIDEN = 171,
|
||||
parameter PKT_AWSTASHLPID_L = 172,
|
||||
parameter PKT_AWSTASHLPID_H = 176,
|
||||
parameter PKT_AWSTASHLPIDEN = 177,
|
||||
parameter PKT_MMUSECSID = 178,
|
||||
parameter PKT_MMUSID_L = 179,
|
||||
parameter PKT_MMUSID_H = 195,
|
||||
parameter PKT_DATALESS = 196,
|
||||
|
||||
|
||||
parameter ST_DATA_W = 102,
|
||||
parameter ST_CHANNEL_W = 32,
|
||||
parameter ROLE_BASED_USER = 0,
|
||||
parameter ENABLE_AXI5 = 0,
|
||||
parameter SYNC_RESET = 0,
|
||||
|
||||
parameter USE_PKT_DATACHK = 1,
|
||||
|
||||
// Slave parameters
|
||||
parameter ADDR_W = PKT_ADDR_H - PKT_ADDR_L + 1,
|
||||
parameter AVS_DATA_W = PKT_DATA_H - PKT_DATA_L + 1,
|
||||
parameter AVS_BURSTCOUNT_W = 4,
|
||||
parameter PKT_SYMBOLS = AVS_DATA_W / PKT_SYMBOL_W,
|
||||
|
||||
// Slave agent parameters
|
||||
parameter USE_MEMORY_BLOCKS = 1,
|
||||
parameter PREVENT_FIFO_OVERFLOW = 0,
|
||||
parameter SUPPRESS_0_BYTEEN_CMD = 1,
|
||||
parameter USE_READRESPONSE = 0,
|
||||
parameter USE_WRITERESPONSE = 0,
|
||||
|
||||
// Derived slave parameters
|
||||
parameter AVS_BE_W = PKT_BYTEEN_H - PKT_BYTEEN_L + 1,
|
||||
parameter BURST_SIZE_W = 3,
|
||||
|
||||
// Derived FIFO width
|
||||
parameter FIFO_DATA_W = ST_DATA_W + 1,
|
||||
|
||||
// ECC parameter
|
||||
parameter ECC_ENABLE = 0
|
||||
) (
|
||||
input clk,
|
||||
input reset,
|
||||
|
||||
// Universal-Avalon anti-slave
|
||||
output [ADDR_W-1:0] m0_address,
|
||||
output [AVS_BURSTCOUNT_W-1:0] m0_burstcount,
|
||||
output [AVS_BE_W-1:0] m0_byteenable,
|
||||
output m0_read,
|
||||
input [AVS_DATA_W-1:0] m0_readdata,
|
||||
input m0_waitrequest,
|
||||
output m0_write,
|
||||
output [AVS_DATA_W-1:0] m0_writedata,
|
||||
input m0_readdatavalid,
|
||||
output m0_debugaccess,
|
||||
output m0_lock,
|
||||
input [1:0] m0_response,
|
||||
input m0_writeresponsevalid,
|
||||
|
||||
// Avalon-ST FIFO interfaces.
|
||||
// Note: there's no need to include the "data" field here, at least for
|
||||
// reads, since readdata is filled in from slave info. To keep life
|
||||
// simple, have a data field, but fill it with 0s.
|
||||
// Av-st response fifo source interface
|
||||
output reg [FIFO_DATA_W-1:0] rf_source_data,
|
||||
output rf_source_valid,
|
||||
output rf_source_startofpacket,
|
||||
output rf_source_endofpacket,
|
||||
input rf_source_ready,
|
||||
|
||||
// Av-st response fifo sink interface
|
||||
input [FIFO_DATA_W-1:0] rf_sink_data,
|
||||
input rf_sink_valid,
|
||||
input rf_sink_startofpacket,
|
||||
input rf_sink_endofpacket,
|
||||
output reg rf_sink_ready,
|
||||
|
||||
// Av-st readdata fifo src interface, data and response
|
||||
// extra 2 bits for storing RESPONSE STATUS
|
||||
output [AVS_DATA_W+1:0] rdata_fifo_src_data,
|
||||
output rdata_fifo_src_valid,
|
||||
input rdata_fifo_src_ready,
|
||||
|
||||
// Av-st readdata fifo sink interface
|
||||
input [AVS_DATA_W+1:0] rdata_fifo_sink_data,
|
||||
input rdata_fifo_sink_valid,
|
||||
output rdata_fifo_sink_ready,
|
||||
input rdata_fifo_sink_error,
|
||||
|
||||
// Av-st sink command packet interface
|
||||
output cp_ready,
|
||||
input cp_valid,
|
||||
input [ST_DATA_W-1:0] cp_data,
|
||||
input [ST_CHANNEL_W-1:0] cp_channel,
|
||||
input cp_startofpacket,
|
||||
input cp_endofpacket,
|
||||
|
||||
// Av-st source response packet interface
|
||||
input rp_ready,
|
||||
output reg rp_valid,
|
||||
output reg [ST_DATA_W-1:0] rp_data,
|
||||
output rp_startofpacket,
|
||||
output rp_endofpacket
|
||||
);
|
||||
// ------------------------------------------------
|
||||
// Local Parameters
|
||||
// ------------------------------------------------
|
||||
localparam DATA_W = PKT_DATA_H - PKT_DATA_L + 1;
|
||||
localparam BE_W = PKT_BYTEEN_H - PKT_BYTEEN_L + 1;
|
||||
localparam MID_W = PKT_SRC_ID_H - PKT_SRC_ID_L + 1;
|
||||
localparam SID_W = PKT_DEST_ID_H - PKT_DEST_ID_L + 1;
|
||||
localparam BYTE_CNT_W = PKT_BYTE_CNT_H - PKT_BYTE_CNT_L + 1;
|
||||
localparam BURSTWRAP_W = PKT_BURSTWRAP_H - PKT_BURSTWRAP_L + 1;
|
||||
localparam BURSTSIZE_W = PKT_BURST_SIZE_H - PKT_BURST_SIZE_L + 1;
|
||||
localparam BITS_TO_MASK = log2ceil(PKT_SYMBOLS);
|
||||
localparam MAX_BURST = 1 << (AVS_BURSTCOUNT_W - 1);
|
||||
localparam BURSTING = (MAX_BURST > PKT_SYMBOLS);
|
||||
localparam PKT_DATACHK_W = DATA_W/8;
|
||||
|
||||
// --------------------------------------------------
|
||||
// Ceil(log2()) function log2ceil of 4 = 2
|
||||
// --------------------------------------------------
|
||||
function integer log2ceil;
|
||||
input reg[63:0] val;
|
||||
reg [63:0] i;
|
||||
|
||||
begin
|
||||
i = 1;
|
||||
log2ceil = 0;
|
||||
|
||||
while (i < val) begin
|
||||
log2ceil = log2ceil + 1;
|
||||
i = i << 1;
|
||||
end
|
||||
end
|
||||
endfunction
|
||||
|
||||
// --------------------------------------------------
|
||||
// calcParity: calculates byte-level parity signal
|
||||
// --------------------------------------------------
|
||||
function reg [PKT_DATACHK_W-1:0] calcParity (
|
||||
input [DATA_W-1:0] data
|
||||
);
|
||||
for (int i=0; i<PKT_DATACHK_W; i++)
|
||||
calcParity[i] = ~(^ data[i*8 +:8]);
|
||||
endfunction
|
||||
|
||||
|
||||
// ------------------------------------------------
|
||||
// Signals
|
||||
// ------------------------------------------------
|
||||
wire [DATA_W-1:0] cmd_data;
|
||||
wire [BE_W-1:0] cmd_byteen;
|
||||
wire [ADDR_W-1:0] cmd_addr;
|
||||
wire [MID_W-1:0] cmd_mid;
|
||||
wire [SID_W-1:0] cmd_sid;
|
||||
wire cmd_read;
|
||||
wire cmd_write;
|
||||
wire cmd_compressed;
|
||||
wire cmd_posted;
|
||||
wire [BYTE_CNT_W-1:0] cmd_byte_cnt;
|
||||
wire [BURSTWRAP_W-1:0] cmd_burstwrap;
|
||||
wire [BURSTSIZE_W-1:0] cmd_burstsize;
|
||||
wire cmd_debugaccess;
|
||||
|
||||
wire suppress_cmd;
|
||||
wire byteen_asserted;
|
||||
wire suppress_read;
|
||||
wire suppress_write;
|
||||
wire needs_response_synthesis;
|
||||
wire generate_response;
|
||||
|
||||
//signals for additional latency due to different memory
|
||||
wire [AVS_DATA_W-1:0] m0_readdata_q;
|
||||
wire m0_readdatavalid_q;
|
||||
wire [1:0] m0_response_q;
|
||||
wire m0_writeresponsevalid_q;
|
||||
reg [AVS_DATA_W-1:0] m0_readdata_1;
|
||||
reg m0_readdatavalid_1;
|
||||
reg [1:0] m0_response_1;
|
||||
reg m0_writeresponsevalid_1;
|
||||
reg [AVS_DATA_W-1:0] m0_readdata_2;
|
||||
reg m0_readdatavalid_2;
|
||||
reg [1:0] m0_response_2;
|
||||
reg m0_writeresponsevalid_2;
|
||||
|
||||
// Assign command fields
|
||||
assign cmd_data = cp_data[PKT_DATA_H :PKT_DATA_L ];
|
||||
assign cmd_byteen = cp_data[PKT_BYTEEN_H:PKT_BYTEEN_L];
|
||||
assign cmd_addr = cp_data[PKT_ADDR_H :PKT_ADDR_L ];
|
||||
assign cmd_compressed = cp_data[PKT_TRANS_COMPRESSED_READ];
|
||||
assign cmd_posted = cp_data[PKT_TRANS_POSTED];
|
||||
assign cmd_write = cp_data[PKT_TRANS_WRITE];
|
||||
assign cmd_read = cp_data[PKT_TRANS_READ];
|
||||
assign cmd_mid = cp_data[PKT_SRC_ID_H :PKT_SRC_ID_L];
|
||||
assign cmd_sid = cp_data[PKT_DEST_ID_H:PKT_DEST_ID_L];
|
||||
assign cmd_byte_cnt = cp_data[PKT_BYTE_CNT_H:PKT_BYTE_CNT_L];
|
||||
assign cmd_burstwrap = cp_data[PKT_BURSTWRAP_H:PKT_BURSTWRAP_L];
|
||||
assign cmd_burstsize = cp_data[PKT_BURST_SIZE_H:PKT_BURST_SIZE_L];
|
||||
assign cmd_debugaccess = cp_data[PKT_PROTECTION_L];
|
||||
|
||||
// Local "ready_for_command" signal: deasserted when the agent is unable to accept
|
||||
// another command, e.g. rdv FIFO is full, (local readdata storage is full &&
|
||||
// ~rp_ready), ...
|
||||
// Say, this could depend on the type of command, for example, even if the
|
||||
// rdv FIFO is full, a write request can be accepted. For later.
|
||||
wire ready_for_command;
|
||||
|
||||
wire local_lock = cp_valid & cp_data[PKT_TRANS_LOCK];
|
||||
wire local_write = cp_valid & cp_data[PKT_TRANS_WRITE];
|
||||
wire local_read = cp_valid & cp_data[PKT_TRANS_READ];
|
||||
wire local_compressed_read = cp_valid & cp_data[PKT_TRANS_COMPRESSED_READ];
|
||||
wire nonposted_write_endofpacket = ~cp_data[PKT_TRANS_POSTED] & local_write & cp_endofpacket;
|
||||
|
||||
// num_symbols is PKT_SYMBOLS, appropriately sized.
|
||||
wire [31:0] int_num_symbols = PKT_SYMBOLS;
|
||||
wire [BYTE_CNT_W-1:0] num_symbols = int_num_symbols[BYTE_CNT_W-1:0];
|
||||
|
||||
// Generation of internal reset synchronization
|
||||
reg internal_sclr;
|
||||
generate if (SYNC_RESET == 1) begin : rst_syncronizer
|
||||
always @ (posedge clk) begin
|
||||
internal_sclr <= reset;
|
||||
end
|
||||
end
|
||||
endgenerate
|
||||
|
||||
generate
|
||||
if (SYNC_RESET ==0 ) begin : async0
|
||||
always_ff @(posedge clk, posedge reset) begin
|
||||
if (reset) begin
|
||||
m0_readdata_2 <= '0;
|
||||
m0_readdatavalid_2 <= '0;
|
||||
m0_response_2 <= '0;
|
||||
m0_writeresponsevalid_2 <= '0;
|
||||
end
|
||||
else begin
|
||||
m0_readdata_2 <= m0_readdata;
|
||||
m0_readdatavalid_2 <= m0_readdatavalid;
|
||||
m0_response_2 <= m0_response;
|
||||
m0_writeresponsevalid_2 <= m0_writeresponsevalid;
|
||||
end
|
||||
end //@always_ff
|
||||
end // async0
|
||||
|
||||
else begin :sync0
|
||||
always_ff @(posedge clk) begin
|
||||
if (internal_sclr) begin
|
||||
m0_readdata_2 <= '0;
|
||||
m0_readdatavalid_2 <= '0;
|
||||
m0_response_2 <= '0;
|
||||
m0_writeresponsevalid_2 <= '0;
|
||||
end
|
||||
else begin
|
||||
m0_readdata_2 <= m0_readdata;
|
||||
m0_readdatavalid_2 <= m0_readdatavalid;
|
||||
m0_response_2 <= m0_response;
|
||||
m0_writeresponsevalid_2 <= m0_writeresponsevalid;
|
||||
end
|
||||
end //@always_ff
|
||||
end // sync0
|
||||
endgenerate
|
||||
|
||||
generate
|
||||
if (SYNC_RESET ==0 ) begin : async1
|
||||
always_ff @(posedge clk, posedge reset) begin
|
||||
if (reset) begin
|
||||
m0_readdata_1 <= '0;
|
||||
m0_readdatavalid_1 <= '0;
|
||||
m0_response_1 <= '0;
|
||||
m0_writeresponsevalid_1 <= '0;
|
||||
end
|
||||
else begin
|
||||
m0_readdata_1 <= m0_readdata_2;
|
||||
m0_readdatavalid_1 <= m0_readdatavalid_2;
|
||||
m0_response_1 <= m0_response_2;
|
||||
m0_writeresponsevalid_1 <= m0_writeresponsevalid_2;
|
||||
end
|
||||
end //@always_ff
|
||||
end // async1
|
||||
|
||||
else begin :sync1
|
||||
always_ff @(posedge clk) begin
|
||||
if (internal_sclr) begin
|
||||
m0_readdata_1 <= '0;
|
||||
m0_readdatavalid_1 <= '0;
|
||||
m0_response_1 <= '0;
|
||||
m0_writeresponsevalid_1 <= '0;
|
||||
end
|
||||
else begin
|
||||
m0_readdata_1 <= m0_readdata_2;
|
||||
m0_readdatavalid_1 <= m0_readdatavalid_2;
|
||||
m0_response_1 <= m0_response_2;
|
||||
m0_writeresponsevalid_1 <= m0_writeresponsevalid_2;
|
||||
end
|
||||
end //@always_ff
|
||||
end // sync1
|
||||
endgenerate
|
||||
|
||||
|
||||
generate
|
||||
if (USE_MEMORY_BLOCKS) begin : Using_M20k_with_2_clk_latency
|
||||
assign m0_readdata_q = m0_readdata_1;
|
||||
assign m0_readdatavalid_q = m0_readdatavalid_1;
|
||||
assign m0_response_q = m0_response_1;
|
||||
assign m0_writeresponsevalid_q = m0_writeresponsevalid_1;
|
||||
end else begin : Using_ALM_memory_with_1_clk_latency
|
||||
assign m0_readdata_q = m0_readdata;
|
||||
assign m0_readdatavalid_q = m0_readdatavalid;
|
||||
assign m0_response_q = m0_response;
|
||||
assign m0_writeresponsevalid_q = m0_writeresponsevalid;
|
||||
end
|
||||
endgenerate
|
||||
|
||||
|
||||
|
||||
generate
|
||||
if (PREVENT_FIFO_OVERFLOW) begin : prevent_fifo_overflow_block
|
||||
// ---------------------------------------------------
|
||||
// Backpressure if the slave says to, or if FIFO overflow may occur.
|
||||
//
|
||||
// All commands are backpressured once the FIFO is full
|
||||
// even if they don't need storage. This breaks a long
|
||||
// combinatorial path from the master read/write through
|
||||
// this logic and back to the master via the backpressure
|
||||
// path.
|
||||
//
|
||||
// To avoid a loss of throughput the FIFO will be parameterized
|
||||
// one slot deeper. The extra slot should never be used in normal
|
||||
// operation, but should a slave misbehave and accept one more
|
||||
// read than it should then backpressure will kick in.
|
||||
//
|
||||
// An example: assume a slave with MPRT = 2. It can accept a
|
||||
// command sequence RRWW without backpressuring. If the FIFO is
|
||||
// only 2 deep, we'd backpressure the writes leading to loss of
|
||||
// throughput. If the FIFO is 3 deep, we'll only backpressure when
|
||||
// RRR... which is an illegal condition anyway.
|
||||
// ---------------------------------------------------
|
||||
|
||||
assign ready_for_command = rf_source_ready;
|
||||
assign cp_ready = (~m0_waitrequest | suppress_cmd) && ready_for_command;
|
||||
|
||||
end else begin : no_prevent_fifo_overflow_block
|
||||
|
||||
// Do not suppress the command or the slave will
|
||||
// not be able to waitrequest
|
||||
assign ready_for_command = 1'b1;
|
||||
// Backpressure only if the slave says to.
|
||||
assign cp_ready = ~m0_waitrequest | suppress_cmd;
|
||||
|
||||
end
|
||||
endgenerate
|
||||
|
||||
generate if (SUPPRESS_0_BYTEEN_CMD && !BURSTING) begin : suppress_0_byteen_cmd_non_bursting
|
||||
assign byteen_asserted = |cmd_byteen;
|
||||
assign suppress_read = ~byteen_asserted;
|
||||
assign suppress_write = ~byteen_asserted;
|
||||
assign suppress_cmd = ~byteen_asserted;
|
||||
end else if (SUPPRESS_0_BYTEEN_CMD && BURSTING) begin: suppress_0_byteen_cmd_bursting
|
||||
assign byteen_asserted = |cmd_byteen;
|
||||
assign suppress_read = ~byteen_asserted;
|
||||
assign suppress_write = 1'b0;
|
||||
assign suppress_cmd = ~byteen_asserted && cmd_read;
|
||||
end else begin : no_suppress_0_byteen_cmd
|
||||
assign suppress_read = 1'b0;
|
||||
assign suppress_write = 1'b0;
|
||||
assign suppress_cmd = 1'b0;
|
||||
end
|
||||
endgenerate
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Extract avalon signals from command packet.
|
||||
// -------------------------------------------------------------------
|
||||
// Mask off the lower bits of address.
|
||||
// The burst adapter before this component will break narrow sized packets
|
||||
// into sub-bursts of length 1. However, the packet addresses are preserved,
|
||||
// which means this component may see size-aligned addresses.
|
||||
//
|
||||
// Masking ensures that the addresses seen by an Avalon slave are aligned to
|
||||
// the full data width instead of the size.
|
||||
//
|
||||
// Example:
|
||||
// output from burst adapter (datawidth=4, size=2 bytes):
|
||||
// subburst1 addr=0, subburst2 addr=2, subburst3 addr=4, subburst4 addr=6
|
||||
// expected output from slave agent:
|
||||
// subburst1 addr=0, subburst2 addr=0, subburst3 addr=4, subburst4 addr=4
|
||||
generate
|
||||
if (BITS_TO_MASK > 0) begin : mask_address
|
||||
if(ADDR_W == BITS_TO_MASK)
|
||||
assign m0_address = { cmd_addr[ADDR_W-1:BITS_TO_MASK-1], {BITS_TO_MASK-1{1'b0}} };
|
||||
else
|
||||
assign m0_address = { cmd_addr[ADDR_W-1:BITS_TO_MASK], {BITS_TO_MASK{1'b0}} };
|
||||
|
||||
end else begin : no_mask_address
|
||||
|
||||
assign m0_address = cmd_addr;
|
||||
|
||||
end
|
||||
endgenerate
|
||||
|
||||
assign m0_byteenable = cmd_byteen;
|
||||
assign m0_writedata = cmd_data;
|
||||
|
||||
// Note: no Avalon-MM slave in existence accepts uncompressed read bursts -
|
||||
// this sort of burst exists only in merlin fabric ST packets. What to do
|
||||
// if we see such a burst? All beats in that burst need to be transmitted
|
||||
// to the slave so we have enough space-time for byteenable expression.
|
||||
//
|
||||
// There can be multiple bursts in a packet, but only one beat per burst
|
||||
// in <most> cases. The exception is when we've decided not to insert a
|
||||
// burst adapter for efficiency reasons, in which case this agent is also
|
||||
// responsible for driving burstcount to 1 on each beat of an uncompressed
|
||||
// read burst.
|
||||
|
||||
assign m0_read = ready_for_command & !suppress_read & (local_compressed_read | local_read);
|
||||
|
||||
generate
|
||||
// AVS_BURSTCOUNT_W and BYTE_CNT_W may not be equal. Assign m0_burstcount
|
||||
// from a sub-range, or 0-pad, as appropriate.
|
||||
if (AVS_BURSTCOUNT_W > BYTE_CNT_W) begin : m0_burstcount_zero_pad
|
||||
wire [AVS_BURSTCOUNT_W - BYTE_CNT_W - 1 : 0] zero_pad = {(AVS_BURSTCOUNT_W - BYTE_CNT_W) {1'b0}};
|
||||
assign m0_burstcount = (local_read & ~local_compressed_read) ?
|
||||
{zero_pad, num_symbols} :
|
||||
{zero_pad, cmd_byte_cnt};
|
||||
end
|
||||
else begin : m0_burstcount_no_pad
|
||||
assign m0_burstcount = (local_read & ~local_compressed_read) ?
|
||||
num_symbols[AVS_BURSTCOUNT_W-1:0] :
|
||||
cmd_byte_cnt[AVS_BURSTCOUNT_W-1:0];
|
||||
end
|
||||
endgenerate
|
||||
|
||||
assign m0_write = ready_for_command & local_write & !suppress_write;
|
||||
assign m0_lock = ready_for_command & local_lock & (m0_read | m0_write);
|
||||
assign m0_debugaccess = cmd_debugaccess;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Indirection layer for response packet values. Some may always wire
|
||||
// directly from the slave translator; others will no doubt emerge from
|
||||
// various FIFOs.
|
||||
// What to put in resp_data when a write occured? Answer: it does not
|
||||
// matter, because only response status is needed for non-posted writes,
|
||||
// and the packet already has a field for that.
|
||||
//
|
||||
// We use the rdata_fifo to store write responses as well. This allows us
|
||||
// to handle backpressure on the response path, and allows write response
|
||||
// merging.
|
||||
assign rdata_fifo_src_valid = m0_readdatavalid_q | m0_writeresponsevalid_q;
|
||||
assign rdata_fifo_src_data = {m0_response_q, m0_readdata_q};
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Generate a token when read commands are suppressed. The token
|
||||
// is stored in the response FIFO, and will be used to synthesize
|
||||
// a read response. The same token is used for non-posted write
|
||||
// response synthesis.
|
||||
//
|
||||
// Note: this token is not generated for suppressed uncompressed read cycles;
|
||||
// the burst uncompression logic at the read side of the response FIFO
|
||||
// generates the correct number of responses.
|
||||
//
|
||||
// When the slave can return the response, let it do its job. Don't
|
||||
// synthesize a response in that case, unless we've suppressed the
|
||||
// the last transfer in a write sub-burst.
|
||||
// ------------------------------------------------------------------
|
||||
wire write_end_of_subburst;
|
||||
assign needs_response_synthesis = ((local_read | local_compressed_read) & suppress_read) ||
|
||||
(!USE_WRITERESPONSE && nonposted_write_endofpacket) ||
|
||||
(USE_WRITERESPONSE && write_end_of_subburst && suppress_write);
|
||||
|
||||
// Avalon-ST interfaces to external response FIFO.
|
||||
//
|
||||
// For efficiency, when synthesizing a write response we only store a non-posted write
|
||||
// transaction at its endofpacket, even if it was split into multiple sub-bursts.
|
||||
//
|
||||
// When not synthesizing write responses, we store each sub-burst in the FIFO.
|
||||
// Each sub-burst to the slave will return a response, which corresponds to one
|
||||
// entry in the FIFO. We merge all the sub-burst responses on the final
|
||||
// sub-burst and send it on the response channel.
|
||||
|
||||
wire internal_cp_endofburst;
|
||||
wire [31:0] minimum_bytecount_wire = PKT_SYMBOLS; // to solve qis warning
|
||||
wire [AVS_BURSTCOUNT_W-1:0] minimum_bytecount;
|
||||
|
||||
assign minimum_bytecount = minimum_bytecount_wire[AVS_BURSTCOUNT_W-1:0];
|
||||
assign internal_cp_endofburst = (cmd_byte_cnt == minimum_bytecount);
|
||||
assign write_end_of_subburst = local_write & internal_cp_endofburst;
|
||||
|
||||
assign rf_source_valid = (local_read | local_compressed_read | (nonposted_write_endofpacket && !USE_WRITERESPONSE) | (USE_WRITERESPONSE && internal_cp_endofburst && local_write))
|
||||
& ready_for_command & cp_ready;
|
||||
assign rf_source_startofpacket = cp_startofpacket;
|
||||
assign rf_source_endofpacket = cp_endofpacket;
|
||||
always @* begin
|
||||
// default: assign every command packet field to the response FIFO...
|
||||
rf_source_data = {1'b0, cp_data};
|
||||
|
||||
// ... and override select fields as needed.
|
||||
rf_source_data[FIFO_DATA_W-1] = needs_response_synthesis;
|
||||
rf_source_data[PKT_DATA_H :PKT_DATA_L] = {DATA_W {1'b0}};
|
||||
rf_source_data[PKT_BYTEEN_H :PKT_BYTEEN_L] = cmd_byteen;
|
||||
rf_source_data[PKT_ADDR_H :PKT_ADDR_L] = cmd_addr;
|
||||
rf_source_data[PKT_TRANS_COMPRESSED_READ] = cmd_compressed;
|
||||
rf_source_data[PKT_TRANS_POSTED] = cmd_posted;
|
||||
rf_source_data[PKT_TRANS_WRITE] = cmd_write;
|
||||
rf_source_data[PKT_TRANS_READ] = cmd_read;
|
||||
rf_source_data[PKT_SRC_ID_H :PKT_SRC_ID_L] = cmd_mid;
|
||||
rf_source_data[PKT_DEST_ID_H:PKT_DEST_ID_L] = cmd_sid;
|
||||
rf_source_data[PKT_BYTE_CNT_H:PKT_BYTE_CNT_L] = cmd_byte_cnt;
|
||||
rf_source_data[PKT_BURSTWRAP_H:PKT_BURSTWRAP_L] = cmd_burstwrap;
|
||||
rf_source_data[PKT_BURST_SIZE_H:PKT_BURST_SIZE_L] = cmd_burstsize;
|
||||
rf_source_data[PKT_PROTECTION_H:PKT_PROTECTION_L] = '0;
|
||||
rf_source_data[PKT_PROTECTION_L] = cmd_debugaccess;
|
||||
end
|
||||
|
||||
wire uncompressor_source_valid;
|
||||
wire [BURSTSIZE_W-1:0] uncompressor_burstsize;
|
||||
wire last_write_response;
|
||||
|
||||
// last_write_response indicates the last response of the broken-up write burst (sub-bursts).
|
||||
// At this time, the final merged response is sent, and rp_valid is only asserted
|
||||
// once for the whole burst.
|
||||
generate
|
||||
if (USE_WRITERESPONSE) begin
|
||||
assign last_write_response = rf_sink_data[PKT_TRANS_WRITE] & rf_sink_endofpacket;
|
||||
always @* begin
|
||||
if (rf_sink_data[PKT_TRANS_WRITE] == 1)
|
||||
rp_valid = ((rdata_fifo_sink_valid | generate_response) & last_write_response & !rf_sink_data[PKT_TRANS_POSTED]);
|
||||
else
|
||||
rp_valid = (rdata_fifo_sink_valid | uncompressor_source_valid);
|
||||
end
|
||||
end else begin
|
||||
assign last_write_response = 1'b0;
|
||||
always @* begin
|
||||
rp_valid = (rdata_fifo_sink_valid | uncompressor_source_valid);
|
||||
end
|
||||
end
|
||||
endgenerate
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Response merging
|
||||
// ------------------------------------------------------------------
|
||||
reg [1:0] current_response;
|
||||
reg [1:0] response_merged;
|
||||
generate
|
||||
if (USE_WRITERESPONSE) begin : response_merging_all
|
||||
reg first_write_response;
|
||||
reg reset_merged_output;
|
||||
reg [1:0] previous_response_in;
|
||||
reg [1:0] previous_response;
|
||||
|
||||
|
||||
if (SYNC_RESET ==0 ) begin : async_reg0
|
||||
always_ff @(posedge clk, posedge reset) begin
|
||||
if (reset) begin
|
||||
first_write_response <= 1'b1;
|
||||
end
|
||||
else begin // Merging work for write response, for read: previous_response_in = current_response
|
||||
if (rf_sink_valid & (rdata_fifo_sink_valid | generate_response) & rf_sink_data[PKT_TRANS_WRITE]) begin
|
||||
first_write_response <= 1'b0;
|
||||
if (rf_sink_endofpacket)
|
||||
first_write_response <= 1'b1;
|
||||
end
|
||||
end
|
||||
end //@always_ff
|
||||
end // async_reg0
|
||||
|
||||
else begin :sync_reg0
|
||||
always_ff @(posedge clk) begin
|
||||
if (internal_sclr) begin
|
||||
first_write_response <= 1'b1;
|
||||
end
|
||||
else begin // Merging work for write response, for read: previous_response_in = current_response
|
||||
if (rf_sink_valid & (rdata_fifo_sink_valid | generate_response) & rf_sink_data[PKT_TRANS_WRITE]) begin
|
||||
first_write_response <= 1'b0;
|
||||
if (rf_sink_endofpacket)
|
||||
first_write_response <= 1'b1;
|
||||
end
|
||||
end
|
||||
end //@always_ff
|
||||
end // sync_reg0
|
||||
|
||||
always_comb begin
|
||||
current_response = generate_response ? 2'b00 : rdata_fifo_sink_data[AVS_DATA_W+1:AVS_DATA_W] | {2{rdata_fifo_sink_error}};
|
||||
reset_merged_output = first_write_response && (rdata_fifo_sink_valid || generate_response);
|
||||
previous_response_in = reset_merged_output ? current_response : previous_response;
|
||||
response_merged = current_response >= previous_response ? current_response: previous_response_in;
|
||||
end
|
||||
|
||||
if (SYNC_RESET == 0) begin : async_reg1
|
||||
|
||||
always_ff @(posedge clk or posedge reset) begin
|
||||
if (reset) begin
|
||||
previous_response <= 2'b00;
|
||||
end
|
||||
else begin
|
||||
if (rf_sink_valid & (rdata_fifo_sink_valid || generate_response)) begin
|
||||
previous_response <= response_merged;
|
||||
end
|
||||
end
|
||||
end
|
||||
end // async_reg1
|
||||
|
||||
else begin : sync_reg1
|
||||
always_ff @(posedge clk ) begin
|
||||
if (internal_sclr) begin
|
||||
previous_response <= 2'b00;
|
||||
end
|
||||
else begin
|
||||
if (rf_sink_valid & (rdata_fifo_sink_valid || generate_response)) begin
|
||||
previous_response <= response_merged;
|
||||
end
|
||||
end
|
||||
end
|
||||
end // sync_reg1
|
||||
|
||||
|
||||
end else begin : response_merging_read_only
|
||||
always @* begin
|
||||
current_response = generate_response ? 2'b00: rdata_fifo_sink_data[AVS_DATA_W+1:AVS_DATA_W] |
|
||||
{2{rdata_fifo_sink_error}};
|
||||
response_merged = current_response;
|
||||
end
|
||||
end
|
||||
endgenerate
|
||||
|
||||
assign generate_response = rf_sink_data[FIFO_DATA_W-1];
|
||||
|
||||
wire [BYTE_CNT_W-1:0] rf_sink_byte_cnt = rf_sink_data[PKT_BYTE_CNT_H:PKT_BYTE_CNT_L];
|
||||
wire rf_sink_compressed = rf_sink_data[PKT_TRANS_COMPRESSED_READ];
|
||||
wire [BURSTWRAP_W-1:0] rf_sink_burstwrap = rf_sink_data[PKT_BURSTWRAP_H:PKT_BURSTWRAP_L];
|
||||
wire [BURSTSIZE_W-1:0] rf_sink_burstsize = rf_sink_data[PKT_BURST_SIZE_H:PKT_BURST_SIZE_L];
|
||||
wire [ADDR_W-1:0] rf_sink_addr = rf_sink_data[PKT_ADDR_H:PKT_ADDR_L];
|
||||
// a non posted write response is always completed in 1 cycle. Modify the startofpacket signal to 1'b1 instead of taking whatever is in the rf_fifo
|
||||
wire rf_sink_startofpacket_wire = rf_sink_data[PKT_TRANS_WRITE] ? 1'b1 : rf_sink_startofpacket;
|
||||
|
||||
wire [BYTE_CNT_W-1:0] burst_byte_cnt;
|
||||
wire [BURSTWRAP_W-1:0] rp_burstwrap;
|
||||
wire [ADDR_W-1:0] rp_address;
|
||||
wire rp_is_compressed;
|
||||
wire ready_for_response;
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// We're typically ready for a response if the network is ready. There
|
||||
// is one exception:
|
||||
//
|
||||
// If the slave issues write responses, we only issue a merged response on
|
||||
// the final sub-burst. As a result, we only care about response channel
|
||||
// availability on the final burst when we send out the merged response.
|
||||
// ------------------------------------------------------------------
|
||||
assign ready_for_response = (USE_WRITERESPONSE) ?
|
||||
rp_ready || (rf_sink_data[PKT_TRANS_WRITE] && !last_write_response) || rf_sink_data[PKT_TRANS_POSTED]:
|
||||
rp_ready;
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Backpressure the readdata fifo if we're supposed to synthesize a response.
|
||||
// This may be a read response (for suppressed reads) or a write response
|
||||
// (for non-posted writes).
|
||||
// ------------------------------------------------------------------
|
||||
assign rdata_fifo_sink_ready = rdata_fifo_sink_valid & ready_for_response & ~(rf_sink_valid & generate_response);
|
||||
|
||||
always @* begin
|
||||
rp_data[PKT_AWATOP_H:PKT_AWATOP_L] = '0 ;
|
||||
rp_data[PKT_AWSTASHNID_H:PKT_AWSTASHNID_L] = '0 ;
|
||||
rp_data[PKT_AWSTASHNIDEN] = '0 ;
|
||||
rp_data[PKT_AWSTASHLPID_H:PKT_AWSTASHLPID_L] = '0 ;
|
||||
rp_data[PKT_AWSTASHLPIDEN] = '0 ;
|
||||
rp_data[PKT_MMUSECSID] = '0 ;
|
||||
rp_data[PKT_MMUSID_H:PKT_MMUSID_L] = '0 ;
|
||||
rp_data[PKT_DATALESS] = '0 ;
|
||||
|
||||
|
||||
// By default, return all fields...
|
||||
rp_data = rf_sink_data[ST_DATA_W - 1 : 0];
|
||||
|
||||
// ... and override specific fields.
|
||||
rp_data[PKT_DATA_H :PKT_DATA_L] = rdata_fifo_sink_data[AVS_DATA_W-1:0];
|
||||
// Assignments directly from the response fifo.
|
||||
rp_data[PKT_TRANS_POSTED] = rf_sink_data[PKT_TRANS_POSTED];
|
||||
rp_data[PKT_TRANS_WRITE] = rf_sink_data[PKT_TRANS_WRITE];
|
||||
rp_data[PKT_SRC_ID_H :PKT_SRC_ID_L] = rf_sink_data[PKT_DEST_ID_H : PKT_DEST_ID_L];
|
||||
rp_data[PKT_DEST_ID_H:PKT_DEST_ID_L] = rf_sink_data[PKT_SRC_ID_H : PKT_SRC_ID_L];
|
||||
rp_data[PKT_BYTEEN_H :PKT_BYTEEN_L] = rf_sink_data[PKT_BYTEEN_H : PKT_BYTEEN_L];
|
||||
rp_data[PKT_PROTECTION_H:PKT_PROTECTION_L] = rf_sink_data[PKT_PROTECTION_H:PKT_PROTECTION_L];
|
||||
|
||||
// Burst uncompressor assignments
|
||||
rp_data[PKT_ADDR_H :PKT_ADDR_L] = rp_address;
|
||||
rp_data[PKT_BURSTWRAP_H:PKT_BURSTWRAP_L] = rp_burstwrap;
|
||||
rp_data[PKT_BYTE_CNT_H:PKT_BYTE_CNT_L] = burst_byte_cnt;
|
||||
rp_data[PKT_TRANS_READ] = rf_sink_data[PKT_TRANS_READ] | rf_sink_data[PKT_TRANS_COMPRESSED_READ];
|
||||
rp_data[PKT_TRANS_COMPRESSED_READ] = rp_is_compressed;
|
||||
|
||||
rp_data[PKT_RESPONSE_STATUS_H:PKT_RESPONSE_STATUS_L] = response_merged;
|
||||
rp_data[PKT_BURST_SIZE_H:PKT_BURST_SIZE_L] = uncompressor_burstsize;
|
||||
// bounce the original size back to the master untouched
|
||||
rp_data[PKT_ORI_BURST_SIZE_H:PKT_ORI_BURST_SIZE_L] = rf_sink_data[PKT_ORI_BURST_SIZE_H:PKT_ORI_BURST_SIZE_L];
|
||||
|
||||
if (ROLE_BASED_USER || ENABLE_AXI5) begin
|
||||
if(USE_PKT_DATACHK == 0)
|
||||
rp_data[PKT_DATACHK_H:PKT_DATACHK_L] = calcParity(rdata_fifo_sink_data[AVS_DATA_W-1:0]);
|
||||
else
|
||||
rp_data[PKT_DATACHK_H:PKT_DATACHK_L] = '0;
|
||||
|
||||
rp_data[PKT_POISON_H:PKT_POISON_L] = '0;
|
||||
rp_data[PKT_SAI_H:PKT_SAI_L] = '0;
|
||||
end
|
||||
if (ROLE_BASED_USER) begin
|
||||
rp_data[PKT_ADDRCHK_H:PKT_ADDRCHK_L] = '0;
|
||||
rp_data[PKT_USER_DATA_H:PKT_USER_DATA_L] = '0;
|
||||
end
|
||||
if(ENABLE_AXI5) begin
|
||||
rp_data[PKT_TRACE] = '0;
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Note: the burst uncompressor may be asked to generate responses for
|
||||
// write packets; these are treated the same as single-cycle uncompressed
|
||||
// reads.
|
||||
// ------------------------------------------------------------------
|
||||
altera_merlin_burst_uncompressor #(
|
||||
.ADDR_W (ADDR_W),
|
||||
.BURSTWRAP_W (BURSTWRAP_W),
|
||||
.BYTE_CNT_W (BYTE_CNT_W),
|
||||
.PKT_SYMBOLS (PKT_SYMBOLS),
|
||||
.BURST_SIZE_W (BURSTSIZE_W),
|
||||
.SYNC_RESET (SYNC_RESET)
|
||||
) uncompressor (
|
||||
.clk (clk),
|
||||
.reset (reset),
|
||||
.sink_startofpacket (rf_sink_startofpacket_wire),
|
||||
.sink_endofpacket (rf_sink_endofpacket),
|
||||
.sink_valid ((rf_sink_valid & (rdata_fifo_sink_valid | generate_response))),
|
||||
.sink_ready (rf_sink_ready),
|
||||
.sink_addr (rf_sink_addr),
|
||||
.sink_burstwrap (rf_sink_burstwrap),
|
||||
.sink_byte_cnt (rf_sink_byte_cnt),
|
||||
.sink_is_compressed (rf_sink_compressed),
|
||||
.sink_burstsize (rf_sink_burstsize),
|
||||
|
||||
.source_startofpacket (rp_startofpacket),
|
||||
.source_endofpacket (rp_endofpacket),
|
||||
.source_valid (uncompressor_source_valid),
|
||||
.source_ready (ready_for_response),
|
||||
.source_addr (rp_address),
|
||||
.source_burstwrap (rp_burstwrap),
|
||||
.source_byte_cnt (burst_byte_cnt),
|
||||
.source_is_compressed (rp_is_compressed),
|
||||
.source_burstsize (uncompressor_burstsize)
|
||||
);
|
||||
|
||||
//--------------------------------------
|
||||
// Assertion: In case slave support response. The slave needs return response in order
|
||||
// Ex: non-posted write followed by a read: write response must complete before read data
|
||||
//--------------------------------------
|
||||
// synthesis translate_off
|
||||
ERROR_write_response_and_read_response_cannot_happen_same_time:
|
||||
assert property ( @(posedge clk)
|
||||
disable iff (reset) (reset === 0) |-> !(m0_writeresponsevalid_q && m0_readdatavalid_q)
|
||||
);
|
||||
// synthesis translate_on
|
||||
endmodule
|
||||
|
||||
|
||||
+383
@@ -0,0 +1,383 @@
|
||||
// (C) 2001-2026 Altera Corporation. All rights reserved.
|
||||
// Your use of Altera 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 Altera Program License Subscription
|
||||
// Agreement, Altera 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 Altera and sold by
|
||||
// Altera or its authorized distributors. Please refer to the applicable
|
||||
// agreement for further details.
|
||||
|
||||
|
||||
// (C) 2001-2017 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.
|
||||
|
||||
|
||||
// (C) 2001-2012 Altera Corporation. All rights reserved.
|
||||
// Your use of Altera Corporation's design tools, logic functions and other
|
||||
// software and tools, and its AMPP partner logic functions, and any output
|
||||
// files 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 Altera Program License Subscription
|
||||
// Agreement, Altera MegaCore Function License Agreement, or other applicable
|
||||
// license agreement, including, without limitation, that your use is for the
|
||||
// sole purpose of programming logic devices manufactured by Altera and sold by
|
||||
// Altera or its authorized distributors. Please refer to the applicable
|
||||
// agreement for further details.
|
||||
|
||||
|
||||
// $Id: //acds/rel/26.1/ip/iconnect/merlin/altera_merlin_slave_agent/altera_merlin_burst_uncompressor.sv#1 $
|
||||
// $Revision: #1 $
|
||||
// $Date: 2026/02/05 $
|
||||
|
||||
// ------------------------------------------
|
||||
// Merlin Burst Uncompressor
|
||||
//
|
||||
// Compressed read bursts -> uncompressed
|
||||
// ------------------------------------------
|
||||
|
||||
`timescale 1 ns / 1 ns
|
||||
|
||||
module altera_merlin_burst_uncompressor
|
||||
#(
|
||||
parameter ADDR_W = 16,
|
||||
parameter BURSTWRAP_W = 3,
|
||||
parameter BYTE_CNT_W = 4,
|
||||
parameter PKT_SYMBOLS = 4,
|
||||
parameter BURST_SIZE_W = 3,
|
||||
parameter SYNC_RESET = 0,
|
||||
parameter USED_IN_WIDTH_ADAPTER = 0
|
||||
)
|
||||
(
|
||||
input clk,
|
||||
input reset,
|
||||
|
||||
// sink ST signals
|
||||
input sink_startofpacket,
|
||||
input sink_endofpacket,
|
||||
input sink_valid,
|
||||
output sink_ready,
|
||||
|
||||
// sink ST "data"
|
||||
input [ADDR_W - 1: 0] sink_addr,
|
||||
input [BURSTWRAP_W - 1 : 0] sink_burstwrap,
|
||||
input [BYTE_CNT_W - 1 : 0] sink_byte_cnt,
|
||||
input sink_is_compressed,
|
||||
input [BURST_SIZE_W-1 : 0] sink_burstsize,
|
||||
|
||||
// source ST signals
|
||||
output source_startofpacket,
|
||||
output source_endofpacket,
|
||||
output source_valid,
|
||||
input source_ready,
|
||||
|
||||
// source ST "data"
|
||||
output [ADDR_W - 1: 0] source_addr,
|
||||
output [BURSTWRAP_W - 1 : 0] source_burstwrap,
|
||||
output [BYTE_CNT_W - 1 : 0] source_byte_cnt,
|
||||
|
||||
// Note: in the slave agent, the output should always be uncompressed. In
|
||||
// other applications, it may be required to leave-compressed or not. How to
|
||||
// control? Seems like a simple mux - pass-through if no uncompression is
|
||||
// required.
|
||||
output source_is_compressed,
|
||||
output [BURST_SIZE_W-1 : 0] source_burstsize
|
||||
);
|
||||
|
||||
//----------------------------------------------------
|
||||
// AXSIZE decoding
|
||||
//
|
||||
// Turns the axsize value into the actual number of bytes
|
||||
// being transferred.
|
||||
// ---------------------------------------------------
|
||||
function reg[63:0] bytes_in_transfer;
|
||||
input [BURST_SIZE_W-1:0] axsize;
|
||||
case (axsize)
|
||||
4'b0000: bytes_in_transfer = 64'b0000000000000000000000000000000000000000000000000000000000000001;
|
||||
4'b0001: bytes_in_transfer = 64'b0000000000000000000000000000000000000000000000000000000000000010;
|
||||
4'b0010: bytes_in_transfer = 64'b0000000000000000000000000000000000000000000000000000000000000100;
|
||||
4'b0011: bytes_in_transfer = 64'b0000000000000000000000000000000000000000000000000000000000001000;
|
||||
4'b0100: bytes_in_transfer = 64'b0000000000000000000000000000000000000000000000000000000000010000;
|
||||
4'b0101: bytes_in_transfer = 64'b0000000000000000000000000000000000000000000000000000000000100000;
|
||||
4'b0110: bytes_in_transfer = 64'b0000000000000000000000000000000000000000000000000000000001000000;
|
||||
4'b0111: bytes_in_transfer = 64'b0000000000000000000000000000000000000000000000000000000010000000;
|
||||
4'b1000: bytes_in_transfer = 64'b0000000000000000000000000000000000000000000000000000000100000000;
|
||||
4'b1001: bytes_in_transfer = 64'b0000000000000000000000000000000000000000000000000000001000000000;
|
||||
default:bytes_in_transfer = 64'b0000000000000000000000000000000000000000000000000000000000000001;
|
||||
endcase
|
||||
|
||||
endfunction
|
||||
|
||||
localparam LG_PKT_SYMBOLS = $clog2(PKT_SYMBOLS);
|
||||
|
||||
// num_symbols is PKT_SYMBOLS, appropriately sized.
|
||||
wire [31:0] int_num_symbols;
|
||||
if(USED_IN_WIDTH_ADAPTER)
|
||||
assign int_num_symbols = (|sink_burstsize) ? PKT_SYMBOLS:1;
|
||||
else
|
||||
assign int_num_symbols = PKT_SYMBOLS;
|
||||
wire [BYTE_CNT_W-1:0] num_symbols = int_num_symbols[BYTE_CNT_W-1:0];
|
||||
|
||||
// def: Burst Compression. In a merlin network, a compressed burst is one
|
||||
// which is transmitted in a single beat. Example: read burst. In
|
||||
// constrast, an uncompressed burst (example: write burst) is transmitted in
|
||||
// one beat per writedata item.
|
||||
//
|
||||
// For compressed bursts which require response packets, burst
|
||||
// uncompression is required. Concrete example: a read burst of size 8
|
||||
// occupies one response-fifo position. When that fifo position reaches the
|
||||
// front of the FIFO, the slave starts providing the required 8 readdatavalid
|
||||
// pulses. The 8 return response beats must be provided in a single packet,
|
||||
// with incrementing address and decrementing byte_cnt fields. Upon receipt
|
||||
// of the final readdata item of the burst, the response FIFO item is
|
||||
// retired.
|
||||
// Burst uncompression logic provides:
|
||||
// a) 2-state FSM (idle, busy)
|
||||
// reset to idle state
|
||||
// transition to busy state for 2nd and subsequent rdv pulses
|
||||
// - a single-cycle burst (aka non-burst read) causes no transition to
|
||||
// busy state.
|
||||
// b) response startofpacket/endofpacket logic. The response FIFO item
|
||||
// will have sop asserted, and may have eop asserted. (In the case of
|
||||
// multiple read bursts transmit in the command fabric in a single packet,
|
||||
// the eop assertion will come in a later FIFO item.) To support packet
|
||||
// conservation, and emit a well-formed packet on the response fabric,
|
||||
// i) response fabric startofpacket is asserted only for the first resp.
|
||||
// beat;
|
||||
// ii) response fabric endofpacket is asserted only for the last resp.
|
||||
// beat.
|
||||
// c) response address field. The response address field contains an
|
||||
// incrementing sequence, such that each readdata item is associated with
|
||||
// its slave-map location. N.b. a) computing the address correctly requires
|
||||
// knowledge of burstwrap behavior b) there may be no clients of the address
|
||||
// field, which makes this field a good target for optimization. See
|
||||
// burst_uncompress_address_counter below.
|
||||
// d) response byte_cnt field. The response byte_cnt field contains a
|
||||
// decrementing sequence, such that each beat of the response contains the
|
||||
// count of bytes to follow. In the case of sub-bursts in a single packet,
|
||||
// the byte_cnt field may decrement down to num_symbols, then back up to
|
||||
// some value, multiple times in the packet.
|
||||
|
||||
reg burst_uncompress_busy;
|
||||
reg [BYTE_CNT_W-1:0] burst_uncompress_byte_counter_lint;
|
||||
wire first_packet_beat;
|
||||
wire last_packet_beat;
|
||||
|
||||
assign first_packet_beat = sink_valid & ~burst_uncompress_busy;
|
||||
|
||||
always @ (posedge clk) begin
|
||||
if (source_valid & source_ready & sink_valid) begin
|
||||
if(burst_uncompress_busy) begin
|
||||
burst_uncompress_byte_counter_lint <= burst_uncompress_byte_counter_lint-num_symbols;
|
||||
end else begin
|
||||
burst_uncompress_byte_counter_lint <= sink_byte_cnt - num_symbols;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
// First cycle: burst_uncompress_byte_counter isn't ready yet, mux the input to
|
||||
// the output.
|
||||
assign source_byte_cnt =
|
||||
first_packet_beat ? sink_byte_cnt : burst_uncompress_byte_counter_lint;
|
||||
assign source_valid = sink_valid;
|
||||
|
||||
// Last packet beat is set throughout receipt of an uncompressed read burst
|
||||
// from the response FIFO - this forces all the burst uncompression machinery
|
||||
// idle.
|
||||
assign last_packet_beat = ~sink_is_compressed |
|
||||
(
|
||||
burst_uncompress_busy ?
|
||||
(sink_valid & (burst_uncompress_byte_counter_lint == num_symbols)) :
|
||||
sink_valid & (sink_byte_cnt == num_symbols)
|
||||
);
|
||||
|
||||
|
||||
// Generation of internal reset synchronization
|
||||
reg internal_sclr;
|
||||
generate if (SYNC_RESET == 1) begin : rst_syncronizer
|
||||
always @ (posedge clk) begin
|
||||
internal_sclr <= reset;
|
||||
end
|
||||
end
|
||||
endgenerate
|
||||
|
||||
generate
|
||||
if (SYNC_RESET == 0) begin : async_rst0
|
||||
always @(posedge clk or posedge reset) begin
|
||||
if (reset) begin
|
||||
burst_uncompress_busy <= '0;
|
||||
end
|
||||
else begin
|
||||
if (source_valid & source_ready & sink_valid) begin
|
||||
// No matter what the current state, last_packet_beat leads to
|
||||
// idle.
|
||||
if (last_packet_beat) begin
|
||||
burst_uncompress_busy <= '0;
|
||||
end
|
||||
else begin
|
||||
burst_uncompress_busy <= 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end // async_rst0
|
||||
else begin // sync_rst0
|
||||
always @(posedge clk ) begin
|
||||
if (internal_sclr) begin
|
||||
burst_uncompress_busy <= '0;
|
||||
end
|
||||
else begin
|
||||
if (source_valid & source_ready & sink_valid) begin
|
||||
// No matter what the current state, last_packet_beat leads to
|
||||
// idle.
|
||||
if (last_packet_beat) begin
|
||||
burst_uncompress_busy <= '0;
|
||||
end
|
||||
else begin
|
||||
burst_uncompress_busy <= 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end // sync_rst0
|
||||
endgenerate
|
||||
//always @ (posedge clk) begin
|
||||
// if (source_valid & source_ready & sink_valid) begin
|
||||
// // No matter what the current state, last_packet_beat leads to
|
||||
// // idle.
|
||||
// if (last_packet_beat) begin
|
||||
// burst_uncompress_byte_counter <= '0;
|
||||
// end
|
||||
// else begin
|
||||
// if (burst_uncompress_busy) begin
|
||||
// burst_uncompress_byte_counter <= (burst_uncompress_byte_counter > 0) ?
|
||||
// (burst_uncompress_byte_counter_lint[BYTE_CNT_W-1:LG_PKT_SYMBOLS] - num_symbols[BYTE_CNT_W-1:LG_PKT_SYMBOLS]) :
|
||||
// (sink_byte_cnt[BYTE_CNT_W-1:LG_PKT_SYMBOLS] - num_symbols[BYTE_CNT_W-1:LG_PKT_SYMBOLS]);
|
||||
// end
|
||||
// else begin // not busy, at least one more beat to go
|
||||
// burst_uncompress_byte_counter <= sink_byte_cnt[BYTE_CNT_W-1:LG_PKT_SYMBOLS] - num_symbols[BYTE_CNT_W-1:LG_PKT_SYMBOLS];
|
||||
// // To do: should busy go true for numsymbols-size compressed
|
||||
// // bursts?
|
||||
// end
|
||||
// end
|
||||
// end
|
||||
//end
|
||||
|
||||
|
||||
reg [ADDR_W - 1 : 0 ] burst_uncompress_address_base;
|
||||
reg [ADDR_W - 1 : 0] burst_uncompress_address_offset;
|
||||
|
||||
wire [63:0] decoded_burstsize_wire;
|
||||
wire [ADDR_W-1:0] decoded_burstsize;
|
||||
|
||||
|
||||
localparam ADD_BURSTWRAP_W = (ADDR_W > BURSTWRAP_W) ? ADDR_W : BURSTWRAP_W;
|
||||
wire [ADD_BURSTWRAP_W-1:0] addr_width_burstwrap;
|
||||
// The input burstwrap value can be used as a mask against address values,
|
||||
// but with one caveat: the address width may be (probably is) wider than
|
||||
// the burstwrap width. The spec says: extend the msb of the burstwrap
|
||||
// value out over the entire address width (but only if the address width
|
||||
// actually is wider than the burstwrap width; otherwise it's a 0-width or
|
||||
// negative range and concatenation multiplier).
|
||||
generate
|
||||
if (ADDR_W > BURSTWRAP_W) begin : addr_sign_extend
|
||||
// Sign-extend, just wires:
|
||||
assign addr_width_burstwrap[ADDR_W - 1 : BURSTWRAP_W] =
|
||||
{(ADDR_W - BURSTWRAP_W) {sink_burstwrap[BURSTWRAP_W - 1]}};
|
||||
assign addr_width_burstwrap[BURSTWRAP_W-1:0] = sink_burstwrap [BURSTWRAP_W-1:0];
|
||||
end
|
||||
else begin
|
||||
assign addr_width_burstwrap[BURSTWRAP_W-1 : 0] = sink_burstwrap;
|
||||
end
|
||||
endgenerate
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (first_packet_beat & source_ready) begin
|
||||
burst_uncompress_address_base <= sink_addr & ~addr_width_burstwrap[ADDR_W-1:0];
|
||||
end
|
||||
end
|
||||
|
||||
//always @(posedge clk or posedge reset) begin
|
||||
// if (reset) begin
|
||||
// burst_uncompress_address_base <= '0;
|
||||
// end
|
||||
// else if (first_packet_beat & source_ready) begin
|
||||
// burst_uncompress_address_base <= sink_addr & ~addr_width_burstwrap[ADDR_W-1:0];
|
||||
// end
|
||||
//end
|
||||
|
||||
assign decoded_burstsize_wire = bytes_in_transfer(sink_burstsize); //expand it to 64 bits
|
||||
assign decoded_burstsize = decoded_burstsize_wire[ADDR_W-1:0]; //then take the width that is needed
|
||||
|
||||
wire [ADDR_W : 0] p1_burst_uncompress_address_offset =
|
||||
(
|
||||
(first_packet_beat ?
|
||||
sink_addr :
|
||||
burst_uncompress_address_offset) + decoded_burstsize
|
||||
) &
|
||||
addr_width_burstwrap[ADDR_W-1:0];
|
||||
wire [ADDR_W-1:0] p1_burst_uncompress_address_offset_lint = p1_burst_uncompress_address_offset [ADDR_W-1:0];
|
||||
|
||||
always @ (posedge clk) begin
|
||||
if (source_ready & source_valid) begin
|
||||
burst_uncompress_address_offset <= p1_burst_uncompress_address_offset_lint;
|
||||
end
|
||||
end
|
||||
|
||||
//always @(posedge clk or posedge reset) begin
|
||||
// if (reset) begin
|
||||
// burst_uncompress_address_offset <= '0;
|
||||
// end
|
||||
// else begin
|
||||
// if (source_ready & source_valid) begin
|
||||
// burst_uncompress_address_offset <= p1_burst_uncompress_address_offset_lint;
|
||||
// // if (first_packet_beat) begin
|
||||
// // burst_uncompress_address_offset <=
|
||||
// // (sink_addr + num_symbols) & addr_width_burstwrap;
|
||||
// // end
|
||||
// // else begin
|
||||
// // burst_uncompress_address_offset <=
|
||||
// // (burst_uncompress_address_offset + num_symbols) & addr_width_burstwrap;
|
||||
// // end
|
||||
// end
|
||||
// end
|
||||
//end
|
||||
|
||||
// On the first packet beat, send the input address out unchanged,
|
||||
// while values are computed/registered for 2nd and subsequent beats.
|
||||
assign source_addr = first_packet_beat ? sink_addr :
|
||||
burst_uncompress_address_base | burst_uncompress_address_offset;
|
||||
assign source_burstwrap = sink_burstwrap;
|
||||
assign source_burstsize = sink_burstsize;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// A single (compressed) read burst will have sop/eop in the same beat.
|
||||
// A sequence of read sub-bursts emitted by a burst adapter in response to a
|
||||
// single read burst will have sop on the first sub-burst, eop on the last.
|
||||
// Assert eop only upon (sink_endofpacket & last_packet_beat) to preserve
|
||||
// packet conservation.
|
||||
assign source_startofpacket = sink_startofpacket & ~burst_uncompress_busy;
|
||||
assign source_endofpacket = sink_endofpacket & last_packet_beat;
|
||||
assign sink_ready = source_valid & source_ready & last_packet_beat;
|
||||
|
||||
// This is correct for the slave agent usage, but won't always be true in the
|
||||
// width adapter. To do: add an "please uncompress" input, and use it to
|
||||
// pass-through or modify, and set source_is_compressed accordingly.
|
||||
assign source_is_compressed = 1'b0;
|
||||
endmodule
|
||||
|
||||
`ifdef QUESTA_INTEL_OEM
|
||||
`pragma questa_oem_00 "mfufSZOYfNPxmSfS+FkCl32e9bHGnpakqHX1nHXvrhE4J6x8qGVCEAJRqHIBXSp/FcyWPq9/UmljeMey51E9VTMH3OCNEvZdEUSPU4/Vf6DgtU26zIfR3Ws2AtmUBXEHD5yEeHuHpEMedz5PLIdzFsBxJ/9OiyM+8A3UVG3icM2FQlZPfaXli71zX1obNH4Hi4tyLUZvYQoJv7xSQMqW1lxant16XP5C2V2aZfTOCZlTuVjbs7t2AvXR8qtB5hlO4OP16VPo84MCPLx2rVhD1zQQWJ7B8d/ZQxcAh23irlYM5PRXVl1hzM1E9XBSwTHX4GiaPXc8KI87MAd2OBRsTVzQ3ploJyDTJ/5iLBZk4lL6RD0/o7jVPAsAA+iYoLIntesrKlzmNSO+ripXoEhypWMwRKSzgZZBPMMElLmdGOVkBpdGTg8XYKHFaxXioKDrffXWH12N3vtI6NzFHQfH/h77pcm8kqSxGEZzefHKCpgRsohq+zmawBPnqIEaklf3w9TR8wCComgJoehSxSSU/SoZucGVczKi/zpxAaV1C3ZvnYRs6KS3lwnftursubOcnVc54fiBCNX0o2tUlOGUN0MZVEhCByjyP7/tDDYHyz9Dyh5CcvlQ1SlPiN2bmCdVaKBDuFQGfnNX4iqkFXbtpf7KyNk9EwAzMRwGegjRDAqiYGeKBW/CfOtS6SxSn5LnfJyo1DRPBwBMYeT9gTB/CrgMTgZ+I0tO5pLPCNfpzFfaADXjL2aK7Oohy9lgFxUbDj3q5P1aPR2PeEeAnnBI1Cr9zvzuR1DljqKvMOVADEKuTYRh0CnptFzPRonyrUW0ISqpzVm4wrGeiVIWDlOU8I0E1VOdTB5G/FOYL7Ebbu+trxrk1HrXg+BTlfLX2HGtuX4biBJX3qBsyXItz0GnbOPIyN3bm3ZPkveSN7/nVnoPqYgXI5x9ilgczDHvSqU9mbmxiKhhU+AFIaVHUSBECnzRd5E6E34UW/Cxs92veqD6Z3nxWZyIP4Xab517bXhz"
|
||||
`endif
|
||||
+841
@@ -0,0 +1,841 @@
|
||||
// (C) 2001-2026 Altera Corporation. All rights reserved.
|
||||
// Your use of Altera 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 Altera Program License Subscription
|
||||
// Agreement, Altera 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 Altera and sold by
|
||||
// Altera or its authorized distributors. Please refer to the applicable
|
||||
// agreement for further details.
|
||||
|
||||
|
||||
// (C) 2001-2011 Altera Corporation. All rights reserved.
|
||||
// Your use of Altera Corporation's design tools, logic functions and other
|
||||
// software and tools, and its AMPP partner logic functions, and any output
|
||||
// files 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 Altera Program License Subscription
|
||||
// Agreement, Altera MegaCore Function License Agreement, or other applicable
|
||||
// license agreement, including, without limitation, that your use is for the
|
||||
// sole purpose of programming logic devices manufactured by Altera and sold by
|
||||
// Altera or its authorized distributors. Please refer to the applicable
|
||||
// agreement for further details.
|
||||
|
||||
`timescale 1 ns / 1 ns
|
||||
|
||||
module qsys_top_altera_merlin_slave_agent_1930_jxauz3i
|
||||
#(
|
||||
// Packet parameters
|
||||
parameter PKT_BEGIN_BURST = 81,
|
||||
parameter PKT_DATA_H = 31,
|
||||
parameter PKT_DATA_L = 0,
|
||||
parameter PKT_SYMBOL_W = 8,
|
||||
parameter PKT_BYTEEN_H = 71,
|
||||
parameter PKT_BYTEEN_L = 68,
|
||||
parameter PKT_ADDR_H = 63,
|
||||
parameter PKT_ADDR_L = 32,
|
||||
parameter PKT_TRANS_LOCK = 87,
|
||||
parameter PKT_TRANS_COMPRESSED_READ = 67,
|
||||
parameter PKT_TRANS_POSTED = 66,
|
||||
parameter PKT_TRANS_WRITE = 65,
|
||||
parameter PKT_TRANS_READ = 64,
|
||||
parameter PKT_SRC_ID_H = 74,
|
||||
parameter PKT_SRC_ID_L = 72,
|
||||
parameter PKT_DEST_ID_H = 77,
|
||||
parameter PKT_DEST_ID_L = 75,
|
||||
parameter PKT_BURSTWRAP_H = 85,
|
||||
parameter PKT_BURSTWRAP_L = 82,
|
||||
parameter PKT_BYTE_CNT_H = 81,
|
||||
parameter PKT_BYTE_CNT_L = 78,
|
||||
parameter PKT_PROTECTION_H = 86,
|
||||
parameter PKT_PROTECTION_L = 86,
|
||||
parameter PKT_RESPONSE_STATUS_H = 89,
|
||||
parameter PKT_RESPONSE_STATUS_L = 88,
|
||||
parameter PKT_BURST_SIZE_H = 92,
|
||||
parameter PKT_BURST_SIZE_L = 90,
|
||||
parameter PKT_ORI_BURST_SIZE_L = 93,
|
||||
parameter PKT_ORI_BURST_SIZE_H = 95,
|
||||
parameter PKT_POISON_L = 97,
|
||||
parameter PKT_POISON_H = 97,
|
||||
parameter PKT_DATACHK_L = 98,
|
||||
parameter PKT_DATACHK_H = 98,
|
||||
parameter PKT_SAI_L = 99,
|
||||
parameter PKT_SAI_H = 99,
|
||||
parameter PKT_ADDRCHK_L = 100,
|
||||
parameter PKT_ADDRCHK_H = 100,
|
||||
parameter PKT_USER_DATA_L = 101,
|
||||
parameter PKT_USER_DATA_H = 101,
|
||||
parameter PKT_ATRACE = 102,
|
||||
parameter PKT_TRACE = 103,
|
||||
parameter PKT_AWAKEUP = 104,
|
||||
|
||||
//ACE5-Lite signals
|
||||
parameter PKT_AWATOP_L = 154,
|
||||
parameter PKT_AWATOP_H = 159,
|
||||
parameter PKT_AWSTASHNID_L = 160,
|
||||
parameter PKT_AWSTASHNID_H = 170,
|
||||
parameter PKT_AWSTASHNIDEN = 171,
|
||||
parameter PKT_AWSTASHLPID_L = 172,
|
||||
parameter PKT_AWSTASHLPID_H = 176,
|
||||
parameter PKT_AWSTASHLPIDEN = 177,
|
||||
parameter PKT_MMUSECSID = 178,
|
||||
parameter PKT_MMUSID_L = 179,
|
||||
parameter PKT_MMUSID_H = 195,
|
||||
parameter PKT_DATALESS = 196,
|
||||
|
||||
|
||||
parameter ST_DATA_W = 102,
|
||||
parameter ST_CHANNEL_W = 32,
|
||||
parameter ROLE_BASED_USER = 0,
|
||||
parameter ENABLE_AXI5 = 0,
|
||||
parameter SYNC_RESET = 0,
|
||||
|
||||
parameter USE_PKT_DATACHK = 1,
|
||||
|
||||
// Slave parameters
|
||||
parameter ADDR_W = PKT_ADDR_H - PKT_ADDR_L + 1,
|
||||
parameter AVS_DATA_W = PKT_DATA_H - PKT_DATA_L + 1,
|
||||
parameter AVS_BURSTCOUNT_W = 4,
|
||||
parameter PKT_SYMBOLS = AVS_DATA_W / PKT_SYMBOL_W,
|
||||
|
||||
// Slave agent parameters
|
||||
parameter USE_MEMORY_BLOCKS = 1,
|
||||
parameter PREVENT_FIFO_OVERFLOW = 0,
|
||||
parameter SUPPRESS_0_BYTEEN_CMD = 1,
|
||||
parameter USE_READRESPONSE = 0,
|
||||
parameter USE_WRITERESPONSE = 0,
|
||||
|
||||
// Derived slave parameters
|
||||
parameter AVS_BE_W = PKT_BYTEEN_H - PKT_BYTEEN_L + 1,
|
||||
parameter BURST_SIZE_W = 3,
|
||||
|
||||
// Derived FIFO width
|
||||
parameter FIFO_DATA_W = ST_DATA_W + 1,
|
||||
|
||||
// ECC parameter
|
||||
parameter ECC_ENABLE = 0
|
||||
) (
|
||||
input clk,
|
||||
input reset,
|
||||
|
||||
// Universal-Avalon anti-slave
|
||||
output [ADDR_W-1:0] m0_address,
|
||||
output [AVS_BURSTCOUNT_W-1:0] m0_burstcount,
|
||||
output [AVS_BE_W-1:0] m0_byteenable,
|
||||
output m0_read,
|
||||
input [AVS_DATA_W-1:0] m0_readdata,
|
||||
input m0_waitrequest,
|
||||
output m0_write,
|
||||
output [AVS_DATA_W-1:0] m0_writedata,
|
||||
input m0_readdatavalid,
|
||||
output m0_debugaccess,
|
||||
output m0_lock,
|
||||
input [1:0] m0_response,
|
||||
input m0_writeresponsevalid,
|
||||
|
||||
// Avalon-ST FIFO interfaces.
|
||||
// Note: there's no need to include the "data" field here, at least for
|
||||
// reads, since readdata is filled in from slave info. To keep life
|
||||
// simple, have a data field, but fill it with 0s.
|
||||
// Av-st response fifo source interface
|
||||
output reg [FIFO_DATA_W-1:0] rf_source_data,
|
||||
output rf_source_valid,
|
||||
output rf_source_startofpacket,
|
||||
output rf_source_endofpacket,
|
||||
input rf_source_ready,
|
||||
|
||||
// Av-st response fifo sink interface
|
||||
input [FIFO_DATA_W-1:0] rf_sink_data,
|
||||
input rf_sink_valid,
|
||||
input rf_sink_startofpacket,
|
||||
input rf_sink_endofpacket,
|
||||
output reg rf_sink_ready,
|
||||
|
||||
// Av-st readdata fifo src interface, data and response
|
||||
// extra 2 bits for storing RESPONSE STATUS
|
||||
output [AVS_DATA_W+1:0] rdata_fifo_src_data,
|
||||
output rdata_fifo_src_valid,
|
||||
input rdata_fifo_src_ready,
|
||||
|
||||
// Av-st readdata fifo sink interface
|
||||
input [AVS_DATA_W+1:0] rdata_fifo_sink_data,
|
||||
input rdata_fifo_sink_valid,
|
||||
output rdata_fifo_sink_ready,
|
||||
input rdata_fifo_sink_error,
|
||||
|
||||
// Av-st sink command packet interface
|
||||
output cp_ready,
|
||||
input cp_valid,
|
||||
input [ST_DATA_W-1:0] cp_data,
|
||||
input [ST_CHANNEL_W-1:0] cp_channel,
|
||||
input cp_startofpacket,
|
||||
input cp_endofpacket,
|
||||
|
||||
// Av-st source response packet interface
|
||||
input rp_ready,
|
||||
output reg rp_valid,
|
||||
output reg [ST_DATA_W-1:0] rp_data,
|
||||
output rp_startofpacket,
|
||||
output rp_endofpacket
|
||||
);
|
||||
// ------------------------------------------------
|
||||
// Local Parameters
|
||||
// ------------------------------------------------
|
||||
localparam DATA_W = PKT_DATA_H - PKT_DATA_L + 1;
|
||||
localparam BE_W = PKT_BYTEEN_H - PKT_BYTEEN_L + 1;
|
||||
localparam MID_W = PKT_SRC_ID_H - PKT_SRC_ID_L + 1;
|
||||
localparam SID_W = PKT_DEST_ID_H - PKT_DEST_ID_L + 1;
|
||||
localparam BYTE_CNT_W = PKT_BYTE_CNT_H - PKT_BYTE_CNT_L + 1;
|
||||
localparam BURSTWRAP_W = PKT_BURSTWRAP_H - PKT_BURSTWRAP_L + 1;
|
||||
localparam BURSTSIZE_W = PKT_BURST_SIZE_H - PKT_BURST_SIZE_L + 1;
|
||||
localparam BITS_TO_MASK = log2ceil(PKT_SYMBOLS);
|
||||
localparam MAX_BURST = 1 << (AVS_BURSTCOUNT_W - 1);
|
||||
localparam BURSTING = (MAX_BURST > PKT_SYMBOLS);
|
||||
localparam PKT_DATACHK_W = DATA_W/8;
|
||||
|
||||
// --------------------------------------------------
|
||||
// Ceil(log2()) function log2ceil of 4 = 2
|
||||
// --------------------------------------------------
|
||||
function integer log2ceil;
|
||||
input reg[63:0] val;
|
||||
reg [63:0] i;
|
||||
|
||||
begin
|
||||
i = 1;
|
||||
log2ceil = 0;
|
||||
|
||||
while (i < val) begin
|
||||
log2ceil = log2ceil + 1;
|
||||
i = i << 1;
|
||||
end
|
||||
end
|
||||
endfunction
|
||||
|
||||
// --------------------------------------------------
|
||||
// calcParity: calculates byte-level parity signal
|
||||
// --------------------------------------------------
|
||||
function reg [PKT_DATACHK_W-1:0] calcParity (
|
||||
input [DATA_W-1:0] data
|
||||
);
|
||||
for (int i=0; i<PKT_DATACHK_W; i++)
|
||||
calcParity[i] = ~(^ data[i*8 +:8]);
|
||||
endfunction
|
||||
|
||||
|
||||
// ------------------------------------------------
|
||||
// Signals
|
||||
// ------------------------------------------------
|
||||
wire [DATA_W-1:0] cmd_data;
|
||||
wire [BE_W-1:0] cmd_byteen;
|
||||
wire [ADDR_W-1:0] cmd_addr;
|
||||
wire [MID_W-1:0] cmd_mid;
|
||||
wire [SID_W-1:0] cmd_sid;
|
||||
wire cmd_read;
|
||||
wire cmd_write;
|
||||
wire cmd_compressed;
|
||||
wire cmd_posted;
|
||||
wire [BYTE_CNT_W-1:0] cmd_byte_cnt;
|
||||
wire [BURSTWRAP_W-1:0] cmd_burstwrap;
|
||||
wire [BURSTSIZE_W-1:0] cmd_burstsize;
|
||||
wire cmd_debugaccess;
|
||||
|
||||
wire suppress_cmd;
|
||||
wire byteen_asserted;
|
||||
wire suppress_read;
|
||||
wire suppress_write;
|
||||
wire needs_response_synthesis;
|
||||
wire generate_response;
|
||||
|
||||
//signals for additional latency due to different memory
|
||||
wire [AVS_DATA_W-1:0] m0_readdata_q;
|
||||
wire m0_readdatavalid_q;
|
||||
wire [1:0] m0_response_q;
|
||||
wire m0_writeresponsevalid_q;
|
||||
reg [AVS_DATA_W-1:0] m0_readdata_1;
|
||||
reg m0_readdatavalid_1;
|
||||
reg [1:0] m0_response_1;
|
||||
reg m0_writeresponsevalid_1;
|
||||
reg [AVS_DATA_W-1:0] m0_readdata_2;
|
||||
reg m0_readdatavalid_2;
|
||||
reg [1:0] m0_response_2;
|
||||
reg m0_writeresponsevalid_2;
|
||||
|
||||
// Assign command fields
|
||||
assign cmd_data = cp_data[PKT_DATA_H :PKT_DATA_L ];
|
||||
assign cmd_byteen = cp_data[PKT_BYTEEN_H:PKT_BYTEEN_L];
|
||||
assign cmd_addr = cp_data[PKT_ADDR_H :PKT_ADDR_L ];
|
||||
assign cmd_compressed = cp_data[PKT_TRANS_COMPRESSED_READ];
|
||||
assign cmd_posted = cp_data[PKT_TRANS_POSTED];
|
||||
assign cmd_write = cp_data[PKT_TRANS_WRITE];
|
||||
assign cmd_read = cp_data[PKT_TRANS_READ];
|
||||
assign cmd_mid = cp_data[PKT_SRC_ID_H :PKT_SRC_ID_L];
|
||||
assign cmd_sid = cp_data[PKT_DEST_ID_H:PKT_DEST_ID_L];
|
||||
assign cmd_byte_cnt = cp_data[PKT_BYTE_CNT_H:PKT_BYTE_CNT_L];
|
||||
assign cmd_burstwrap = cp_data[PKT_BURSTWRAP_H:PKT_BURSTWRAP_L];
|
||||
assign cmd_burstsize = cp_data[PKT_BURST_SIZE_H:PKT_BURST_SIZE_L];
|
||||
assign cmd_debugaccess = cp_data[PKT_PROTECTION_L];
|
||||
|
||||
// Local "ready_for_command" signal: deasserted when the agent is unable to accept
|
||||
// another command, e.g. rdv FIFO is full, (local readdata storage is full &&
|
||||
// ~rp_ready), ...
|
||||
// Say, this could depend on the type of command, for example, even if the
|
||||
// rdv FIFO is full, a write request can be accepted. For later.
|
||||
wire ready_for_command;
|
||||
|
||||
wire local_lock = cp_valid & cp_data[PKT_TRANS_LOCK];
|
||||
wire local_write = cp_valid & cp_data[PKT_TRANS_WRITE];
|
||||
wire local_read = cp_valid & cp_data[PKT_TRANS_READ];
|
||||
wire local_compressed_read = cp_valid & cp_data[PKT_TRANS_COMPRESSED_READ];
|
||||
wire nonposted_write_endofpacket = ~cp_data[PKT_TRANS_POSTED] & local_write & cp_endofpacket;
|
||||
|
||||
// num_symbols is PKT_SYMBOLS, appropriately sized.
|
||||
wire [31:0] int_num_symbols = PKT_SYMBOLS;
|
||||
wire [BYTE_CNT_W-1:0] num_symbols = int_num_symbols[BYTE_CNT_W-1:0];
|
||||
|
||||
// Generation of internal reset synchronization
|
||||
reg internal_sclr;
|
||||
generate if (SYNC_RESET == 1) begin : rst_syncronizer
|
||||
always @ (posedge clk) begin
|
||||
internal_sclr <= reset;
|
||||
end
|
||||
end
|
||||
endgenerate
|
||||
|
||||
generate
|
||||
if (SYNC_RESET ==0 ) begin : async0
|
||||
always_ff @(posedge clk, posedge reset) begin
|
||||
if (reset) begin
|
||||
m0_readdata_2 <= '0;
|
||||
m0_readdatavalid_2 <= '0;
|
||||
m0_response_2 <= '0;
|
||||
m0_writeresponsevalid_2 <= '0;
|
||||
end
|
||||
else begin
|
||||
m0_readdata_2 <= m0_readdata;
|
||||
m0_readdatavalid_2 <= m0_readdatavalid;
|
||||
m0_response_2 <= m0_response;
|
||||
m0_writeresponsevalid_2 <= m0_writeresponsevalid;
|
||||
end
|
||||
end //@always_ff
|
||||
end // async0
|
||||
|
||||
else begin :sync0
|
||||
always_ff @(posedge clk) begin
|
||||
if (internal_sclr) begin
|
||||
m0_readdata_2 <= '0;
|
||||
m0_readdatavalid_2 <= '0;
|
||||
m0_response_2 <= '0;
|
||||
m0_writeresponsevalid_2 <= '0;
|
||||
end
|
||||
else begin
|
||||
m0_readdata_2 <= m0_readdata;
|
||||
m0_readdatavalid_2 <= m0_readdatavalid;
|
||||
m0_response_2 <= m0_response;
|
||||
m0_writeresponsevalid_2 <= m0_writeresponsevalid;
|
||||
end
|
||||
end //@always_ff
|
||||
end // sync0
|
||||
endgenerate
|
||||
|
||||
generate
|
||||
if (SYNC_RESET ==0 ) begin : async1
|
||||
always_ff @(posedge clk, posedge reset) begin
|
||||
if (reset) begin
|
||||
m0_readdata_1 <= '0;
|
||||
m0_readdatavalid_1 <= '0;
|
||||
m0_response_1 <= '0;
|
||||
m0_writeresponsevalid_1 <= '0;
|
||||
end
|
||||
else begin
|
||||
m0_readdata_1 <= m0_readdata_2;
|
||||
m0_readdatavalid_1 <= m0_readdatavalid_2;
|
||||
m0_response_1 <= m0_response_2;
|
||||
m0_writeresponsevalid_1 <= m0_writeresponsevalid_2;
|
||||
end
|
||||
end //@always_ff
|
||||
end // async1
|
||||
|
||||
else begin :sync1
|
||||
always_ff @(posedge clk) begin
|
||||
if (internal_sclr) begin
|
||||
m0_readdata_1 <= '0;
|
||||
m0_readdatavalid_1 <= '0;
|
||||
m0_response_1 <= '0;
|
||||
m0_writeresponsevalid_1 <= '0;
|
||||
end
|
||||
else begin
|
||||
m0_readdata_1 <= m0_readdata_2;
|
||||
m0_readdatavalid_1 <= m0_readdatavalid_2;
|
||||
m0_response_1 <= m0_response_2;
|
||||
m0_writeresponsevalid_1 <= m0_writeresponsevalid_2;
|
||||
end
|
||||
end //@always_ff
|
||||
end // sync1
|
||||
endgenerate
|
||||
|
||||
|
||||
generate
|
||||
if (USE_MEMORY_BLOCKS) begin : Using_M20k_with_2_clk_latency
|
||||
assign m0_readdata_q = m0_readdata_1;
|
||||
assign m0_readdatavalid_q = m0_readdatavalid_1;
|
||||
assign m0_response_q = m0_response_1;
|
||||
assign m0_writeresponsevalid_q = m0_writeresponsevalid_1;
|
||||
end else begin : Using_ALM_memory_with_1_clk_latency
|
||||
assign m0_readdata_q = m0_readdata;
|
||||
assign m0_readdatavalid_q = m0_readdatavalid;
|
||||
assign m0_response_q = m0_response;
|
||||
assign m0_writeresponsevalid_q = m0_writeresponsevalid;
|
||||
end
|
||||
endgenerate
|
||||
|
||||
|
||||
|
||||
generate
|
||||
if (PREVENT_FIFO_OVERFLOW) begin : prevent_fifo_overflow_block
|
||||
// ---------------------------------------------------
|
||||
// Backpressure if the slave says to, or if FIFO overflow may occur.
|
||||
//
|
||||
// All commands are backpressured once the FIFO is full
|
||||
// even if they don't need storage. This breaks a long
|
||||
// combinatorial path from the master read/write through
|
||||
// this logic and back to the master via the backpressure
|
||||
// path.
|
||||
//
|
||||
// To avoid a loss of throughput the FIFO will be parameterized
|
||||
// one slot deeper. The extra slot should never be used in normal
|
||||
// operation, but should a slave misbehave and accept one more
|
||||
// read than it should then backpressure will kick in.
|
||||
//
|
||||
// An example: assume a slave with MPRT = 2. It can accept a
|
||||
// command sequence RRWW without backpressuring. If the FIFO is
|
||||
// only 2 deep, we'd backpressure the writes leading to loss of
|
||||
// throughput. If the FIFO is 3 deep, we'll only backpressure when
|
||||
// RRR... which is an illegal condition anyway.
|
||||
// ---------------------------------------------------
|
||||
|
||||
assign ready_for_command = rf_source_ready;
|
||||
assign cp_ready = (~m0_waitrequest | suppress_cmd) && ready_for_command;
|
||||
|
||||
end else begin : no_prevent_fifo_overflow_block
|
||||
|
||||
// Do not suppress the command or the slave will
|
||||
// not be able to waitrequest
|
||||
assign ready_for_command = 1'b1;
|
||||
// Backpressure only if the slave says to.
|
||||
assign cp_ready = ~m0_waitrequest | suppress_cmd;
|
||||
|
||||
end
|
||||
endgenerate
|
||||
|
||||
generate if (SUPPRESS_0_BYTEEN_CMD && !BURSTING) begin : suppress_0_byteen_cmd_non_bursting
|
||||
assign byteen_asserted = |cmd_byteen;
|
||||
assign suppress_read = ~byteen_asserted;
|
||||
assign suppress_write = ~byteen_asserted;
|
||||
assign suppress_cmd = ~byteen_asserted;
|
||||
end else if (SUPPRESS_0_BYTEEN_CMD && BURSTING) begin: suppress_0_byteen_cmd_bursting
|
||||
assign byteen_asserted = |cmd_byteen;
|
||||
assign suppress_read = ~byteen_asserted;
|
||||
assign suppress_write = 1'b0;
|
||||
assign suppress_cmd = ~byteen_asserted && cmd_read;
|
||||
end else begin : no_suppress_0_byteen_cmd
|
||||
assign suppress_read = 1'b0;
|
||||
assign suppress_write = 1'b0;
|
||||
assign suppress_cmd = 1'b0;
|
||||
end
|
||||
endgenerate
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Extract avalon signals from command packet.
|
||||
// -------------------------------------------------------------------
|
||||
// Mask off the lower bits of address.
|
||||
// The burst adapter before this component will break narrow sized packets
|
||||
// into sub-bursts of length 1. However, the packet addresses are preserved,
|
||||
// which means this component may see size-aligned addresses.
|
||||
//
|
||||
// Masking ensures that the addresses seen by an Avalon slave are aligned to
|
||||
// the full data width instead of the size.
|
||||
//
|
||||
// Example:
|
||||
// output from burst adapter (datawidth=4, size=2 bytes):
|
||||
// subburst1 addr=0, subburst2 addr=2, subburst3 addr=4, subburst4 addr=6
|
||||
// expected output from slave agent:
|
||||
// subburst1 addr=0, subburst2 addr=0, subburst3 addr=4, subburst4 addr=4
|
||||
generate
|
||||
if (BITS_TO_MASK > 0) begin : mask_address
|
||||
if(ADDR_W == BITS_TO_MASK)
|
||||
assign m0_address = { cmd_addr[ADDR_W-1:BITS_TO_MASK-1], {BITS_TO_MASK-1{1'b0}} };
|
||||
else
|
||||
assign m0_address = { cmd_addr[ADDR_W-1:BITS_TO_MASK], {BITS_TO_MASK{1'b0}} };
|
||||
|
||||
end else begin : no_mask_address
|
||||
|
||||
assign m0_address = cmd_addr;
|
||||
|
||||
end
|
||||
endgenerate
|
||||
|
||||
assign m0_byteenable = cmd_byteen;
|
||||
assign m0_writedata = cmd_data;
|
||||
|
||||
// Note: no Avalon-MM slave in existence accepts uncompressed read bursts -
|
||||
// this sort of burst exists only in merlin fabric ST packets. What to do
|
||||
// if we see such a burst? All beats in that burst need to be transmitted
|
||||
// to the slave so we have enough space-time for byteenable expression.
|
||||
//
|
||||
// There can be multiple bursts in a packet, but only one beat per burst
|
||||
// in <most> cases. The exception is when we've decided not to insert a
|
||||
// burst adapter for efficiency reasons, in which case this agent is also
|
||||
// responsible for driving burstcount to 1 on each beat of an uncompressed
|
||||
// read burst.
|
||||
|
||||
assign m0_read = ready_for_command & !suppress_read & (local_compressed_read | local_read);
|
||||
|
||||
generate
|
||||
// AVS_BURSTCOUNT_W and BYTE_CNT_W may not be equal. Assign m0_burstcount
|
||||
// from a sub-range, or 0-pad, as appropriate.
|
||||
if (AVS_BURSTCOUNT_W > BYTE_CNT_W) begin : m0_burstcount_zero_pad
|
||||
wire [AVS_BURSTCOUNT_W - BYTE_CNT_W - 1 : 0] zero_pad = {(AVS_BURSTCOUNT_W - BYTE_CNT_W) {1'b0}};
|
||||
assign m0_burstcount = (local_read & ~local_compressed_read) ?
|
||||
{zero_pad, num_symbols} :
|
||||
{zero_pad, cmd_byte_cnt};
|
||||
end
|
||||
else begin : m0_burstcount_no_pad
|
||||
assign m0_burstcount = (local_read & ~local_compressed_read) ?
|
||||
num_symbols[AVS_BURSTCOUNT_W-1:0] :
|
||||
cmd_byte_cnt[AVS_BURSTCOUNT_W-1:0];
|
||||
end
|
||||
endgenerate
|
||||
|
||||
assign m0_write = ready_for_command & local_write & !suppress_write;
|
||||
assign m0_lock = ready_for_command & local_lock & (m0_read | m0_write);
|
||||
assign m0_debugaccess = cmd_debugaccess;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Indirection layer for response packet values. Some may always wire
|
||||
// directly from the slave translator; others will no doubt emerge from
|
||||
// various FIFOs.
|
||||
// What to put in resp_data when a write occured? Answer: it does not
|
||||
// matter, because only response status is needed for non-posted writes,
|
||||
// and the packet already has a field for that.
|
||||
//
|
||||
// We use the rdata_fifo to store write responses as well. This allows us
|
||||
// to handle backpressure on the response path, and allows write response
|
||||
// merging.
|
||||
assign rdata_fifo_src_valid = m0_readdatavalid_q | m0_writeresponsevalid_q;
|
||||
assign rdata_fifo_src_data = {m0_response_q, m0_readdata_q};
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Generate a token when read commands are suppressed. The token
|
||||
// is stored in the response FIFO, and will be used to synthesize
|
||||
// a read response. The same token is used for non-posted write
|
||||
// response synthesis.
|
||||
//
|
||||
// Note: this token is not generated for suppressed uncompressed read cycles;
|
||||
// the burst uncompression logic at the read side of the response FIFO
|
||||
// generates the correct number of responses.
|
||||
//
|
||||
// When the slave can return the response, let it do its job. Don't
|
||||
// synthesize a response in that case, unless we've suppressed the
|
||||
// the last transfer in a write sub-burst.
|
||||
// ------------------------------------------------------------------
|
||||
wire write_end_of_subburst;
|
||||
assign needs_response_synthesis = ((local_read | local_compressed_read) & suppress_read) ||
|
||||
(!USE_WRITERESPONSE && nonposted_write_endofpacket) ||
|
||||
(USE_WRITERESPONSE && write_end_of_subburst && suppress_write);
|
||||
|
||||
// Avalon-ST interfaces to external response FIFO.
|
||||
//
|
||||
// For efficiency, when synthesizing a write response we only store a non-posted write
|
||||
// transaction at its endofpacket, even if it was split into multiple sub-bursts.
|
||||
//
|
||||
// When not synthesizing write responses, we store each sub-burst in the FIFO.
|
||||
// Each sub-burst to the slave will return a response, which corresponds to one
|
||||
// entry in the FIFO. We merge all the sub-burst responses on the final
|
||||
// sub-burst and send it on the response channel.
|
||||
|
||||
wire internal_cp_endofburst;
|
||||
wire [31:0] minimum_bytecount_wire = PKT_SYMBOLS; // to solve qis warning
|
||||
wire [AVS_BURSTCOUNT_W-1:0] minimum_bytecount;
|
||||
|
||||
assign minimum_bytecount = minimum_bytecount_wire[AVS_BURSTCOUNT_W-1:0];
|
||||
assign internal_cp_endofburst = (cmd_byte_cnt == minimum_bytecount);
|
||||
assign write_end_of_subburst = local_write & internal_cp_endofburst;
|
||||
|
||||
assign rf_source_valid = (local_read | local_compressed_read | (nonposted_write_endofpacket && !USE_WRITERESPONSE) | (USE_WRITERESPONSE && internal_cp_endofburst && local_write))
|
||||
& ready_for_command & cp_ready;
|
||||
assign rf_source_startofpacket = cp_startofpacket;
|
||||
assign rf_source_endofpacket = cp_endofpacket;
|
||||
always @* begin
|
||||
// default: assign every command packet field to the response FIFO...
|
||||
rf_source_data = {1'b0, cp_data};
|
||||
|
||||
// ... and override select fields as needed.
|
||||
rf_source_data[FIFO_DATA_W-1] = needs_response_synthesis;
|
||||
rf_source_data[PKT_DATA_H :PKT_DATA_L] = {DATA_W {1'b0}};
|
||||
rf_source_data[PKT_BYTEEN_H :PKT_BYTEEN_L] = cmd_byteen;
|
||||
rf_source_data[PKT_ADDR_H :PKT_ADDR_L] = cmd_addr;
|
||||
rf_source_data[PKT_TRANS_COMPRESSED_READ] = cmd_compressed;
|
||||
rf_source_data[PKT_TRANS_POSTED] = cmd_posted;
|
||||
rf_source_data[PKT_TRANS_WRITE] = cmd_write;
|
||||
rf_source_data[PKT_TRANS_READ] = cmd_read;
|
||||
rf_source_data[PKT_SRC_ID_H :PKT_SRC_ID_L] = cmd_mid;
|
||||
rf_source_data[PKT_DEST_ID_H:PKT_DEST_ID_L] = cmd_sid;
|
||||
rf_source_data[PKT_BYTE_CNT_H:PKT_BYTE_CNT_L] = cmd_byte_cnt;
|
||||
rf_source_data[PKT_BURSTWRAP_H:PKT_BURSTWRAP_L] = cmd_burstwrap;
|
||||
rf_source_data[PKT_BURST_SIZE_H:PKT_BURST_SIZE_L] = cmd_burstsize;
|
||||
rf_source_data[PKT_PROTECTION_H:PKT_PROTECTION_L] = '0;
|
||||
rf_source_data[PKT_PROTECTION_L] = cmd_debugaccess;
|
||||
end
|
||||
|
||||
wire uncompressor_source_valid;
|
||||
wire [BURSTSIZE_W-1:0] uncompressor_burstsize;
|
||||
wire last_write_response;
|
||||
|
||||
// last_write_response indicates the last response of the broken-up write burst (sub-bursts).
|
||||
// At this time, the final merged response is sent, and rp_valid is only asserted
|
||||
// once for the whole burst.
|
||||
generate
|
||||
if (USE_WRITERESPONSE) begin
|
||||
assign last_write_response = rf_sink_data[PKT_TRANS_WRITE] & rf_sink_endofpacket;
|
||||
always @* begin
|
||||
if (rf_sink_data[PKT_TRANS_WRITE] == 1)
|
||||
rp_valid = ((rdata_fifo_sink_valid | generate_response) & last_write_response & !rf_sink_data[PKT_TRANS_POSTED]);
|
||||
else
|
||||
rp_valid = (rdata_fifo_sink_valid | uncompressor_source_valid);
|
||||
end
|
||||
end else begin
|
||||
assign last_write_response = 1'b0;
|
||||
always @* begin
|
||||
rp_valid = (rdata_fifo_sink_valid | uncompressor_source_valid);
|
||||
end
|
||||
end
|
||||
endgenerate
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Response merging
|
||||
// ------------------------------------------------------------------
|
||||
reg [1:0] current_response;
|
||||
reg [1:0] response_merged;
|
||||
generate
|
||||
if (USE_WRITERESPONSE) begin : response_merging_all
|
||||
reg first_write_response;
|
||||
reg reset_merged_output;
|
||||
reg [1:0] previous_response_in;
|
||||
reg [1:0] previous_response;
|
||||
|
||||
|
||||
if (SYNC_RESET ==0 ) begin : async_reg0
|
||||
always_ff @(posedge clk, posedge reset) begin
|
||||
if (reset) begin
|
||||
first_write_response <= 1'b1;
|
||||
end
|
||||
else begin // Merging work for write response, for read: previous_response_in = current_response
|
||||
if (rf_sink_valid & (rdata_fifo_sink_valid | generate_response) & rf_sink_data[PKT_TRANS_WRITE]) begin
|
||||
first_write_response <= 1'b0;
|
||||
if (rf_sink_endofpacket)
|
||||
first_write_response <= 1'b1;
|
||||
end
|
||||
end
|
||||
end //@always_ff
|
||||
end // async_reg0
|
||||
|
||||
else begin :sync_reg0
|
||||
always_ff @(posedge clk) begin
|
||||
if (internal_sclr) begin
|
||||
first_write_response <= 1'b1;
|
||||
end
|
||||
else begin // Merging work for write response, for read: previous_response_in = current_response
|
||||
if (rf_sink_valid & (rdata_fifo_sink_valid | generate_response) & rf_sink_data[PKT_TRANS_WRITE]) begin
|
||||
first_write_response <= 1'b0;
|
||||
if (rf_sink_endofpacket)
|
||||
first_write_response <= 1'b1;
|
||||
end
|
||||
end
|
||||
end //@always_ff
|
||||
end // sync_reg0
|
||||
|
||||
always_comb begin
|
||||
current_response = generate_response ? 2'b00 : rdata_fifo_sink_data[AVS_DATA_W+1:AVS_DATA_W] | {2{rdata_fifo_sink_error}};
|
||||
reset_merged_output = first_write_response && (rdata_fifo_sink_valid || generate_response);
|
||||
previous_response_in = reset_merged_output ? current_response : previous_response;
|
||||
response_merged = current_response >= previous_response ? current_response: previous_response_in;
|
||||
end
|
||||
|
||||
if (SYNC_RESET == 0) begin : async_reg1
|
||||
|
||||
always_ff @(posedge clk or posedge reset) begin
|
||||
if (reset) begin
|
||||
previous_response <= 2'b00;
|
||||
end
|
||||
else begin
|
||||
if (rf_sink_valid & (rdata_fifo_sink_valid || generate_response)) begin
|
||||
previous_response <= response_merged;
|
||||
end
|
||||
end
|
||||
end
|
||||
end // async_reg1
|
||||
|
||||
else begin : sync_reg1
|
||||
always_ff @(posedge clk ) begin
|
||||
if (internal_sclr) begin
|
||||
previous_response <= 2'b00;
|
||||
end
|
||||
else begin
|
||||
if (rf_sink_valid & (rdata_fifo_sink_valid || generate_response)) begin
|
||||
previous_response <= response_merged;
|
||||
end
|
||||
end
|
||||
end
|
||||
end // sync_reg1
|
||||
|
||||
|
||||
end else begin : response_merging_read_only
|
||||
always @* begin
|
||||
current_response = generate_response ? 2'b00: rdata_fifo_sink_data[AVS_DATA_W+1:AVS_DATA_W] |
|
||||
{2{rdata_fifo_sink_error}};
|
||||
response_merged = current_response;
|
||||
end
|
||||
end
|
||||
endgenerate
|
||||
|
||||
assign generate_response = rf_sink_data[FIFO_DATA_W-1];
|
||||
|
||||
wire [BYTE_CNT_W-1:0] rf_sink_byte_cnt = rf_sink_data[PKT_BYTE_CNT_H:PKT_BYTE_CNT_L];
|
||||
wire rf_sink_compressed = rf_sink_data[PKT_TRANS_COMPRESSED_READ];
|
||||
wire [BURSTWRAP_W-1:0] rf_sink_burstwrap = rf_sink_data[PKT_BURSTWRAP_H:PKT_BURSTWRAP_L];
|
||||
wire [BURSTSIZE_W-1:0] rf_sink_burstsize = rf_sink_data[PKT_BURST_SIZE_H:PKT_BURST_SIZE_L];
|
||||
wire [ADDR_W-1:0] rf_sink_addr = rf_sink_data[PKT_ADDR_H:PKT_ADDR_L];
|
||||
// a non posted write response is always completed in 1 cycle. Modify the startofpacket signal to 1'b1 instead of taking whatever is in the rf_fifo
|
||||
wire rf_sink_startofpacket_wire = rf_sink_data[PKT_TRANS_WRITE] ? 1'b1 : rf_sink_startofpacket;
|
||||
|
||||
wire [BYTE_CNT_W-1:0] burst_byte_cnt;
|
||||
wire [BURSTWRAP_W-1:0] rp_burstwrap;
|
||||
wire [ADDR_W-1:0] rp_address;
|
||||
wire rp_is_compressed;
|
||||
wire ready_for_response;
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// We're typically ready for a response if the network is ready. There
|
||||
// is one exception:
|
||||
//
|
||||
// If the slave issues write responses, we only issue a merged response on
|
||||
// the final sub-burst. As a result, we only care about response channel
|
||||
// availability on the final burst when we send out the merged response.
|
||||
// ------------------------------------------------------------------
|
||||
assign ready_for_response = (USE_WRITERESPONSE) ?
|
||||
rp_ready || (rf_sink_data[PKT_TRANS_WRITE] && !last_write_response) || rf_sink_data[PKT_TRANS_POSTED]:
|
||||
rp_ready;
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Backpressure the readdata fifo if we're supposed to synthesize a response.
|
||||
// This may be a read response (for suppressed reads) or a write response
|
||||
// (for non-posted writes).
|
||||
// ------------------------------------------------------------------
|
||||
assign rdata_fifo_sink_ready = rdata_fifo_sink_valid & ready_for_response & ~(rf_sink_valid & generate_response);
|
||||
|
||||
always @* begin
|
||||
rp_data[PKT_AWATOP_H:PKT_AWATOP_L] = '0 ;
|
||||
rp_data[PKT_AWSTASHNID_H:PKT_AWSTASHNID_L] = '0 ;
|
||||
rp_data[PKT_AWSTASHNIDEN] = '0 ;
|
||||
rp_data[PKT_AWSTASHLPID_H:PKT_AWSTASHLPID_L] = '0 ;
|
||||
rp_data[PKT_AWSTASHLPIDEN] = '0 ;
|
||||
rp_data[PKT_MMUSECSID] = '0 ;
|
||||
rp_data[PKT_MMUSID_H:PKT_MMUSID_L] = '0 ;
|
||||
rp_data[PKT_DATALESS] = '0 ;
|
||||
|
||||
|
||||
// By default, return all fields...
|
||||
rp_data = rf_sink_data[ST_DATA_W - 1 : 0];
|
||||
|
||||
// ... and override specific fields.
|
||||
rp_data[PKT_DATA_H :PKT_DATA_L] = rdata_fifo_sink_data[AVS_DATA_W-1:0];
|
||||
// Assignments directly from the response fifo.
|
||||
rp_data[PKT_TRANS_POSTED] = rf_sink_data[PKT_TRANS_POSTED];
|
||||
rp_data[PKT_TRANS_WRITE] = rf_sink_data[PKT_TRANS_WRITE];
|
||||
rp_data[PKT_SRC_ID_H :PKT_SRC_ID_L] = rf_sink_data[PKT_DEST_ID_H : PKT_DEST_ID_L];
|
||||
rp_data[PKT_DEST_ID_H:PKT_DEST_ID_L] = rf_sink_data[PKT_SRC_ID_H : PKT_SRC_ID_L];
|
||||
rp_data[PKT_BYTEEN_H :PKT_BYTEEN_L] = rf_sink_data[PKT_BYTEEN_H : PKT_BYTEEN_L];
|
||||
rp_data[PKT_PROTECTION_H:PKT_PROTECTION_L] = rf_sink_data[PKT_PROTECTION_H:PKT_PROTECTION_L];
|
||||
|
||||
// Burst uncompressor assignments
|
||||
rp_data[PKT_ADDR_H :PKT_ADDR_L] = rp_address;
|
||||
rp_data[PKT_BURSTWRAP_H:PKT_BURSTWRAP_L] = rp_burstwrap;
|
||||
rp_data[PKT_BYTE_CNT_H:PKT_BYTE_CNT_L] = burst_byte_cnt;
|
||||
rp_data[PKT_TRANS_READ] = rf_sink_data[PKT_TRANS_READ] | rf_sink_data[PKT_TRANS_COMPRESSED_READ];
|
||||
rp_data[PKT_TRANS_COMPRESSED_READ] = rp_is_compressed;
|
||||
|
||||
rp_data[PKT_RESPONSE_STATUS_H:PKT_RESPONSE_STATUS_L] = response_merged;
|
||||
rp_data[PKT_BURST_SIZE_H:PKT_BURST_SIZE_L] = uncompressor_burstsize;
|
||||
// bounce the original size back to the master untouched
|
||||
rp_data[PKT_ORI_BURST_SIZE_H:PKT_ORI_BURST_SIZE_L] = rf_sink_data[PKT_ORI_BURST_SIZE_H:PKT_ORI_BURST_SIZE_L];
|
||||
|
||||
if (ROLE_BASED_USER || ENABLE_AXI5) begin
|
||||
if(USE_PKT_DATACHK == 0)
|
||||
rp_data[PKT_DATACHK_H:PKT_DATACHK_L] = calcParity(rdata_fifo_sink_data[AVS_DATA_W-1:0]);
|
||||
else
|
||||
rp_data[PKT_DATACHK_H:PKT_DATACHK_L] = '0;
|
||||
|
||||
rp_data[PKT_POISON_H:PKT_POISON_L] = '0;
|
||||
rp_data[PKT_SAI_H:PKT_SAI_L] = '0;
|
||||
end
|
||||
if (ROLE_BASED_USER) begin
|
||||
rp_data[PKT_ADDRCHK_H:PKT_ADDRCHK_L] = '0;
|
||||
rp_data[PKT_USER_DATA_H:PKT_USER_DATA_L] = '0;
|
||||
end
|
||||
if(ENABLE_AXI5) begin
|
||||
rp_data[PKT_TRACE] = '0;
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Note: the burst uncompressor may be asked to generate responses for
|
||||
// write packets; these are treated the same as single-cycle uncompressed
|
||||
// reads.
|
||||
// ------------------------------------------------------------------
|
||||
altera_merlin_burst_uncompressor #(
|
||||
.ADDR_W (ADDR_W),
|
||||
.BURSTWRAP_W (BURSTWRAP_W),
|
||||
.BYTE_CNT_W (BYTE_CNT_W),
|
||||
.PKT_SYMBOLS (PKT_SYMBOLS),
|
||||
.BURST_SIZE_W (BURSTSIZE_W),
|
||||
.SYNC_RESET (SYNC_RESET)
|
||||
) uncompressor (
|
||||
.clk (clk),
|
||||
.reset (reset),
|
||||
.sink_startofpacket (rf_sink_startofpacket_wire),
|
||||
.sink_endofpacket (rf_sink_endofpacket),
|
||||
.sink_valid ((rf_sink_valid & (rdata_fifo_sink_valid | generate_response))),
|
||||
.sink_ready (rf_sink_ready),
|
||||
.sink_addr (rf_sink_addr),
|
||||
.sink_burstwrap (rf_sink_burstwrap),
|
||||
.sink_byte_cnt (rf_sink_byte_cnt),
|
||||
.sink_is_compressed (rf_sink_compressed),
|
||||
.sink_burstsize (rf_sink_burstsize),
|
||||
|
||||
.source_startofpacket (rp_startofpacket),
|
||||
.source_endofpacket (rp_endofpacket),
|
||||
.source_valid (uncompressor_source_valid),
|
||||
.source_ready (ready_for_response),
|
||||
.source_addr (rp_address),
|
||||
.source_burstwrap (rp_burstwrap),
|
||||
.source_byte_cnt (burst_byte_cnt),
|
||||
.source_is_compressed (rp_is_compressed),
|
||||
.source_burstsize (uncompressor_burstsize)
|
||||
);
|
||||
|
||||
//--------------------------------------
|
||||
// Assertion: In case slave support response. The slave needs return response in order
|
||||
// Ex: non-posted write followed by a read: write response must complete before read data
|
||||
//--------------------------------------
|
||||
// synthesis translate_off
|
||||
ERROR_write_response_and_read_response_cannot_happen_same_time:
|
||||
assert property ( @(posedge clk)
|
||||
disable iff (reset) (reset === 0) |-> !(m0_writeresponsevalid_q && m0_readdatavalid_q)
|
||||
);
|
||||
// synthesis translate_on
|
||||
endmodule
|
||||
|
||||
|
||||
Reference in New Issue
Block a user