| ////////////////////////////////////////////////////////////////////// | |
| //// //// | |
| //// Generic Dual-Port Synchronous RAM //// | |
| //// //// | |
| //// This file is part of memory library available from //// | |
| //// http://www.opencores.org/cvsweb.shtml/generic_memories/ //// | |
| //// //// | |
| //// Description //// | |
| //// This block is a wrapper with common dual-port //// | |
| //// synchronous memory interface for different //// | |
| //// types of ASIC and FPGA RAMs. Beside universal memory //// | |
| //// interface it also provides behavioral model of generic //// | |
| //// dual-port synchronous RAM. //// | |
| //// It also contains a fully synthesizeable model for FPGAs. //// | |
| //// It should be used in all OPENCORES designs that want to be //// | |
| //// portable accross different target technologies and //// | |
| //// independent of target memory. //// | |
| //// //// | |
| //// Supported ASIC RAMs are: //// | |
| //// - Artisan Dual-Port Sync RAM //// | |
| //// - Avant! Two-Port Sync RAM (*) //// | |
| //// - Virage 2-port Sync RAM //// | |
| //// //// | |
| //// Supported FPGA RAMs are: //// | |
| //// - Generic FPGA (VENDOR_FPGA) //// | |
| //// Tested RAMs: Altera, Xilinx //// | |
| //// Synthesis tools: LeonardoSpectrum, Synplicity //// | |
| //// - Xilinx (VENDOR_XILINX) //// | |
| //// - Altera (VENDOR_ALTERA) //// | |
| //// //// | |
| //// To Do: //// | |
| //// - fix Avant! //// | |
| //// - add additional RAMs (VS etc) //// | |
| //// //// | |
| //// Author(s): //// | |
| //// - Richard Herveille, richard@asics.ws //// | |
| //// - Damjan Lampret, lampret@opencores.org //// | |
| //// //// | |
| ////////////////////////////////////////////////////////////////////// | |
| //// //// | |
| //// Copyright (C) 2000 Authors and OPENCORES.ORG //// | |
| //// //// | |
| //// This source file may be used and distributed without //// | |
| //// restriction provided that this copyright statement is not //// | |
| //// removed from the file and that any derivative work contains //// | |
| //// the original copyright notice and the associated disclaimer. //// | |
| //// //// | |
| //// This source file is free software; you can redistribute it //// | |
| //// and/or modify it under the terms of the GNU Lesser General //// | |
| //// Public License as published by the Free Software Foundation; //// | |
| //// either version 2.1 of the License, or (at your option) any //// | |
| //// later version. //// | |
| //// //// | |
| //// This source is distributed in the hope that it will be //// | |
| //// useful, but WITHOUT ANY WARRANTY; without even the implied //// | |
| //// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// | |
| //// PURPOSE. See the GNU Lesser General Public License for more //// | |
| //// details. //// | |
| //// //// | |
| //// You should have received a copy of the GNU Lesser General //// | |
| //// Public License along with this source; if not, download it //// | |
| //// from http://www.opencores.org/lgpl.shtml //// | |
| //// //// | |
| ////////////////////////////////////////////////////////////////////// | |
| // | |
| // CVS Revision History | |
| // | |
| // $Log: not supported by cvs2svn $ | |
| // Revision 1.2 2001/11/08 19:11:31 samg | |
| // added valid checks to behvioral model | |
| // | |
| // Revision 1.1.1.1 2001/09/14 09:57:10 rherveille | |
| // Major cleanup. | |
| // Files are now compliant to Altera & Xilinx memories. | |
| // Memories are now compatible, i.e. drop-in replacements. | |
| // Added synthesizeable generic FPGA description. | |
| // Created "generic_memories" cvs entry. | |
| // | |
| // Revision 1.1.1.2 2001/08/21 13:09:27 damjan | |
| // *** empty log message *** | |
| // | |
| // Revision 1.1 2001/08/20 18:23:20 damjan | |
| // Initial revision | |
| // | |
| // Revision 1.1 2001/08/09 13:39:33 lampret | |
| // Major clean-up. | |
| // | |
| // Revision 1.2 2001/07/30 05:38:02 lampret | |
| // Adding empty directories required by HDL coding guidelines | |
| // | |
| // | |
| //`define VENDOR_FPGA | |
| //`define VENDOR_XILINX | |
| //`define VENDOR_ALTERA | |
| module usb1d_generic_dpram( | |
| // Generic synchronous dual-port RAM interface | |
| rclk, rrst, rce, oe, raddr, dout, | |
| wclk, wrst, wce, we, waddr, di | |
| ); | |
| // | |
| // Default address and data buses width | |
| // | |
| parameter aw = 5; // number of bits in address-bus | |
| parameter dw = 16; // number of bits in data-bus | |
| // | |
| // Generic synchronous double-port RAM interface | |
| // | |
| // read port | |
| input rclk; // read clock, rising edge trigger | |
| input rrst; // read port reset, active high | |
| input rce; // read port chip enable, active high | |
| input oe; // output enable, active high | |
| input [aw-1:0] raddr; // read address | |
| output [dw-1:0] dout; // data output | |
| // write port | |
| input wclk; // write clock, rising edge trigger | |
| input wrst; // write port reset, active high | |
| input wce; // write port chip enable, active high | |
| input we; // write enable, active high | |
| input [aw-1:0] waddr; // write address | |
| input [dw-1:0] di; // data input | |
| // | |
| // Module body | |
| // | |
| `ifdef VENDOR_FPGA | |
| // | |
| // Instantiation synthesizeable FPGA memory | |
| // | |
| // This code has been tested using LeonardoSpectrum and Synplicity. | |
| // The code correctly instantiates Altera EABs and Xilinx BlockRAMs. | |
| // | |
| reg [dw-1 :0] mem [(1<<aw) -1:0]; // instantiate memory | |
| reg [dw-1:0] dout; // data output registers | |
| // read operation | |
| /* | |
| always@(posedge rclk) | |
| if (rce) // clock enable instructs Xilinx tools to use SelectRAM (LUTS) instead of BlockRAM | |
| do <= #1 mem[raddr]; | |
| */ | |
| always@(posedge rclk) | |
| dout <= #1 mem[raddr]; | |
| // write operation | |
| always@(posedge wclk) | |
| if (we && wce) | |
| mem[waddr] <= #1 di; | |
| `else | |
| `ifdef VENDOR_XILINX | |
| // | |
| // Instantiation of FPGA memory: | |
| // | |
| // Virtex/Spartan2 BlockRAMs | |
| // | |
| xilinx_ram_dp xilinx_ram( | |
| // read port | |
| .CLKA(rclk), | |
| .RSTA(rrst), | |
| .ENA(rce), | |
| .ADDRA(raddr), | |
| .DIA( {dw{1'b0}} ), | |
| .WEA(1'b0), | |
| .DOA(dout), | |
| // write port | |
| .CLKB(wclk), | |
| .RSTB(wrst), | |
| .ENB(wce), | |
| .ADDRB(waddr), | |
| .DIB(di), | |
| .WEB(we), | |
| .DOB() | |
| ); | |
| defparam | |
| xilinx_ram.dwidth = dw, | |
| xilinx_ram.awidth = aw; | |
| `else | |
| `ifdef VENDOR_ALTERA | |
| // | |
| // Instantiation of FPGA memory: | |
| // | |
| // Altera FLEX/APEX EABs | |
| // | |
| altera_ram_dp altera_ram( | |
| // read port | |
| .rdclock(rclk), | |
| .rdclocken(rce), | |
| .rdaddress(raddr), | |
| .q(dout), | |
| // write port | |
| .wrclock(wclk), | |
| .wrclocken(wce), | |
| .wren(we), | |
| .wraddress(waddr), | |
| .data(di) | |
| ); | |
| defparam | |
| altera_ram.dwidth = dw, | |
| altera_ram.awidth = aw; | |
| `else | |
| `ifdef VENDOR_ARTISAN | |
| // | |
| // Instantiation of ASIC memory: | |
| // | |
| // Artisan Synchronous Double-Port RAM (ra2sh) | |
| // | |
| art_hsdp #(dw, 1<<aw, aw) artisan_sdp( | |
| // read port | |
| .qa(dout), | |
| .clka(rclk), | |
| .cena(~rce), | |
| .wena(1'b1), | |
| .aa(raddr), | |
| .da( {dw{1'b0}} ), | |
| .oena(~oe), | |
| // write port | |
| .qb(), | |
| .clkb(wclk), | |
| .cenb(~wce), | |
| .wenb(~we), | |
| .ab(waddr), | |
| .db(di), | |
| .oenb(1'b1) | |
| ); | |
| `else | |
| `ifdef VENDOR_AVANT | |
| // | |
| // Instantiation of ASIC memory: | |
| // | |
| // Avant! Asynchronous Two-Port RAM | |
| // | |
| avant_atp avant_atp( | |
| .web(~we), | |
| .reb(), | |
| .oeb(~oe), | |
| .rcsb(), | |
| .wcsb(), | |
| .ra(raddr), | |
| .wa(waddr), | |
| .di(di), | |
| .do(dout) | |
| ); | |
| `else | |
| `ifdef VENDOR_VIRAGE | |
| // | |
| // Instantiation of ASIC memory: | |
| // | |
| // Virage Synchronous 2-port R/W RAM | |
| // | |
| virage_stp virage_stp( | |
| // read port | |
| .CLKA(rclk), | |
| .MEA(rce_a), | |
| .ADRA(raddr), | |
| .DA( {dw{1'b0}} ), | |
| .WEA(1'b0), | |
| .OEA(oe), | |
| .QA(dout), | |
| // write port | |
| .CLKB(wclk), | |
| .MEB(wce), | |
| .ADRB(waddr), | |
| .DB(di), | |
| .WEB(we), | |
| .OEB(1'b1), | |
| .QB() | |
| ); | |
| `else | |
| // | |
| // Generic dual-port synchronous RAM model | |
| // | |
| // | |
| // Generic RAM's registers and wires | |
| // | |
| reg [dw-1:0] mem [(1<<aw)-1:0]; // RAM content | |
| reg [dw-1:0] do_reg; // RAM data output register | |
| // | |
| // Data output drivers | |
| // | |
| assign dout = (oe & rce) ? do_reg : {dw{1'bz}}; | |
| // read operation | |
| always @(posedge rclk) | |
| if (rce) | |
| do_reg <= #1 (we && (waddr==raddr)) ? {dw{1'b x}} : mem[raddr]; | |
| // write operation | |
| always @(posedge wclk) | |
| if (wce && we) | |
| mem[waddr] <= #1 di; | |
| // Task prints range of memory | |
| // *** Remember that tasks are non reentrant, don't call this task in parallel for multiple instantiations. | |
| task print_ram; | |
| input [aw-1:0] start; | |
| input [aw-1:0] finish; | |
| integer rnum; | |
| begin | |
| for (rnum=start;rnum<=finish;rnum=rnum+1) | |
| $display("Addr %h = %h",rnum,mem[rnum]); | |
| end | |
| endtask | |
| `endif // !VENDOR_VIRAGE | |
| `endif // !VENDOR_AVANT | |
| `endif // !VENDOR_ARTISAN | |
| `endif // !VENDOR_ALTERA | |
| `endif // !VENDOR_XILINX | |
| `endif // !VENDOR_FPGA | |
| endmodule | |
| // | |
| // Black-box modules | |
| // | |
| `ifdef VENDOR_ALTERA | |
| module altera_ram_dp( | |
| data, | |
| wraddress, | |
| rdaddress, | |
| wren, | |
| wrclock, | |
| wrclocken, | |
| rdclock, | |
| rdclocken, | |
| q) /* synthesis black_box */; | |
| parameter awidth = 7; | |
| parameter dwidth = 8; | |
| input [dwidth -1:0] data; | |
| input [awidth -1:0] wraddress; | |
| input [awidth -1:0] rdaddress; | |
| input wren; | |
| input wrclock; | |
| input wrclocken; | |
| input rdclock; | |
| input rdclocken; | |
| output [dwidth -1:0] q; | |
| // synopsis translate_off | |
| // exemplar translate_off | |
| syn_dpram_rowr #( | |
| "UNUSED", | |
| dwidth, | |
| awidth, | |
| 1 << awidth | |
| ) | |
| altera_dpram_model ( | |
| // read port | |
| .RdClock(rdclock), | |
| .RdClken(rdclocken), | |
| .RdAddress(rdaddress), | |
| .RdEn(1'b1), | |
| .Q(q), | |
| // write port | |
| .WrClock(wrclock), | |
| .WrClken(wrclocken), | |
| .WrAddress(wraddress), | |
| .WrEn(wren), | |
| .Data(data) | |
| ); | |
| // exemplar translate_on | |
| // synopsis translate_on | |
| endmodule | |
| `endif // VENDOR_ALTERA | |
| `ifdef VENDOR_XILINX | |
| module xilinx_ram_dp ( | |
| ADDRA, | |
| CLKA, | |
| ADDRB, | |
| CLKB, | |
| DIA, | |
| WEA, | |
| DIB, | |
| WEB, | |
| ENA, | |
| ENB, | |
| RSTA, | |
| RSTB, | |
| DOA, | |
| DOB) /* synthesis black_box */ ; | |
| parameter awidth = 7; | |
| parameter dwidth = 8; | |
| // port_a | |
| input CLKA; | |
| input RSTA; | |
| input ENA; | |
| input [awidth-1:0] ADDRA; | |
| input [dwidth-1:0] DIA; | |
| input WEA; | |
| output [dwidth-1:0] DOA; | |
| // port_b | |
| input CLKB; | |
| input RSTB; | |
| input ENB; | |
| input [awidth-1:0] ADDRB; | |
| input [dwidth-1:0] DIB; | |
| input WEB; | |
| output [dwidth-1:0] DOB; | |
| // insert simulation model | |
| // synopsys translate_off | |
| // exemplar translate_off | |
| C_MEM_DP_BLOCK_V1_0 #( | |
| awidth, | |
| awidth, | |
| 1, | |
| 1, | |
| "0", | |
| 1 << awidth, | |
| 1 << awidth, | |
| 1, | |
| 1, | |
| 1, | |
| 1, | |
| 1, | |
| 1, | |
| 1, | |
| 1, | |
| 1, | |
| 1, | |
| 1, | |
| 1, | |
| 1, | |
| "", | |
| 16, | |
| 0, | |
| 0, | |
| 1, | |
| 1, | |
| 1, | |
| 1, | |
| dwidth, | |
| dwidth) | |
| xilinx_dpram_model ( | |
| .ADDRA(ADDRA), | |
| .CLKA(CLKA), | |
| .ADDRB(ADDRB), | |
| .CLKB(CLKB), | |
| .DIA(DIA), | |
| .WEA(WEA), | |
| .DIB(DIB), | |
| .WEB(WEB), | |
| .ENA(ENA), | |
| .ENB(ENB), | |
| .RSTA(RSTA), | |
| .RSTB(RSTB), | |
| .DOA(DOA), | |
| .DOB(DOB)); | |
| // exemplar translate_on | |
| // synopsys translate_on | |
| endmodule | |
| `endif // VENDOR_XILINX |