// (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