264 lines
11 KiB
Systemverilog
264 lines
11 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/main/ip/merlin/altera_merlin_axi_master_ni/address_alignment.sv#3 $
|
|
// $Revision: #3 $
|
|
// $Date: 2012/07/11 $
|
|
// $Author: tgngo $
|
|
|
|
//-----------------------------------------
|
|
// Address alignment:
|
|
// This component will aglin input address with input size
|
|
// Support address increment with butst type and burstwrap value
|
|
//-----------------------------------------
|
|
`timescale 1 ns / 1 ns
|
|
|
|
module altera_merlin_address_alignment
|
|
#(
|
|
parameter
|
|
ADDR_W = 12,
|
|
BURSTWRAP_W = 12,
|
|
TYPE_W = 2,
|
|
SIZE_W = 3,
|
|
INCREMENT_ADDRESS = 1,
|
|
NUMSYMBOLS = 8,
|
|
SELECT_BITS = log2(NUMSYMBOLS),
|
|
IN_DATA_W = ADDR_W + (BURSTWRAP_W-1) + TYPE_W + SIZE_W,
|
|
OUT_DATA_W = ADDR_W + SELECT_BITS
|
|
)
|
|
(
|
|
input clk,
|
|
input reset,
|
|
|
|
input [IN_DATA_W-1:0] in_data, // in_data = {wrap_boundary, address, type, size}
|
|
input in_valid,
|
|
//output in_ready,
|
|
input in_sop,
|
|
input in_eop,
|
|
|
|
output reg [OUT_DATA_W-1:0] out_data,
|
|
input out_ready
|
|
//output out_valid
|
|
|
|
);
|
|
typedef enum bit [1:0]
|
|
{
|
|
FIXED = 2'b00,
|
|
INCR = 2'b01,
|
|
WRAP = 2'b10,
|
|
RESERVED = 2'b11
|
|
} AxiBurstType;
|
|
//----------------------------------------------------
|
|
// AXSIZE decoding
|
|
//
|
|
// Turns the axsize value into the actual number of bytes
|
|
// being transferred.
|
|
// ---------------------------------------------------
|
|
|
|
function reg[9:0] bytes_in_transfer;
|
|
input [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
|
|
|
|
//--------------------------------------
|
|
// Burst type decode
|
|
//--------------------------------------
|
|
AxiBurstType write_burst_type;
|
|
|
|
function AxiBurstType burst_type_decode
|
|
(
|
|
input [1:0] axburst
|
|
);
|
|
AxiBurstType burst_type;
|
|
begin
|
|
case (axburst)
|
|
2'b00 : burst_type = FIXED;
|
|
2'b01 : burst_type = INCR;
|
|
2'b10 : burst_type = WRAP;
|
|
2'b11 : burst_type = RESERVED;
|
|
default : burst_type = INCR;
|
|
endcase
|
|
return burst_type;
|
|
end
|
|
endfunction
|
|
|
|
//----------------------------------------------------
|
|
// Ubiquitous, familiar log2 function
|
|
//----------------------------------------------------
|
|
function integer log2;
|
|
input integer value;
|
|
|
|
value = value - 1;
|
|
for(log2 = 0; value > 0; log2 = log2 + 1)
|
|
value = value >> 1;
|
|
|
|
endfunction
|
|
//------------------------------------------------------------------------
|
|
// This component will read address and size and check
|
|
// if this is aligned or not. If not then it will align this address to the size
|
|
// of the transfer:
|
|
// Check alignment:
|
|
// - With data width, can define maximun how many lower bits of address to indicate this
|
|
// address align to the size
|
|
// - Ex: 32 bits data => size can be: 1, 2, 4 bytes
|
|
// For 4 bytes: when 2 lower bits of address equal 0, this is aligned address
|
|
// addr=00|00| (0), 01|00| (4) => align to size of 4 bytes
|
|
// addr=00|01| (1) => start addr at 1, is not aligned to size 4 byte
|
|
// For 2 bytes: use last one bit to indicate algined or not
|
|
// addr=000|0| (0), 001|0| (2) => align to size of 2 bytes
|
|
// addr=000|1| (1), 001|1| (3) => not align to 2 bytes
|
|
// As size runtime change, creat mask and change accordingly to size, can detect address alignment
|
|
// and to align to size, apply this mask with zero to the address.
|
|
//-------------------------------------------------------------------------
|
|
|
|
// THe function return a vector which has width [(SELECT_BITS * 2) -1 : 0]
|
|
// in which the first part contains the mask to check if this address aligned or not
|
|
// second part contains the mast to mask address to align to size
|
|
|
|
function reg[(SELECT_BITS*2)-1 : 0] mask_select_and_align_address;
|
|
input [ADDR_W-1:0] address;
|
|
input [SIZE_W-1:0] size; // size is in AXI coding: 001 -> 2 bytes
|
|
|
|
integer i;
|
|
reg [SELECT_BITS-1:0] mask_address;
|
|
reg [SELECT_BITS-1:0] check_unaligned; // any bits =1 -> unalgined (except size = 0; 1 byte)
|
|
mask_address = '1;
|
|
check_unaligned = '0;
|
|
for(i = 0; i < SELECT_BITS ; i = i + 1) begin
|
|
if (i < size) begin
|
|
check_unaligned[i] = address[i];
|
|
mask_address[i] = 1'b0;
|
|
end
|
|
end
|
|
mask_select_and_align_address = {check_unaligned,mask_address};
|
|
endfunction
|
|
|
|
|
|
|
|
reg [ADDR_W-1 : 0] in_address;
|
|
reg [ADDR_W-1 : 0] first_address_aligned;
|
|
reg [SIZE_W-1 : 0] in_size;
|
|
reg [(SELECT_BITS*2)-1 : 0] output_masks;
|
|
// Extract information from input data
|
|
assign in_address = in_data[SIZE_W+ADDR_W-1 : SIZE_W];
|
|
assign in_size = in_data[SIZE_W-1 : 0];
|
|
|
|
// Generate the masks
|
|
always_comb
|
|
begin
|
|
output_masks = mask_select_and_align_address(in_address, in_size);
|
|
end
|
|
|
|
// Align address if needed
|
|
|
|
generate
|
|
// SELECT_BITS == 1: input packet has 1 NUMSYMBOLS (1 bytes), it is aligned
|
|
if (SELECT_BITS == 0)
|
|
assign first_address_aligned = in_address;
|
|
else begin
|
|
// SELECT_BITS ==1 :input packet 2 bytes (2 SYMBOLS)
|
|
wire [SELECT_BITS-1 : 0] aligned_address_bits;
|
|
if (SELECT_BITS == 1)
|
|
assign aligned_address_bits = in_address[0] & output_masks[0];
|
|
else
|
|
assign aligned_address_bits = in_address[SELECT_BITS-1:0] & output_masks[SELECT_BITS-1:0];
|
|
assign first_address_aligned = {in_address[ADDR_W-1 : SELECT_BITS], aligned_address_bits};
|
|
end
|
|
endgenerate
|
|
|
|
|
|
|
|
// Increment address base on size, first address keep the same
|
|
generate
|
|
if (INCREMENT_ADDRESS)
|
|
begin
|
|
reg [ADDR_W-1 : 0] increment_address;
|
|
reg [ADDR_W-1 : 0] out_aligned_address_burst;
|
|
reg [ADDR_W-1 : 0] address_burst;
|
|
reg [ADDR_W-1 : 0] base_address;
|
|
reg [9 : 0] number_bytes_transfer;
|
|
reg [ADDR_W-1 : 0] burstwrap_mask;
|
|
reg [ADDR_W-1 : 0] burst_address_high;
|
|
reg [ADDR_W-1 : 0] burst_address_low;
|
|
reg [BURSTWRAP_W-2 :0] in_burstwrap_boundary;
|
|
reg [TYPE_W-1 : 0] in_type;
|
|
//------------------------------------------------
|
|
// Use the extended burstwrap value to split the high (constant) and
|
|
// low (changing) part of the address
|
|
//-----------------------------------------------
|
|
assign in_type = in_data[SIZE_W+ADDR_W+TYPE_W-1 : SIZE_W+ADDR_W];
|
|
assign in_burstwrap_boundary = in_data[IN_DATA_W-1 : ADDR_W+TYPE_W+SIZE_W];
|
|
assign burstwrap_mask = {{(ADDR_W - BURSTWRAP_W){1'b0}}, in_burstwrap_boundary};
|
|
assign burst_address_high = out_aligned_address_burst & ~burstwrap_mask;
|
|
assign burst_address_low = out_aligned_address_burst;
|
|
assign number_bytes_transfer = bytes_in_transfer(in_size);
|
|
assign write_burst_type = burst_type_decode(in_type);
|
|
|
|
always @*
|
|
begin
|
|
if (in_sop)
|
|
begin
|
|
out_aligned_address_burst = in_address;
|
|
base_address = first_address_aligned;
|
|
end
|
|
else
|
|
begin
|
|
out_aligned_address_burst = address_burst;
|
|
base_address = out_aligned_address_burst;
|
|
end
|
|
case (write_burst_type)
|
|
INCR:
|
|
increment_address = base_address + number_bytes_transfer;
|
|
WRAP:
|
|
increment_address = ((burst_address_low + number_bytes_transfer) & burstwrap_mask) | burst_address_high;
|
|
FIXED:
|
|
increment_address = out_aligned_address_burst;
|
|
default:
|
|
increment_address = base_address + number_bytes_transfer;
|
|
endcase // case (write_burst_type)
|
|
end // always @ *
|
|
always_ff @(posedge clk, negedge reset)
|
|
begin
|
|
if (!reset)
|
|
begin
|
|
address_burst <= '0;
|
|
end
|
|
else
|
|
begin
|
|
if (in_valid & out_ready)
|
|
address_burst <= increment_address;
|
|
end
|
|
end
|
|
// send data to output with 2 part: [mask_t0_algin][address_aligned_increment]
|
|
assign out_data = {output_masks[SELECT_BITS-1 : 0], out_aligned_address_burst};
|
|
end // if (INCREMENT_ADDRESS)
|
|
else
|
|
begin
|
|
assign out_data = {output_masks[SELECT_BITS-1 : 0], first_address_aligned};
|
|
end // else: !if(INCREMENT_ADDRESS)
|
|
|
|
endgenerate
|
|
endmodule
|