1 |
2 |
jclaytons |
//----------------------------------------------------------------------------
|
2 |
|
|
// Wishbone memory_sizer core
|
3 |
|
|
//
|
4 |
|
|
// This file is part of the "memory_sizer" project.
|
5 |
|
|
// http://www.opencores.org/cores/memory_sizer
|
6 |
|
|
//
|
7 |
|
|
//
|
8 |
|
|
// Description: See description below (which suffices for IP core
|
9 |
|
|
// specification document.)
|
10 |
|
|
//
|
11 |
|
|
// Copyright (C) 2001 John Clayton and OPENCORES.ORG
|
12 |
|
|
//
|
13 |
|
|
// This source file may be used and distributed without restriction provided
|
14 |
|
|
// that this copyright statement is not removed from the file and that any
|
15 |
|
|
// derivative work contains the original copyright notice and the associated
|
16 |
|
|
// disclaimer.
|
17 |
|
|
//
|
18 |
|
|
// This source file is free software; you can redistribute it and/or modify
|
19 |
|
|
// it under the terms of the GNU Lesser General Public License as published
|
20 |
|
|
// by the Free Software Foundation; either version 2.1 of the License, or
|
21 |
|
|
// (at your option) any later version.
|
22 |
|
|
//
|
23 |
|
|
// This source is distributed in the hope that it will be useful, but WITHOUT
|
24 |
|
|
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
25 |
|
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
26 |
|
|
// License for more details.
|
27 |
|
|
//
|
28 |
|
|
// You should have received a copy of the GNU Lesser General Public License
|
29 |
|
|
// along with this source.
|
30 |
|
|
// If not, download it from http://www.opencores.org/lgpl.shtml
|
31 |
|
|
//
|
32 |
|
|
//-------------------------------------------------------------------------------------
|
33 |
|
|
//
|
34 |
|
|
// Author: John Clayton
|
35 |
|
|
// Date : November 5, 2001
|
36 |
|
|
// Update: 11/05/01 copied this file from rs232_syscon.v (pared down).
|
37 |
|
|
// Update: 11/16/01 Continued coding efforts. Redesigned logic to include scalable
|
38 |
|
|
// "byte sized barrel shifter" and byte reversal blocks (the byte
|
39 |
|
|
// reversal is implemented as a function "byte_reversal").
|
40 |
|
|
// Changed encoding of memory_width_i and access_width_i.
|
41 |
|
|
// Implemented new counting and byte enable logic.
|
42 |
|
|
// Update: 12/04/01 Realized there was a mistake in the byte enable logic.
|
43 |
|
|
// Fixed it by using dat_shift to shift the byte enables.
|
44 |
|
|
// Made "byte_enable_source" twice as wide.
|
45 |
|
|
// Update: 12/05/01 Eliminated the "count" in favor of using "dat_shift" along
|
46 |
|
|
// with new terminal_count logic, in order to fix flaws found
|
47 |
|
|
// in the terminal_count signal. Fixed byte steering for
|
48 |
|
|
// stores. Tested using N_PP = 4, and LOG2_N_PP = 2 and saw
|
49 |
|
|
// correct operation for all sizes of store operations.
|
50 |
|
|
// Update: 12/13/01 Began testing with read logic. Found byte enable problem
|
51 |
|
|
// during writes. Removed "byte_dirty" bits.
|
52 |
|
|
// Update: 12/14/01 Added "latch_be_source" to create byte enables for reading
|
53 |
|
|
// which are based on the size of the memory (which fixed a
|
54 |
|
|
// bug in reading.) The module appears to be fully working,
|
55 |
|
|
// except for "big_endian" reads.
|
56 |
|
|
// Update: 12/17/01 Introduced the "middle_bus" in order to decouple the
|
57 |
|
|
// byte reverser from the byte steering logic, so that for
|
58 |
|
|
// writes byte reversing is done first, but for reads then
|
59 |
|
|
// byte reversing is done last. Introduced "latch_be_adjust"
|
60 |
|
|
// to cover big endian reads -- all is now working.
|
61 |
|
|
// Update: 12/17/01 Removed "middle_bus" (the two units are still decoupled!)
|
62 |
|
|
// because it seemed unnecessary. This freed up Tbuffs, but
|
63 |
|
|
// had no effect on resource utilization (slices). Also, the
|
64 |
|
|
// maximum reported clock speed increased. Removed debug
|
65 |
|
|
// port.
|
66 |
|
|
// Update: 12/18/01 Added file header according to opencores recommendations.
|
67 |
|
|
//
|
68 |
|
|
// Description
|
69 |
|
|
//-------------------------------------------------------------------------------------
|
70 |
|
|
// This logic module takes care of sizing bus transfers between a small
|
71 |
|
|
// microprocessor and its memory. It enables the microprocessor to
|
72 |
|
|
// generate access requests for different widths (read/write BYTE, WORD and
|
73 |
|
|
// DWORD, etc.) using memory which is sized independently of the accesses.
|
74 |
|
|
//
|
75 |
|
|
// Thus, a 32-bit microprocessor using 32-bit wide accesses can use this block
|
76 |
|
|
// in order to boot from an 8-bit wide flash device. This block takes care of
|
77 |
|
|
// generating the four 8-bit memory cycles that are required in order to read
|
78 |
|
|
// each DWORD for alimentation of the microprocessor.
|
79 |
|
|
//
|
80 |
|
|
// Also, if the memory supports byte enables during a write cycle, then this
|
81 |
|
|
// block "steers" a smaller data word to the appropriate location within a
|
82 |
|
|
// larger memory word, and activates the appropriate byte enables so that only
|
83 |
|
|
// the BYTEs which are affected by the write cycle are actually overwritten.
|
84 |
|
|
//
|
85 |
|
|
// Moreover, the memory_sizer block takes care of translating little-endian
|
86 |
|
|
// formats into big-endian formats and vice-versa. This is accomplished by the
|
87 |
|
|
// use of a single input bit "endianness_i"
|
88 |
|
|
//
|
89 |
|
|
// The memory_sizer block does not latch or store the parameters which it uses
|
90 |
|
|
// for operation. The input signals determine its operation on an ongoing
|
91 |
|
|
// basis. In fact, the only data storage present in this block is the latching
|
92 |
|
|
// provided for data which must be held during multiple cycle read operations.
|
93 |
|
|
// (There are also some counters, which don't count as data storage...)
|
94 |
|
|
//
|
95 |
|
|
// Encoding for access_width_i and memory_width_i is as follows:
|
96 |
|
|
//
|
97 |
|
|
// Bits Significance
|
98 |
|
|
// ------ ------------
|
99 |
|
|
// 0001 8-bits wide (1 byte)
|
100 |
|
|
// 0010 16-bits wide (2 bytes)
|
101 |
|
|
// 0100 32-bits wide (4 bytes)
|
102 |
|
|
// 1000 64-bits wide (8 bytes)
|
103 |
|
|
//
|
104 |
|
|
// (The access_width_i and memory_width_i inputs are sized according to the
|
105 |
|
|
// parameter LOG2_N_PP, but the significance is the same, using whatever
|
106 |
|
|
// lsbs are present.)
|
107 |
|
|
//
|
108 |
|
|
// It is envisioned that a designer may include this block for flexibility.
|
109 |
|
|
// If all of the memory accesses are of a single width, and the memory matches
|
110 |
|
|
// that width, and there is no need for endianness translation, then the user
|
111 |
|
|
// could hard-code the "memory_width_i" and "access_width_i" to correspond
|
112 |
|
|
// to the same width, hard-code the "endianness_i" input to the desired value
|
113 |
|
|
// and then the memory_sizer block would effectively do nothing, or very little.
|
114 |
|
|
// Most of its size and resources would be optimized out of the design at
|
115 |
|
|
// compile time. The dat_shift counter and read-storage latches would not be
|
116 |
|
|
// used, and so they would not even be synthesized.
|
117 |
|
|
//
|
118 |
|
|
// On the other hand, if the memory in the SOC (system on a chip) comprises
|
119 |
|
|
// various width devices, then the decode logic which selects the blocks of
|
120 |
|
|
// memory is ORed (for each like-sized block) and then concatenated in the
|
121 |
|
|
// proper order to generate a dynamic "mem_width_i" signal to the
|
122 |
|
|
// memory_sizer, so that the different size accesses are accomodated. The
|
123 |
|
|
// processor side, meanwhile (being "access_width_i"), could still be
|
124 |
|
|
// hard-wired to a given width, or be connected so that different width loads
|
125 |
|
|
// and stores are generated as needed.
|
126 |
|
|
//
|
127 |
|
|
// This block may generate exceptions to the processor, in the case of a write
|
128 |
|
|
// request, for example, to store a BYTE into a DWORD wide memory which doesn't
|
129 |
|
|
// support the use of byte enables. Although this could be done by reading the
|
130 |
|
|
// wider memory and masking in the correct BYTE, followed by storing the
|
131 |
|
|
// results back into the memory, this was deemed too complex a task for this
|
132 |
|
|
// block. Responsibility for such operations, if desired, would devolve upon
|
133 |
|
|
// the microprocessor itself. Support of byte enables is indicated by a "1" on
|
134 |
|
|
// the "memory_has_be_i" line.
|
135 |
|
|
//
|
136 |
|
|
// The clock used by memory_sizer is not limited to the speed of the clock used
|
137 |
|
|
// by the microprocessor. Since the memory_sizer contains only combinational
|
138 |
|
|
// logic, simple counters and some possible latches, it might run much faster
|
139 |
|
|
// than the microprocessor. In that case, generate two clocks which are
|
140 |
|
|
// synchronous: one for the processor, and another for memory_sizer.
|
141 |
|
|
// The memory_sizer clock could be 2x, 4x or even 8x that of the processor.
|
142 |
|
|
// In this way, the memory_sizer block can complete multiple memory read cycles
|
143 |
|
|
// in the same time as a single processor cycle -- assuming the memory is fast
|
144 |
|
|
// enough to support it -- and thereby the memory latency can be reduced.
|
145 |
|
|
//
|
146 |
|
|
// The memory_sizer block is not responsible for implementing wait states for
|
147 |
|
|
// the memory, especially since the number of wait states required can vary
|
148 |
|
|
// for each type and width of memory used. Instead, there is an "access_ack_o"
|
149 |
|
|
// signal to indicate completion of the entire requested memory access to the
|
150 |
|
|
// processor. On the memory side, there is "memory_ack_i" used to indicate to
|
151 |
|
|
// the memory_sizer block that the memory has completed the current cycle in
|
152 |
|
|
// progress. Therefore, in order to implement wait states, the memory sytem
|
153 |
|
|
// address decoder logic should generate the "memory_ack_i" signal based on the
|
154 |
|
|
// different types of memory present within the system, which can also be
|
155 |
|
|
// programmable. A parameterized watchdog timer inside of the memory sizer block
|
156 |
|
|
// indicates when "memory_ack_i" has not been asserted in a reasonable number
|
157 |
|
|
// of clock cycles. When this occurs, an exception is raised. The timer
|
158 |
|
|
// is started when "sel_i" is active (high). sel_i must remain active
|
159 |
|
|
// until the access is completed, otherwise the timer will reset and the
|
160 |
|
|
// access is aborted. If you don't want to use the watchdog portion of this
|
161 |
|
|
// block then simply don't connect the exception_watchdog_o line, and the watchdog
|
162 |
|
|
// timer will be optimized out of the logic.
|
163 |
|
|
//
|
164 |
|
|
// If desired, registers can be placed on the memory side of the block. They
|
165 |
|
|
// are treated just like memory of a given width, although access requests for
|
166 |
|
|
// misaligned writes, or writes which are smaller than the size of the registers,
|
167 |
|
|
// should generate exceptions, unless the registers support byte enables.
|
168 |
|
|
//
|
169 |
|
|
// Addresses are always assumed to be byte addresses in this unit, since the
|
170 |
|
|
// smallest granularity of data used in it is the BYTE. Also, the data bus
|
171 |
|
|
// size used must be a multiple of 8 bits, for the same reason.
|
172 |
|
|
//
|
173 |
|
|
//-------------------------------------------------------------------------------------
|
174 |
|
|
|
175 |
|
|
`define BYTE_SIZE 8 // Number of bits in one byte
|
176 |
|
|
|
177 |
|
|
|
178 |
|
|
module memory_sizer (
|
179 |
|
|
clk_i,
|
180 |
|
|
reset_i,
|
181 |
|
|
sel_i,
|
182 |
|
|
memory_ack_i,
|
183 |
|
|
memory_has_be_i,
|
184 |
|
|
memory_width_i,
|
185 |
|
|
access_width_i,
|
186 |
|
|
access_big_endian_i,
|
187 |
|
|
adr_i,
|
188 |
|
|
we_i,
|
189 |
|
|
dat_io,
|
190 |
|
|
memory_dat_io,
|
191 |
|
|
memory_adr_o, // Same width as adr_i (only lsbs are modified)
|
192 |
|
|
memory_we_o,
|
193 |
|
|
memory_be_o,
|
194 |
|
|
access_ack_o,
|
195 |
|
|
exception_be_o,
|
196 |
|
|
exception_watchdog_o
|
197 |
|
|
);
|
198 |
|
|
|
199 |
|
|
// Parameters
|
200 |
|
|
|
201 |
|
|
// The timer value can be from [0 to (2^WATCHDOG_TIMER_BITS_PP)-1] inclusive.
|
202 |
|
|
parameter N_PP = 4; // number of bytes in data bus
|
203 |
|
|
parameter LOG2_N_PP = 2; // log base 2 of data bus size (bytes)
|
204 |
|
|
parameter ADR_BITS_PP = 32; // # of bits in adr buses
|
205 |
|
|
parameter WATCHDOG_TIMER_VALUE_PP = 12; // # of sys_clks before ack expected
|
206 |
|
|
parameter WATCHDOG_TIMER_BITS_PP = 4; // # of bits needed for timer
|
207 |
|
|
|
208 |
|
|
|
209 |
|
|
// I/O declarations
|
210 |
|
|
input clk_i; // Memory sub-system clock input
|
211 |
|
|
input reset_i; // Reset signal for this module
|
212 |
|
|
input sel_i; // Enables watchdog timer, activates memory_sizer
|
213 |
|
|
input memory_ack_i; // Ack from memory (delay for wait states)
|
214 |
|
|
input memory_has_be_i; // Indicates memory at current address has byte enables
|
215 |
|
|
input [LOG2_N_PP:0] memory_width_i; // Width code of memory
|
216 |
|
|
input [LOG2_N_PP:0] access_width_i; // Width code of access request
|
217 |
|
|
input access_big_endian_i; // 0=little endian, 1=big endian
|
218 |
|
|
input [ADR_BITS_PP-1:0] adr_i; // Address bus input
|
219 |
|
|
input we_i; // type of access
|
220 |
|
|
inout [`BYTE_SIZE*N_PP-1:0] dat_io; // processor data bus
|
221 |
|
|
inout [`BYTE_SIZE*N_PP-1:0] memory_dat_io; // data bus to memory
|
222 |
|
|
output [ADR_BITS_PP-1:0] memory_adr_o; // address bus to memory
|
223 |
|
|
output memory_we_o; // we to memory
|
224 |
|
|
output [N_PP-1:0] memory_be_o; // byte enables to memory
|
225 |
|
|
output access_ack_o; // shows that access is completed
|
226 |
|
|
output exception_be_o; // exception for write to non-byte-enabled memory
|
227 |
|
|
output exception_watchdog_o; // exception for memory_ack_i watch dog timeout
|
228 |
|
|
|
229 |
|
|
// Internal signal declarations
|
230 |
|
|
wire [2*N_PP-1:0] memory_be_source; // Unshifted byte enables for writing
|
231 |
|
|
wire [2*N_PP-1:0] latch_be_source; // Unshifted byte enables for reading
|
232 |
|
|
wire [N_PP-1:0] latch_be; // "latch_be" is like "memory_be_o"
|
233 |
|
|
wire [N_PP-1:0] latch_be_lil_endian; // but used internally for reads.
|
234 |
|
|
wire [N_PP-1:0] latch_be_big_endian;
|
235 |
|
|
wire [LOG2_N_PP-1:0] latch_be_adjust;
|
236 |
|
|
wire [LOG2_N_PP+1:0] dat_shift_next; // Next dat_shift value (extra bit
|
237 |
|
|
// is for terminal count compare.)
|
238 |
|
|
wire [LOG2_N_PP-1:0] alignment; // shows aligment of access
|
239 |
|
|
wire terminal_count; // signifies last store cycle
|
240 |
|
|
wire [`BYTE_SIZE*N_PP-1:0] steer_dat_i; // data input to byte steering logic
|
241 |
|
|
wire [`BYTE_SIZE*N_PP-1:0] revrs_dat_i; // data input to byte reversing logic
|
242 |
|
|
|
243 |
|
|
reg [LOG2_N_PP-1:0] byte_mux_select; // selects which bytes to transfer
|
244 |
|
|
reg [LOG2_N_PP:0] dat_shift; // shift amt. for data and byte enables
|
245 |
|
|
reg [`BYTE_SIZE*N_PP-1:0] revrs_dat_o; // data out from byte reversing logic
|
246 |
|
|
reg [`BYTE_SIZE*N_PP-1:0] steer_dat_o; // data out from byte steering logic
|
247 |
|
|
reg [`BYTE_SIZE*N_PP-1:0] read_dat; // read data (after latch bypassing)
|
248 |
|
|
reg [`BYTE_SIZE*N_PP-1:0] latched_read_dat; // read values before latch bypass
|
249 |
|
|
|
250 |
|
|
|
251 |
|
|
reg [WATCHDOG_TIMER_BITS_PP-1:0] watchdog_count;
|
252 |
|
|
|
253 |
|
|
//--------------------------------------------------------------------------
|
254 |
|
|
// Instantiations
|
255 |
|
|
//--------------------------------------------------------------------------
|
256 |
|
|
|
257 |
|
|
|
258 |
|
|
//--------------------------------------------------------------------------
|
259 |
|
|
// Functions & Tasks
|
260 |
|
|
//--------------------------------------------------------------------------
|
261 |
|
|
|
262 |
|
|
function [`BYTE_SIZE*N_PP-1:0] byte_reversal;
|
263 |
|
|
input [`BYTE_SIZE*N_PP-1:0] din;
|
264 |
|
|
integer k;
|
265 |
|
|
begin
|
266 |
|
|
for (k=0; k<N_PP; k=k+1)
|
267 |
|
|
byte_reversal[`BYTE_SIZE*(N_PP-k)-1:`BYTE_SIZE*(N_PP-k-1)]
|
268 |
|
|
<= din[`BYTE_SIZE*(k+1)-1:`BYTE_SIZE*k];
|
269 |
|
|
end
|
270 |
|
|
endfunction
|
271 |
|
|
|
272 |
|
|
//--------------------------------------------------------------------------
|
273 |
|
|
// Module code
|
274 |
|
|
//--------------------------------------------------------------------------
|
275 |
|
|
|
276 |
|
|
// Mask off the address bits that don't matter for alignment
|
277 |
|
|
assign alignment = (memory_width_i - 1) & adr_i[LOG2_N_PP-1:0];
|
278 |
|
|
|
279 |
|
|
// Setting up the basic (alignment shifted) byte enables
|
280 |
|
|
assign memory_be_source = ((1<<access_width_i)-1);
|
281 |
|
|
assign latch_be_source = ((1<<memory_width_i)-1);
|
282 |
|
|
|
283 |
|
|
// Assigning the byte enables and latch enables
|
284 |
|
|
assign memory_be_o = we_i?((memory_be_source << alignment) >> dat_shift)
|
285 |
|
|
:{N_PP{1'b1}};
|
286 |
|
|
// (memory byte enables are all high for reads!)
|
287 |
|
|
|
288 |
|
|
// For big_endian reads, the latch byte enables (and indeed the data also)
|
289 |
|
|
// are shifted using a special mapping, which causes the data to appear at
|
290 |
|
|
// the opposite end of the "read_data" bus.
|
291 |
|
|
assign latch_be_lil_endian = ((latch_be_source << dat_shift) >> alignment);
|
292 |
|
|
assign latch_be_adjust = ~(access_width_i[LOG2_N_PP-1:0]-1);
|
293 |
|
|
assign latch_be_big_endian = latch_be_lil_endian << latch_be_adjust;
|
294 |
|
|
assign latch_be = (access_big_endian_i)?latch_be_big_endian
|
295 |
|
|
:latch_be_lil_endian;
|
296 |
|
|
|
297 |
|
|
// Exceptions
|
298 |
|
|
assign exception_be_o = (alignment != 0) && ~memory_has_be_i;
|
299 |
|
|
assign exception_watchdog_o = (watchdog_count == WATCHDOG_TIMER_VALUE_PP);
|
300 |
|
|
|
301 |
|
|
// Pass signals to memory
|
302 |
|
|
assign memory_we_o = we_i;
|
303 |
|
|
|
304 |
|
|
|
305 |
|
|
// Enable the data bus outputs in each direction
|
306 |
|
|
assign dat_io = (sel_i && ~we_i)?revrs_dat_o:{`BYTE_SIZE*N_PP{1'bZ}};
|
307 |
|
|
assign memory_dat_io = (sel_i && we_i)?steer_dat_o:{`BYTE_SIZE*N_PP{1'bZ}};
|
308 |
|
|
|
309 |
|
|
// Decide which bus supplies the byte reversing logic
|
310 |
|
|
// (One could just use a single mux here instead of the tri-state buffers.
|
311 |
|
|
// in fact, the synthesis tool might decide to change the tri-state buffers
|
312 |
|
|
// into simple 2:1 muxes...)
|
313 |
|
|
assign revrs_dat_i = (~we_i)?read_dat:{`BYTE_SIZE*N_PP{1'bZ}};
|
314 |
|
|
assign revrs_dat_i = (we_i)?dat_io:{`BYTE_SIZE*N_PP{1'bZ}};
|
315 |
|
|
|
316 |
|
|
|
317 |
|
|
// Decide which bus supplies the byte steering logic
|
318 |
|
|
// (One could just use a single mux here instead of the tri-state buffers.
|
319 |
|
|
// in fact, the synthesis tool might decide to change the tri-state buffers
|
320 |
|
|
// into simple 2:1 muxes...)
|
321 |
|
|
assign steer_dat_i = (~we_i)?memory_dat_io:{`BYTE_SIZE*N_PP{1'bZ}};
|
322 |
|
|
assign steer_dat_i = (we_i)?revrs_dat_o:{`BYTE_SIZE*N_PP{1'bZ}};
|
323 |
|
|
|
324 |
|
|
|
325 |
|
|
// This logic latches the data bytes which are read during the first cycles
|
326 |
|
|
// of an access. During the final cycle of the access, then "terminal_count"
|
327 |
|
|
// is asserted by the counting logic, which causes the latches which are
|
328 |
|
|
// "non-dirty" (i.e. which do not yet contain data) to be bypassed by muxes.
|
329 |
|
|
// This means that for single cycle accesses, the data will flow directly
|
330 |
|
|
// around the latches and an extra clock cycle will not be needed in order
|
331 |
|
|
// to latch the data...
|
332 |
|
|
always @(posedge clk_i)
|
333 |
|
|
begin: BYTE_LATCHES
|
334 |
|
|
integer i;
|
335 |
|
|
|
336 |
|
|
if (reset_i || terminal_count || ~sel_i)
|
337 |
|
|
begin
|
338 |
|
|
latched_read_dat <= 0;
|
339 |
|
|
end
|
340 |
|
|
else if (sel_i && ~we_i && memory_ack_i)
|
341 |
|
|
begin
|
342 |
|
|
for (i=0;i<N_PP;i=i+1)
|
343 |
|
|
begin
|
344 |
|
|
if (latch_be[i]) latched_read_dat[`BYTE_SIZE*(i+1)-1:`BYTE_SIZE*i]
|
345 |
|
|
<= steer_dat_o[`BYTE_SIZE*(i+1)-1:`BYTE_SIZE*i];
|
346 |
|
|
end
|
347 |
|
|
end
|
348 |
|
|
end
|
349 |
|
|
|
350 |
|
|
// This part handles the bypass muxes
|
351 |
|
|
always @(
|
352 |
|
|
terminal_count or
|
353 |
|
|
latch_be or
|
354 |
|
|
steer_dat_o or
|
355 |
|
|
latched_read_dat
|
356 |
|
|
)
|
357 |
|
|
begin: LATCH_BYPASS
|
358 |
|
|
integer j;
|
359 |
|
|
|
360 |
|
|
for (j=0;j<N_PP;j=j+1)
|
361 |
|
|
begin
|
362 |
|
|
if (terminal_count && latch_be[j])
|
363 |
|
|
read_dat[`BYTE_SIZE*(j+1)-1:`BYTE_SIZE*j]
|
364 |
|
|
<= steer_dat_o[`BYTE_SIZE*(j+1)-1:`BYTE_SIZE*j];
|
365 |
|
|
else read_dat[`BYTE_SIZE*(j+1)-1:`BYTE_SIZE*j]
|
366 |
|
|
<= latched_read_dat[`BYTE_SIZE*(j+1)-1:`BYTE_SIZE*j];
|
367 |
|
|
end
|
368 |
|
|
end
|
369 |
|
|
|
370 |
|
|
|
371 |
|
|
// Byte reversal logic (reused for both reads and writes)
|
372 |
|
|
always @(
|
373 |
|
|
revrs_dat_i or
|
374 |
|
|
access_big_endian_i
|
375 |
|
|
)
|
376 |
|
|
begin
|
377 |
|
|
// Reverse the bytes of the data bus, if needed
|
378 |
|
|
if (access_big_endian_i) revrs_dat_o <= byte_reversal(revrs_dat_i);
|
379 |
|
|
else revrs_dat_o <= revrs_dat_i;
|
380 |
|
|
end
|
381 |
|
|
|
382 |
|
|
|
383 |
|
|
// Steering logic (reused for both reads and writes)
|
384 |
|
|
always @(
|
385 |
|
|
steer_dat_i or
|
386 |
|
|
dat_shift or
|
387 |
|
|
alignment or
|
388 |
|
|
we_i or
|
389 |
|
|
access_width_i or
|
390 |
|
|
access_big_endian_i
|
391 |
|
|
)
|
392 |
|
|
begin
|
393 |
|
|
// If bytes are reversed, an extra "bit inversion mask" is applied
|
394 |
|
|
// to reflect a new mapping which is correct for reversed bytes.
|
395 |
|
|
if (access_big_endian_i && we_i)
|
396 |
|
|
byte_mux_select <= (dat_shift[LOG2_N_PP-1:0] ^ ~(access_width_i-1))
|
397 |
|
|
- alignment;
|
398 |
|
|
else if (~access_big_endian_i && we_i)
|
399 |
|
|
byte_mux_select <= dat_shift - alignment;
|
400 |
|
|
// For reads, negate the shift amount
|
401 |
|
|
else if (access_big_endian_i && ~we_i)
|
402 |
|
|
byte_mux_select <= alignment
|
403 |
|
|
- (dat_shift[LOG2_N_PP-1:0] ^ ~(access_width_i-1));
|
404 |
|
|
else if (~access_big_endian_i && ~we_i)
|
405 |
|
|
byte_mux_select <= alignment - dat_shift;
|
406 |
|
|
|
407 |
|
|
// Rotate the data bus (byte-sized barrel shifter!)
|
408 |
|
|
steer_dat_o <= (
|
409 |
|
|
(steer_dat_i >> `BYTE_SIZE*byte_mux_select)
|
410 |
|
|
|(steer_dat_i << `BYTE_SIZE*(N_PP-byte_mux_select))
|
411 |
|
|
);
|
412 |
|
|
end
|
413 |
|
|
|
414 |
|
|
|
415 |
|
|
// This is the counting logic.
|
416 |
|
|
// It is implemented using "count_next" in order to detect when
|
417 |
|
|
// the last cycle is being performed, which is when the "next" count
|
418 |
|
|
// equals or exceeds the total size of the access requested in bytes.
|
419 |
|
|
// (Using the "next" approach avoids issues relating to different
|
420 |
|
|
// memory sizes!)
|
421 |
|
|
always @(posedge clk_i)
|
422 |
|
|
begin
|
423 |
|
|
if (reset_i || terminal_count || ~sel_i) dat_shift <= 0;
|
424 |
|
|
else if (memory_ack_i) dat_shift <= dat_shift_next;
|
425 |
|
|
end
|
426 |
|
|
|
427 |
|
|
assign dat_shift_next = dat_shift + memory_width_i;
|
428 |
|
|
assign terminal_count = (dat_shift_next >= (access_width_i + alignment));
|
429 |
|
|
assign memory_adr_o = adr_i + dat_shift;
|
430 |
|
|
assign access_ack_o = terminal_count && sel_i;
|
431 |
|
|
|
432 |
|
|
// This is the watchdog timer
|
433 |
|
|
// It runs whenever the memory_sizer is selected for an access, and the
|
434 |
|
|
// memory has not yet responded with an ack signal.
|
435 |
|
|
always @(posedge clk_i)
|
436 |
|
|
begin
|
437 |
|
|
if (reset_i || ~sel_i || memory_ack_i) watchdog_count <= 0;
|
438 |
|
|
else if (~exception_watchdog_o) watchdog_count <= watchdog_count + 1;
|
439 |
|
|
end
|
440 |
|
|
|
441 |
|
|
|
442 |
|
|
endmodule
|
443 |
|
|
|
444 |
|
|
|