b8da6409 |
1 | ////////////////////////////////////////////////////////////////////// |
2 | //// //// |
3 | //// Generic Dual-Port Synchronous RAM //// |
4 | //// //// |
5 | //// This file is part of memory library available from //// |
6 | //// http://www.opencores.org/cvsweb.shtml/generic_memories/ //// |
7 | //// //// |
8 | //// Description //// |
9 | //// This block is a wrapper with common dual-port //// |
10 | //// synchronous memory interface for different //// |
11 | //// types of ASIC and FPGA RAMs. Beside universal memory //// |
12 | //// interface it also provides behavioral model of generic //// |
13 | //// dual-port synchronous RAM. //// |
14 | //// It also contains a fully synthesizeable model for FPGAs. //// |
15 | //// It should be used in all OPENCORES designs that want to be //// |
16 | //// portable accross different target technologies and //// |
17 | //// independent of target memory. //// |
18 | //// //// |
19 | //// Supported ASIC RAMs are: //// |
20 | //// - Artisan Dual-Port Sync RAM //// |
21 | //// - Avant! Two-Port Sync RAM (*) //// |
22 | //// - Virage 2-port Sync RAM //// |
23 | //// //// |
24 | //// Supported FPGA RAMs are: //// |
25 | //// - Generic FPGA (VENDOR_FPGA) //// |
26 | //// Tested RAMs: Altera, Xilinx //// |
27 | //// Synthesis tools: LeonardoSpectrum, Synplicity //// |
28 | //// - Xilinx (VENDOR_XILINX) //// |
29 | //// - Altera (VENDOR_ALTERA) //// |
30 | //// //// |
31 | //// To Do: //// |
32 | //// - fix Avant! //// |
33 | //// - add additional RAMs (VS etc) //// |
34 | //// //// |
35 | //// Author(s): //// |
36 | //// - Richard Herveille, richard@asics.ws //// |
37 | //// - Damjan Lampret, lampret@opencores.org //// |
38 | //// //// |
39 | ////////////////////////////////////////////////////////////////////// |
40 | //// //// |
41 | //// Copyright (C) 2000 Authors and OPENCORES.ORG //// |
42 | //// //// |
43 | //// This source file may be used and distributed without //// |
44 | //// restriction provided that this copyright statement is not //// |
45 | //// removed from the file and that any derivative work contains //// |
46 | //// the original copyright notice and the associated disclaimer. //// |
47 | //// //// |
48 | //// This source file is free software; you can redistribute it //// |
49 | //// and/or modify it under the terms of the GNU Lesser General //// |
50 | //// Public License as published by the Free Software Foundation; //// |
51 | //// either version 2.1 of the License, or (at your option) any //// |
52 | //// later version. //// |
53 | //// //// |
54 | //// This source is distributed in the hope that it will be //// |
55 | //// useful, but WITHOUT ANY WARRANTY; without even the implied //// |
56 | //// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// |
57 | //// PURPOSE. See the GNU Lesser General Public License for more //// |
58 | //// details. //// |
59 | //// //// |
60 | //// You should have received a copy of the GNU Lesser General //// |
61 | //// Public License along with this source; if not, download it //// |
62 | //// from http://www.opencores.org/lgpl.shtml //// |
63 | //// //// |
64 | ////////////////////////////////////////////////////////////////////// |
65 | // |
66 | // CVS Revision History |
67 | // |
68 | // $Log: generic_dpram.v,v $ |
69 | // Revision 1.1 2007-02-11 22:05:26 sithglan |
70 | // += dpram |
71 | // |
72 | // Revision 1.4 2002/09/28 08:18:52 rherveille |
73 | // Changed synthesizeable FPGA memory implementation. |
74 | // Fixed some issues with Xilinx BlockRAM |
75 | // |
76 | // Revision 1.3 2001/11/09 00:34:18 samg |
77 | // minor changes: unified with all common rams |
78 | // |
79 | // Revision 1.2 2001/11/08 19:11:31 samg |
80 | // added valid checks to behvioral model |
81 | // |
82 | // Revision 1.1.1.1 2001/09/14 09:57:10 rherveille |
83 | // Major cleanup. |
84 | // Files are now compliant to Altera & Xilinx memories. |
85 | // Memories are now compatible, i.e. drop-in replacements. |
86 | // Added synthesizeable generic FPGA description. |
87 | // Created "generic_memories" cvs entry. |
88 | // |
89 | // Revision 1.1.1.2 2001/08/21 13:09:27 damjan |
90 | // *** empty log message *** |
91 | // |
92 | // Revision 1.1 2001/08/20 18:23:20 damjan |
93 | // Initial revision |
94 | // |
95 | // Revision 1.1 2001/08/09 13:39:33 lampret |
96 | // Major clean-up. |
97 | // |
98 | // Revision 1.2 2001/07/30 05:38:02 lampret |
99 | // Adding empty directories required by HDL coding guidelines |
100 | // |
101 | // |
102 | |
103 | //`include "timescale.v" |
104 | |
105 | //`define VENDOR_FPGA |
106 | //`define VENDOR_XILINX |
107 | //`define VENDOR_ALTERA |
108 | |
109 | module generic_dpram( |
110 | // Generic synchronous dual-port RAM interface |
111 | rclk, rrst, rce, oe, raddr, do, |
112 | wclk, wrst, wce, we, waddr, di |
113 | ); |
114 | |
115 | // |
116 | // Default address and data buses width |
117 | // |
118 | parameter aw = 5; // number of bits in address-bus |
119 | parameter dw = 16; // number of bits in data-bus |
120 | |
121 | // |
122 | // Generic synchronous double-port RAM interface |
123 | // |
124 | // read port |
125 | input rclk; // read clock, rising edge trigger |
126 | input rrst; // read port reset, active high |
127 | input rce; // read port chip enable, active high |
128 | input oe; // output enable, active high |
129 | input [aw-1:0] raddr; // read address |
130 | output [dw-1:0] do; // data output |
131 | |
132 | // write port |
133 | input wclk; // write clock, rising edge trigger |
134 | input wrst; // write port reset, active high |
135 | input wce; // write port chip enable, active high |
136 | input we; // write enable, active high |
137 | input [aw-1:0] waddr; // write address |
138 | input [dw-1:0] di; // data input |
139 | |
140 | // |
141 | // Module body |
142 | // |
143 | |
144 | `ifdef VENDOR_FPGA |
145 | // |
146 | // Instantiation synthesizeable FPGA memory |
147 | // |
148 | // This code has been tested using LeonardoSpectrum and Synplicity. |
149 | // The code correctly instantiates Altera EABs and Xilinx BlockRAMs. |
150 | // |
151 | reg [dw-1:0] mem [(1<<aw) -1:0]; // instantiate memory |
152 | reg [aw-1:0] ra; // register read address |
153 | |
154 | // read operation |
155 | always @(posedge rclk) |
156 | if (rce) |
157 | ra <= #1 raddr; |
158 | |
159 | assign do = mem[ra]; |
160 | |
161 | // write operation |
162 | always@(posedge wclk) |
163 | if (we && wce) |
164 | mem[waddr] <= #1 di; |
165 | |
166 | `else |
167 | |
168 | `ifdef VENDOR_XILINX |
169 | // |
170 | // Instantiation of FPGA memory: |
171 | // |
172 | // Virtex/Spartan2 BlockRAMs |
173 | // |
174 | xilinx_ram_dp xilinx_ram( |
175 | // read port |
176 | .CLKA(rclk), |
177 | .RSTA(rrst), |
178 | .ENA(rce), |
179 | .ADDRA(raddr), |
180 | .DIA( {dw{1'b0}} ), |
181 | .WEA(1'b0), |
182 | .DOA(do), |
183 | |
184 | // write port |
185 | .CLKB(wclk), |
186 | .RSTB(wrst), |
187 | .ENB(wce), |
188 | .ADDRB(waddr), |
189 | .DIB(di), |
190 | .WEB(we), |
191 | .DOB() |
192 | ); |
193 | |
194 | defparam |
195 | xilinx_ram.dwidth = dw, |
196 | xilinx_ram.awidth = aw; |
197 | |
198 | `else |
199 | |
200 | `ifdef VENDOR_ALTERA |
201 | // |
202 | // Instantiation of FPGA memory: |
203 | // |
204 | // Altera FLEX/APEX EABs |
205 | // |
206 | altera_ram_dp altera_ram( |
207 | // read port |
208 | .rdclock(rclk), |
209 | .rdclocken(rce), |
210 | .rdaddress(raddr), |
211 | .q(do), |
212 | |
213 | // write port |
214 | .wrclock(wclk), |
215 | .wrclocken(wce), |
216 | .wren(we), |
217 | .wraddress(waddr), |
218 | .data(di) |
219 | ); |
220 | |
221 | defparam |
222 | altera_ram.dwidth = dw, |
223 | altera_ram.awidth = aw; |
224 | |
225 | `else |
226 | |
227 | `ifdef VENDOR_ARTISAN |
228 | |
229 | // |
230 | // Instantiation of ASIC memory: |
231 | // |
232 | // Artisan Synchronous Double-Port RAM (ra2sh) |
233 | // |
234 | art_hsdp #(dw, 1<<aw, aw) artisan_sdp( |
235 | // read port |
236 | .qa(do), |
237 | .clka(rclk), |
238 | .cena(~rce), |
239 | .wena(1'b1), |
240 | .aa(raddr), |
241 | .da( {dw{1'b0}} ), |
242 | .oena(~oe), |
243 | |
244 | // write port |
245 | .qb(), |
246 | .clkb(wclk), |
247 | .cenb(~wce), |
248 | .wenb(~we), |
249 | .ab(waddr), |
250 | .db(di), |
251 | .oenb(1'b1) |
252 | ); |
253 | |
254 | `else |
255 | |
256 | `ifdef VENDOR_AVANT |
257 | |
258 | // |
259 | // Instantiation of ASIC memory: |
260 | // |
261 | // Avant! Asynchronous Two-Port RAM |
262 | // |
263 | avant_atp avant_atp( |
264 | .web(~we), |
265 | .reb(), |
266 | .oeb(~oe), |
267 | .rcsb(), |
268 | .wcsb(), |
269 | .ra(raddr), |
270 | .wa(waddr), |
271 | .di(di), |
272 | .do(do) |
273 | ); |
274 | |
275 | `else |
276 | |
277 | `ifdef VENDOR_VIRAGE |
278 | |
279 | // |
280 | // Instantiation of ASIC memory: |
281 | // |
282 | // Virage Synchronous 2-port R/W RAM |
283 | // |
284 | virage_stp virage_stp( |
285 | // read port |
286 | .CLKA(rclk), |
287 | .MEA(rce_a), |
288 | .ADRA(raddr), |
289 | .DA( {dw{1'b0}} ), |
290 | .WEA(1'b0), |
291 | .OEA(oe), |
292 | .QA(do), |
293 | |
294 | // write port |
295 | .CLKB(wclk), |
296 | .MEB(wce), |
297 | .ADRB(waddr), |
298 | .DB(di), |
299 | .WEB(we), |
300 | .OEB(1'b1), |
301 | .QB() |
302 | ); |
303 | |
304 | `else |
305 | |
306 | // |
307 | // Generic dual-port synchronous RAM model |
308 | // |
309 | |
310 | // |
311 | // Generic RAM's registers and wires |
312 | // |
313 | reg [dw-1:0] mem [(1<<aw)-1:0]; // RAM content |
314 | reg [dw-1:0] do_reg; // RAM data output register |
315 | |
316 | // |
317 | // Data output drivers |
318 | // |
319 | assign do = (oe & rce) ? do_reg : {dw{1'bz}}; |
320 | |
321 | // read operation |
322 | always @(posedge rclk) |
323 | if (rce) |
324 | do_reg <= #1 (we && (waddr==raddr)) ? {dw{1'b x}} : mem[raddr]; |
325 | |
326 | // write operation |
327 | always @(posedge wclk) |
328 | if (wce && we) |
329 | mem[waddr] <= #1 di; |
330 | |
331 | |
332 | // Task prints range of memory |
333 | // *** Remember that tasks are non reentrant, don't call this task in parallel for multiple instantiations. |
334 | task print_ram; |
335 | input [aw-1:0] start; |
336 | input [aw-1:0] finish; |
337 | integer rnum; |
338 | begin |
339 | for (rnum=start;rnum<=finish;rnum=rnum+1) |
340 | $display("Addr %h = %h",rnum,mem[rnum]); |
341 | end |
342 | endtask |
343 | |
344 | `endif // !VENDOR_VIRAGE |
345 | `endif // !VENDOR_AVANT |
346 | `endif // !VENDOR_ARTISAN |
347 | `endif // !VENDOR_ALTERA |
348 | `endif // !VENDOR_XILINX |
349 | `endif // !VENDOR_FPGA |
350 | |
351 | endmodule |
352 | |
353 | // |
354 | // Black-box modules |
355 | // |
356 | |
357 | `ifdef VENDOR_ALTERA |
358 | module altera_ram_dp( |
359 | data, |
360 | wraddress, |
361 | rdaddress, |
362 | wren, |
363 | wrclock, |
364 | wrclocken, |
365 | rdclock, |
366 | rdclocken, |
367 | q) /* synthesis black_box */; |
368 | |
369 | parameter awidth = 7; |
370 | parameter dwidth = 8; |
371 | |
372 | input [dwidth -1:0] data; |
373 | input [awidth -1:0] wraddress; |
374 | input [awidth -1:0] rdaddress; |
375 | input wren; |
376 | input wrclock; |
377 | input wrclocken; |
378 | input rdclock; |
379 | input rdclocken; |
380 | output [dwidth -1:0] q; |
381 | |
382 | // synopsis translate_off |
383 | // exemplar translate_off |
384 | |
385 | syn_dpram_rowr #( |
386 | "UNUSED", |
387 | dwidth, |
388 | awidth, |
389 | 1 << awidth |
390 | ) |
391 | altera_dpram_model ( |
392 | // read port |
393 | .RdClock(rdclock), |
394 | .RdClken(rdclocken), |
395 | .RdAddress(rdaddress), |
396 | .RdEn(1'b1), |
397 | .Q(q), |
398 | |
399 | // write port |
400 | .WrClock(wrclock), |
401 | .WrClken(wrclocken), |
402 | .WrAddress(wraddress), |
403 | .WrEn(wren), |
404 | .Data(data) |
405 | ); |
406 | |
407 | // exemplar translate_on |
408 | // synopsis translate_on |
409 | |
410 | endmodule |
411 | `endif // VENDOR_ALTERA |
412 | |
413 | `ifdef VENDOR_XILINX |
414 | module xilinx_ram_dp ( |
415 | ADDRA, |
416 | CLKA, |
417 | ADDRB, |
418 | CLKB, |
419 | DIA, |
420 | WEA, |
421 | DIB, |
422 | WEB, |
423 | ENA, |
424 | ENB, |
425 | RSTA, |
426 | RSTB, |
427 | DOA, |
428 | DOB) /* synthesis black_box */ ; |
429 | |
430 | parameter awidth = 7; |
431 | parameter dwidth = 8; |
432 | |
433 | // port_a |
434 | input CLKA; |
435 | input RSTA; |
436 | input ENA; |
437 | input [awidth-1:0] ADDRA; |
438 | input [dwidth-1:0] DIA; |
439 | input WEA; |
440 | output [dwidth-1:0] DOA; |
441 | |
442 | // port_b |
443 | input CLKB; |
444 | input RSTB; |
445 | input ENB; |
446 | input [awidth-1:0] ADDRB; |
447 | input [dwidth-1:0] DIB; |
448 | input WEB; |
449 | output [dwidth-1:0] DOB; |
450 | |
451 | // insert simulation model |
452 | |
453 | |
454 | // synopsys translate_off |
455 | // exemplar translate_off |
456 | |
457 | C_MEM_DP_BLOCK_V1_0 #( |
458 | awidth, |
459 | awidth, |
460 | 1, |
461 | 1, |
462 | "0", |
463 | 1 << awidth, |
464 | 1 << awidth, |
465 | 1, |
466 | 1, |
467 | 1, |
468 | 1, |
469 | 1, |
470 | 1, |
471 | 1, |
472 | 1, |
473 | 1, |
474 | 1, |
475 | 1, |
476 | 1, |
477 | 1, |
478 | "", |
479 | 16, |
480 | 0, |
481 | 0, |
482 | 1, |
483 | 1, |
484 | 1, |
485 | 1, |
486 | dwidth, |
487 | dwidth) |
488 | xilinx_dpram_model ( |
489 | .ADDRA(ADDRA), |
490 | .CLKA(CLKA), |
491 | .ADDRB(ADDRB), |
492 | .CLKB(CLKB), |
493 | .DIA(DIA), |
494 | .WEA(WEA), |
495 | .DIB(DIB), |
496 | .WEB(WEB), |
497 | .ENA(ENA), |
498 | .ENB(ENB), |
499 | .RSTA(RSTA), |
500 | .RSTB(RSTB), |
501 | .DOA(DOA), |
502 | .DOB(DOB)); |
503 | |
504 | // exemplar translate_on |
505 | // synopsys translate_on |
506 | |
507 | endmodule |
508 | `endif // VENDOR_XILINX |