Updated Verilog to have multiport. Added 1rw,1rw/1r Verilog testbench.

This commit is contained in:
Matt Guthaus 2019-01-11 14:15:16 -08:00
parent f0ab155172
commit 5de7ff3773
15 changed files with 459 additions and 54 deletions

View File

@ -10,7 +10,7 @@ from vector import vector
from pin_layout import pin_layout
import lef
class layout(lef.lef):
class layout():
"""
Class consisting of a set of objs and instances for a module
This provides a set of useful generic types for hierarchy
@ -21,7 +21,6 @@ class layout(lef.lef):
"""
def __init__(self, name):
lef.lef.__init__(self, ["metal1", "metal2", "metal3"])
self.name = name
self.width = None
self.height = None

View File

@ -2,9 +2,8 @@ import debug
import re
import os
import math
import verilog
class spice(verilog.verilog):
class spice():
"""
This provides a set of useful generic types for hierarchy
management. If a module is a custom designed cell, it will read from

View File

@ -9,7 +9,8 @@ from collections import defaultdict
class lef:
"""
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):
# LEF db units per micron

View File

@ -1,60 +1,165 @@
import debug
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):
""" Write a behavioral Verilog model. """
self.vf = open(verilog_name, "w")
self.vf.write("// OpenRAM SRAM model\n")
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("module {0}(DATA,ADDR,CSb,WEb,OEb,clk);\n".format(self.name))
self.vf.write("\n")
self.vf.write("module {0}(\n".format(self.name))
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 ADDR_WIDTH = {0} ;\n".format(self.addr_size))
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("\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(" 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(" // Tri-State Buffer control\n")
self.vf.write(" // output : When WEb = 1, oeb = 0, csb = 0\n")
self.vf.write(" assign DATA = (!CSb && !OEb && WEb) ? data_out : {0}'bz;\n".format(self.word_size))
self.vf.write("\n")
self.vf.write(" // Memory Write Block\n")
self.vf.write(" // Write Operation : When WEb = 0, CSb = 0\n")
self.vf.write(" always @ (posedge clk)\n")
self.vf.write(" begin : MEM_WRITE\n")
self.vf.write(" if ( !CSb && !WEb ) begin\n")
self.vf.write(" mem[ADDR] = DATA;\n")
self.vf.write(" $display($time,\" Writing %m ABUS=%b DATA=%b\",ADDR,DATA);\n")
self.vf.write(" end\n")
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")
for port in self.all_ports:
self.register_inputs(port)
# This is the memory array itself
self.vf.write("reg [DATA_WIDTH-1:0] mem [0:RAM_DEPTH-1];\n")
for port in self.all_ports:
if port in self.write_ports:
self.add_write_block(port)
if port in self.read_ports:
self.add_read_block(port)
self.vf.write("\n")
self.vf.write("endmodule\n")
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")

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -50,7 +50,7 @@ print("Words per row: {}".format(c.words_per_row))
output_extensions = ["sp","v","lib","py","html"]
if not OPTS.netlist_only:
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,sep="\n")

View File

@ -48,6 +48,9 @@ class sram():
def sp_write(self,name):
self.s.sp_write(name)
def lef_write(self,name):
self.s.lef_write(name)
def gds_write(self,name):
self.s.gds_write(name)
@ -63,21 +66,21 @@ class sram():
start_time = datetime.datetime.now()
gdsname = OPTS.output_path + self.s.name + ".gds"
print("GDS: Writing to {0}".format(gdsname))
self.s.gds_write(gdsname)
self.gds_write(gdsname)
print_time("GDS", datetime.datetime.now(), start_time)
# Create a LEF physical model
start_time = datetime.datetime.now()
lefname = OPTS.output_path + self.s.name + ".lef"
print("LEF: Writing to {0}".format(lefname))
self.s.lef_write(lefname)
self.lef_write(lefname)
print_time("LEF", datetime.datetime.now(), start_time)
# Save the spice file
start_time = datetime.datetime.now()
spname = OPTS.output_path + self.s.name + ".sp"
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)
# Save the extracted spice file
@ -126,5 +129,5 @@ class sram():
start_time = datetime.datetime.now()
vname = OPTS.output_path + self.s.name + ".v"
print("Verilog: Writing to {0}".format(vname))
self.s.verilog_write(vname)
self.verilog_write(vname)
print_time("Verilog", datetime.datetime.now(), start_time)

View File

@ -21,7 +21,7 @@ class sram_1bank(sram_base):
"""
def __init__(self, name, sram_config):
sram_base.__init__(self, name, sram_config)
def create_modules(self):
"""
This adds the modules for a single bank SRAM with control

View File

@ -8,14 +8,18 @@ from vector import vector
from globals import OPTS, print_time
import logical_effort
from design import design
class sram_base(design):
from verilog import verilog
from lef import lef
class sram_base(design, verilog, lef):
"""
Dynamically generated SRAM by connecting banks to control logic. The
number of banks should be 1 , 2 or 4
"""
def __init__(self, name, sram_config):
design.__init__(self, name)
lef.__init__(self, ["metal1", "metal2", "metal3"])
verilog.__init__(self)
self.sram_config = sram_config
sram_config.set_local_config(self)
@ -531,4 +535,4 @@ class sram_base(design):
return bank_sen_cin

View File

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

View File

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