Merge branch 'dev' into rbl_revamp

This commit is contained in:
Matt Guthaus 2019-07-26 18:01:43 -07:00
commit 0c5cd2ced9
19 changed files with 712 additions and 134 deletions

View File

@ -18,15 +18,11 @@ class verilog:
def verilog_write(self,verilog_name):
""" Write a behavioral Verilog model. """
self.vf = open(verilog_name, "w")
# Determine if optional write mask is used
self.wmask_enabled = False
if self.word_size != self.write_size:
self.wmask_enabled = True
self.vf.write("// OpenRAM SRAM model\n")
self.vf.write("// Words: {0}\n".format(self.num_words))
self.vf.write("// Word size: {0}\n".format(self.word_size))
if self.wmask_enabled:
if self.write_size is not None:
self.vf.write("// Write size: {0}\n\n".format(self.write_size))
else:
self.vf.write("\n")
@ -41,12 +37,12 @@ class verilog:
self.vf.write("// Port {0}: W\n".format(port))
if port in self.readwrite_ports:
self.vf.write(" clk{0},csb{0},web{0},".format(port))
if self.wmask_enabled:
if self.write_size is not None:
self.vf.write("wmask{},".format(port))
self.vf.write("ADDR{0},DIN{0},DOUT{0}".format(port))
elif port in self.write_ports:
self.vf.write(" clk{0},csb{0},".format(port))
if self.wmask_enabled:
if self.write_size is not None:
self.vf.write("wmask{},".format(port))
self.vf.write("ADDR{0},DIN{0}".format(port))
elif port in self.read_ports:
@ -56,9 +52,9 @@ class verilog:
self.vf.write(",\n")
self.vf.write("\n );\n\n")
if self.wmask_enabled:
self.num_wmask = int(self.word_size/self.write_size)
self.vf.write(" parameter NUM_WMASK = {0} ;\n".format(self.num_wmask))
if self.write_size is not None:
self.num_wmasks = int(self.word_size/self.write_size)
self.vf.write(" parameter NUM_WMASKS = {0} ;\n".format(self.num_wmasks))
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")
@ -103,8 +99,8 @@ class verilog:
if port in self.readwrite_ports:
self.vf.write(" reg web{0}_reg;\n".format(port))
if port in self.write_ports:
if self.wmask_enabled:
self.vf.write(" reg [NUM_WMASK-1:0] wmask{0}_reg;\n".format(port))
if self.write_size is not None:
self.vf.write(" reg [NUM_WMASKS-1:0] wmask{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))
@ -123,7 +119,7 @@ class verilog:
if port in self.readwrite_ports:
self.vf.write(" web{0}_reg = web{0};\n".format(port))
if port in self.write_ports:
if self.wmask_enabled:
if self.write_size is not None:
self.vf.write(" wmask{0}_reg = wmask{0};\n".format(port))
self.vf.write(" ADDR{0}_reg = ADDR{0};\n".format(port))
if port in self.write_ports:
@ -138,13 +134,13 @@ class verilog:
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))
if self.wmask_enabled:
if self.write_size is not None:
self.vf.write(" $display($time,\" Writing %m ADDR{0}=%b DIN{0}=%b wmask{0}=%b\",ADDR{0}_reg,DIN{0}_reg,wmask{0}_reg);\n".format(port))
else:
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))
if self.wmask_enabled:
if self.write_size is not None:
self.vf.write(" $display($time,\" Writing %m ADDR{0}=%b DIN{0}=%b wmask{0}=%b\",ADDR{0}_reg,DIN{0}_reg,wmask{0}_reg);\n".format(port))
else:
self.vf.write(" $display($time,\" Writing %m ADDR{0}=%b DIN{0}=%b\",ADDR{0}_reg,DIN{0}_reg);\n".format(port))
@ -160,8 +156,8 @@ class verilog:
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))
if (self.wmask_enabled):
self.vf.write(" input [NUM_WMASK-1:0] wmask{0}; // write mask\n".format(port))
if self.write_size is not None:
self.vf.write(" input [NUM_WMASKS-1:0] wmask{0}; // write mask\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))
@ -179,18 +175,18 @@ class verilog:
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:
if self.wmask_enabled:
if self.write_size is not None:
self.vf.write(" if ( !csb{0}_reg && !web{0}_reg ) begin\n".format(port))
else:
self.vf.write(" if ( !csb{0}_reg && !web{0}_reg )\n".format(port))
else:
if self.wmask_enabled:
if self.write_size is not None:
self.vf.write(" if (!csb{0}_reg) begin\n".format(port))
else:
self.vf.write(" if (!csb{0}_reg)\n".format(port))
if self.wmask_enabled:
for mask in range(0,self.num_wmask):
if self.write_size is not None:
for mask in range(0,self.num_wmasks):
lower = mask * self.write_size
upper = lower + self.write_size-1
self.vf.write(" if (wmask{0}_reg[{1}])\n".format(port,mask))

View File

@ -46,6 +46,10 @@ class delay(simulation):
self.targ_read_ports = []
self.targ_write_ports = []
self.period = 0
if self.write_size is not None:
self.num_wmasks = int(self.word_size / self.write_size)
else:
self.num_wmasks = 0
self.set_load_slew(0,0)
self.set_corner(corner)
self.create_signal_names()
@ -1183,46 +1187,48 @@ class delay(simulation):
# For now, ignore data patterns and write ones or zeros
data_ones = "1"*self.word_size
data_zeros = "0"*self.word_size
wmask_ones = "1"*self.num_wmasks
wmask_zeroes = "0"*self.num_wmasks
if self.t_current == 0:
self.add_noop_all_ports("Idle cycle (no positive clock edge)",
inverse_address, data_zeros)
inverse_address, data_zeros,wmask_zeroes)
self.add_write("W data 1 address {}".format(inverse_address),
inverse_address,data_ones,write_port)
inverse_address,data_ones,wmask_ones,write_port)
self.add_write("W data 0 address {} to write value".format(self.probe_address),
self.probe_address,data_zeros,write_port)
self.probe_address,data_zeros,wmask_ones,write_port)
self.measure_cycles[write_port][sram_op.WRITE_ZERO] = len(self.cycle_times)-1
# This also ensures we will have a H->L transition on the next read
self.add_read("R data 1 address {} to set DOUT caps".format(inverse_address),
inverse_address,data_zeros,read_port)
inverse_address,data_zeros,wmask_ones,read_port)
self.add_read("R data 0 address {} to check W0 worked".format(self.probe_address),
self.probe_address,data_zeros,read_port)
self.probe_address,data_zeros,wmask_ones,read_port)
self.measure_cycles[read_port][sram_op.READ_ZERO] = len(self.cycle_times)-1
self.add_noop_all_ports("Idle cycle (if read takes >1 cycle)",
inverse_address,data_zeros)
inverse_address,data_zeros,wmask_zeroes)
self.add_write("W data 1 address {} to write value".format(self.probe_address),
self.probe_address,data_ones,write_port)
self.probe_address,data_ones,wmask_ones,write_port)
self.measure_cycles[write_port][sram_op.WRITE_ONE] = len(self.cycle_times)-1
self.add_write("W data 0 address {} to clear DIN caps".format(inverse_address),
inverse_address,data_zeros,write_port)
inverse_address,data_zeros,wmask_ones,write_port)
# This also ensures we will have a L->H transition on the next read
self.add_read("R data 0 address {} to clear DOUT caps".format(inverse_address),
inverse_address,data_zeros,read_port)
inverse_address,data_zeros,wmask_ones,read_port)
self.add_read("R data 1 address {} to check W1 worked".format(self.probe_address),
self.probe_address,data_zeros,read_port)
self.probe_address,data_zeros,wmask_ones,read_port)
self.measure_cycles[read_port][sram_op.READ_ONE] = len(self.cycle_times)-1
self.add_noop_all_ports("Idle cycle (if read takes >1 cycle))",
self.probe_address,data_zeros)
self.probe_address,data_zeros,wmask_zeroes)
def get_available_port(self,get_read_port):

