1 |
32 |
redbear |
// (C) 2001-2017 Intel Corporation. All rights reserved.
|
2 |
|
|
// Your use of Intel Corporation's design tools, logic functions and other
|
3 |
|
|
// software and tools, and its AMPP partner logic functions, and any output
|
4 |
40 |
redbear |
// files from any of the foregoing (including device programming or simulation
|
5 |
32 |
redbear |
// files), and any associated documentation or information are expressly subject
|
6 |
|
|
// to the terms and conditions of the Intel Program License Subscription
|
7 |
40 |
redbear |
// Agreement, Intel FPGA IP License Agreement, or other applicable
|
8 |
32 |
redbear |
// license agreement, including, without limitation, that your use is for the
|
9 |
|
|
// sole purpose of programming logic devices manufactured by Intel and sold by
|
10 |
|
|
// Intel or its authorized distributors. Please refer to the applicable
|
11 |
|
|
// agreement for further details.
|
12 |
|
|
|
13 |
|
|
|
14 |
|
|
// $Id: //acds/main/ip/merlin/altera_merlin_axi_master_ni/address_alignment.sv#3 $
|
15 |
|
|
// $Revision: #3 $
|
16 |
|
|
// $Date: 2012/07/11 $
|
17 |
|
|
// $Author: tgngo $
|
18 |
|
|
|
19 |
|
|
//-----------------------------------------
|
20 |
|
|
// Address alignment:
|
21 |
|
|
// This component will aglin input address with input size
|
22 |
|
|
// Support address increment with butst type and burstwrap value
|
23 |
|
|
//-----------------------------------------
|
24 |
|
|
`timescale 1 ns / 1 ns
|
25 |
|
|
|
26 |
|
|
module altera_merlin_address_alignment
|
27 |
|
|
#(
|
28 |
|
|
parameter
|
29 |
|
|
ADDR_W = 12,
|
30 |
|
|
BURSTWRAP_W = 12,
|
31 |
|
|
TYPE_W = 2,
|
32 |
|
|
SIZE_W = 3,
|
33 |
|
|
INCREMENT_ADDRESS = 1,
|
34 |
|
|
NUMSYMBOLS = 8,
|
35 |
|
|
SELECT_BITS = log2(NUMSYMBOLS),
|
36 |
|
|
IN_DATA_W = ADDR_W + (BURSTWRAP_W-1) + TYPE_W + SIZE_W,
|
37 |
|
|
OUT_DATA_W = ADDR_W + SELECT_BITS
|
38 |
|
|
)
|
39 |
|
|
(
|
40 |
|
|
input clk,
|
41 |
|
|
input reset,
|
42 |
|
|
|
43 |
|
|
input [IN_DATA_W-1:0] in_data, // in_data = {wrap_boundary, address, type, size}
|
44 |
|
|
input in_valid,
|
45 |
|
|
//output in_ready,
|
46 |
|
|
input in_sop,
|
47 |
|
|
input in_eop,
|
48 |
|
|
|
49 |
|
|
output reg [OUT_DATA_W-1:0] out_data,
|
50 |
|
|
input out_ready
|
51 |
|
|
//output out_valid
|
52 |
|
|
|
53 |
|
|
);
|
54 |
|
|
typedef enum bit [1:0]
|
55 |
|
|
{
|
56 |
|
|
FIXED = 2'b00,
|
57 |
|
|
INCR = 2'b01,
|
58 |
|
|
WRAP = 2'b10,
|
59 |
|
|
RESERVED = 2'b11
|
60 |
|
|
} AxiBurstType;
|
61 |
|
|
//----------------------------------------------------
|
62 |
|
|
// AXSIZE decoding
|
63 |
|
|
//
|
64 |
|
|
// Turns the axsize value into the actual number of bytes
|
65 |
|
|
// being transferred.
|
66 |
|
|
// ---------------------------------------------------
|
67 |
|
|
|
68 |
|
|
function reg[9:0] bytes_in_transfer;
|
69 |
|
|
input [SIZE_W-1:0] axsize;
|
70 |
|
|
case (axsize)
|
71 |
|
|
4'b0000: bytes_in_transfer = 10'b0000000001;
|
72 |
|
|
4'b0001: bytes_in_transfer = 10'b0000000010;
|
73 |
|
|
4'b0010: bytes_in_transfer = 10'b0000000100;
|
74 |
|
|
4'b0011: bytes_in_transfer = 10'b0000001000;
|
75 |
|
|
4'b0100: bytes_in_transfer = 10'b0000010000;
|
76 |
|
|
4'b0101: bytes_in_transfer = 10'b0000100000;
|
77 |
|
|
4'b0110: bytes_in_transfer = 10'b0001000000;
|
78 |
|
|
4'b0111: bytes_in_transfer = 10'b0010000000;
|
79 |
|
|
4'b1000: bytes_in_transfer = 10'b0100000000;
|
80 |
|
|
4'b1001: bytes_in_transfer = 10'b1000000000;
|
81 |
|
|
default: bytes_in_transfer = 10'b0000000001;
|
82 |
|
|
endcase
|
83 |
|
|
endfunction
|
84 |
|
|
|
85 |
|
|
//--------------------------------------
|
86 |
|
|
// Burst type decode
|
87 |
|
|
//--------------------------------------
|
88 |
|
|
AxiBurstType write_burst_type;
|
89 |
|
|
|
90 |
|
|
function AxiBurstType burst_type_decode
|
91 |
|
|
(
|
92 |
|
|
input [1:0] axburst
|
93 |
|
|
);
|
94 |
|
|
AxiBurstType burst_type;
|
95 |
|
|
begin
|
96 |
|
|
case (axburst)
|
97 |
|
|
2'b00 : burst_type = FIXED;
|
98 |
|
|
2'b01 : burst_type = INCR;
|
99 |
|
|
2'b10 : burst_type = WRAP;
|
100 |
|
|
2'b11 : burst_type = RESERVED;
|
101 |
|
|
default : burst_type = INCR;
|
102 |
|
|
endcase
|
103 |
|
|
return burst_type;
|
104 |
|
|
end
|
105 |
|
|
endfunction
|
106 |
|
|
|
107 |
|
|
//----------------------------------------------------
|
108 |
|
|
// Ubiquitous, familiar log2 function
|
109 |
|
|
//----------------------------------------------------
|
110 |
|
|
function integer log2;
|
111 |
|
|
input integer value;
|
112 |
|
|
|
113 |
|
|
value = value - 1;
|
114 |
|
|
for(log2 = 0; value > 0; log2 = log2 + 1)
|
115 |
|
|
value = value >> 1;
|
116 |
|
|
|
117 |
|
|
endfunction
|
118 |
|
|
//------------------------------------------------------------------------
|
119 |
|
|
// This component will read address and size and check
|
120 |
|
|
// if this is aligned or not. If not then it will align this address to the size
|
121 |
|
|
// of the transfer:
|
122 |
|
|
// Check alignment:
|
123 |
|
|
// - With data width, can define maximun how many lower bits of address to indicate this
|
124 |
|
|
// address align to the size
|
125 |
|
|
// - Ex: 32 bits data => size can be: 1, 2, 4 bytes
|
126 |
|
|
// For 4 bytes: when 2 lower bits of address equal 0, this is aligned address
|
127 |
|
|
// addr=00|00| (0), 01|00| (4) => align to size of 4 bytes
|
128 |
|
|
// addr=00|01| (1) => start addr at 1, is not aligned to size 4 byte
|
129 |
|
|
// For 2 bytes: use last one bit to indicate algined or not
|
130 |
|
|
// addr=000|0| (0), 001|0| (2) => align to size of 2 bytes
|
131 |
|
|
// addr=000|1| (1), 001|1| (3) => not align to 2 bytes
|
132 |
|
|
// As size runtime change, creat mask and change accordingly to size, can detect address alignment
|
133 |
|
|
// and to align to size, apply this mask with zero to the address.
|
134 |
|
|
//-------------------------------------------------------------------------
|
135 |
|
|
|
136 |
|
|
// THe function return a vector which has width [(SELECT_BITS * 2) -1 : 0]
|
137 |
|
|
// in which the first part contains the mask to check if this address aligned or not
|
138 |
|
|
// second part contains the mast to mask address to align to size
|
139 |
|
|
|
140 |
|
|
function reg[(SELECT_BITS*2)-1 : 0] mask_select_and_align_address;
|
141 |
|
|
input [ADDR_W-1:0] address;
|
142 |
|
|
input [SIZE_W-1:0] size; // size is in AXI coding: 001 -> 2 bytes
|
143 |
|
|
|
144 |
|
|
integer i;
|
145 |
|
|
reg [SELECT_BITS-1:0] mask_address;
|
146 |
|
|
reg [SELECT_BITS-1:0] check_unaligned; // any bits =1 -> unalgined (except size = 0; 1 byte)
|
147 |
|
|
mask_address = '1;
|
148 |
|
|
check_unaligned = '0;
|
149 |
|
|
for(i = 0; i < SELECT_BITS ; i = i + 1) begin
|
150 |
|
|
if (i < size) begin
|
151 |
|
|
check_unaligned[i] = address[i];
|
152 |
|
|
mask_address[i] = 1'b0;
|
153 |
|
|
end
|
154 |
|
|
end
|
155 |
|
|
mask_select_and_align_address = {check_unaligned,mask_address};
|
156 |
|
|
endfunction
|
157 |
|
|
|
158 |
|
|
|
159 |
|
|
|
160 |
|
|
reg [ADDR_W-1 : 0] in_address;
|
161 |
|
|
reg [ADDR_W-1 : 0] first_address_aligned;
|
162 |
|
|
reg [SIZE_W-1 : 0] in_size;
|
163 |
|
|
reg [(SELECT_BITS*2)-1 : 0] output_masks;
|
164 |
|
|
// Extract information from input data
|
165 |
|
|
assign in_address = in_data[SIZE_W+ADDR_W-1 : SIZE_W];
|
166 |
|
|
assign in_size = in_data[SIZE_W-1 : 0];
|
167 |
|
|
|
168 |
|
|
// Generate the masks
|
169 |
|
|
always_comb
|
170 |
|
|
begin
|
171 |
|
|
output_masks = mask_select_and_align_address(in_address, in_size);
|
172 |
|
|
end
|
173 |
|
|
|
174 |
|
|
// Align address if needed
|
175 |
|
|
|
176 |
|
|
generate
|
177 |
|
|
// SELECT_BITS == 1: input packet has 1 NUMSYMBOLS (1 bytes), it is aligned
|
178 |
|
|
if (SELECT_BITS == 0)
|
179 |
|
|
assign first_address_aligned = in_address;
|
180 |
|
|
else begin
|
181 |
|
|
// SELECT_BITS ==1 :input packet 2 bytes (2 SYMBOLS)
|
182 |
|
|
wire [SELECT_BITS-1 : 0] aligned_address_bits;
|
183 |
|
|
if (SELECT_BITS == 1)
|
184 |
|
|
assign aligned_address_bits = in_address[0] & output_masks[0];
|
185 |
|
|
else
|
186 |
|
|
assign aligned_address_bits = in_address[SELECT_BITS-1:0] & output_masks[SELECT_BITS-1:0];
|
187 |
|
|
assign first_address_aligned = {in_address[ADDR_W-1 : SELECT_BITS], aligned_address_bits};
|
188 |
|
|
end
|
189 |
|
|
endgenerate
|
190 |
|
|
|
191 |
|
|
|
192 |
|
|
|
193 |
|
|
// Increment address base on size, first address keep the same
|
194 |
|
|
generate
|
195 |
|
|
if (INCREMENT_ADDRESS)
|
196 |
|
|
begin
|
197 |
|
|
reg [ADDR_W-1 : 0] increment_address;
|
198 |
|
|
reg [ADDR_W-1 : 0] out_aligned_address_burst;
|
199 |
|
|
reg [ADDR_W-1 : 0] address_burst;
|
200 |
|
|
reg [ADDR_W-1 : 0] base_address;
|
201 |
|
|
reg [9 : 0] number_bytes_transfer;
|
202 |
|
|
reg [ADDR_W-1 : 0] burstwrap_mask;
|
203 |
|
|
reg [ADDR_W-1 : 0] burst_address_high;
|
204 |
|
|
reg [ADDR_W-1 : 0] burst_address_low;
|
205 |
|
|
reg [BURSTWRAP_W-2 :0] in_burstwrap_boundary;
|
206 |
|
|
reg [TYPE_W-1 : 0] in_type;
|
207 |
|
|
//------------------------------------------------
|
208 |
|
|
// Use the extended burstwrap value to split the high (constant) and
|
209 |
|
|
// low (changing) part of the address
|
210 |
|
|
//-----------------------------------------------
|
211 |
|
|
assign in_type = in_data[SIZE_W+ADDR_W+TYPE_W-1 : SIZE_W+ADDR_W];
|
212 |
|
|
assign in_burstwrap_boundary = in_data[IN_DATA_W-1 : ADDR_W+TYPE_W+SIZE_W];
|
213 |
|
|
assign burstwrap_mask = {{(ADDR_W - BURSTWRAP_W){1'b0}}, in_burstwrap_boundary};
|
214 |
|
|
assign burst_address_high = out_aligned_address_burst & ~burstwrap_mask;
|
215 |
|
|
assign burst_address_low = out_aligned_address_burst;
|
216 |
|
|
assign number_bytes_transfer = bytes_in_transfer(in_size);
|
217 |
|
|
assign write_burst_type = burst_type_decode(in_type);
|
218 |
|
|
|
219 |
|
|
always @*
|
220 |
|
|
begin
|
221 |
|
|
if (in_sop)
|
222 |
|
|
begin
|
223 |
|
|
out_aligned_address_burst = in_address;
|
224 |
|
|
base_address = first_address_aligned;
|
225 |
|
|
end
|
226 |
|
|
else
|
227 |
|
|
begin
|
228 |
|
|
out_aligned_address_burst = address_burst;
|
229 |
|
|
base_address = out_aligned_address_burst;
|
230 |
|
|
end
|
231 |
|
|
case (write_burst_type)
|
232 |
|
|
INCR:
|
233 |
|
|
increment_address = base_address + number_bytes_transfer;
|
234 |
|
|
WRAP:
|
235 |
|
|
increment_address = ((burst_address_low + number_bytes_transfer) & burstwrap_mask) | burst_address_high;
|
236 |
|
|
FIXED:
|
237 |
|
|
increment_address = out_aligned_address_burst;
|
238 |
|
|
default:
|
239 |
|
|
increment_address = base_address + number_bytes_transfer;
|
240 |
|
|
endcase // case (write_burst_type)
|
241 |
|
|
end // always @ *
|
242 |
|
|
always_ff @(posedge clk, negedge reset)
|
243 |
|
|
begin
|
244 |
|
|
if (!reset)
|
245 |
|
|
begin
|
246 |
|
|
address_burst <= '0;
|
247 |
|
|
end
|
248 |
|
|
else
|
249 |
|
|
begin
|
250 |
|
|
if (in_valid & out_ready)
|
251 |
|
|
address_burst <= increment_address;
|
252 |
|
|
end
|
253 |
|
|
end
|
254 |
|
|
// send data to output with 2 part: [mask_t0_algin][address_aligned_increment]
|
255 |
|
|
assign out_data = {output_masks[SELECT_BITS-1 : 0], out_aligned_address_burst};
|
256 |
|
|
end // if (INCREMENT_ADDRESS)
|
257 |
|
|
else
|
258 |
|
|
begin
|
259 |
|
|
assign out_data = {output_masks[SELECT_BITS-1 : 0], first_address_aligned};
|
260 |
|
|
end // else: !if(INCREMENT_ADDRESS)
|
261 |
|
|
|
262 |
|
|
endgenerate
|
263 |
|
|
endmodule
|