1 |
56 |
nyawn |
//////////////////////////////////////////////////////////////////////
|
2 |
|
|
//// ////
|
3 |
|
|
//// onchip_ram_top.v ////
|
4 |
|
|
//// ////
|
5 |
|
|
//// ////
|
6 |
|
|
//// ////
|
7 |
|
|
//// Author(s): ////
|
8 |
|
|
//// De Nayer Instituut (emsys.denayer.wenk.be) ////
|
9 |
|
|
//// Nathan Yawn (nathan.yawn@epfl.ch) ////
|
10 |
|
|
//// ////
|
11 |
|
|
//// ////
|
12 |
|
|
//// ////
|
13 |
|
|
//////////////////////////////////////////////////////////////////////
|
14 |
|
|
//// ////
|
15 |
|
|
//// Copyright (C) 2003-2008 Authors ////
|
16 |
|
|
//// ////
|
17 |
|
|
//// This source file may be used and distributed without ////
|
18 |
|
|
//// restriction provided that this copyright statement is not ////
|
19 |
|
|
//// removed from the file and that any derivative work contains ////
|
20 |
|
|
//// the original copyright notice and the associated disclaimer. ////
|
21 |
|
|
//// ////
|
22 |
|
|
//// This source file is free software; you can redistribute it ////
|
23 |
|
|
//// and/or modify it under the terms of the GNU Lesser General ////
|
24 |
|
|
//// Public License as published by the Free Software Foundation; ////
|
25 |
|
|
//// either version 2.1 of the License, or (at your option) any ////
|
26 |
|
|
//// later version. ////
|
27 |
|
|
//// ////
|
28 |
|
|
//// This source is distributed in the hope that it will be ////
|
29 |
|
|
//// useful, but WITHOUT ANY WARRANTY; without even the implied ////
|
30 |
|
|
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
|
31 |
|
|
//// PURPOSE. See the GNU Lesser General Public License for more ////
|
32 |
|
|
//// details. ////
|
33 |
|
|
//// ////
|
34 |
|
|
//// You should have received a copy of the GNU Lesser General ////
|
35 |
|
|
//// Public License along with this source; if not, download it ////
|
36 |
|
|
//// from http://www.opencores.org/lgpl.shtml ////
|
37 |
|
|
//// ////
|
38 |
|
|
//////////////////////////////////////////////////////////////////////
|
39 |
|
|
// //
|
40 |
|
|
// This file is a simple wrapper for on-chip (FPGA) RAM blocks, //
|
41 |
|
|
// coupled with a simple WISHBONE bus interface. It supports 2- //
|
42 |
|
|
// cycle writes, and 1-cycle reads. Bursts using bus tags (for //
|
43 |
|
|
// registered-feedback busses) are not supported at present. //
|
44 |
|
|
// Altera ALTSYNCRAM blocks are instantiated directly. Xilinx //
|
45 |
|
|
// BRAM blocks are not as easy to declare for a wide range of //
|
46 |
|
|
// devices, they are implied instead of declared directly. //
|
47 |
|
|
// //
|
48 |
|
|
//////////////////////////////////////////////////////////////////////
|
49 |
|
|
//
|
50 |
|
|
// CVS Revision History
|
51 |
|
|
//
|
52 |
|
|
// $Log: onchip_ram_top.v,v $
|
53 |
|
|
// Revision 1.1 2010-03-29 19:34:52 Nathan
|
54 |
|
|
// The onchip_ram memory unit is not distributed on the OpenCores website as of this checkin; this version of the core may be used with the advanced debug system testbench until it is.
|
55 |
|
|
//
|
56 |
|
|
// Revision 1.1 2008/07/18 20:13:48 Nathan
|
57 |
|
|
// Changed directory structure to match existing projects.
|
58 |
|
|
//
|
59 |
|
|
// Revision 1.2 2008/05/22 19:56:36 Nathan
|
60 |
|
|
// Added implied BRAM for Xilinx FPGAs. Also added copyright, CVS log, and brief description.
|
61 |
|
|
//
|
62 |
|
|
|
63 |
|
|
|
64 |
|
|
`define ALTERA
|
65 |
|
|
|
66 |
|
|
|
67 |
|
|
module onchip_ram_top (
|
68 |
|
|
wb_clk_i, wb_rst_i,
|
69 |
|
|
wb_dat_i, wb_dat_o, wb_adr_i, wb_sel_i, wb_we_i, wb_cyc_i,
|
70 |
|
|
wb_stb_i, wb_ack_o, wb_err_o
|
71 |
|
|
);
|
72 |
|
|
|
73 |
|
|
// Function to calculate width of address signal.
|
74 |
|
|
function integer log2;
|
75 |
|
|
input [31:0] value;
|
76 |
|
|
for (log2=0; value>0; log2=log2+1)
|
77 |
|
|
value = value>>1;
|
78 |
|
|
endfunction
|
79 |
|
|
|
80 |
|
|
//
|
81 |
|
|
// Parameters
|
82 |
|
|
//
|
83 |
|
|
parameter dwidth = 32;
|
84 |
|
|
parameter size_bytes = 4096;
|
85 |
|
|
parameter initfile = "NONE";
|
86 |
|
|
parameter words = (size_bytes / (dwidth/8)); // Don't override this. Really.
|
87 |
|
|
parameter awidth = log2(size_bytes)-1; // Don't override this either.
|
88 |
|
|
parameter bewidth = (dwidth/8); // Or this.
|
89 |
|
|
|
90 |
|
|
//
|
91 |
|
|
// I/O Ports
|
92 |
|
|
//
|
93 |
|
|
input wb_clk_i;
|
94 |
|
|
input wb_rst_i;
|
95 |
|
|
//
|
96 |
|
|
// WB slave i/f
|
97 |
|
|
//
|
98 |
|
|
input [dwidth-1:0] wb_dat_i;
|
99 |
|
|
output [dwidth-1:0] wb_dat_o;
|
100 |
|
|
input [awidth-1:0] wb_adr_i;
|
101 |
|
|
input [bewidth-1:0] wb_sel_i;
|
102 |
|
|
input wb_we_i;
|
103 |
|
|
input wb_cyc_i;
|
104 |
|
|
input wb_stb_i;
|
105 |
|
|
output wb_ack_o;
|
106 |
|
|
output wb_err_o;
|
107 |
|
|
//
|
108 |
|
|
// Internal regs and wires
|
109 |
|
|
//
|
110 |
|
|
wire we;
|
111 |
|
|
wire [bewidth-1:0] be_i;
|
112 |
|
|
wire [dwidth-1:0] wb_dat_o;
|
113 |
|
|
wire ack_we;
|
114 |
|
|
reg ack_we1;
|
115 |
|
|
reg ack_we2;
|
116 |
|
|
reg ack_re;
|
117 |
|
|
|
118 |
|
|
//
|
119 |
|
|
// Aliases and simple assignments
|
120 |
|
|
//
|
121 |
|
|
assign wb_ack_o = ack_re | ack_we;
|
122 |
|
|
assign wb_err_o = 1'b0; //wb_cyc_i & wb_stb_i & ???;
|
123 |
|
|
assign we = wb_cyc_i & wb_stb_i & wb_we_i & (|wb_sel_i[bewidth-1:0]);
|
124 |
|
|
assign be_i = (wb_cyc_i & wb_stb_i) * wb_sel_i;
|
125 |
|
|
|
126 |
|
|
//
|
127 |
|
|
// Write acknowledge
|
128 |
|
|
// Little trick to keep the writes single-cycle:
|
129 |
|
|
// set the write ack signal on the falling clk edge, so it will be set halfway through the
|
130 |
|
|
// cycle and be registered at the end of the first clock cycle. To prevent contention for
|
131 |
|
|
// the next half-cycle, latch the ack_we1 signal on the next rising edge, and force the
|
132 |
|
|
// bus output low when that latched signal is high.
|
133 |
|
|
always @ (negedge wb_clk_i or posedge wb_rst_i)
|
134 |
|
|
begin
|
135 |
|
|
if (wb_rst_i)
|
136 |
|
|
ack_we1 <= 1'b0;
|
137 |
|
|
else
|
138 |
|
|
if (wb_cyc_i & wb_stb_i & wb_we_i & ~ack_we)
|
139 |
|
|
ack_we1 <= #1 1'b1;
|
140 |
|
|
else
|
141 |
|
|
ack_we1 <= #1 1'b0;
|
142 |
|
|
end
|
143 |
|
|
|
144 |
|
|
always @ (posedge wb_clk_i or posedge wb_rst_i)
|
145 |
|
|
begin
|
146 |
|
|
if (wb_rst_i)
|
147 |
|
|
ack_we2 <= 1'b0;
|
148 |
|
|
else
|
149 |
|
|
ack_we2 <= ack_we1;
|
150 |
|
|
end
|
151 |
|
|
|
152 |
|
|
assign ack_we = ack_we1 & ~ack_we2;
|
153 |
|
|
|
154 |
|
|
|
155 |
|
|
//
|
156 |
|
|
// read acknowledge
|
157 |
|
|
//
|
158 |
|
|
always @ (posedge wb_clk_i or posedge wb_rst_i)
|
159 |
|
|
begin
|
160 |
|
|
if (wb_rst_i)
|
161 |
|
|
ack_re <= 1'b0;
|
162 |
|
|
else
|
163 |
|
|
if (wb_cyc_i & wb_stb_i & ~wb_err_o & ~wb_we_i & ~ack_re)
|
164 |
|
|
ack_re <= 1'b1;
|
165 |
|
|
else
|
166 |
|
|
ack_re <= 1'b0;
|
167 |
|
|
end
|
168 |
|
|
|
169 |
|
|
|
170 |
|
|
`ifdef ALTERA
|
171 |
|
|
//
|
172 |
|
|
// change intended_device_family according to the FPGA device (Stratix or Cyclone)
|
173 |
|
|
//
|
174 |
|
|
altsyncram altsyncram_component (
|
175 |
|
|
.wren_a (we),
|
176 |
|
|
.clock0 (wb_clk_i),
|
177 |
|
|
.byteena_a (be_i),
|
178 |
|
|
.address_a (wb_adr_i[awidth-1:2]),
|
179 |
|
|
.data_a (wb_dat_i),
|
180 |
|
|
.q_a (wb_dat_o));
|
181 |
|
|
defparam
|
182 |
|
|
altsyncram_component.intended_device_family = "CycloneII",
|
183 |
|
|
altsyncram_component.width_a = dwidth,
|
184 |
|
|
altsyncram_component.widthad_a = (awidth-2),
|
185 |
|
|
altsyncram_component.numwords_a = (words),
|
186 |
|
|
altsyncram_component.operation_mode = "SINGLE_PORT",
|
187 |
|
|
altsyncram_component.outdata_reg_a = "UNREGISTERED",
|
188 |
|
|
altsyncram_component.indata_aclr_a = "NONE",
|
189 |
|
|
altsyncram_component.wrcontrol_aclr_a = "NONE",
|
190 |
|
|
altsyncram_component.address_aclr_a = "NONE",
|
191 |
|
|
altsyncram_component.outdata_aclr_a = "NONE",
|
192 |
|
|
altsyncram_component.width_byteena_a = bewidth,
|
193 |
|
|
altsyncram_component.byte_size = 8,
|
194 |
|
|
altsyncram_component.byteena_aclr_a = "NONE",
|
195 |
|
|
altsyncram_component.ram_block_type = "AUTO",
|
196 |
|
|
altsyncram_component.lpm_type = "altsyncram",
|
197 |
|
|
altsyncram_component.init_file = initfile;
|
198 |
|
|
|
199 |
|
|
|
200 |
|
|
`else
|
201 |
|
|
// Xilinx does not have anything so neat as a resizable memory array.
|
202 |
|
|
// We use generic code, which will imply a BRAM array.
|
203 |
|
|
// This will also work for non-Xilinx architectures, but be warned that
|
204 |
|
|
// it will not be recognized as an implied RAM block by the current Altera
|
205 |
|
|
// tools.
|
206 |
|
|
|
207 |
|
|
// The actual memory array...4 banks, for 4 separate byte lanes
|
208 |
|
|
reg [7:0] mem_bank0 [0:(words-1)];
|
209 |
|
|
reg [7:0] mem_bank1 [0:(words-1)];
|
210 |
|
|
reg [7:0] mem_bank2 [0:(words-1)];
|
211 |
|
|
reg [7:0] mem_bank3 [0:(words-1)];
|
212 |
|
|
|
213 |
|
|
// Write enables, qualified with byte lane enables
|
214 |
|
|
wire we_0, we_1, we_2, we_3;
|
215 |
|
|
|
216 |
|
|
// Enable, indicates any read or write operation
|
217 |
|
|
wire en;
|
218 |
|
|
|
219 |
|
|
// Yes, separate address registers, which will hold identical data. This
|
220 |
|
|
// is necessary to correctly imply a Xilinx BRAM. Because that's just
|
221 |
|
|
// how they roll.
|
222 |
|
|
reg [(awidth-3):0] addr_reg0;
|
223 |
|
|
reg [(awidth-3):0] addr_reg1;
|
224 |
|
|
reg [(awidth-3):0] addr_reg2;
|
225 |
|
|
reg [(awidth-3):0] addr_reg3;
|
226 |
|
|
|
227 |
|
|
assign we_0 = be_i[0] & wb_we_i;
|
228 |
|
|
assign we_1 = be_i[1] & wb_we_i;
|
229 |
|
|
assign we_2 = be_i[2] & wb_we_i;
|
230 |
|
|
assign we_3 = be_i[3] & wb_we_i;
|
231 |
|
|
|
232 |
|
|
assign en = (|be_i);
|
233 |
|
|
|
234 |
|
|
// Sequential bits. Setting of the address registers, and memory array writes.
|
235 |
|
|
always @ (posedge wb_clk_i)
|
236 |
|
|
begin
|
237 |
|
|
if (en)
|
238 |
|
|
begin
|
239 |
|
|
addr_reg0 <= wb_adr_i[(awidth-1):2];
|
240 |
|
|
if (we_0)
|
241 |
|
|
begin
|
242 |
|
|
mem_bank0[wb_adr_i[(awidth-1):2]] <= wb_dat_i[7:0];
|
243 |
|
|
end
|
244 |
|
|
end
|
245 |
|
|
|
246 |
|
|
if (en)
|
247 |
|
|
begin
|
248 |
|
|
addr_reg1 <= wb_adr_i[(awidth-1):2];
|
249 |
|
|
if (we_1)
|
250 |
|
|
begin
|
251 |
|
|
mem_bank1[wb_adr_i[(awidth-1):2]] <= wb_dat_i[15:8];
|
252 |
|
|
end
|
253 |
|
|
end
|
254 |
|
|
|
255 |
|
|
if (en)
|
256 |
|
|
begin
|
257 |
|
|
addr_reg2 <= wb_adr_i[(awidth-1):2];
|
258 |
|
|
if (we_2)
|
259 |
|
|
begin
|
260 |
|
|
mem_bank2[wb_adr_i[(awidth-1):2]] <= wb_dat_i[23:16];
|
261 |
|
|
end
|
262 |
|
|
end
|
263 |
|
|
|
264 |
|
|
if (en)
|
265 |
|
|
begin
|
266 |
|
|
addr_reg3 <= wb_adr_i[(awidth-1):2];
|
267 |
|
|
if (we_3)
|
268 |
|
|
begin
|
269 |
|
|
mem_bank3[wb_adr_i[(awidth-1):2]] <= wb_dat_i[31:24];
|
270 |
|
|
end
|
271 |
|
|
end
|
272 |
|
|
|
273 |
|
|
end
|
274 |
|
|
|
275 |
|
|
|
276 |
|
|
// Data output. Combinatorial, no output register.
|
277 |
|
|
assign wb_dat_o = {mem_bank3[addr_reg2], mem_bank2[addr_reg2], mem_bank1[addr_reg1], mem_bank0[addr_reg0]};
|
278 |
|
|
|
279 |
|
|
`endif
|
280 |
|
|
|
281 |
|
|
endmodule
|