View File

@ -33,6 +33,11 @@ class functional(simulation):
if OPTS.is_unit_test:
random.seed(12345)
if self.write_size is not None:
self.num_wmasks = int(self.word_size / self.write_size)
else:
self.num_wmasks = 0
self.set_corner(corner)
self.set_spice_constants()
self.set_stimulus_variables()
@ -43,12 +48,21 @@ class functional(simulation):
self.create_graph()
self.set_internal_spice_names()
self.initialize_wmask()
# Number of checks can be changed
self.num_cycles = 2
self.stored_words = {}
self.write_check = []
self.read_check = []
def initialize_wmask(self):
self.wmask = ""
if self.write_size is not None:
# initialize all wmask bits to 1
for bit in range(self.num_wmasks):
self.wmask += "1"
def run(self, feasible_period=None):
if feasible_period: #period defaults to tech.py feasible period otherwise.
self.period = feasible_period
@ -68,37 +82,44 @@ class functional(simulation):
return self.check_stim_results()
def write_random_memory_sequence(self):
rw_ops = ["noop", "write", "read"]
w_ops = ["noop", "write"]
if self.write_size is not None:
rw_ops = ["noop", "write", "partial_write", "read"]
w_ops = ["noop", "write", "partial_write"]
else:
rw_ops = ["noop", "write", "read"]
w_ops = ["noop", "write"]
r_ops = ["noop", "read"]
rw_read_din_data = "0"*self.word_size
check = 0
# First cycle idle
comment = self.gen_cycle_comment("noop", "0"*self.word_size, "0"*self.addr_size, 0, self.t_current)
self.add_noop_all_ports(comment, "0"*self.addr_size, "0"*self.word_size)
comment = self.gen_cycle_comment("noop", "0"*self.word_size, "0"*self.addr_size, self.wmask, 0, self.t_current)
self.add_noop_all_ports(comment, "0"*self.addr_size, "0"*self.word_size, "0"*self.num_wmasks)
# Write at least once
addr = self.gen_addr()
word = self.gen_data()
comment = self.gen_cycle_comment("write", word, addr, 0, self.t_current)
self.add_write(comment, addr, word, 0)
# print("write", self.t_current, addr, word)
comment = self.gen_cycle_comment("write", word, addr, self.wmask, 0, self.t_current)
self.add_write(comment, addr, word, self.wmask, 0)
self.stored_words[addr] = word
# Read at least once. For multiport, it is important that one read cycle uses all RW and R port to read from the same address simultaniously.
# This will test the viablilty of the transistor sizing in the bitcell.
for port in self.all_ports:
if port in self.write_ports:
self.add_noop_one_port("0"*self.addr_size, "0"*self.word_size, port)
self.add_noop_one_port("0"*self.addr_size, "0"*self.word_size, "0"*self.num_wmasks, port)
else:
comment = self.gen_cycle_comment("read", word, addr, port, self.t_current)
self.add_read_one_port(comment, addr, rw_read_din_data, port)
# print("read", self.t_current, addr, word)
comment = self.gen_cycle_comment("read", word, addr, self.wmask, port, self.t_current)
self.add_read_one_port(comment, addr, rw_read_din_data, "1"*self.num_wmasks, port)
self.write_check.append([word, "{0}{1}".format(self.dout_name,port), self.t_current+self.period, check])
check += 1
self.cycle_times.append(self.t_current)
self.t_current += self.period
# Perform a random sequence of writes and reads on random ports, using random addresses and random words
# and random write masks (if applicable)
for i in range(self.num_cycles):
w_addrs = []
for port in self.all_ports:
@ -112,26 +133,51 @@ class functional(simulation):
if op == "noop":
addr = "0"*self.addr_size
word = "0"*self.word_size
self.add_noop_one_port(addr, word, port)
wmask = "0" * self.num_wmasks
self.add_noop_one_port(addr, word, wmask, port)
elif op == "write":
addr = self.gen_addr()
word = self.gen_data()
# print("write",self.t_current,addr,word)
# two ports cannot write to the same address
if addr in w_addrs:
self.add_noop_one_port("0"*self.addr_size, "0"*self.word_size, port)
self.add_noop_one_port("0"*self.addr_size, "0"*self.word_size, "0"*self.num_wmasks, port)
else:
comment = self.gen_cycle_comment("write", word, addr, port, self.t_current)
self.add_write_one_port(comment, addr, word, port)
comment = self.gen_cycle_comment("write", word, addr, self.wmask, port, self.t_current)
self.add_write_one_port(comment, addr, word, self.wmask, port)
self.stored_words[addr] = word
w_addrs.append(addr)
elif op == "partial_write":
#write only to a word that's been written to
(addr,old_word) = self.get_data()
word = self.gen_data()
wmask = self.gen_wmask()
new_word = word
for bit in range(len(wmask)):
# When the write mask's bits are 0, the old data values should appear in the new word
# as to not overwrite the old values
if wmask[bit] == "0":
lower = bit * self.write_size
upper = lower + self.write_size - 1
new_word = new_word[:lower] + old_word[lower:upper+1] + new_word[upper + 1:]
# print("partial_w",self.t_current,addr,wmask,word, "partial_w_word:", new_word)
# two ports cannot write to the same address
if addr in w_addrs:
self.add_noop_one_port("0"*self.addr_size, "0"*self.word_size, "0"*self.num_wmasks, port)
else:
comment = self.gen_cycle_comment("partial_write", word, addr, wmask, port, self.t_current)
self.add_write_one_port(comment, addr, word, wmask, port)
self.stored_words[addr] = new_word
w_addrs.append(addr)
else:
(addr,word) = random.choice(list(self.stored_words.items()))
# print("read",self.t_current,addr,word)
# cannot read from an address that is currently being written to
if addr in w_addrs:
self.add_noop_one_port("0"*self.addr_size, "0"*self.word_size, port)
self.add_noop_one_port("0"*self.addr_size, "0"*self.word_size, "0"*self.num_wmasks, port)
else:
comment = self.gen_cycle_comment("read", word, addr, port, self.t_current)
self.add_read_one_port(comment, addr, rw_read_din_data, port)
comment = self.gen_cycle_comment("read", word, addr, self.wmask, port, self.t_current)
self.add_read_one_port(comment, addr, rw_read_din_data, "1"*self.num_wmasks, port)
self.write_check.append([word, "{0}{1}".format(self.dout_name,port), self.t_current+self.period, check])
check += 1
@ -139,8 +185,8 @@ class functional(simulation):
self.t_current += self.period
# Last cycle idle needed to correctly measure the value on the second to last clock edge
comment = self.gen_cycle_comment("noop", "0"*self.word_size, "0"*self.addr_size, 0, self.t_current)
self.add_noop_all_ports(comment, "0"*self.addr_size, "0"*self.word_size)
comment = self.gen_cycle_comment("noop", "0"*self.word_size, "0"*self.addr_size, self.wmask, 0, self.t_current)
self.add_noop_all_ports(comment, "0"*self.addr_size, "0"*self.word_size, "0"*self.num_wmasks)
def read_stim_results(self):
# Extrat DOUT values from spice timing.lis
@ -174,23 +220,56 @@ class functional(simulation):
self.read_check[i][2])
return(0, error)
return(1, "SUCCESS")
def gen_wmask(self):
wmask = ""
# generate a random wmask
for bit in range(self.num_wmasks):
rand = random.randint(0, 1)
wmask += str(rand)
# prevent the wmask from having all bits on or off (this is not a partial write)
all_zeroes = True
all_ones = True
for bit in range(self.num_wmasks):
if wmask[bit]=="0":
all_ones = False
elif wmask[bit]=="1":
all_zeroes = False
if all_zeroes:
index = random.randint(0, self.num_wmasks - 1)
wmask = wmask[:index] + "1" + wmask[index + 1:]
elif all_ones:
index = random.randint(0, self.num_wmasks - 1)
wmask = wmask[:index] + "0" + wmask[index + 1:]
# wmask must be reversed since a python list goes right to left and sram bits go left to right.
return wmask[::-1]
def gen_data(self):
""" Generates a random word to write. """
rand = random.randint(0,(2**self.word_size)-1)
data_bits = self.convert_to_bin(rand,False)
return data_bits
def gen_data_all_bits(self):
""" Generates a random word, either all 0's or all 1's, to write. """
rand = random.randint(0,1)
bits = []
for bit in range(self.word_size):
bits.append(rand)
data_bits = ''.join(map(str,bits))
return data_bits
def gen_addr(self):
""" Generates a random address value to write to. """
rand = random.randint(0,(2**self.addr_size)-1)
addr_bits = self.convert_to_bin(rand,True)
return addr_bits
return addr_bits
def get_data(self):
""" Gets an available address and corresponding word. """
# Currently unused but may need later depending on how the functional test develops
addr = random.choice(self.stored_words.keys())
addr = random.choice(list(self.stored_words.keys()))
word = self.stored_words[addr]
return (addr,word)
@ -269,6 +348,17 @@ class functional(simulation):
for port in self.readwrite_ports:
self.stim.gen_pwl("WEB{}".format(port), self.cycle_times , self.web_values[port], self.period, self.slew, 0.05)
# Generate wmask bits
for port in self.write_ports:
if self.write_size is not None:
self.sf.write("\n* Generation of wmask signals\n")
for bit in range(self.num_wmasks):
sig_name = "WMASK{0}_{1} ".format(port, bit)
# self.stim.gen_pwl(sig_name, self.cycle_times, self.data_values[port][bit], self.period,
# self.slew, 0.05)
self.stim.gen_pwl(sig_name, self.cycle_times, self.wmask_values[port][bit], self.period,
self.slew, 0.05)
# Generate CLK signals
for port in self.all_ports:
self.stim.gen_pulse(sig_name="{0}{1}".format(tech.spice["clk"], port),

View File

@ -34,6 +34,11 @@ class simulation():
self.readwrite_ports = self.sram.readwrite_ports
self.read_ports = self.sram.read_ports
self.write_ports = self.sram.write_ports
if self.write_size is not None:
self.num_wmasks = int(self.word_size/self.write_size)
else:
self.num_wmasks = 0
def set_corner(self,corner):
""" Set the corner values """
@ -75,6 +80,7 @@ class simulation():
# Three dimensional list to handle each addr and data bits for wach port over the number of checks
self.addr_values = [[[] for bit in range(self.addr_size)] for port in self.all_ports]
self.data_values = [[[] for bit in range(self.word_size)] for port in self.write_ports]
self.wmask_values = [[[] for bit in range(self.num_wmasks)] for port in self.write_ports]
# For generating comments in SPICE stimulus
self.cycle_comments = []
@ -126,8 +132,22 @@ class simulation():
else:
debug.error("Non-binary address string",1)
bit -= 1
def add_wmask(self, wmask, port):
""" Add the array of address values """
debug.check(len(wmask) == self.num_wmasks, "Invalid wmask size.")
bit = self.num_wmasks - 1
for c in wmask:
if c == "0":
self.wmask_values[port][bit].append(0)
elif c == "1":
self.wmask_values[port][bit].append(1)
else:
debug.error("Non-binary wmask string", 1)
bit -= 1
def add_write(self, comment, address, data, port):
def add_write(self, comment, address, data, wmask, port):
""" Add the control values for a write cycle. """
debug.check(port in self.write_ports, "Cannot add write cycle to a read port. Port {0}, Write Ports {1}".format(port, self.write_ports))
debug.info(2, comment)
@ -140,15 +160,16 @@ class simulation():
self.add_control_one_port(port, "write")
self.add_data(data,port)
self.add_address(address,port)
self.add_wmask(wmask,port)
#This value is hard coded here. Possibly change to member variable or set in add_noop_one_port
noop_data = "0"*self.word_size
#Add noops to all other ports.
for unselected_port in self.all_ports:
if unselected_port != port:
self.add_noop_one_port(address, noop_data, unselected_port)
self.add_noop_one_port(address, noop_data, wmask, unselected_port)
def add_read(self, comment, address, din_data, port):
def add_read(self, comment, address, din_data, wmask, port):
""" Add the control values for a read cycle. """
debug.check(port in self.read_ports, "Cannot add read cycle to a write port. Port {0}, Read Ports {1}".format(port, self.read_ports))
debug.info(2, comment)
@ -162,6 +183,7 @@ class simulation():
#If the port is also a readwrite then add data.
if port in self.write_ports:
self.add_data(din_data,port)
self.add_wmask(wmask,port)
self.add_address(address, port)
#This value is hard coded here. Possibly change to member variable or set in add_noop_one_port
@ -169,9 +191,9 @@ class simulation():
#Add noops to all other ports.
for unselected_port in self.all_ports:
if unselected_port != port:
self.add_noop_one_port(address, noop_data, unselected_port)
self.add_noop_one_port(address, noop_data, wmask, unselected_port)
def add_noop_all_ports(self, comment, address, data):
def add_noop_all_ports(self, comment, address, data, wmask):
""" Add the control values for a noop to all ports. """
debug.info(2, comment)
self.fn_cycle_comments.append(comment)
@ -181,19 +203,20 @@ class simulation():
self.t_current += self.period
for port in self.all_ports:
self.add_noop_one_port(address, data, port)
def add_write_one_port(self, comment, address, data, port):
self.add_noop_one_port(address, data, wmask, port)
def add_write_one_port(self, comment, address, data, wmask, port):
""" Add the control values for a write cycle. Does not increment the period. """
debug.check(port in self.write_ports, "Cannot add write cycle to a read port. Port {0}, Write Ports {1}".format(port, self.write_ports))
debug.info(2, comment)
self.fn_cycle_comments.append(comment)
self.add_control_one_port(port, "write")
self.add_data(data,port)
self.add_address(address,port)
self.add_wmask(wmask,port)
def add_read_one_port(self, comment, address, din_data, port):
def add_read_one_port(self, comment, address, din_data, wmask, port):
""" Add the control values for a read cycle. Does not increment the period. """
debug.check(port in self.read_ports, "Cannot add read cycle to a write port. Port {0}, Read Ports {1}".format(port, self.read_ports))
debug.info(2, comment)
@ -203,13 +226,15 @@ class simulation():
#If the port is also a readwrite then add data.
if port in self.write_ports:
self.add_data(din_data,port)
self.add_wmask(wmask,port)
self.add_address(address, port)
def add_noop_one_port(self, address, data, port):
def add_noop_one_port(self, address, data, wmask, port):
""" Add the control values for a noop to a single port. Does not increment the period. """
self.add_control_one_port(port, "noop")
if port in self.write_ports:
self.add_data(data,port)
self.add_wmask(wmask,port)
self.add_address(address, port)
def append_cycle_comment(self, port, comment):
@ -223,18 +248,26 @@ class simulation():
time_spacing,
comment))
def gen_cycle_comment(self, op, word, addr, port, t_current):
def gen_cycle_comment(self, op, word, addr, wmask, port, t_current):
if op == "noop":
comment = "\tIdle during cycle {0} ({1}ns - {2}ns)".format(int(t_current/self.period),
t_current,
t_current+self.period)
elif op == "write":
comment = "\tWriting {0} to address {1} (from port {2}) during cycle {3} ({4}ns - {5}ns)".format(word,
addr,
port,
int(t_current/self.period),
t_current,
t_current+self.period)
addr,
port,
int(t_current/self.period),
t_current,
t_current+self.period)
elif op == "partial_write":
comment = "\tWriting (partial) {0} to address {1} with mask bit {2} (from port {3}) during cycle {4} ({5}ns - {6}ns)".format(word,
addr,
wmask,
port,
int(t_current / self.period),
t_current,
t_current + self.period)
else:
comment = "\tReading {0} from address {1} (from port {2}) during cycle {3} ({4}ns - {5}ns)".format(word,
addr,
@ -267,11 +300,14 @@ class simulation():
for port in range(total_ports):
if (port in read_index) and (port in write_index):
pin_names.append("WEB{0}".format(port))
if (self.write_size != self.word_size):
pin_names.append("WMASK{0}".format(port))
for port in range(total_ports):
pin_names.append("{0}{1}".format(tech.spice["clk"], port))
if self.write_size is not None:
for port in write_index:
for bit in range(self.num_wmasks):
pin_names.append("WMASK{0}_{1}".format(port,bit))
for read_output in read_index:
for i in range(dbits):

View File

@ -729,7 +729,7 @@ class VlsiLayout:
def getBlockages(self,layer):
"""
Return all blockages on a given layer in [llx, lly, urx, ury] format and
Return all blockages on a given layer in [coordinate 1, coordinate 2,...] format and
user units.
"""
blockages = []
@ -744,7 +744,7 @@ class VlsiLayout:
def getAllShapes(self,layer):
"""
Return all shapes on a given layer in [llx, lly, urx, ury] format and user units for rectangles
Return all shapes on a given layer in [llx, lly, urx, ury] format and user units for rectangles
and [coordinate 1, coordinate 2,...] format and user units for polygons.
"""
boundaries = set()

View File

@ -470,18 +470,16 @@ def report_status():
debug.error("{0} is not an integer in config file.".format(OPTS.word_size))
if type(OPTS.num_words)!=int:
debug.error("{0} is not an integer in config file.".format(OPTS.sram_size))
if type(OPTS.write_size) != int and OPTS.write_size != None:
if type(OPTS.write_size) is not int and OPTS.write_size is not None:
debug.error("{0} is not an integer in config file.".format(OPTS.write_size))
# Determine if a write mask is specified by the user; if it's not, the mask write size should
# be the same as the word size so that an entire word is written at once
if OPTS.write_size==None:
OPTS.write_size = OPTS.word_size
if (OPTS.write_size < 1 or OPTS.write_size > OPTS.word_size):
debug.error("Write size needs to be between 1 bit and {0} bits.".format(OPTS.word_size))
if (OPTS.word_size % OPTS.write_size != 0):
debug.error("Write size needs to be an integer multiple of word size.")
# If a write mask is specified by the user, the mask write size should be the same as
# the word size so that an entire word is written at once.
if OPTS.write_size is not None:
if (OPTS.write_size < 1 or OPTS.write_size > OPTS.word_size):
debug.error("Write size needs to be between 1 bit and {0} bits.".format(OPTS.word_size))
if (OPTS.word_size % OPTS.write_size != 0):
debug.error("Write size needs to be an integer multiple of word size.")
if not OPTS.tech_name:
debug.error("Tech name must be specified in config file.")

View File

@ -30,6 +30,10 @@ class bank(design.design):
self.sram_config = sram_config
sram_config.set_local_config(self)
if self.write_size is not None:
self.num_wmasks = int(self.word_size/self.write_size)
else:
self.num_wmasks = 0
if name == "":
name = "bank_{0}_{1}".format(self.word_size, self.num_words)
@ -85,9 +89,6 @@ class bank(design.design):
for port in self.write_ports:
for bit in range(self.word_size):
self.add_pin("din{0}_{1}".format(port,bit),"INPUT")
# if (self.word_size != self.write_size):
# for bit in range(self.word_size):
# self.add_pin()
for port in self.all_ports:
for bit in range(self.addr_size):
self.add_pin("addr{0}_{1}".format(port,bit),"INPUT")
@ -103,6 +104,8 @@ class bank(design.design):
self.add_pin("p_en_bar{0}".format(port), "INPUT")
for port in self.write_ports:
self.add_pin("w_en{0}".format(port), "INPUT")
for bit in range(self.num_wmasks):
self.add_pin("bank_wmask{0}_{1}".format(port,bit),"INPUT")
for port in self.all_ports:
self.add_pin("wl_en{0}".format(port), "INPUT")
self.add_pin("vdd","POWER")
@ -464,6 +467,8 @@ class bank(design.design):
temp.append("p_en_bar{0}".format(port))
if port in self.write_ports:
temp.append("w_en{0}".format(port))
for bit in range(self.num_wmasks):
temp.append("bank_wmask{0}_{1}".format(port, bit))
temp.extend(["vdd","gnd"])
self.connect_inst(temp)

View File

@ -21,7 +21,7 @@ class control_logic(design.design):
Dynamically generated Control logic for the total SRAM circuit.
"""
def __init__(self, num_rows, words_per_row, word_size, write_size, sram=None, port_type="rw", name=""):
def __init__(self, num_rows, words_per_row, word_size, sram=None, port_type="rw", name=""):
""" Constructor """
name = "control_logic_" + port_type
design.design.__init__(self, name)
@ -35,7 +35,6 @@ class control_logic(design.design):
self.words_per_row = words_per_row
self.word_size = word_size
self.port_type = port_type
self.write_size = write_size
self.num_cols = word_size*words_per_row
self.num_words = num_rows*words_per_row
@ -661,12 +660,14 @@ class control_logic(design.design):
def place_pen_row(self,row):
x_off = self.control_x_offset
(y_off,mirror)=self.get_offset(row)
offset = vector(x_off,y_off)
self.p_en_bar_inst.place(offset, mirror)
self.row_end_inst.append(self.p_en_bar_inst)
def route_pen(self):
in_map = zip(["A"], ["gated_clk_bar"])
self.connect_vertical_bus(in_map, self.p_en_bar_inst, self.rail_offsets)
@ -782,8 +783,6 @@ class control_logic(design.design):
def route_dffs(self):
if self.port_type == "rw":
#print("hi")
#if (self.word_size == self.write_size):
dff_out_map = zip(["dout_bar_0", "dout_bar_1", "dout_1"], ["cs", "we", "we_bar"])
else:
dff_out_map = zip(["dout_bar_0"], ["cs"])

View File

@ -187,9 +187,15 @@ class multibank(design.design):
words_per_row=self.words_per_row)
self.add_mod(self.sense_amp_array)
self.write_driver_array = self.mod_write_driver_array(columns=self.num_cols,
word_size=self.word_size)
self.add_mod(self.write_driver_array)
if self.write_size is not None:
self.write_mask_driver_array = self.mod_write_mask_driver_array(columns=self.num_cols,
word_size=self.word_size,
write_size=self.write_size)
self.add_mod(self.write_mask_driver_array)
else:
self.write_driver_array = self.mod_write_driver_array(columns=self.num_cols,
word_size=self.word_size)
self.add_mod(self.write_driver_array)
self.row_decoder = self.mod_decoder(rows=self.num_rows)
self.add_mod(self.row_decoder)

View File

@ -22,6 +22,10 @@ class port_data(design.design):
sram_config.set_local_config(self)
self.port = port
if self.write_size is not None:
self.num_wmasks = int(self.word_size/self.write_size)
else:
self.num_wmasks = 0
if name == "":
name = "port_data_{0}".format(self.port)
@ -54,9 +58,14 @@ class port_data(design.design):
if self.write_driver_array:
self.create_write_driver_array()
if self.write_size is not None:
self.create_write_mask_and_array()
else:
self.write_mask_and_array_inst = None
else:
self.write_driver_array_inst = None
self.write_mask_and_array_inst = None
if self.column_mux_array:
self.create_column_mux_array()
else:
@ -94,6 +103,8 @@ class port_data(design.design):
self.add_pin("p_en_bar", "INPUT")
if self.port in self.write_ports:
self.add_pin("w_en", "INPUT")
for bit in range(self.num_wmasks):
self.add_pin("bank_wmask_{}".format(bit),"INPUT")
self.add_pin("vdd","POWER")
self.add_pin("gnd","GROUND")
@ -175,11 +186,21 @@ class port_data(design.design):
if self.port in self.write_ports:
self.write_driver_array = factory.create(module_type="write_driver_array",
columns=self.num_cols,
word_size=self.word_size)
word_size=self.word_size,
write_size=self.write_size)
self.add_mod(self.write_driver_array)
if self.write_size is not None:
self.write_mask_and_array = factory.create(module_type="write_mask_and_array",
columns=self.num_cols,
word_size=self.word_size,
write_size=self.write_size)
self.add_mod(self.write_mask_and_array)
else:
self.write_mask_and_array_inst = None
else:
self.write_driver_array = None
self.write_mask_and_array = None
def precompute_constants(self):
""" Get some preliminary data ready """
@ -289,20 +310,43 @@ class port_data(design.design):
temp = []
for bit in range(self.word_size):
temp.append("din_{}".format(bit))
for bit in range(self.word_size):
if (self.words_per_row == 1):
temp.append("bl_{0}".format(bit))
temp.append("br_{0}".format(bit))
else:
temp.append("bl_out_{0}".format(bit))
temp.append("br_out_{0}".format(bit))
temp.extend(["w_en", "vdd", "gnd"])
temp.append(self.bl_names[self.port]+"_out_{0}".format(bit))
temp.append(self.br_names[self.port]+"_out_{0}".format(bit))
if self.write_size is not None:
for i in range(self.num_wmasks):
temp.append("wdriver_sel_{}".format(i))
else:
temp.append("w_en")
temp.extend(["vdd", "gnd"])
self.connect_inst(temp)
def create_write_mask_and_array(self):
""" Creating Write Masks """
self.write_mask_and_array_inst = self.add_inst(name="write_mask_and_array{}".format(self.port),
mod=self.write_mask_and_array)
temp = []
for bit in range(self.num_wmasks):
temp.append("bank_wmask_{}".format(bit))
temp.extend(["w_en"])
for bit in range(self.num_wmasks):
temp.append("wdriver_sel_{}".format(bit))
temp.extend(["vdd", "gnd"])
self.connect_inst(temp)
def place_write_driver_array(self, offset):
""" Placing Write Driver """
self.write_driver_array_inst.place(offset=offset, mirror="MX")
self .write_driver_array_inst.place(offset=offset, mirror="MX")
def compute_instance_offsets(self):

View File

@ -19,7 +19,7 @@ class write_driver_array(design.design):
Dynamically generated write driver array of all bitlines.
"""
def __init__(self, name, columns, word_size):
def __init__(self, name, columns, word_size,write_size=None):
design.design.__init__(self, name)
debug.info(1, "Creating {0}".format(self.name))
self.add_comment("columns: {0}".format(columns))
@ -27,8 +27,12 @@ class write_driver_array(design.design):
self.columns = columns
self.word_size = word_size
self.write_size = write_size
self.words_per_row = int(columns / word_size)
if self.write_size is not None:
self.num_wmasks = int(self.word_size/self.write_size)
self.create_netlist()
if not OPTS.netlist_only:
self.create_layout()
@ -59,7 +63,11 @@ class write_driver_array(design.design):
for i in range(self.word_size):
self.add_pin("bl_{0}".format(i))
self.add_pin("br_{0}".format(i))
self.add_pin("en")
if self.write_size != None:
for i in range(self.num_wmasks):
self.add_pin("en_{}".format(i))
else:
self.add_pin("en")
self.add_pin("vdd")
self.add_pin("gnd")
@ -73,16 +81,28 @@ class write_driver_array(design.design):
def create_write_array(self):
self.driver_insts = {}
w = 0
windex=0
for i in range(0,self.columns,self.words_per_row):
name = "write_driver{}".format(i)
index = int(i/self.words_per_row)
self.driver_insts[index]=self.add_inst(name=name,
mod=self.driver)
self.connect_inst(["data_{0}".format(index),
"bl_{0}".format(index),
"br_{0}".format(index),
"en", "vdd", "gnd"])
if self.write_size is not None:
self.connect_inst(["data_{0}".format(index),
"bl_{0}".format(index),
"br_{0}".format(index),
"en_{0}".format(windex), "vdd", "gnd"])
w+=1
if w == self.write_size:
w = 0
windex+=1
else:
self.connect_inst(["data_{0}".format(index),
"bl_{0}".format(index),
"br_{0}".format(index),
"en", "vdd", "gnd"])
def place_write_array(self):

View File

@ -0,0 +1,160 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
from math import log
import design
from tech import drc
import debug
from sram_factory import factory
from vector import vector
from globals import OPTS
class write_mask_and_array(design.design):
"""
Array of tristate drivers to write to the bitlines through the column mux.
Dynamically generated write driver array of all bitlines.
"""
def __init__(self, name, columns, word_size, write_size):
design.design.__init__(self, name)
debug.info(1, "Creating {0}".format(self.name))
self.add_comment("columns: {0}".format(columns))
self.add_comment("word_size {0}".format(word_size))
self.add_comment("write_size {0}".format(write_size))
self.columns = columns
self.word_size = word_size
self.write_size = write_size
self.words_per_row = int(columns / word_size)
self.num_wmasks = int(word_size / write_size)
self.create_netlist()
# if not OPTS.netlist_only:
# self.create_layout()
def create_netlist(self):
self.add_modules()
self.add_pins()
# self.create_write_mask_array()
self.create_and2_array()
# def create_layout(self):
#
# if self.bitcell.width > self.driver.width:
# self.width = self.columns * self.bitcell.width
# else:
# self.width = self.columns * self.driver.width
#
# self.height = self.driver.height
#
# self.place_write_array()
# self.add_layout_pins()
# self.add_boundary()
# self.DRC_LVS()
def add_pins(self):
for bit in range(self.num_wmasks):
self.add_pin("wmask_in_{}".format(bit),"INPUT")
self.add_pin("en", "INPUT")
for bit in range(self.num_wmasks):
self.add_pin("wmask_out_{}".format(bit),"OUTPUT")
self.add_pin("vdd","POWER")
self.add_pin("gnd","GROUND")
def add_modules(self):
self.wmask = factory.create(module_type="dff_buf")
#self.add_mod(self.wmask)
dff_height = self.wmask.height
self.and2 = factory.create(module_type="pand2",
size=4,
height=dff_height)
self.add_mod(self.and2)
# def create_write_mask_array(self):
# self.wmask_insts = {}
# for bit in range(self.num_wmask):
# name = "write_mask_{}".format(bit)
# self.wmask_insts[bit] = self.add_inst(name=name,
# mod=self.wmask)
#
# self.connect_inst(["wmask_{}".format(bit),
# "bank_wmask_{}".format(bit),
# "bank_wmask_bar_{}".format(bit),
# "clk", "vdd", "gnd"])
def create_and2_array(self):
self.and2_insts = {}
for bit in range(self.num_wmasks):
name = "and2_{}".format(bit)
self.and2_insts[bit] = self.add_inst(name=name,
mod=self.and2)
self.connect_inst(["wmask_in_{}".format(bit),
"en",
"wmask_out_{}".format(bit),
"vdd", "gnd"])
# def place_write_array(self):
# if self.bitcell.width > self.driver.width:
# driver_spacing = self.bitcell.width
# else:
# driver_spacing = self.driver.width
#
# for i in range(0, self.columns, self.words_per_row):
# index = int(i / self.words_per_row)
# base = vector(i * driver_spacing, 0)
# self.driver_insts[index].place(base)
# def add_layout_pins(self):
# for i in range(self.word_size):
# din_pin = self.driver_insts[i].get_pin("din")
# self.add_layout_pin(text="data_{0}".format(i),
# layer="metal2",
# offset=din_pin.ll(),
# width=din_pin.width(),
# height=din_pin.height())
# bl_pin = self.driver_insts[i].get_pin("bl")
# self.add_layout_pin(text="bl_{0}".format(i),
# layer="metal2",
# offset=bl_pin.ll(),
# width=bl_pin.width(),
# height=bl_pin.height())
#
# br_pin = self.driver_insts[i].get_pin("br")
# self.add_layout_pin(text="br_{0}".format(i),
# layer="metal2",
# offset=br_pin.ll(),
# width=br_pin.width(),
# height=br_pin.height())
#
# for n in ["vdd", "gnd"]:
# pin_list = self.driver_insts[i].get_pins(n)
# for pin in pin_list:
# pin_pos = pin.center()
# # Add the M2->M3 stack
# self.add_via_center(layers=("metal2", "via2", "metal3"),
# offset=pin_pos)
# self.add_layout_pin_rect_center(text=n,
# layer="metal3",
# offset=pin_pos)
#
# self.add_layout_pin(text="en",
# layer="metal1",
# offset=self.driver_insts[0].get_pin("en").ll().scale(0, 1),
# width=self.width,
# height=drc('minwidth_metal1'))
# def get_w_en_cin(self):
# """Get the relative capacitance of all the enable connections in the bank"""
# # The enable is connected to a nand2 for every row.
# return self.driver.get_w_en_cin() * len(self.driver_insts)

View File

@ -143,4 +143,5 @@ class options(optparse.Values):
wordline_driver = "wordline_driver"
write_driver_array = "write_driver_array"
write_driver = "write_driver"
write_mask_and_array = "write_mask_and_array"

View File

@ -46,7 +46,7 @@ class sram_1bank(sram_base):
self.data_dff_insts = self.create_data_dff()
if (self.write_size != self.word_size):
if self.write_size is not None:
self.wmask_dff_insts = self.create_wmask_dff()
@ -126,17 +126,35 @@ class sram_1bank(sram_base):
self.data_dff_insts[port].place(data_pos[port])
# Add the write mask flops to the left of the din flops.
if (self.write_size != self.word_size):
if self.write_size is not None:
if port in self.write_ports:
wmask_pos[port] = vector(self.bank.bank_array_ur.x - self.data_dff_insts[port].width,
self.bank.height + max_gap_size + self.data_dff_insts[port].height)
self.wmask_dff_insts[port].place(wmask_pos[port], mirror="MX")
wmask_pos[port] = vector(self.bank.bank_array_ll.x - self.control_logic_insts[port].width,
-max_gap_size - self.wmask_dff_insts[port].height)
self.wmask_dff_insts[port].place(wmask_pos[port])
if len(self.all_ports)>1:
# Port 1
port = 1
# Add the data flops above the bank to the left of the upper-right of bank array
# This relies on the upper-right of the array of the bank
# decoder in upper left, bank in upper right, sensing in lower right.
# These flops go below the sensing and leave a gap to channel route to the
# sense amps.
if port in self.write_ports:
data_pos[port] = vector(self.bank.bank_array_ur.x - self.data_dff_insts[port].width,
self.bank.height + max_gap_size + self.dff.height)
self.data_dff_insts[port].place(data_pos[port], mirror="MX")
# Add the write mask flops to the left of the din flops.
if self.write_size is not None:
if port in self.write_ports:
wmask_pos[port] = vector(self.bank.bank_array_ur.x - self.data_dff_insts[port].width,
self.bank.height + max_gap_size + self.data_dff_insts[port].height)
self.wmask_dff_insts[port].place(wmask_pos[port], mirror="MX")
else:
data_pos[port] = self.bank_inst.ur()
# Add the col address flops above the bank to the right of the upper-right of bank array
if self.col_addr_dff:
@ -368,7 +386,7 @@ class sram_1bank(sram_base):
#Data dffs and wmask dffs are only for writing so are not useful for evaluating read delay.
for inst in self.data_dff_insts:
self.graph_inst_exclude.add(inst)
if (self.write_size != self.word_size):
if self.write_size is not None:
for inst in self.wmask_dff_insts:
self.graph_inst_exclude.add(inst)

View File

@ -34,12 +34,18 @@ class sram_base(design, verilog, lef):
sram_config.set_local_config(self)
self.bank_insts = []
if self.write_size is not None:
self.num_wmasks = int(self.word_size/self.write_size)
else:
self.num_wmasks = 0
#For logical effort delay calculations.
self.all_mods_except_control_done = False
def add_pins(self):
""" Add pins for entire SRAM. """
for port in self.write_ports:
for bit in range(self.word_size):
self.add_pin("DIN{0}[{1}]".format(port,bit),"INPUT")
@ -69,9 +75,9 @@ class sram_base(design, verilog, lef):
for port in self.all_ports:
self.add_pin("clk{}".format(port),"INPUT")
# add the optional write mask pins
if self.word_size != self.write_size:
for port in self.write_ports:
self.add_pin("wmask{}".format(port),"INPUT")
for port in self.write_ports:
for bit in range(self.num_wmasks):
self.add_pin("wmask{0}[{1}]".format(port,bit),"INPUT")
for port in self.read_ports:
for bit in range(self.word_size):
self.add_pin("DOUT{0}[{1}]".format(port,bit),"OUTPUT")
@ -149,7 +155,7 @@ class sram_base(design, verilog, lef):
elif "metal3" in tech.layer:
from supply_tree_router import supply_tree_router as router
rtr=router(("metal3",), self)
rtr.route()
@ -278,8 +284,9 @@ class sram_base(design, verilog, lef):
self.data_dff = dff_array(name="data_dff", rows=1, columns=self.word_size)
self.add_mod(self.data_dff)
self.wmask_dff = dff_array(name="wmask_dff", rows=1, columns=int(self.word_size/self.write_size))
self.add_mod(self.wmask_dff)
if self.write_size is not None:
self.wmask_dff = dff_array(name="wmask_dff", rows=1, columns=self.num_wmasks)
self.add_mod(self.wmask_dff)
# Create the bank module (up to four are instantiated)
@ -305,23 +312,20 @@ class sram_base(design, verilog, lef):
self.control_logic_rw = self.mod_control_logic(num_rows=self.num_rows,
words_per_row=self.words_per_row,
word_size=self.word_size,
write_size = self.write_size,
sram=self,
sram=self,
port_type="rw")
self.add_mod(self.control_logic_rw)
if len(self.writeonly_ports)>0:
self.control_logic_w = self.mod_control_logic(num_rows=self.num_rows,
words_per_row=self.words_per_row,
word_size=self.word_size,
write_size=self.write_size,
sram=self,
sram=self,
port_type="w")
self.add_mod(self.control_logic_w)
if len(self.readonly_ports)>0:
self.control_logic_r = self.mod_control_logic(num_rows=self.num_rows,
words_per_row=self.words_per_row,
word_size=self.word_size,
write_size=self.write_size,
sram=self,
port_type="r")
self.add_mod(self.control_logic_r)
@ -354,6 +358,8 @@ class sram_base(design, verilog, lef):
temp.append("p_en_bar{0}".format(port))
for port in self.write_ports:
temp.append("w_en{0}".format(port))
for bit in range(self.num_wmasks):
temp.append("bank_wmask{}[{}]".format(port, bit))
for port in self.all_ports:
temp.append("wl_en{0}".format(port))
temp.extend(["vdd", "gnd"])
@ -455,7 +461,6 @@ class sram_base(design, verilog, lef):
def create_wmask_dff(self):
""" Add and place all wmask flops """
num_wmask = int(self.word_size/self.write_size)
insts = []
for port in self.all_ports:
if port in self.write_ports:
@ -468,9 +473,9 @@ class sram_base(design, verilog, lef):
# inputs, outputs/output/bar
inputs = []
outputs = []
for bit in range(num_wmask):
for bit in range(self.num_wmasks):
inputs.append("wmask{}[{}]".format(port, bit))
outputs.append("BANK_WMASK{}[{}]".format(port, bit))
outputs.append("bank_wmask{}[{}]".format(port, bit))
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port), "vdd", "gnd"])
@ -496,12 +501,14 @@ class sram_base(design, verilog, lef):
if port in self.readwrite_ports:
temp.append("web{}".format(port))
temp.append("clk{}".format(port))
if port in self.read_ports:
temp.append("rbl_bl{}".format(port))
# Ouputs
if port in self.read_ports:
temp.append("rbl_wl{}".format(port))
if port in self.read_ports:
temp.append("s_en{}".format(port))
if port in self.write_ports:

