////////////////////////////////////////////////////////////////////// | |
//// //// | |
//// 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 |