1207 lines
56 KiB
Systemverilog
1207 lines
56 KiB
Systemverilog
// (C) 2001-2015 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/15.1/ip/merlin/altera_merlin_width_adapter/altera_merlin_width_adapter.sv#1 $
|
|
// $Revision: #1 $
|
|
// $Date: 2015/08/09 $
|
|
// $Author: swbranch $
|
|
|
|
// -----------------------------------------------------
|
|
// Merlin Width Adapter
|
|
// -----------------------------------------------------
|
|
|
|
`timescale 1 ns / 1 ns
|
|
|
|
module altera_merlin_width_adapter
|
|
#(
|
|
parameter IN_PKT_ADDR_L = 0,
|
|
parameter IN_PKT_ADDR_H = 31,
|
|
parameter IN_PKT_DATA_L = 32,
|
|
parameter IN_PKT_DATA_H = 63,
|
|
parameter IN_PKT_BYTEEN_L = 64,
|
|
parameter IN_PKT_BYTEEN_H = 67,
|
|
parameter IN_PKT_TRANS_COMPRESSED_READ = 72,
|
|
parameter IN_PKT_BYTE_CNT_L = 73,
|
|
parameter IN_PKT_BYTE_CNT_H = 77,
|
|
parameter IN_PKT_BURSTWRAP_L = 78,
|
|
parameter IN_PKT_BURSTWRAP_H = 82,
|
|
parameter IN_PKT_BURST_SIZE_L = 83,
|
|
parameter IN_PKT_BURST_SIZE_H = 85,
|
|
parameter IN_PKT_RESPONSE_STATUS_L = 86,
|
|
parameter IN_PKT_RESPONSE_STATUS_H = 87,
|
|
parameter IN_PKT_TRANS_EXCLUSIVE = 88,
|
|
parameter IN_PKT_BURST_TYPE_L = 89,
|
|
parameter IN_PKT_BURST_TYPE_H = 90,
|
|
parameter IN_PKT_ORI_BURST_SIZE_L = 91,
|
|
parameter IN_PKT_ORI_BURST_SIZE_H = 93,
|
|
parameter IN_PKT_TRANS_WRITE = 94,
|
|
parameter IN_ST_DATA_W = 110,
|
|
|
|
parameter OUT_PKT_ADDR_L = 0,
|
|
parameter OUT_PKT_ADDR_H = 31,
|
|
parameter OUT_PKT_DATA_L = 32,
|
|
parameter OUT_PKT_DATA_H = 47,
|
|
parameter OUT_PKT_BYTEEN_L = 48,
|
|
parameter OUT_PKT_BYTEEN_H = 49,
|
|
parameter OUT_PKT_TRANS_COMPRESSED_READ = 54,
|
|
parameter OUT_PKT_BYTE_CNT_L = 55,
|
|
parameter OUT_PKT_BYTE_CNT_H = 59,
|
|
parameter OUT_PKT_BURST_SIZE_L = 60,
|
|
parameter OUT_PKT_BURST_SIZE_H = 62,
|
|
parameter OUT_PKT_RESPONSE_STATUS_L = 63,
|
|
parameter OUT_PKT_RESPONSE_STATUS_H = 64,
|
|
parameter OUT_PKT_TRANS_EXCLUSIVE = 65,
|
|
parameter OUT_PKT_BURST_TYPE_L = 66,
|
|
parameter OUT_PKT_BURST_TYPE_H = 67,
|
|
parameter OUT_PKT_ORI_BURST_SIZE_L = 68,
|
|
parameter OUT_PKT_ORI_BURST_SIZE_H = 70,
|
|
parameter OUT_ST_DATA_W = 92,
|
|
|
|
parameter ST_CHANNEL_W = 32,
|
|
parameter OPTIMIZE_FOR_RSP = 0,
|
|
|
|
parameter PACKING = 1, // 1: Enables packing in Avalon systems
|
|
parameter CONSTANT_BURST_SIZE = 1, // 1: Optimizes for Avalon-only systems as those always have full size transactions
|
|
parameter RESPONSE_PATH = 0, // 0: This adapter is on command path, 1: This adapter is on response path
|
|
|
|
// Address alignment can be turned off (an optimisation) if all connected
|
|
// masters only issue aligned addresses.
|
|
parameter ENABLE_ADDRESS_ALIGNMENT = 1
|
|
)
|
|
(
|
|
input clk,
|
|
input reset,
|
|
output reg in_ready,
|
|
input in_valid,
|
|
input [ST_CHANNEL_W-1:0] in_channel,
|
|
input [IN_ST_DATA_W-1:0] in_data,
|
|
input in_startofpacket,
|
|
input in_endofpacket,
|
|
input out_ready,
|
|
output reg out_valid,
|
|
output reg [ST_CHANNEL_W-1:0] out_channel,
|
|
output reg [OUT_ST_DATA_W-1:0] out_data,
|
|
output reg out_startofpacket,
|
|
output reg out_endofpacket,
|
|
|
|
input [2:0] in_command_size_data
|
|
);
|
|
|
|
// ------------------------------------------------------------
|
|
// Local Parameters
|
|
// ------------------------------------------------------------
|
|
localparam IN_NUMSYMBOLS = IN_PKT_BYTEEN_H - IN_PKT_BYTEEN_L + 1;
|
|
localparam IN_DATA_W = IN_PKT_DATA_H - IN_PKT_DATA_L + 1;
|
|
localparam IN_BYTEEN_W = IN_NUMSYMBOLS;
|
|
|
|
localparam OUT_NUMSYMBOLS = OUT_PKT_BYTEEN_H - OUT_PKT_BYTEEN_L + 1;
|
|
localparam OUT_DATA_W = OUT_PKT_DATA_H - OUT_PKT_DATA_L + 1;
|
|
localparam OUT_BYTEEN_W = OUT_NUMSYMBOLS;
|
|
|
|
localparam BURST_TYPE_W = IN_PKT_BURST_TYPE_H - IN_PKT_BURST_TYPE_L + 1;
|
|
localparam BURST_SIZE_W = IN_PKT_BURST_SIZE_H - IN_PKT_BURST_SIZE_L + 1;
|
|
localparam RESPONSE_STATUS_W = IN_PKT_RESPONSE_STATUS_H - IN_PKT_RESPONSE_STATUS_L + 1;
|
|
localparam SYMBOL_W = IN_DATA_W / IN_NUMSYMBOLS;
|
|
localparam ADDRESS_W = IN_PKT_ADDR_H - IN_PKT_ADDR_L + 1;
|
|
localparam BYTE_CNT_W = IN_PKT_BYTE_CNT_H - IN_PKT_BYTE_CNT_L + 1;
|
|
localparam OUT_BYTE_CNT_W = OUT_PKT_BYTE_CNT_H - OUT_PKT_BYTE_CNT_L + 1;
|
|
localparam BWRAP_W = IN_PKT_BURSTWRAP_H - IN_PKT_BURSTWRAP_L + 1;
|
|
localparam SIZE_W = 2 ** BURST_SIZE_W;
|
|
|
|
localparam RATIO = (IN_NUMSYMBOLS > OUT_NUMSYMBOLS ?
|
|
IN_NUMSYMBOLS / OUT_NUMSYMBOLS :
|
|
OUT_NUMSYMBOLS / IN_NUMSYMBOLS );
|
|
localparam WIDE_NUMSYMBOLS = (IN_NUMSYMBOLS > OUT_NUMSYMBOLS ?
|
|
IN_NUMSYMBOLS : OUT_NUMSYMBOLS );
|
|
localparam WIDE_DATA = (IN_NUMSYMBOLS > OUT_NUMSYMBOLS ?
|
|
IN_DATA_W - (OUT_NUMSYMBOLS*SYMBOL_W) :
|
|
OUT_DATA_W - (IN_NUMSYMBOLS*SYMBOL_W));
|
|
localparam OUT_SEGMENT_W = OUT_NUMSYMBOLS * SYMBOL_W;
|
|
|
|
localparam NW_BITFORSELECT_R = clogb2(IN_NUMSYMBOLS);
|
|
localparam NW_BITFORSELECT_L = clogb2(OUT_NUMSYMBOLS) - 1;
|
|
localparam ALIGNED_BITS_L = clogb2(OUT_NUMSYMBOLS) - 1;
|
|
localparam WN_ADDR_LSBS = clogb2(RATIO);
|
|
localparam WN_ADDR_SELECT = clogb2(IN_NUMSYMBOLS);
|
|
localparam LOG_OUT_NUMSYMBOLS = clogb2(OUT_NUMSYMBOLS);
|
|
|
|
// ------------------------------------------------------------
|
|
// Utility Functions
|
|
// ------------------------------------------------------------
|
|
|
|
function integer clogb2;
|
|
input [63:0] value;
|
|
begin
|
|
clogb2 = 0;
|
|
while (value>0) begin
|
|
value = value >> 1;
|
|
clogb2 = clogb2 + 1;
|
|
end
|
|
clogb2 = clogb2 - 1;
|
|
end
|
|
endfunction // clogb2
|
|
|
|
function integer min;
|
|
input [31:0] a;
|
|
input [31:0] b;
|
|
begin
|
|
return (a < b) ? a : b;
|
|
end
|
|
endfunction
|
|
|
|
function integer max;
|
|
input [31:0] a;
|
|
input [31:0] b;
|
|
begin
|
|
return (a > b) ? a : b;
|
|
end
|
|
endfunction
|
|
|
|
function reg [clogb2(RATIO)-1:0] mask_to_select_correct_segments_for_size;
|
|
input [clogb2(RATIO)-1:0] select_output_segment;
|
|
input [9:0] size_ratio;
|
|
input int msb_select_bit;
|
|
|
|
integer i;
|
|
mask_to_select_correct_segments_for_size = '1;
|
|
for (i=0; i < msb_select_bit; i = i +1'b1 ) begin
|
|
if (clogb2(size_ratio) > i)
|
|
mask_to_select_correct_segments_for_size[i] = select_output_segment[i];
|
|
end
|
|
endfunction
|
|
|
|
function reg [ADDRESS_W-1:0] choose_packed_address_base_on_size;
|
|
input [9:0] size_ratio;
|
|
input int msb_select_bit;
|
|
|
|
integer i;
|
|
choose_packed_address_base_on_size = '1;
|
|
for (i=0; i < msb_select_bit; i = i +1'b1 ) begin
|
|
if (clogb2(size_ratio) > i)
|
|
choose_packed_address_base_on_size[i + NW_BITFORSELECT_R] = 1'b0;
|
|
end
|
|
endfunction
|
|
|
|
// ------------------------------------------------------------
|
|
// Computes how many bytes are in this transfer, based on the size
|
|
// encoding.
|
|
// ------------------------------------------------------------
|
|
function reg[9:0] bytes_in_transfer;
|
|
input [BURST_SIZE_W-1:0] axsize;
|
|
|
|
case (axsize)
|
|
4'b0000: bytes_in_transfer = 10'b0000000001;
|
|
4'b0001: bytes_in_transfer = 10'b0000000010;
|
|
4'b0010: bytes_in_transfer = 10'b0000000100;
|
|
4'b0011: bytes_in_transfer = 10'b0000001000;
|
|
4'b0100: bytes_in_transfer = 10'b0000010000;
|
|
4'b0101: bytes_in_transfer = 10'b0000100000;
|
|
4'b0110: bytes_in_transfer = 10'b0001000000;
|
|
4'b0111: bytes_in_transfer = 10'b0010000000;
|
|
4'b1000: bytes_in_transfer = 10'b0100000000;
|
|
4'b1001: bytes_in_transfer = 10'b1000000000;
|
|
default: bytes_in_transfer = 10'b0000000001;
|
|
endcase
|
|
|
|
endfunction
|
|
|
|
// ------------------------------------------------------------
|
|
// Pseudo-field Parameters
|
|
//
|
|
// The width adapter widens the data and byteenable fields in the
|
|
// output packet, thus changing the output packet format. By using
|
|
// pseudo-fields, we can avoid remapping each individual field to
|
|
// the output, which is a non-scalable solution.
|
|
//
|
|
// How? Assume the packet format is { FIRST, byteen, MID, data, LAST },
|
|
// where byteen and data positions are interchangeable. FIRST, MID and
|
|
// LAST are pseudo-fields that represent the collection of fields in
|
|
// those positions.
|
|
//
|
|
// Not all the pseudo-fields may exist for a given packet format. A
|
|
// non-existent field has reversed indices, so we have to be careful
|
|
// when using them.
|
|
// ------------------------------------------------------------
|
|
|
|
localparam IN_FIRST_L = 0,
|
|
IN_FIRST_H = min(IN_PKT_BYTEEN_L, IN_PKT_DATA_L) - 1,
|
|
IN_MID_L = min(IN_PKT_DATA_H, IN_PKT_BYTEEN_H) + 1,
|
|
IN_MID_H = max(IN_PKT_DATA_L, IN_PKT_BYTEEN_L) - 1,
|
|
IN_LAST_L = max(IN_PKT_BYTEEN_H, IN_PKT_DATA_H) + 1,
|
|
IN_LAST_H = IN_ST_DATA_W - 1,
|
|
|
|
FIRST_EXISTS = (IN_FIRST_H >= IN_FIRST_L),
|
|
MID_EXISTS = (IN_MID_H >= IN_MID_L),
|
|
LAST_EXISTS = (IN_LAST_H >= IN_LAST_L),
|
|
|
|
FIRST_W = IN_FIRST_H - IN_FIRST_L + 1,
|
|
MID_W = IN_MID_H - IN_MID_L + 1,
|
|
LAST_W = IN_LAST_H - IN_LAST_L + 1,
|
|
|
|
// -------------------------------------------------
|
|
// We cannot split the output map into generate blocks as we
|
|
// do for the inputs because address and size are mapped over
|
|
// the pseudo-fields. We ensure that the indices are always
|
|
// legal, even if the field is unused later on.
|
|
|
|
OUT_FIRST_L = 0,
|
|
OUT_FIRST_H = FIRST_EXISTS ?
|
|
min(OUT_PKT_BYTEEN_L, OUT_PKT_DATA_L) - 1 :
|
|
OUT_FIRST_L,
|
|
OUT_MID_L = min(OUT_PKT_DATA_H, OUT_PKT_BYTEEN_H) + 1,
|
|
OUT_MID_H = MID_EXISTS ?
|
|
max(OUT_PKT_DATA_L, OUT_PKT_BYTEEN_L) - 1 :
|
|
OUT_MID_L,
|
|
OUT_LAST_L = max(OUT_PKT_BYTEEN_H, OUT_PKT_DATA_H) + 1,
|
|
OUT_LAST_H = LAST_EXISTS ?
|
|
OUT_ST_DATA_W - 1 :
|
|
OUT_LAST_L;
|
|
|
|
// ------------------------------------------------------------
|
|
// Signals
|
|
// ------------------------------------------------------------
|
|
reg [BURST_SIZE_W-1:0] in_size_field;
|
|
reg [IN_DATA_W-1:0] in_data_field;
|
|
reg [IN_BYTEEN_W-1:0] in_byteen_field;
|
|
reg [ADDRESS_W-1:0] in_address_field;
|
|
reg [ADDRESS_W-1:0] address_from_packet;
|
|
reg [BYTE_CNT_W-1:0] in_byte_cnt_field;
|
|
reg [BWRAP_W-1:0] in_burstwrap_field;
|
|
reg [RESPONSE_STATUS_W-1:0] in_response_status_field;
|
|
reg in_cmpr_read;
|
|
reg in_lock_field;
|
|
reg in_write;
|
|
reg [BURST_TYPE_W-1:0] in_burst_type_field;
|
|
reg [BYTE_CNT_W-1:0] quantized_byte_cnt_field;
|
|
|
|
reg [BURST_SIZE_W-1:0] out_size_field;
|
|
reg [OUT_DATA_W-1:0] out_data_field;
|
|
reg [OUT_BYTEEN_W-1:0] out_byteen_field;
|
|
reg [ADDRESS_W-1:0] out_address_field;
|
|
reg out_cmpr_read;
|
|
reg [BYTE_CNT_W-1:0] out_byte_cnt_field;
|
|
reg out_lock_field;
|
|
reg [BURST_TYPE_W-1:0] out_burst_type_field;
|
|
reg [RESPONSE_STATUS_W-1:0] out_response_status_field;
|
|
|
|
reg [FIRST_W-1:0] in_first_field;
|
|
reg [FIRST_W-1:0] out_first_field;
|
|
reg [MID_W-1:0] in_mid_field;
|
|
reg [MID_W-1:0] out_mid_field;
|
|
reg [LAST_W-1:0] in_last_field;
|
|
reg [LAST_W-1:0] out_last_field;
|
|
|
|
reg [WIDE_DATA-1:0] data_reg;
|
|
reg [WIDE_NUMSYMBOLS-1:0] byteen_reg;
|
|
reg [ADDRESS_W-1:0] address_reg;
|
|
reg [BYTE_CNT_W-1:0] byte_cnt_reg;
|
|
reg use_reg;
|
|
reg startofpacket_reg;
|
|
reg endofpacket_reg;
|
|
reg [OUT_SEGMENT_W-1:0] mask;
|
|
reg [RESPONSE_STATUS_W-1:0] response_status_reg;
|
|
|
|
|
|
reg [ADDRESS_W-1:0] int_output_sel;
|
|
reg [clogb2(RATIO)-1:0] output_sel;
|
|
reg [OUT_SEGMENT_W-1:0] data_array [0:RATIO-1];
|
|
reg [OUT_NUMSYMBOLS-1:0] byteen_array [0:RATIO-1];
|
|
|
|
// In narrow-to-wide adaptation, each input datum/byteenable bit maps to
|
|
// one of OUT_NUMSYMBOLS/IN_NUMSYMBOLS subfields in the wider output
|
|
// packet. (Call these subfields "segments".) A subfield of the input
|
|
// address, in_bitforselect, selects the segment. Examples:
|
|
// 8-16 adaptation: in_bitforselect = in_address_field[0]
|
|
// 8-32 adaptation: in_bitforselect = in_address_field[1:0]
|
|
// 8-64 adaptation: in_bitforselect = in_address_field[2:0]
|
|
// 16-32 adaptation: in_bitforselect = in_address_field[1]
|
|
// 32-64 adaptation: in_bitforselect = in_address_field[2]
|
|
|
|
// The width of in_bitforselect is
|
|
// log2(OUT_NUM_SYMBOLS) - log2(IN_NUM_SYMBOLS) =
|
|
// log2(RATIO)
|
|
|
|
// The msb of in_bitforselect is driven by
|
|
// in_adress_field[log2(OUT_NUMSYMBOLS) - 1]
|
|
// The lsb of in_adress_field is driven by
|
|
// in_adress_field[log2(IN_NUMSYMBOLS)]
|
|
|
|
|
|
reg [clogb2(RATIO)-1:0] in_bitforselect;
|
|
integer i, j;
|
|
|
|
// ----------------------------------------
|
|
// Input Field Mapping
|
|
// ----------------------------------------
|
|
reg [ADDRESS_W-1:0] address_for_adaptation;
|
|
always @* begin
|
|
in_size_field = in_data[IN_PKT_BURST_SIZE_H :IN_PKT_BURST_SIZE_L ];
|
|
in_data_field = in_data[IN_PKT_DATA_H :IN_PKT_DATA_L ];
|
|
in_byteen_field = in_data[IN_PKT_BYTEEN_H :IN_PKT_BYTEEN_L ];
|
|
address_from_packet = in_data[IN_PKT_ADDR_H :IN_PKT_ADDR_L ];
|
|
in_byte_cnt_field = in_data[IN_PKT_BYTE_CNT_H :IN_PKT_BYTE_CNT_L ];
|
|
in_cmpr_read = in_data[IN_PKT_TRANS_COMPRESSED_READ];
|
|
in_write = in_data[IN_PKT_TRANS_WRITE];
|
|
in_lock_field = in_data[IN_PKT_TRANS_EXCLUSIVE];
|
|
in_burst_type_field = in_data[IN_PKT_BURST_TYPE_H :IN_PKT_BURST_TYPE_L ];
|
|
in_response_status_field = in_data[IN_PKT_RESPONSE_STATUS_H :IN_PKT_RESPONSE_STATUS_L];
|
|
end
|
|
|
|
// ----------------------------------------
|
|
// Process unaligned address for first address of the burst
|
|
// ----------------------------------------
|
|
generate
|
|
if (IN_NUMSYMBOLS > OUT_NUMSYMBOLS && ENABLE_ADDRESS_ALIGNMENT) begin
|
|
reg [ADDRESS_W + (BWRAP_W-1) + BURST_SIZE_W + BURST_TYPE_W - 1 :0] address_for_alignment;
|
|
reg [ADDRESS_W + clogb2(IN_NUMSYMBOLS)-1:0] address_after_aligned;
|
|
|
|
assign address_for_alignment = {address_from_packet, in_size_field};
|
|
assign address_for_adaptation = address_after_aligned[ADDRESS_W-1:0];
|
|
|
|
altera_merlin_address_alignment
|
|
#(
|
|
.ADDR_W (ADDRESS_W),
|
|
.BURSTWRAP_W (BWRAP_W),
|
|
.INCREMENT_ADDRESS (0),
|
|
.NUMSYMBOLS (IN_NUMSYMBOLS),
|
|
.SIZE_W (BURST_SIZE_W)
|
|
) check_and_align_address_to_size
|
|
(
|
|
.clk (clk),
|
|
.reset (reset),
|
|
.in_data (address_for_alignment),
|
|
.out_data (address_after_aligned),
|
|
.in_valid (),
|
|
.in_sop (),
|
|
.in_eop (),
|
|
.out_ready ()
|
|
);
|
|
end else begin
|
|
assign address_for_adaptation = address_from_packet;
|
|
end
|
|
endgenerate
|
|
|
|
generate begin
|
|
if (FIRST_EXISTS) begin
|
|
always @* begin
|
|
in_first_field = in_data[IN_FIRST_H:IN_FIRST_L];
|
|
end
|
|
end else begin
|
|
always @* begin
|
|
in_first_field = '0;
|
|
end
|
|
end
|
|
if (MID_EXISTS) begin
|
|
always @* begin
|
|
in_mid_field = in_data[IN_MID_H:IN_MID_L];
|
|
end
|
|
end else begin
|
|
always @* begin
|
|
in_mid_field = '0;
|
|
end
|
|
end
|
|
if (LAST_EXISTS) begin
|
|
always @* begin
|
|
in_last_field = in_data[IN_LAST_H:IN_LAST_L];
|
|
end
|
|
end
|
|
end
|
|
endgenerate
|
|
|
|
generate
|
|
|
|
//-------------------------------------------------------
|
|
//-------------------------------------------------------
|
|
// Wide-to-Narrow
|
|
//
|
|
// For every input cycle, we drive out a bunch'o'output
|
|
// cycles. Nothing fancier. Yes, it could be more
|
|
// optimal, but we'll leave that for another day.
|
|
//-------------------------------------------------------
|
|
//-------------------------------------------------------
|
|
if (IN_NUMSYMBOLS > OUT_NUMSYMBOLS) begin
|
|
|
|
wire [31:0] cmd_burst_size = CONSTANT_BURST_SIZE ? IN_NUMSYMBOLS : bytes_in_transfer(in_size_field);
|
|
|
|
// Below mess is just to avoid Quartus warnings about mis-sized assignments.
|
|
wire [31:0] int_out_numsymbols = OUT_NUMSYMBOLS;
|
|
wire [clogb2(OUT_NUMSYMBOLS):0] sized_out_numsymbols = int_out_numsymbols[clogb2(OUT_NUMSYMBOLS):0];
|
|
|
|
wire [31:0] int_out_size = (cmd_burst_size < OUT_NUMSYMBOLS) ? cmd_burst_size : OUT_NUMSYMBOLS;
|
|
wire [SIZE_W-1:0] sized_out_size = int_out_size[SIZE_W-1:0];
|
|
|
|
wire [31:0] int_ratio_minus_1 = (cmd_burst_size / OUT_NUMSYMBOLS) - 1;
|
|
wire [clogb2(RATIO)-1:0] sized_ratio_minus_1 = int_ratio_minus_1[clogb2(RATIO)-1:0];
|
|
|
|
wire [31:0] int_log2_out_numsymbols = clogb2(OUT_NUMSYMBOLS);
|
|
wire [BURST_SIZE_W-1:0] log2_out_numsymbols = int_log2_out_numsymbols[BURST_SIZE_W-1:0];
|
|
|
|
wire [31:0] int_byte_cnt_factor = (in_size_field < log2_out_numsymbols) ? log2_out_numsymbols : in_size_field;
|
|
wire [BURST_SIZE_W-1:0] sized_byte_cnt_factor = int_byte_cnt_factor[BURST_SIZE_W-1:0];
|
|
|
|
reg single_response_expected;
|
|
reg only_one_segment_asserted;
|
|
reg [RATIO-1:0] segments_with_be_asserted;
|
|
reg [clogb2(RATIO)-1:0] count;
|
|
|
|
assign single_response_expected = (RESPONSE_PATH && ((only_one_segment_asserted && in_startofpacket && in_endofpacket) || in_write));
|
|
|
|
always @(posedge clk, posedge reset) begin
|
|
if (reset) begin
|
|
address_reg <= '0;
|
|
byte_cnt_reg <= '0;
|
|
count <= '0;
|
|
use_reg <= '0;
|
|
endofpacket_reg <= '0;
|
|
data_reg <= '0;
|
|
byteen_reg <= '0;
|
|
end else begin
|
|
// If we're not working on a wide datum,
|
|
// then wait until one arrives.
|
|
if (~use_reg) begin
|
|
|
|
if (CONSTANT_BURST_SIZE) begin // when the system contains ONLY Avalon masters and slaves
|
|
address_reg[ADDRESS_W -1 : WN_ADDR_SELECT] <= in_address_field[ADDRESS_W -1 : WN_ADDR_SELECT];
|
|
address_reg[WN_ADDR_SELECT - 1 : 0] <= sized_out_numsymbols;
|
|
data_reg <= in_data_field[IN_DATA_W-1:OUT_NUMSYMBOLS*SYMBOL_W];
|
|
byteen_reg <= in_byteen_field >> OUT_NUMSYMBOLS;
|
|
byte_cnt_reg <= in_byte_cnt_field - sized_out_numsymbols;
|
|
end else begin
|
|
address_reg <= in_address_field + sized_out_size;
|
|
byte_cnt_reg <= (in_byte_cnt_field >> clogb2(IN_NUMSYMBOLS) << sized_byte_cnt_factor) - sized_out_numsymbols;
|
|
end
|
|
|
|
endofpacket_reg <= in_endofpacket;
|
|
|
|
if (in_valid && out_ready && !in_cmpr_read && (cmd_burst_size > OUT_NUMSYMBOLS) && !single_response_expected) begin
|
|
// Data has arrived!
|
|
count <= sized_ratio_minus_1;
|
|
use_reg <= 1'b1;
|
|
end
|
|
|
|
end else begin // if (count == 0)
|
|
// We have a wide datum in progress. Just wait until
|
|
// the previous datum is taken, and then set
|
|
// up the next transfer.
|
|
if (out_ready) begin
|
|
if (CONSTANT_BURST_SIZE) begin
|
|
address_reg[ADDRESS_W -1 : WN_ADDR_SELECT] <= in_address_field[ADDRESS_W -1 : WN_ADDR_SELECT];
|
|
address_reg[WN_ADDR_SELECT - 1 : 0] <= address_reg[WN_ADDR_SELECT - 1 : 0] + sized_out_numsymbols;
|
|
data_reg <= data_reg >> (OUT_NUMSYMBOLS * SYMBOL_W);
|
|
byteen_reg <= byteen_reg >> (OUT_NUMSYMBOLS);
|
|
end else begin
|
|
address_reg <= address_reg + sized_out_size;
|
|
end
|
|
byte_cnt_reg <= byte_cnt_reg - sized_out_numsymbols;
|
|
count <= count - 1'b1;
|
|
if (count == 1'b1)
|
|
// We're at the end of this word.
|
|
use_reg <= '0;
|
|
|
|
end // if (out_ready)
|
|
end // else: !if(count == 0)
|
|
end // if (posedge clk)
|
|
end // always @ (clk, reset)
|
|
|
|
|
|
always @* begin
|
|
// Calculate in_ready.
|
|
// If count is 0, then we don't have data underway, and we
|
|
// definitely won't be ready for it the first time 'round.
|
|
// If count is '1', then we're finishing a set, and we're
|
|
// ready if the output is.
|
|
// If count > 1, then we're mid set, and certainly
|
|
// not ready.
|
|
in_ready = 0;
|
|
if ( (cmd_burst_size <= OUT_NUMSYMBOLS) || count == 1 || in_cmpr_read )
|
|
in_ready = out_ready;
|
|
|
|
out_valid = in_valid;
|
|
out_channel = in_channel;
|
|
out_startofpacket = in_startofpacket;
|
|
out_endofpacket = 0;
|
|
|
|
out_size_field = (cmd_burst_size < OUT_NUMSYMBOLS) ? in_size_field : log2_out_numsymbols;
|
|
if (CONSTANT_BURST_SIZE) begin // For Avalon only
|
|
out_byteen_field = in_byteen_field[OUT_NUMSYMBOLS-1:0];
|
|
out_data_field = in_data_field[OUT_NUMSYMBOLS * SYMBOL_W-1:0];
|
|
out_byte_cnt_field = in_byte_cnt_field;
|
|
end else begin
|
|
out_byte_cnt_field = in_byte_cnt_field >> clogb2(IN_NUMSYMBOLS) << sized_byte_cnt_factor;
|
|
end
|
|
|
|
out_first_field = in_first_field;
|
|
out_mid_field = in_mid_field;
|
|
out_last_field = in_last_field;
|
|
out_cmpr_read = in_cmpr_read;
|
|
out_lock_field = in_lock_field;
|
|
out_burst_type_field = in_burst_type_field;
|
|
out_response_status_field = in_response_status_field;
|
|
|
|
// Case when command size <= OUT_NUMSYMBOLS: pass the cycle
|
|
// through, unmodified
|
|
if (cmd_burst_size <= OUT_NUMSYMBOLS) begin
|
|
out_endofpacket = in_endofpacket;
|
|
in_address_field = address_from_packet;
|
|
end // (cmd_burst_size <= OUT_NUMSYMBOLS)
|
|
else begin
|
|
// Case when we need to bus size data (size > OUT_NUMSYMBOLS).
|
|
out_lock_field = 0;
|
|
// Change fixed burst type opcodes to the repeated wrap
|
|
// opcode.
|
|
if (in_burst_type_field == 2'b00) begin
|
|
out_burst_type_field = 2'b11;
|
|
end
|
|
// On the first address of the burst, align and send this
|
|
// address to the network
|
|
in_address_field = address_for_adaptation;
|
|
end // (cmd_burst_size > OUT_NUMSYMBOLS)
|
|
|
|
out_address_field = in_address_field;
|
|
int_output_sel = in_address_field >> log2_out_numsymbols ;
|
|
if (in_cmpr_read)
|
|
out_endofpacket = 1;
|
|
|
|
if (use_reg) begin
|
|
|
|
out_startofpacket = 0;
|
|
// If it's the last cycle, or if there's no more data,
|
|
// we can allow an endofpacket.
|
|
if (count == 1)
|
|
out_endofpacket = endofpacket_reg;
|
|
|
|
out_byte_cnt_field = byte_cnt_reg;
|
|
out_address_field = address_reg;
|
|
if (CONSTANT_BURST_SIZE) begin // Avalon system
|
|
out_data_field = data_reg[(OUT_NUMSYMBOLS * SYMBOL_W)-1:0];
|
|
out_byteen_field = byteen_reg[OUT_NUMSYMBOLS-1:0];
|
|
byteen_array = '{RATIO {0} };
|
|
data_array = '{RATIO {0} };
|
|
end
|
|
int_output_sel = address_reg >> log2_out_numsymbols;
|
|
end
|
|
|
|
output_sel = int_output_sel[WN_ADDR_LSBS-1:0];
|
|
if (!CONSTANT_BURST_SIZE) begin
|
|
out_byteen_field = byteen_array[output_sel];
|
|
out_data_field = data_array[output_sel];
|
|
end
|
|
|
|
// Check each output-sized segment to see whether it
|
|
// is enabled (byteenables)
|
|
segments_with_be_asserted = 0;
|
|
for (i = 0; i < RATIO; i=i+1) begin
|
|
segments_with_be_asserted[i] = |in_byteen_field[i*OUT_BYTEEN_W +: OUT_BYTEEN_W];
|
|
end
|
|
|
|
// Determine whether only one segment is asserted. This code detects a power of two,
|
|
// i.e. only 1 bit is asserted.
|
|
only_one_segment_asserted = (segments_with_be_asserted && !(segments_with_be_asserted & (segments_with_be_asserted - 1)));
|
|
|
|
//-----------------------------------------
|
|
// Optimization for non-bursting wide-narrow response.
|
|
//
|
|
// Only one segment of the wide word will have asserted
|
|
// byteenables. Just pass that segment through and drop
|
|
// the rest. This should synthesize to an and-or mux.
|
|
//-----------------------------------------
|
|
if (OPTIMIZE_FOR_RSP | single_response_expected) begin
|
|
out_startofpacket = in_startofpacket;
|
|
out_endofpacket = in_endofpacket;
|
|
in_ready = out_ready;
|
|
//-----------------------------------------
|
|
// Not correct, but nothing in the response path looks
|
|
// at these today (10.1). Must be corrected when we allow
|
|
// multiple width adapters on a path.
|
|
//-----------------------------------------
|
|
out_address_field = in_address_field;
|
|
out_byte_cnt_field = in_byte_cnt_field;
|
|
|
|
out_data_field = '0;
|
|
out_byteen_field = '0;
|
|
for (i = 0; i < RATIO; i=i+1) begin
|
|
mask = '0;
|
|
for (j = 0; j < OUT_NUMSYMBOLS; j=j+1) begin
|
|
mask |= {SYMBOL_W{in_byteen_field[i*OUT_NUMSYMBOLS+j]}} << (j*SYMBOL_W);
|
|
end
|
|
|
|
out_data_field |= mask & in_data_field[i*OUT_SEGMENT_W +: OUT_SEGMENT_W];
|
|
out_byteen_field |= in_byteen_field[i*OUT_NUMSYMBOLS +: OUT_NUMSYMBOLS];
|
|
end
|
|
end
|
|
else begin // to prevent latches
|
|
j = 0;
|
|
mask = '0;
|
|
end
|
|
|
|
end // always @ *
|
|
|
|
//-------------------------------------------------------
|
|
// Configuration Error Checking
|
|
//-------------------------------------------------------
|
|
// synthesis translate_off
|
|
initial begin
|
|
if (RATIO * OUT_NUMSYMBOLS != IN_NUMSYMBOLS) begin
|
|
$display("%m : The ratio of input symbols to output symbols must be an integer.");
|
|
$stop();
|
|
end
|
|
end
|
|
// synthesis translate_on
|
|
if (!CONSTANT_BURST_SIZE) begin
|
|
integer ibyte;
|
|
always @* begin
|
|
for(ibyte=0; ibyte<RATIO; ibyte=ibyte+1) begin: mux_mapping
|
|
data_array[ibyte] = in_data_field[(ibyte*OUT_NUMSYMBOLS*SYMBOL_W)+:OUT_NUMSYMBOLS*SYMBOL_W];
|
|
byteen_array[ibyte] = in_byteen_field[(ibyte*OUT_NUMSYMBOLS)+:OUT_NUMSYMBOLS];
|
|
end
|
|
end
|
|
end
|
|
end // if (IN_NUMSYMBOLS > OUT_NUMSYMBOLS)
|
|
|
|
//-------------------------------------------------------
|
|
//-------------------------------------------------------
|
|
// Narrow-to-Wide
|
|
//-------------------------------------------------------
|
|
//-------------------------------------------------------
|
|
if (OUT_NUMSYMBOLS > IN_NUMSYMBOLS) begin
|
|
wire p0_valid;
|
|
reg p0_startofpacket;
|
|
reg p0_endofpacket;
|
|
reg [IN_DATA_W-1:0] p0_data_field;
|
|
reg [IN_BYTEEN_W-1:0] p0_byteen_field;
|
|
reg [ADDRESS_W-1:0] p0_address_field;
|
|
reg [BWRAP_W-1:0] p0_bwrap_field;
|
|
reg [BYTE_CNT_W-1:0] p0_byte_cnt_field;
|
|
reg [clogb2(RATIO)-1:0] p0_bitforselect;
|
|
reg p0_cmpr_read;
|
|
reg [FIRST_W-1:0] p0_first_field;
|
|
reg [MID_W-1:0] p0_mid_field;
|
|
reg [LAST_W-1:0] p0_last_field;
|
|
reg p0_use_reg;
|
|
reg [ST_CHANNEL_W-1:0] p0_channel;
|
|
reg [BURST_SIZE_W-1:0] p0_burst_size;
|
|
reg [BURST_SIZE_W-1:0] p0_ori_burst_size;
|
|
reg p0_out_lock_field;
|
|
reg [BURST_TYPE_W-1:0] p0_burst_type_field;
|
|
|
|
reg [RESPONSE_STATUS_W-1:0] p0_response_status_field;
|
|
reg p0_reg_startofpacket;
|
|
reg p0_reg_endofpacket;
|
|
reg [IN_DATA_W-1:0] p0_reg_data_field;
|
|
reg [IN_BYTEEN_W-1:0] p0_reg_byteen_field;
|
|
reg [ADDRESS_W-1:0] p0_reg_address_field;
|
|
reg [BWRAP_W-1:0] p0_reg_bwrap_field;
|
|
reg [BYTE_CNT_W-1:0] p0_reg_byte_cnt_field;
|
|
reg [clogb2(RATIO)-1:0] p0_reg_bitforselect;
|
|
reg p0_reg_cmpr_read;
|
|
reg [FIRST_W-1:0] p0_reg_first_field;
|
|
reg [MID_W-1:0] p0_reg_mid_field;
|
|
reg [LAST_W-1:0] p0_reg_last_field;
|
|
reg [ST_CHANNEL_W-1:0] p0_reg_channel;
|
|
reg [BURST_SIZE_W-1:0] p0_reg_burst_size;
|
|
reg [BURST_SIZE_W-1:0] p0_reg_ori_burst_size;
|
|
reg [BURST_TYPE_W-1:0] p0_reg_burst_type_field;
|
|
reg [RESPONSE_STATUS_W-1:0] p0_reg_response_status_field;
|
|
reg p0_reg_out_lock_field;
|
|
wire p1_valid;
|
|
reg p1_ready;
|
|
reg p1_startofpacket;
|
|
reg p1_endofpacket;
|
|
reg [IN_DATA_W-1:0] p1_data_field;
|
|
reg [IN_BYTEEN_W-1:0] p1_byteen_field;
|
|
reg [ADDRESS_W-1:0] p1_address_field;
|
|
reg [ADDRESS_W-1:0] out_address_field_mask;
|
|
reg [BYTE_CNT_W-1:0] p1_byte_cnt_field;
|
|
|
|
reg [BURST_SIZE_W-1:0] p1_burst_size;
|
|
reg [BYTE_CNT_W-1:0] p1_byte_cnt_unpack_field;
|
|
wire response_data_packing;
|
|
reg [clogb2(RATIO)-1:0] p1_shift_correct_ouput_segments;
|
|
reg [clogb2(RATIO)-1:0] p1_push_data_to_output;
|
|
|
|
reg p1_cmpr_read;
|
|
reg [RESPONSE_STATUS_W-1:0] p1_response_status_field;
|
|
reg unc_sink_valid;
|
|
wire unc_sink_ready;
|
|
wire unc_src_startofpacket;
|
|
wire unc_src_endofpacket;
|
|
wire unc_src_valid;
|
|
wire [ADDRESS_W-1:0] unc_src_addr;
|
|
wire [BYTE_CNT_W-1:0] unc_src_byte_cnt;
|
|
|
|
wire aligned_addr;
|
|
wire aligned_byte_cnt;
|
|
wire unaligned_read;
|
|
|
|
reg [BYTE_CNT_W-1:0] count;
|
|
reg count_eq_zero;
|
|
|
|
wire [31:0] int_in_numsymbols = IN_NUMSYMBOLS;
|
|
wire [BYTE_CNT_W-1:0] byte_cnt_sized_in_num_symbols =
|
|
int_in_numsymbols[BYTE_CNT_W-1:0];
|
|
reg [9:0] cmd_burst_size;
|
|
wire [31:0] out_numsymbols_wire = LOG_OUT_NUMSYMBOLS;
|
|
wire [31:0] int_encoded_burstsize = NW_BITFORSELECT_R; //NW_BITFORSELECT_R is the log2 of IN_NUMSYMBOLS
|
|
wire [BURST_SIZE_W-1:0] encoded_burstsize = int_encoded_burstsize[BURST_SIZE_W-1:0];
|
|
|
|
// Care about burstwrap on command path only
|
|
if (RESPONSE_PATH == 0) begin
|
|
assign in_burstwrap_field = in_data[IN_PKT_BURSTWRAP_H:IN_PKT_BURSTWRAP_L];
|
|
end
|
|
else begin
|
|
assign in_burstwrap_field = {BWRAP_W{1'b1}};
|
|
end
|
|
|
|
// To use "read response merging" the Width adapter need to know the size of the command
|
|
// to check if downside happen. For AXI system, the fifo will store this number (non-packing: we use "combined width adapter")
|
|
// but in case system without AXI, the system use stand alone width adapter and it cannot read this value
|
|
// Make a condition incase we see stand alone WA, set this in_command_burst_size to input size
|
|
//wire [2:0] in_command_burst_size = out_numsymbols_wire[2:0];
|
|
//if (!((PACKING == 1) & (CONSTANT_BURST_SIZE == 1))) // stand alone WA
|
|
// begin
|
|
// assign in_command_burst_size = in_command_size_data;
|
|
// end
|
|
reg [BURST_SIZE_W-1:0] in_ori_size_field;
|
|
always @* begin
|
|
in_ori_size_field = in_data[IN_PKT_ORI_BURST_SIZE_H :IN_PKT_ORI_BURST_SIZE_L ];
|
|
end
|
|
|
|
reg [9:0] size_ratio;
|
|
// --------------------------------------------
|
|
// Stage 0: buffer the input cycle if read burst
|
|
// uncompression is going to happen.
|
|
//
|
|
// This avoids the possibility of a master receiving a premature
|
|
// response while its read burst is still being waitrequested.
|
|
// --------------------------------------------
|
|
always @(posedge clk, posedge reset) begin
|
|
if (reset) begin
|
|
p0_use_reg <= 1'b0;
|
|
p0_reg_startofpacket <= 1'b0;
|
|
p0_reg_endofpacket <= 1'b0;
|
|
p0_reg_data_field <= '0;
|
|
p0_reg_bwrap_field <= '0;
|
|
p0_reg_byteen_field <= '0;
|
|
p0_reg_address_field <= '0;
|
|
p0_reg_byte_cnt_field <= '0;
|
|
p0_reg_cmpr_read <= 1'b0;
|
|
p0_reg_first_field <= '0;
|
|
p0_reg_mid_field <= '0;
|
|
p0_reg_last_field <= '0;
|
|
p0_reg_channel <= '0;
|
|
p0_reg_burst_size <= '0;
|
|
p0_reg_ori_burst_size <= '0;
|
|
p0_reg_out_lock_field <= '0;
|
|
p0_reg_burst_type_field <= '0;
|
|
p0_reg_response_status_field <= '0;
|
|
end else begin
|
|
if (unaligned_read & in_valid)
|
|
p0_use_reg <= 1'b1;
|
|
if (unc_src_endofpacket & p1_ready)
|
|
p0_use_reg <= 1'b0;
|
|
|
|
if (unaligned_read) begin
|
|
p0_reg_startofpacket <= p0_startofpacket;
|
|
p0_reg_endofpacket <= p0_endofpacket;
|
|
p0_reg_data_field <= p0_data_field;
|
|
p0_reg_bwrap_field <= p0_bwrap_field;
|
|
p0_reg_byteen_field <= p0_byteen_field;
|
|
p0_reg_address_field <= p0_address_field;
|
|
p0_reg_byte_cnt_field <= p0_byte_cnt_field;
|
|
p0_reg_cmpr_read <= p0_cmpr_read;
|
|
p0_reg_first_field <= p0_first_field;
|
|
p0_reg_mid_field <= p0_mid_field;
|
|
p0_reg_last_field <= p0_last_field;
|
|
p0_reg_channel <= p0_channel;
|
|
p0_reg_burst_size <= p0_burst_size;
|
|
p0_reg_ori_burst_size <= p0_ori_burst_size;
|
|
p0_reg_out_lock_field <= p0_out_lock_field;
|
|
p0_reg_burst_type_field <= p0_burst_type_field;
|
|
p0_reg_response_status_field <= p0_response_status_field;
|
|
end
|
|
end
|
|
end
|
|
|
|
always @* begin
|
|
in_ready = p1_ready;
|
|
|
|
// accept on the first cycle
|
|
if (unaligned_read & in_valid & ~p0_use_reg)
|
|
in_ready = 1;
|
|
|
|
if (p0_use_reg)
|
|
in_ready = 0;
|
|
end
|
|
|
|
always @* begin
|
|
p0_startofpacket = in_startofpacket;
|
|
p0_endofpacket = in_endofpacket;
|
|
p0_data_field = in_data_field;
|
|
p0_bwrap_field = in_burstwrap_field;
|
|
p0_byteen_field = in_byteen_field;
|
|
//p0_address_field = in_address_field;
|
|
p0_address_field = address_for_adaptation; // read address from oacket
|
|
|
|
p0_byte_cnt_field = in_byte_cnt_field;
|
|
p0_cmpr_read = in_cmpr_read;
|
|
p0_first_field = in_first_field;
|
|
p0_mid_field = in_mid_field;
|
|
p0_last_field = in_last_field;
|
|
p0_channel = in_channel;
|
|
p0_burst_size = in_size_field;
|
|
p0_ori_burst_size = in_ori_size_field;
|
|
p0_out_lock_field = in_lock_field;
|
|
p0_burst_type_field = in_burst_type_field;
|
|
p0_response_status_field = in_response_status_field;
|
|
if (p0_use_reg) begin
|
|
p0_startofpacket = p0_reg_startofpacket;
|
|
p0_endofpacket = p0_reg_endofpacket;
|
|
p0_data_field = p0_reg_data_field;
|
|
p0_bwrap_field = p0_reg_bwrap_field;
|
|
p0_byteen_field = p0_reg_byteen_field;
|
|
p0_address_field = p0_reg_address_field;
|
|
p0_byte_cnt_field = p0_reg_byte_cnt_field;
|
|
p0_cmpr_read = p0_reg_cmpr_read;
|
|
p0_first_field = p0_reg_first_field;
|
|
p0_mid_field = p0_reg_mid_field;
|
|
p0_last_field = p0_reg_last_field;
|
|
p0_channel = p0_reg_channel;
|
|
p0_burst_size = p0_reg_burst_size;
|
|
p0_ori_burst_size = p0_reg_ori_burst_size;
|
|
p0_out_lock_field = p0_reg_out_lock_field;
|
|
p0_burst_type_field = p0_reg_burst_type_field;
|
|
p0_response_status_field = p0_reg_response_status_field;
|
|
end
|
|
end
|
|
|
|
assign p0_valid = in_valid | p0_use_reg;
|
|
|
|
// --------------------------------------------
|
|
// Stage 1: uncompress the input packet if necessary
|
|
// --------------------------------------------
|
|
assign p1_valid = (unaligned_read) ? unc_src_valid : p0_valid;
|
|
assign aligned_addr = (p0_address_field[ALIGNED_BITS_L:0] == 0);
|
|
assign aligned_byte_cnt = (p0_byte_cnt_field[ALIGNED_BITS_L:0] == 0);
|
|
if ((RESPONSE_PATH == 0) && (PACKING == 1)) begin // if this is avalon then checking on aligned,
|
|
assign unaligned_read = p0_cmpr_read & (~aligned_addr || ~aligned_byte_cnt);
|
|
end else begin
|
|
assign unaligned_read = '0;
|
|
end
|
|
|
|
always @* begin
|
|
p1_data_field = p0_data_field;
|
|
p1_byteen_field = p0_byteen_field;
|
|
p1_startofpacket = p0_startofpacket;
|
|
p1_endofpacket = p0_endofpacket;
|
|
p1_address_field = p0_address_field;
|
|
p1_byte_cnt_field = p0_byte_cnt_field;
|
|
p1_cmpr_read = p0_cmpr_read;
|
|
p1_response_status_field = p0_response_status_field;
|
|
p1_burst_size = p0_burst_size;
|
|
unc_sink_valid = 0;
|
|
|
|
if (unaligned_read) begin
|
|
unc_sink_valid = p0_valid;
|
|
|
|
p1_startofpacket = unc_src_startofpacket;
|
|
p1_endofpacket = unc_src_endofpacket;
|
|
p1_address_field = unc_src_addr;
|
|
p1_byte_cnt_field = unc_src_byte_cnt;
|
|
p1_cmpr_read = 0;
|
|
end
|
|
end
|
|
|
|
altera_merlin_burst_uncompressor
|
|
#(
|
|
.ADDR_W (ADDRESS_W),
|
|
.BURSTWRAP_W (BWRAP_W),
|
|
.BYTE_CNT_W (BYTE_CNT_W),
|
|
.PKT_SYMBOLS (IN_NUMSYMBOLS),
|
|
.BURST_SIZE_W(BURST_SIZE_W)
|
|
) uncompressor (
|
|
.clk (clk),
|
|
.reset (reset),
|
|
|
|
.sink_startofpacket (p0_startofpacket),
|
|
.sink_endofpacket (p0_endofpacket),
|
|
.sink_valid (unc_sink_valid),
|
|
.sink_ready (unc_sink_ready),
|
|
.sink_addr (p0_address_field),
|
|
.sink_burstwrap (p0_bwrap_field),
|
|
.sink_byte_cnt (p0_byte_cnt_field),
|
|
.sink_is_compressed (1'b1), // should always be compressed
|
|
.sink_burstsize (encoded_burstsize),
|
|
|
|
.source_startofpacket (unc_src_startofpacket),
|
|
.source_endofpacket (unc_src_endofpacket),
|
|
.source_valid (unc_src_valid),
|
|
.source_ready (p1_ready),
|
|
.source_addr (unc_src_addr),
|
|
.source_burstwrap (),
|
|
.source_byte_cnt (unc_src_byte_cnt),
|
|
.source_is_compressed (),
|
|
.source_burstsize ()
|
|
);
|
|
|
|
// --------------------------------------------
|
|
// Stage 2: perform narrow to wide adaptation on the beats
|
|
// --------------------------------------------
|
|
|
|
always @(posedge clk, posedge reset) begin
|
|
if (reset) begin
|
|
data_reg <= '0;
|
|
byteen_reg <= '0;
|
|
startofpacket_reg <= '0;
|
|
count <= '0;
|
|
count_eq_zero <= '1;
|
|
response_status_reg <= '0;
|
|
end else begin
|
|
|
|
if (p1_valid && (out_ready || ~out_valid)) begin
|
|
// Lay input data & input byte enables into
|
|
// the temp registers
|
|
data_reg <= data_reg | (p1_data_field << (p1_shift_correct_ouput_segments *IN_NUMSYMBOLS*SYMBOL_W));
|
|
byteen_reg <= byteen_reg | (p1_byteen_field << (p1_shift_correct_ouput_segments *IN_NUMSYMBOLS));
|
|
response_status_reg <= out_response_status_field;
|
|
// Capture the stuff that's to be held constant
|
|
if (count_eq_zero) begin
|
|
startofpacket_reg <= p1_startofpacket;
|
|
if (~p1_endofpacket) begin
|
|
count <= p1_byte_cnt_field - byte_cnt_sized_in_num_symbols;
|
|
count_eq_zero <=
|
|
~|(p1_byte_cnt_field - byte_cnt_sized_in_num_symbols);
|
|
end
|
|
end else begin
|
|
count <= count - byte_cnt_sized_in_num_symbols;
|
|
count_eq_zero <= ~|(count - byte_cnt_sized_in_num_symbols);
|
|
end
|
|
|
|
//if (p1_endofpacket || (p1_shift_correct_ouput_segments == '1)) begin
|
|
if (p1_endofpacket || (p1_push_data_to_output == '1)) begin
|
|
data_reg <= '0;
|
|
byteen_reg <= '0;
|
|
response_status_reg <= '0;
|
|
end
|
|
|
|
if (out_valid && out_ready) begin
|
|
startofpacket_reg <= '0;
|
|
end
|
|
|
|
end // if (p1_valid && (out_ready || ~out_valid))
|
|
end // if (posedge clk)
|
|
end // always @ (clk, reset)
|
|
|
|
always @* begin
|
|
// Handle narrow-size transaction from the master:
|
|
// The width of in_bitforselect is
|
|
// log2(OUT_NUM_SYMBOLS) - log2(IN_NUM_SYMBOLS) =
|
|
// log2(RATIO)
|
|
// The msb of in_bitforselect is driven by: in_adress_field[log2(OUT_NUMSYMBOLS) - 1]
|
|
// The lsb of in_adress_field is driven by: in_adress_field[log2(IN_NUMSYMBOLS)]
|
|
|
|
// The function: mask_to_select_segments_for_size: is used to build a mask that changed at run-time
|
|
// when narrow-size transaction, It recaculates the width of in_bitforselect base on size ratio
|
|
|
|
// EX: Full-size transaction (2 bytes)N-W: in_bitforselect = in_address[1:0]
|
|
// Narrow-size transaction(1 byte)N-W: in_bitforselect = {1, in_address[0]}
|
|
|
|
p1_shift_correct_ouput_segments = p1_address_field[NW_BITFORSELECT_L:NW_BITFORSELECT_R];
|
|
|
|
// size ratio betwen command size and response size
|
|
//cmd_burst_size = bytes_in_transfer(in_command_burst_size);
|
|
cmd_burst_size = bytes_in_transfer(p0_ori_burst_size);
|
|
|
|
size_ratio = cmd_burst_size >> in_size_field;
|
|
|
|
if (RESPONSE_PATH == 0) begin
|
|
// if the WA is on command path, Avalon interconnect default
|
|
// bitselectfor data packing and push out data are same, compile time
|
|
p1_push_data_to_output = p1_shift_correct_ouput_segments;
|
|
end else begin
|
|
// the WA is on reponse path and default: PACKING = 1
|
|
// on response path, need based on size, run-time, to determinite output segment
|
|
p1_push_data_to_output = mask_to_select_correct_segments_for_size(p1_shift_correct_ouput_segments, size_ratio, clogb2(RATIO));
|
|
out_address_field_mask = choose_packed_address_base_on_size(size_ratio, clogb2(RATIO));
|
|
end
|
|
|
|
// We push data to the output whenever the input is
|
|
// an endofpacket, or the input drives the most-significant
|
|
// segment of the wider output word.
|
|
out_valid = 0;
|
|
if (PACKING == 1) begin
|
|
if (p1_endofpacket || (p1_push_data_to_output == '1)) begin
|
|
out_valid = p1_valid;
|
|
end
|
|
end else begin
|
|
out_valid = p1_valid;
|
|
end
|
|
|
|
out_startofpacket = p1_startofpacket || startofpacket_reg;
|
|
out_endofpacket = p1_endofpacket;
|
|
|
|
// Compressed read with byte_cnt > input interface width:
|
|
// this is a read burst spanning more than the originating
|
|
// interface of data, so all byteenables must be asserted.
|
|
if (p1_cmpr_read && (p1_byte_cnt_field > IN_NUMSYMBOLS)) begin
|
|
out_byteen_field = '1;
|
|
end else begin
|
|
if (PACKING == 1) begin // byteenable only affect on command path
|
|
out_byteen_field = byteen_reg |
|
|
(p1_byteen_field << (p1_shift_correct_ouput_segments*IN_NUMSYMBOLS));
|
|
end else begin // non-packing: shift input byteenable to correct position
|
|
out_byteen_field = (p1_byteen_field << (p1_shift_correct_ouput_segments*IN_NUMSYMBOLS));
|
|
end
|
|
end
|
|
|
|
// caculate bytecnt "unpack" according to OUTNUMSYMBOLS
|
|
p1_byte_cnt_unpack_field = p1_byte_cnt_field << clogb2(RATIO);
|
|
out_address_field = p1_address_field;
|
|
|
|
if (RESPONSE_PATH == 0) begin
|
|
if (PACKING == 1) begin // if the WA is on command path, Avalon interconnect default
|
|
out_data_field = data_reg | (p1_data_field << (p1_shift_correct_ouput_segments *IN_NUMSYMBOLS*SYMBOL_W));
|
|
out_byte_cnt_field = quantized_byte_cnt_field;
|
|
out_address_field[NW_BITFORSELECT_L:0] = 0;
|
|
out_size_field = out_numsymbols_wire[BURST_SIZE_W-1:0]; // for Avalon the size is converted to slave side
|
|
end else begin
|
|
out_data_field = (p1_data_field << (p1_shift_correct_ouput_segments *IN_NUMSYMBOLS*SYMBOL_W));
|
|
out_byte_cnt_field = p1_byte_cnt_unpack_field;
|
|
out_size_field = p1_burst_size;
|
|
end
|
|
end else begin // the WA is on reponse path and default: PACKING = 1
|
|
//if (in_size_field < in_command_burst_size) begin // downsize happen on command path, the response need packing
|
|
if (in_size_field < in_ori_size_field) begin // downsize happen on command path, the response need packing
|
|
out_data_field = data_reg
|
|
| (p1_data_field << (p1_shift_correct_ouput_segments *IN_NUMSYMBOLS*SYMBOL_W));
|
|
out_address_field = p1_address_field & out_address_field_mask;
|
|
out_size_field = p1_burst_size;
|
|
out_byte_cnt_field = p1_byte_cnt_field;
|
|
end else begin // narrow transaction on command path, reponse packet will not packed
|
|
out_data_field = (p1_data_field << (p1_shift_correct_ouput_segments *IN_NUMSYMBOLS*SYMBOL_W));
|
|
out_byte_cnt_field = p1_byte_cnt_field;
|
|
out_size_field = p1_burst_size;
|
|
end
|
|
end
|
|
|
|
//if (in_size_field < in_command_burst_size) begin // downsize happen on command path, the response need packing
|
|
if (in_size_field < in_ori_size_field) begin // downsize happen on command path, the response need packing
|
|
// Response merging: rules: DECERR(11) > SLVERR (10) > OKAY (00)
|
|
// EXOKAY will not happen on merging
|
|
out_response_status_field = '0;
|
|
if (response_status_reg >= p1_response_status_field) begin
|
|
out_response_status_field = response_status_reg;
|
|
end else begin
|
|
out_response_status_field = p1_response_status_field;
|
|
end
|
|
end else begin // narrow transaction on command path, reponse packet will not packed
|
|
out_response_status_field = p1_response_status_field;
|
|
end
|
|
|
|
out_cmpr_read = p1_cmpr_read;
|
|
|
|
// nothing touches these fields, so assign them
|
|
// directly from the input fields
|
|
out_first_field = p0_first_field;
|
|
out_mid_field = p0_mid_field;
|
|
out_last_field = p0_last_field;
|
|
out_lock_field = p0_out_lock_field;
|
|
out_channel = p0_channel;
|
|
out_burst_type_field = p0_burst_type_field;
|
|
end // always @ *
|
|
|
|
//-------------------------------------------------------
|
|
// output byte_cnt, rounded up to alignment with the output-side
|
|
// address map footprint implied by the input-side access.
|
|
//
|
|
// See "option 3" in Appendix C of
|
|
// merlin_interconnect_architecture_fd_91.doc.
|
|
//-------------------------------------------------------
|
|
reg [NW_BITFORSELECT_L:0] low_addr_bits;
|
|
|
|
always @* begin
|
|
low_addr_bits = p1_address_field[NW_BITFORSELECT_L:0];
|
|
|
|
quantized_byte_cnt_field = low_addr_bits +
|
|
p1_byte_cnt_field +
|
|
{clogb2(OUT_NUMSYMBOLS){1'b1}};
|
|
quantized_byte_cnt_field[NW_BITFORSELECT_L:0] = '0;
|
|
end
|
|
|
|
//-------------------------------------------------------
|
|
// Backpressure
|
|
//-------------------------------------------------------
|
|
always @ * begin
|
|
p1_ready = out_ready || ~out_valid;
|
|
end
|
|
|
|
end // if (OUT_NUMSYMBOLS > IN_NUMSYMBOLS)
|
|
|
|
//-------------------------------------------------------
|
|
//-------------------------------------------------------
|
|
// Same Width. Seems kind of silly, but let's be complete.
|
|
//-------------------------------------------------------
|
|
//-------------------------------------------------------
|
|
if (OUT_NUMSYMBOLS == IN_NUMSYMBOLS) begin
|
|
|
|
always @* begin
|
|
in_ready = out_ready;
|
|
out_valid = in_valid;
|
|
out_channel = in_channel;
|
|
out_startofpacket = in_startofpacket;
|
|
out_endofpacket = in_endofpacket;
|
|
out_size_field = in_size_field;
|
|
out_data_field = in_data_field;
|
|
out_byteen_field = in_byteen_field;
|
|
out_address_field = in_address_field;
|
|
out_byte_cnt_field = in_byte_cnt_field;
|
|
out_response_status_field = in_response_status_field;
|
|
out_lock_field = in_lock_field;
|
|
out_burst_type_field = in_burst_type_field;
|
|
out_cmpr_read = in_cmpr_read;
|
|
out_first_field = in_first_field;
|
|
out_mid_field = in_mid_field;
|
|
out_last_field = in_last_field;
|
|
end // always @ *
|
|
|
|
end // if (OUT_NUMSYMBOLS == IN_NUMSYMBOLS)
|
|
|
|
endgenerate
|
|
|
|
// ---------------------------------------
|
|
// Output Field Mapping
|
|
//
|
|
// Conditionally assign the pseudo-fields. Assign address and size
|
|
// last, because they partly override the pseudo-fields.
|
|
// ---------------------------------------
|
|
always @* begin
|
|
if (FIRST_EXISTS)
|
|
out_data[OUT_FIRST_H:OUT_FIRST_L] = out_first_field;
|
|
if (MID_EXISTS)
|
|
out_data[OUT_MID_H:OUT_MID_L] = out_mid_field;
|
|
if (LAST_EXISTS)
|
|
out_data[OUT_LAST_H:OUT_LAST_L] = out_last_field;
|
|
|
|
out_data[OUT_PKT_BURST_SIZE_H : OUT_PKT_BURST_SIZE_L ] = out_size_field;
|
|
out_data[OUT_PKT_DATA_H : OUT_PKT_DATA_L ] = out_data_field;
|
|
out_data[OUT_PKT_BYTEEN_H : OUT_PKT_BYTEEN_L ] = out_byteen_field;
|
|
out_data[OUT_PKT_ADDR_H : OUT_PKT_ADDR_L ] = out_address_field;
|
|
out_data[OUT_PKT_BYTE_CNT_H : OUT_PKT_BYTE_CNT_L ] = out_byte_cnt_field;
|
|
out_data[OUT_PKT_TRANS_COMPRESSED_READ ] = out_cmpr_read;
|
|
out_data[OUT_PKT_TRANS_EXCLUSIVE ] = out_lock_field;
|
|
out_data[OUT_PKT_BURST_TYPE_H : OUT_PKT_BURST_TYPE_L ] = out_burst_type_field;
|
|
out_data[OUT_PKT_RESPONSE_STATUS_H : OUT_PKT_RESPONSE_STATUS_L] = out_response_status_field;
|
|
end // always @ *
|
|
|
|
endmodule // width_adapter
|
|
|