View File

@ -23,8 +23,6 @@ class sram_config:
# This will get over-written when we determine the organization
self.words_per_row = words_per_row
if self.write_size == None:
self.write_size = self.word_size
self.compute_sizes()

View File

@ -0,0 +1,59 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
#Copyright (c) 2016-2019 Regents of the University of California and The Board
#of Regents for the Oklahoma Agricultural and Mechanical College
#(acting for and on behalf of Oklahoma State University)
#All rights reserved.
#
"""
Run a regression test on a control_logic
"""
import unittest
from testutils import header,openram_test
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
from globals import OPTS
from sram_factory import factory
import debug
class control_logic_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
import control_logic
import tech
# check control logic for multi-port
OPTS.bitcell = "pbitcell"
OPTS.replica_bitcell = "replica_pbitcell"
OPTS.num_rw_ports = 1
OPTS.num_w_ports = 1
OPTS.num_r_ports = 1
debug.info(1, "Testing sample for control_logic for multiport, only write control logic")
a = factory.create(module_type="control_logic", num_rows=128, words_per_row=1, word_size=8, port_type="rw")
self.local_check(a)
# OPTS.num_rw_ports = 0
# OPTS.num_w_ports = 1
debug.info(1, "Testing sample for control_logic for multiport, only write control logic")
a = factory.create(module_type="control_logic", num_rows=128, words_per_row=1, word_size=8, port_type="w")
self.local_check(a)
# OPTS.num_w_ports = 0
# OPTS.num_r_ports = 1
debug.info(1, "Testing sample for control_logic for multiport, only read control logic")
a = factory.create(module_type="control_logic", num_rows=128, words_per_row=1, word_size=8, port_type="r")
self.local_check(a)
globals.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main()

