516 lines
12 KiB
Verilog
516 lines
12 KiB
Verilog
//////////////////////////////////////////////////////////////////////
|
|
//// ////
|
|
//// 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: generic_dpram.v,v $
|
|
// Revision 1.3 2003/03/18 21:45:48 rherveille
|
|
// Added WISHBONE revB.3 Registered Feedback Cycles support
|
|
//
|
|
// Revision 1.4 2002/09/28 08:18:52 rherveille
|
|
// Changed synthesizeable FPGA memory implementation.
|
|
// Fixed some issues with Xilinx BlockRAM
|
|
//
|
|
// Revision 1.3 2001/11/09 00:34:18 samg
|
|
// minor changes: unified with all common rams
|
|
//
|
|
// 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
|
|
//
|
|
//
|
|
|
|
//synopsys translate_off
|
|
`include "timescale.v"
|
|
//synopsys translate_on
|
|
|
|
`define VENDOR_FPGA
|
|
//`define VENDOR_XILINX
|
|
//`define VENDOR_ALTERA
|
|
|
|
module generic_dpram(
|
|
// Generic synchronous dual-port RAM interface
|
|
rclk, rrst, rce, oe, raddr, do,
|
|
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] do; // 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.
|
|
//
|
|
|
|
// NOTE:
|
|
// 'synthesis syn_ramstyle="block_ram"' is a Synplify attribute.
|
|
// It instructs Synplify to map to BlockRAMs instead of the default SelectRAMs
|
|
|
|
reg [dw-1:0] mem [(1<<aw) -1:0] /* synthesis syn_ramstyle="block_ram" */;
|
|
reg [aw-1:0] ra; // register read address
|
|
|
|
// read operation
|
|
always @(posedge rclk)
|
|
if (rce)
|
|
ra <= #1 raddr;
|
|
|
|
assign do = mem[ra];
|
|
|
|
// 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(do),
|
|
|
|
// 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(do),
|
|
|
|
// 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(do),
|
|
.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(do)
|
|
);
|
|
|
|
`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(do),
|
|
|
|
// 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 do = (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
|