mirror of https://github.com/VLSIDA/OpenRAM.git
Updated Verilog to have multiport. Added 1rw,1rw/1r Verilog testbench.
This commit is contained in:
parent
f0ab155172
commit
5de7ff3773
|
|
@ -10,7 +10,7 @@ from vector import vector
|
||||||
from pin_layout import pin_layout
|
from pin_layout import pin_layout
|
||||||
import lef
|
import lef
|
||||||
|
|
||||||
class layout(lef.lef):
|
class layout():
|
||||||
"""
|
"""
|
||||||
Class consisting of a set of objs and instances for a module
|
Class consisting of a set of objs and instances for a module
|
||||||
This provides a set of useful generic types for hierarchy
|
This provides a set of useful generic types for hierarchy
|
||||||
|
|
@ -21,7 +21,6 @@ class layout(lef.lef):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, name):
|
def __init__(self, name):
|
||||||
lef.lef.__init__(self, ["metal1", "metal2", "metal3"])
|
|
||||||
self.name = name
|
self.name = name
|
||||||
self.width = None
|
self.width = None
|
||||||
self.height = None
|
self.height = None
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,8 @@ import debug
|
||||||
import re
|
import re
|
||||||
import os
|
import os
|
||||||
import math
|
import math
|
||||||
import verilog
|
|
||||||
|
|
||||||
class spice(verilog.verilog):
|
class spice():
|
||||||
"""
|
"""
|
||||||
This provides a set of useful generic types for hierarchy
|
This provides a set of useful generic types for hierarchy
|
||||||
management. If a module is a custom designed cell, it will read from
|
management. If a module is a custom designed cell, it will read from
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,8 @@ from collections import defaultdict
|
||||||
class lef:
|
class lef:
|
||||||
"""
|
"""
|
||||||
SRAM LEF Class open GDS file, read pins information, obstruction
|
SRAM LEF Class open GDS file, read pins information, obstruction
|
||||||
and write them to LEF file
|
and write them to LEF file.
|
||||||
|
This is inherited by the sram_base class.
|
||||||
"""
|
"""
|
||||||
def __init__(self,layers):
|
def __init__(self,layers):
|
||||||
# LEF db units per micron
|
# LEF db units per micron
|
||||||
|
|
|
||||||
|
|
@ -1,60 +1,165 @@
|
||||||
import debug
|
import debug
|
||||||
|
|
||||||
class verilog:
|
class verilog:
|
||||||
""" Create a behavioral Verilog file for simulation."""
|
"""
|
||||||
|
Create a behavioral Verilog file for simulation.
|
||||||
|
This is inherited by the sram_base class.
|
||||||
|
"""
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
def verilog_write(self,verilog_name):
|
def verilog_write(self,verilog_name):
|
||||||
""" Write a behavioral Verilog model. """
|
""" Write a behavioral Verilog model. """
|
||||||
|
|
||||||
self.vf = open(verilog_name, "w")
|
self.vf = open(verilog_name, "w")
|
||||||
|
|
||||||
self.vf.write("// OpenRAM SRAM model\n")
|
self.vf.write("// OpenRAM SRAM model\n")
|
||||||
self.vf.write("// Words: {0}\n".format(self.num_words))
|
self.vf.write("// Words: {0}\n".format(self.num_words))
|
||||||
self.vf.write("// Word size: {0}\n\n".format(self.word_size))
|
self.vf.write("// Word size: {0}\n\n".format(self.word_size))
|
||||||
|
|
||||||
self.vf.write("module {0}(DATA,ADDR,CSb,WEb,OEb,clk);\n".format(self.name))
|
self.vf.write("module {0}(\n".format(self.name))
|
||||||
self.vf.write("\n")
|
for port in self.all_ports:
|
||||||
|
if port in self.readwrite_ports:
|
||||||
|
self.vf.write("// Port {0}: RW\n".format(port))
|
||||||
|
elif port in self.read_ports:
|
||||||
|
self.vf.write("// Port {0}: R\n".format(port))
|
||||||
|
elif port in self.write_ports:
|
||||||
|
self.vf.write("// Port {0}: W\n".format(port))
|
||||||
|
if port in self.readwrite_ports:
|
||||||
|
self.vf.write(" clk{0},csb{0},web{0},ADDR{0},DIN{0},DOUT{0}".format(port))
|
||||||
|
elif port in self.write_ports:
|
||||||
|
self.vf.write(" clk{0},csb{0},ADDR{0},DIN{0}".format(port))
|
||||||
|
elif port in self.read_ports:
|
||||||
|
self.vf.write(" clk{0},csb{0},ADDR{0},DOUT{0}".format(port))
|
||||||
|
# Continue for every port on a new line
|
||||||
|
if port != self.all_ports[-1]:
|
||||||
|
self.vf.write(",\n")
|
||||||
|
self.vf.write("\n );\n\n")
|
||||||
|
|
||||||
self.vf.write(" parameter DATA_WIDTH = {0} ;\n".format(self.word_size))
|
self.vf.write(" parameter DATA_WIDTH = {0} ;\n".format(self.word_size))
|
||||||
self.vf.write(" parameter ADDR_WIDTH = {0} ;\n".format(self.addr_size))
|
self.vf.write(" parameter ADDR_WIDTH = {0} ;\n".format(self.addr_size))
|
||||||
self.vf.write(" parameter RAM_DEPTH = 1 << ADDR_WIDTH;\n")
|
self.vf.write(" parameter RAM_DEPTH = 1 << ADDR_WIDTH;\n")
|
||||||
|
self.vf.write(" // FIXME: This delay is arbitrary.\n")
|
||||||
self.vf.write(" parameter DELAY = 3 ;\n")
|
self.vf.write(" parameter DELAY = 3 ;\n")
|
||||||
self.vf.write("\n")
|
|
||||||
self.vf.write(" inout [DATA_WIDTH-1:0] DATA;\n")
|
|
||||||
self.vf.write(" input [ADDR_WIDTH-1:0] ADDR;\n")
|
|
||||||
self.vf.write(" input CSb; // active low chip select\n")
|
|
||||||
self.vf.write(" input WEb; // active low write control\n")
|
|
||||||
self.vf.write(" input OEb; // active output enable\n")
|
|
||||||
self.vf.write(" input clk; // clock\n")
|
|
||||||
self.vf.write("\n")
|
self.vf.write("\n")
|
||||||
self.vf.write(" reg [DATA_WIDTH-1:0] data_out ;\n")
|
|
||||||
self.vf.write(" reg [DATA_WIDTH-1:0] mem [0:RAM_DEPTH-1];\n")
|
for port in self.all_ports:
|
||||||
|
self.add_inputs_outputs(port)
|
||||||
|
|
||||||
self.vf.write("\n")
|
self.vf.write("\n")
|
||||||
self.vf.write(" // Tri-State Buffer control\n")
|
|
||||||
self.vf.write(" // output : When WEb = 1, oeb = 0, csb = 0\n")
|
for port in self.all_ports:
|
||||||
self.vf.write(" assign DATA = (!CSb && !OEb && WEb) ? data_out : {0}'bz;\n".format(self.word_size))
|
self.register_inputs(port)
|
||||||
self.vf.write("\n")
|
|
||||||
self.vf.write(" // Memory Write Block\n")
|
# This is the memory array itself
|
||||||
self.vf.write(" // Write Operation : When WEb = 0, CSb = 0\n")
|
self.vf.write("reg [DATA_WIDTH-1:0] mem [0:RAM_DEPTH-1];\n")
|
||||||
self.vf.write(" always @ (posedge clk)\n")
|
|
||||||
self.vf.write(" begin : MEM_WRITE\n")
|
for port in self.all_ports:
|
||||||
self.vf.write(" if ( !CSb && !WEb ) begin\n")
|
if port in self.write_ports:
|
||||||
self.vf.write(" mem[ADDR] = DATA;\n")
|
self.add_write_block(port)
|
||||||
self.vf.write(" $display($time,\" Writing %m ABUS=%b DATA=%b\",ADDR,DATA);\n")
|
if port in self.read_ports:
|
||||||
self.vf.write(" end\n")
|
self.add_read_block(port)
|
||||||
self.vf.write(" end\n\n")
|
|
||||||
self.vf.write("\n")
|
|
||||||
self.vf.write(" // Memory Read Block\n")
|
|
||||||
self.vf.write(" // Read Operation : When WEb = 1, CSb = 0\n")
|
|
||||||
self.vf.write(" always @ (posedge clk)\n")
|
|
||||||
self.vf.write(" begin : MEM_READ\n")
|
|
||||||
self.vf.write(" if (!CSb && WEb) begin\n")
|
|
||||||
self.vf.write(" data_out <= #(DELAY) mem[ADDR];\n")
|
|
||||||
self.vf.write(" $display($time,\" Reading %m ABUS=%b DATA=%b\",ADDR,mem[ADDR]);\n")
|
|
||||||
self.vf.write(" end\n")
|
|
||||||
self.vf.write(" end\n")
|
|
||||||
self.vf.write("\n")
|
self.vf.write("\n")
|
||||||
self.vf.write("endmodule\n")
|
self.vf.write("endmodule\n")
|
||||||
|
|
||||||
|
|
||||||
self.vf.close()
|
self.vf.close()
|
||||||
|
|
||||||
|
|
||||||
|
def register_inputs(self, port):
|
||||||
|
"""
|
||||||
|
Register the control signal, address and data inputs.
|
||||||
|
"""
|
||||||
|
self.add_regs(port)
|
||||||
|
self.add_flops(port)
|
||||||
|
|
||||||
|
def add_regs(self, port):
|
||||||
|
"""
|
||||||
|
Create the input regs for the given port.
|
||||||
|
"""
|
||||||
|
self.vf.write(" reg csb{0}_reg;\n".format(port))
|
||||||
|
if port in self.readwrite_ports:
|
||||||
|
self.vf.write(" reg web{0}_reg;\n".format(port))
|
||||||
|
self.vf.write(" reg [ADDR_WIDTH-1:0] ADDR{0}_reg;\n".format(port))
|
||||||
|
if port in self.write_ports:
|
||||||
|
self.vf.write(" reg [DATA_WIDTH-1:0] DIN{0}_reg;\n".format(port))
|
||||||
|
if port in self.read_ports:
|
||||||
|
self.vf.write(" reg [DATA_WIDTH-1:0] DOUT{0};\n".format(port))
|
||||||
|
|
||||||
|
def add_flops(self, port):
|
||||||
|
"""
|
||||||
|
Add the flop behavior logic for a port.
|
||||||
|
"""
|
||||||
|
self.vf.write("\n")
|
||||||
|
self.vf.write(" // All inputs are registers\n")
|
||||||
|
self.vf.write(" always @(posedge clk{0})\n".format(port))
|
||||||
|
self.vf.write(" begin\n")
|
||||||
|
self.vf.write(" csb{0}_reg = csb{0};\n".format(port))
|
||||||
|
if port in self.readwrite_ports:
|
||||||
|
self.vf.write(" web{0}_reg = web{0};\n".format(port))
|
||||||
|
self.vf.write(" ADDR{0}_reg = ADDR{0};\n".format(port))
|
||||||
|
if port in self.write_ports:
|
||||||
|
self.vf.write(" DIN{0}_reg = DIN{0};\n".format(port))
|
||||||
|
if port in self.read_ports:
|
||||||
|
self.vf.write(" DOUT{0} = {1}'bx;\n".format(port,self.word_size))
|
||||||
|
if port in self.readwrite_ports:
|
||||||
|
self.vf.write(" if ( !csb{0}_reg && web{0}_reg ) \n".format(port))
|
||||||
|
self.vf.write(" $display($time,\" Reading %m ADDR{0}=%b DOUT{0}=%b\",ADDR{0}_reg,mem[ADDR{0}_reg]);\n".format(port))
|
||||||
|
elif port in self.read_ports:
|
||||||
|
self.vf.write(" if ( !csb{0}_reg ) \n".format(port))
|
||||||
|
self.vf.write(" $display($time,\" Reading %m ADDR{0}=%b DOUT{0}=%b\",ADDR{0}_reg,mem[ADDR{0}_reg]);\n".format(port))
|
||||||
|
|
||||||
|
if port in self.readwrite_ports:
|
||||||
|
self.vf.write(" if ( !csb{0}_reg && !web{0}_reg )\n".format(port))
|
||||||
|
self.vf.write(" $display($time,\" Writing %m ADDR{0}=%b DIN{0}=%b\",ADDR{0}_reg,DIN{0}_reg);\n".format(port))
|
||||||
|
elif port in self.write_ports:
|
||||||
|
self.vf.write(" if ( !csb{0}_reg )\n".format(port))
|
||||||
|
self.vf.write(" $display($time,\" Writing %m ADDR{0}=%b DIN{0}=%b\",ADDR{0}_reg,DIN{0}_reg);\n".format(port))
|
||||||
|
self.vf.write(" end\n\n")
|
||||||
|
|
||||||
|
|
||||||
|
def add_inputs_outputs(self, port):
|
||||||
|
"""
|
||||||
|
Add the module input and output declaration for a port.
|
||||||
|
"""
|
||||||
|
self.vf.write(" input clk{0}; // clock\n".format(port))
|
||||||
|
self.vf.write(" input csb{0}; // active low chip select\n".format(port))
|
||||||
|
if port in self.readwrite_ports:
|
||||||
|
self.vf.write(" input web{0}; // active low write control\n".format(port))
|
||||||
|
self.vf.write(" input [ADDR_WIDTH-1:0] ADDR{0};\n".format(port))
|
||||||
|
if port in self.write_ports:
|
||||||
|
self.vf.write(" input [DATA_WIDTH-1:0] DIN{0};\n".format(port))
|
||||||
|
if port in self.read_ports:
|
||||||
|
self.vf.write(" output [DATA_WIDTH-1:0] DOUT{0};\n".format(port))
|
||||||
|
|
||||||
|
def add_write_block(self, port):
|
||||||
|
"""
|
||||||
|
Add a write port block. Multiple simultaneous writes to the same address
|
||||||
|
have arbitrary priority and are not allowed.
|
||||||
|
"""
|
||||||
|
self.vf.write("\n")
|
||||||
|
self.vf.write(" // Memory Write Block Port {0}\n".format(port))
|
||||||
|
self.vf.write(" // Write Operation : When web{0} = 0, csb{0} = 0\n".format(port))
|
||||||
|
self.vf.write(" always @ (negedge clk{0})\n".format(port))
|
||||||
|
self.vf.write(" begin : MEM_WRITE{0}\n".format(port))
|
||||||
|
if port in self.readwrite_ports:
|
||||||
|
self.vf.write(" if ( !csb{0}_reg && !web{0}_reg )\n".format(port))
|
||||||
|
else:
|
||||||
|
self.vf.write(" if (!csb{0}_reg)\n".format(port))
|
||||||
|
self.vf.write(" mem[ADDR{0}_reg] = DIN{0}_reg;\n".format(port))
|
||||||
|
self.vf.write(" end\n")
|
||||||
|
|
||||||
|
def add_read_block(self, port):
|
||||||
|
"""
|
||||||
|
Add a read port block.
|
||||||
|
"""
|
||||||
|
self.vf.write("\n")
|
||||||
|
self.vf.write(" // Memory Read Block Port {0}\n".format(port))
|
||||||
|
self.vf.write(" // Read Operation : When web{0} = 1, csb{0} = 0\n".format(port))
|
||||||
|
self.vf.write(" always @ (negedge clk{0})\n".format(port))
|
||||||
|
self.vf.write(" begin : MEM_READ{0}\n".format(port))
|
||||||
|
if port in self.readwrite_ports:
|
||||||
|
self.vf.write(" if (!csb{0}_reg && web{0}_reg)\n".format(port))
|
||||||
|
else:
|
||||||
|
self.vf.write(" if (!csb{0}_reg)\n".format(port))
|
||||||
|
self.vf.write(" DOUT{0} <= #(DELAY) mem[ADDR{0}_reg];\n".format(port))
|
||||||
|
self.vf.write(" end\n")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
word_size = 8
|
||||||
|
num_words = 128
|
||||||
|
|
||||||
|
tech_name = "scn4m_subm"
|
||||||
|
process_corners = ["TT"]
|
||||||
|
supply_voltages = [ 5.0 ]
|
||||||
|
temperatures = [ 25 ]
|
||||||
|
|
||||||
|
output_path = "temp"
|
||||||
|
output_name = "sram_{0}_{1}_{2}".format(word_size,num_words,tech_name)
|
||||||
|
|
||||||
|
drc_name = "magic"
|
||||||
|
lvs_name = "netgen"
|
||||||
|
pex_name = "magic"
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
word_size = 2
|
||||||
|
num_words = 16
|
||||||
|
|
||||||
|
bitcell = "bitcell_1rw_1r"
|
||||||
|
replica_bitcell = "replica_bitcell_1rw_1r"
|
||||||
|
num_rw_ports = 1
|
||||||
|
num_r_ports = 1
|
||||||
|
num_w_ports = 0
|
||||||
|
|
||||||
|
tech_name = "scn4m_subm"
|
||||||
|
process_corners = ["TT"]
|
||||||
|
supply_voltages = [5.0]
|
||||||
|
temperatures = [25]
|
||||||
|
|
||||||
|
output_path = "temp"
|
||||||
|
output_name = "sram_1rw_1r_{0}_{1}_{2}".format(word_size,num_words,tech_name)
|
||||||
|
|
||||||
|
drc_name = "magic"
|
||||||
|
lvs_name = "netgen"
|
||||||
|
pex_name = "magic"
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
word_size = 16
|
||||||
|
num_words = 256
|
||||||
|
|
||||||
|
tech_name = "scn4m_subm"
|
||||||
|
process_corners = ["TT"]
|
||||||
|
supply_voltages = [ 3.3 ]
|
||||||
|
temperatures = [ 25 ]
|
||||||
|
|
||||||
|
output_path = "temp"
|
||||||
|
output_name = "sram_{0}_{1}_{2}".format(word_size,num_words,tech_name)
|
||||||
|
|
||||||
|
drc_name = "magic"
|
||||||
|
lvs_name = "netgen"
|
||||||
|
pex_name = "magic"
|
||||||
|
|
@ -50,7 +50,7 @@ print("Words per row: {}".format(c.words_per_row))
|
||||||
output_extensions = ["sp","v","lib","py","html"]
|
output_extensions = ["sp","v","lib","py","html"]
|
||||||
if not OPTS.netlist_only:
|
if not OPTS.netlist_only:
|
||||||
output_extensions.extend(["gds","lef"])
|
output_extensions.extend(["gds","lef"])
|
||||||
output_files = ["{0}.{1}".format(OPTS.output_name,x) for x in output_extensions]
|
output_files = ["{0}{1}.{2}".format(OPTS.output_path,OPTS.output_name,x) for x in output_extensions]
|
||||||
print("Output files are: ")
|
print("Output files are: ")
|
||||||
print(*output_files,sep="\n")
|
print(*output_files,sep="\n")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,9 @@ class sram():
|
||||||
def sp_write(self,name):
|
def sp_write(self,name):
|
||||||
self.s.sp_write(name)
|
self.s.sp_write(name)
|
||||||
|
|
||||||
|
def lef_write(self,name):
|
||||||
|
self.s.lef_write(name)
|
||||||
|
|
||||||
def gds_write(self,name):
|
def gds_write(self,name):
|
||||||
self.s.gds_write(name)
|
self.s.gds_write(name)
|
||||||
|
|
||||||
|
|
@ -63,21 +66,21 @@ class sram():
|
||||||
start_time = datetime.datetime.now()
|
start_time = datetime.datetime.now()
|
||||||
gdsname = OPTS.output_path + self.s.name + ".gds"
|
gdsname = OPTS.output_path + self.s.name + ".gds"
|
||||||
print("GDS: Writing to {0}".format(gdsname))
|
print("GDS: Writing to {0}".format(gdsname))
|
||||||
self.s.gds_write(gdsname)
|
self.gds_write(gdsname)
|
||||||
print_time("GDS", datetime.datetime.now(), start_time)
|
print_time("GDS", datetime.datetime.now(), start_time)
|
||||||
|
|
||||||
# Create a LEF physical model
|
# Create a LEF physical model
|
||||||
start_time = datetime.datetime.now()
|
start_time = datetime.datetime.now()
|
||||||
lefname = OPTS.output_path + self.s.name + ".lef"
|
lefname = OPTS.output_path + self.s.name + ".lef"
|
||||||
print("LEF: Writing to {0}".format(lefname))
|
print("LEF: Writing to {0}".format(lefname))
|
||||||
self.s.lef_write(lefname)
|
self.lef_write(lefname)
|
||||||
print_time("LEF", datetime.datetime.now(), start_time)
|
print_time("LEF", datetime.datetime.now(), start_time)
|
||||||
|
|
||||||
# Save the spice file
|
# Save the spice file
|
||||||
start_time = datetime.datetime.now()
|
start_time = datetime.datetime.now()
|
||||||
spname = OPTS.output_path + self.s.name + ".sp"
|
spname = OPTS.output_path + self.s.name + ".sp"
|
||||||
print("SP: Writing to {0}".format(spname))
|
print("SP: Writing to {0}".format(spname))
|
||||||
self.s.sp_write(spname)
|
self.sp_write(spname)
|
||||||
print_time("Spice writing", datetime.datetime.now(), start_time)
|
print_time("Spice writing", datetime.datetime.now(), start_time)
|
||||||
|
|
||||||
# Save the extracted spice file
|
# Save the extracted spice file
|
||||||
|
|
@ -126,5 +129,5 @@ class sram():
|
||||||
start_time = datetime.datetime.now()
|
start_time = datetime.datetime.now()
|
||||||
vname = OPTS.output_path + self.s.name + ".v"
|
vname = OPTS.output_path + self.s.name + ".v"
|
||||||
print("Verilog: Writing to {0}".format(vname))
|
print("Verilog: Writing to {0}".format(vname))
|
||||||
self.s.verilog_write(vname)
|
self.verilog_write(vname)
|
||||||
print_time("Verilog", datetime.datetime.now(), start_time)
|
print_time("Verilog", datetime.datetime.now(), start_time)
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ class sram_1bank(sram_base):
|
||||||
"""
|
"""
|
||||||
def __init__(self, name, sram_config):
|
def __init__(self, name, sram_config):
|
||||||
sram_base.__init__(self, name, sram_config)
|
sram_base.__init__(self, name, sram_config)
|
||||||
|
|
||||||
def create_modules(self):
|
def create_modules(self):
|
||||||
"""
|
"""
|
||||||
This adds the modules for a single bank SRAM with control
|
This adds the modules for a single bank SRAM with control
|
||||||
|
|
|
||||||
|
|
@ -8,14 +8,18 @@ from vector import vector
|
||||||
from globals import OPTS, print_time
|
from globals import OPTS, print_time
|
||||||
import logical_effort
|
import logical_effort
|
||||||
from design import design
|
from design import design
|
||||||
|
from verilog import verilog
|
||||||
class sram_base(design):
|
from lef import lef
|
||||||
|
|
||||||
|
class sram_base(design, verilog, lef):
|
||||||
"""
|
"""
|
||||||
Dynamically generated SRAM by connecting banks to control logic. The
|
Dynamically generated SRAM by connecting banks to control logic. The
|
||||||
number of banks should be 1 , 2 or 4
|
number of banks should be 1 , 2 or 4
|
||||||
"""
|
"""
|
||||||
def __init__(self, name, sram_config):
|
def __init__(self, name, sram_config):
|
||||||
design.__init__(self, name)
|
design.__init__(self, name)
|
||||||
|
lef.__init__(self, ["metal1", "metal2", "metal3"])
|
||||||
|
verilog.__init__(self)
|
||||||
|
|
||||||
self.sram_config = sram_config
|
self.sram_config = sram_config
|
||||||
sram_config.set_local_config(self)
|
sram_config.set_local_config(self)
|
||||||
|
|
@ -531,4 +535,4 @@ class sram_base(design):
|
||||||
return bank_sen_cin
|
return bank_sen_cin
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,143 @@
|
||||||
|
`define assert(signal, value) \
|
||||||
|
if (!(signal === value)) begin \
|
||||||
|
$display("ASSERTION FAILED in %m: signal != value"); \
|
||||||
|
$finish;\
|
||||||
|
end
|
||||||
|
|
||||||
|
module sram_1rw_1r_tb;
|
||||||
|
reg clk;
|
||||||
|
|
||||||
|
// 1rw port
|
||||||
|
reg [3:0] addr0;
|
||||||
|
reg [1:0] din0;
|
||||||
|
reg csb0;
|
||||||
|
reg web0;
|
||||||
|
wire [1:0] dout0;
|
||||||
|
|
||||||
|
// 1r port
|
||||||
|
reg [3:0] addr1;
|
||||||
|
reg csb1;
|
||||||
|
wire [1:0] dout1;
|
||||||
|
|
||||||
|
sram_1rw_1r_2_16_scn4m_subm U0 (.DIN0(din0),
|
||||||
|
.DOUT0(dout0),
|
||||||
|
.ADDR0(addr0),
|
||||||
|
.csb0(csb0),
|
||||||
|
.web0(web0),
|
||||||
|
.clk0(clk),
|
||||||
|
.DOUT1(dout1),
|
||||||
|
.ADDR1(addr1),
|
||||||
|
.csb1(csb1),
|
||||||
|
.clk1(clk)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
initial
|
||||||
|
begin
|
||||||
|
|
||||||
|
//$monitor("%g addr0=%b din0=%b dout0=%b addr1=%b dout1=%b",
|
||||||
|
// $time, addr0, din0, dout0, addr1, dout1);
|
||||||
|
|
||||||
|
clk = 1;
|
||||||
|
csb0 = 1;
|
||||||
|
web0 = 1;
|
||||||
|
addr0 = 0;
|
||||||
|
din0 = 0;
|
||||||
|
|
||||||
|
csb1 = 1;
|
||||||
|
addr1 = 0;
|
||||||
|
|
||||||
|
// write
|
||||||
|
#10 din0=2'b10;
|
||||||
|
addr0=4'h1;
|
||||||
|
web0 = 0;
|
||||||
|
csb0 = 0;
|
||||||
|
// nop
|
||||||
|
csb1 = 1;
|
||||||
|
addr1 = 0;
|
||||||
|
|
||||||
|
// write another
|
||||||
|
#10 din0=2'b01;
|
||||||
|
addr0=4'hC;
|
||||||
|
web0 = 0;
|
||||||
|
csb0 = 0;
|
||||||
|
// read last
|
||||||
|
csb1 = 0;
|
||||||
|
addr1 = 4'h1;
|
||||||
|
|
||||||
|
#10 `assert(dout1, 2'b10)
|
||||||
|
|
||||||
|
// read undefined
|
||||||
|
din0=2'b11;
|
||||||
|
addr0=4'h0;
|
||||||
|
web0 = 1;
|
||||||
|
csb0 = 0;
|
||||||
|
// read another
|
||||||
|
csb1 = 0;
|
||||||
|
addr1 = 4'hC;
|
||||||
|
|
||||||
|
#10 `assert(dout0, 2'bxx)
|
||||||
|
`assert(dout1, 2'b01)
|
||||||
|
|
||||||
|
// read defined
|
||||||
|
din0=2'b11;
|
||||||
|
addr0=4'hC;
|
||||||
|
web0 = 1;
|
||||||
|
csb0 = 0;
|
||||||
|
// read undefined
|
||||||
|
csb1 = 0;
|
||||||
|
addr1 = 4'hD;
|
||||||
|
|
||||||
|
#10 `assert(dout0, 2'b01)
|
||||||
|
`assert(dout1, 2'bxx)
|
||||||
|
|
||||||
|
// write another
|
||||||
|
din0=2'b11;
|
||||||
|
addr0=4'hA;
|
||||||
|
web0 = 0;
|
||||||
|
csb0 = 0;
|
||||||
|
// read the feedthrough value
|
||||||
|
csb1 = 0;
|
||||||
|
addr1 = 4'hA;
|
||||||
|
|
||||||
|
#10 `assert(dout1, 2'b11)
|
||||||
|
|
||||||
|
// read defined
|
||||||
|
din0=2'b11;
|
||||||
|
addr0=4'h1;
|
||||||
|
web0 = 1;
|
||||||
|
csb0 = 0;
|
||||||
|
// read old value
|
||||||
|
csb1 = 0;
|
||||||
|
addr1 = 4'h1;
|
||||||
|
|
||||||
|
#10 `assert(dout0, 2'b10)
|
||||||
|
`assert(dout1, 2'b10)
|
||||||
|
|
||||||
|
// read defined
|
||||||
|
din0=2'b11;
|
||||||
|
addr0=4'hA;
|
||||||
|
web0 = 1;
|
||||||
|
csb0 = 0;
|
||||||
|
// dual read
|
||||||
|
csb1 = 0;
|
||||||
|
addr1 = 4'hA;
|
||||||
|
#10 `assert(dout0, 2'b11)
|
||||||
|
`assert(dout1, 2'b11)
|
||||||
|
|
||||||
|
// read undefined
|
||||||
|
din0=2'b11;
|
||||||
|
addr0=4'h0;
|
||||||
|
web0 = 1;
|
||||||
|
csb0 = 0;
|
||||||
|
|
||||||
|
#10 `assert(dout0, 2'bxx)
|
||||||
|
|
||||||
|
#10 $finish;
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
always
|
||||||
|
#5 clk = !clk;
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,103 @@
|
||||||
|
`define assert(signal, value) \
|
||||||
|
if (!(signal === value)) begin \
|
||||||
|
$display("ASSERTION FAILED in %m: signal != value"); \
|
||||||
|
$finish;\
|
||||||
|
end
|
||||||
|
|
||||||
|
module sram_1rw_tb;
|
||||||
|
reg clk;
|
||||||
|
|
||||||
|
reg [3:0] addr0;
|
||||||
|
reg [1:0] din0;
|
||||||
|
reg csb0;
|
||||||
|
reg web0;
|
||||||
|
wire [1:0] dout0;
|
||||||
|
|
||||||
|
sram_2_16_scn4m_subm U0 (.DIN0(din0),
|
||||||
|
.DOUT0(dout0),
|
||||||
|
.ADDR0(addr0),
|
||||||
|
.csb0(csb0),
|
||||||
|
.web0(web0),
|
||||||
|
.clk0(clk)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
initial
|
||||||
|
begin
|
||||||
|
|
||||||
|
//$monitor("%g addr0=%b din0=%b dout0=%b",
|
||||||
|
// $time, addr0, din0, dout0);
|
||||||
|
|
||||||
|
|
||||||
|
clk = 1;
|
||||||
|
csb0 = 1;
|
||||||
|
web0 = 1;
|
||||||
|
addr0 = 0;
|
||||||
|
din0 = 0;
|
||||||
|
|
||||||
|
// write
|
||||||
|
#10 din0=2'b10;
|
||||||
|
addr0=4'h1;
|
||||||
|
web0 = 0;
|
||||||
|
csb0 = 0;
|
||||||
|
|
||||||
|
// write another
|
||||||
|
#10 din0=2'b01;
|
||||||
|
addr0=4'hC;
|
||||||
|
web0 = 0;
|
||||||
|
csb0 = 0;
|
||||||
|
|
||||||
|
// read undefined
|
||||||
|
#10 din0=2'b11;
|
||||||
|
addr0=4'h0;
|
||||||
|
web0 = 1;
|
||||||
|
csb0 = 0;
|
||||||
|
|
||||||
|
#10 `assert(dout0, 2'bxx)
|
||||||
|
|
||||||
|
// read defined
|
||||||
|
din0=2'b11;
|
||||||
|
addr0=4'hC;
|
||||||
|
web0 = 1;
|
||||||
|
csb0 = 0;
|
||||||
|
|
||||||
|
#10 `assert(dout0, 2'b01)
|
||||||
|
|
||||||
|
// write another
|
||||||
|
din0=2'b11;
|
||||||
|
addr0=4'hA;
|
||||||
|
web0 = 0;
|
||||||
|
csb0 = 0;
|
||||||
|
|
||||||
|
// read defined
|
||||||
|
#10 din0=2'b11;
|
||||||
|
addr0=4'h1;
|
||||||
|
web0 = 1;
|
||||||
|
csb0 = 0;
|
||||||
|
|
||||||
|
#10 `assert(dout0, 2'b10)
|
||||||
|
|
||||||
|
// read defined
|
||||||
|
din0=2'b11;
|
||||||
|
addr0=4'hA;
|
||||||
|
web0 = 1;
|
||||||
|
csb0 = 0;
|
||||||
|
|
||||||
|
#10 `assert(dout0, 2'b11)
|
||||||
|
|
||||||
|
// read undefined
|
||||||
|
din0=2'b11;
|
||||||
|
addr0=4'h0;
|
||||||
|
web0 = 1;
|
||||||
|
csb0 = 0;
|
||||||
|
|
||||||
|
#10 `assert(dout0, 2'bxx)
|
||||||
|
|
||||||
|
#10 $finish;
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
always
|
||||||
|
#5 clk = !clk;
|
||||||
|
|
||||||
|
endmodule
|
||||||
Loading…
Reference in New Issue