View File

@ -0,0 +1,73 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import unittest
from testutils import *
import sys, os
sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
from sram_factory import factory
import debug
# @unittest.skip("SKIPPING psram_wmask_func_test")
class psram_wmask_func_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
OPTS.analytical_delay = False
OPTS.netlist_only = True
OPTS.trim_netlist = False
OPTS.bitcell = "bitcell_1w_1r"
OPTS.replica_bitcell = "replica_bitcell_1w_1r"
OPTS.num_rw_ports = 0
OPTS.num_w_ports = 1
OPTS.num_r_ports = 1
# This is a hack to reload the characterizer __init__ with the spice version
from importlib import reload
import characterizer
reload(characterizer)
from characterizer import functional, delay
from sram_config import sram_config
c = sram_config(word_size=8,
num_words=16,
write_size=2,
num_banks=1)
c.words_per_row = 1
c.recompute_sizes()
debug.info(1,
"Functional test for sram with {} bit words, {} words, {} words per row, {} bit writes, {} banks".format(
c.word_size,
c.num_words,
c.words_per_row,
c.write_size,
c.num_banks))
s = factory.create(module_type="sram", sram_config=c)
tempspice = OPTS.openram_temp + "temp.sp"
s.sp_write(tempspice)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
f = functional(s.s, tempspice, corner)
f.num_cycles = 10
(fail, error) = f.run()
self.assertTrue(fail, error)
globals.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())

View File

@ -0,0 +1,62 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import unittest
from testutils import *
import sys,os
sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
from sram_factory import factory
import debug
#@unittest.skip("SKIPPING sram_wmask_func_test")
class sram_wmask_func_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
OPTS.analytical_delay = False
OPTS.netlist_only = True
OPTS.trim_netlist = False
# This is a hack to reload the characterizer __init__ with the spice version
from importlib import reload
import characterizer
reload(characterizer)
from characterizer import functional, delay
from sram_config import sram_config
c = sram_config(word_size=8,
num_words=16,
write_size=4,
num_banks=1)
c.words_per_row=1
c.recompute_sizes()
debug.info(1, "Functional test for sram with {} bit words, {} words, {} words per row, {} bit writes, {} banks".format(c.word_size,
c.num_words,
c.words_per_row,
c.write_size,
c.num_banks))
s = factory.create(module_type="sram", sram_config=c)
tempspice = OPTS.openram_temp + "temp.sp"
s.sp_write(tempspice)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
f = functional(s.s, tempspice, corner)
f.num_cycles = 10
(fail, error) = f.run()
self.assertTrue(fail, error)
globals.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())