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