Made delay.py a child of simulation.py. Removed duplicate code in delay and changed some in simulation

This commit is contained in:
Hunter Nichols 2018-10-09 17:44:28 -07:00
parent a3bec5518c
commit 3ac2d29940
5 changed files with 71 additions and 234 deletions

View File

@ -7,8 +7,9 @@ from .trim_spice import *
from .charutils import * from .charutils import *
import utils import utils
from globals import OPTS from globals import OPTS
from .simulation import simulation
class delay(): class delay(simulation):
"""Functions to measure the delay and power of an SRAM at a given address and """Functions to measure the delay and power of an SRAM at a given address and
data bit. data bit.
@ -26,27 +27,14 @@ class delay():
""" """
def __init__(self, sram, spfile, corner): def __init__(self, sram, spfile, corner):
self.sram = sram simulation.__init__(self, sram, spfile, corner)
self.name = sram.name
self.word_size = self.sram.word_size
self.addr_size = self.sram.addr_size
self.num_cols = self.sram.num_cols
self.num_rows = self.sram.num_rows
self.num_banks = self.sram.num_banks
self.sp_file = spfile
self.total_ports = self.sram.total_ports
self.total_write = self.sram.total_write
self.total_read = self.sram.total_read
self.read_index = self.sram.read_index
self.write_index = self.sram.write_index
self.port_id = self.sram.port_id
# These are the member variables for a simulation # These are the member variables for a simulation
self.targ_read_ports = []
self.targ_write_ports = []
self.period = 0 self.period = 0
self.set_load_slew(0,0) self.set_load_slew(0,0)
self.set_corner(corner) self.set_corner(corner)
self.create_port_names()
self.create_signal_names() self.create_signal_names()
#Create global measure names. Should maybe be an input at some point. #Create global measure names. Should maybe be an input at some point.
@ -66,34 +54,6 @@ class delay():
#This is TODO once multiport control has been finalized. #This is TODO once multiport control has been finalized.
#self.control_name = "CSB" #self.control_name = "CSB"
def create_port_names(self):
"""Generates the port names to be used in characterization and sets default simulation target ports"""
self.write_ports = []
self.read_ports = []
self.total_port_num = OPTS.num_rw_ports + OPTS.num_w_ports + OPTS.num_r_ports
#save a member variable to avoid accessing global. readwrite ports have different control signals.
self.readwrite_port_num = OPTS.num_rw_ports
#Generate the port names. readwrite ports are required to be added first for this to work.
for readwrite_port_num in range(OPTS.num_rw_ports):
self.read_ports.append(readwrite_port_num)
self.write_ports.append(readwrite_port_num)
#This placement is intentional. It makes indexing input data easier. See self.data_values
for write_port_num in range(OPTS.num_rw_ports, OPTS.num_rw_ports+OPTS.num_w_ports):
self.write_ports.append(write_port_num)
for read_port_num in range(OPTS.num_rw_ports+OPTS.num_w_ports, OPTS.num_rw_ports+OPTS.num_w_ports+OPTS.num_r_ports):
self.read_ports.append(read_port_num)
#Set the default target ports for simulation. Default is all the ports.
self.targ_read_ports = self.read_ports
self.targ_write_ports = self.write_ports
def set_corner(self,corner):
""" Set the corner values """
self.corner = corner
(self.process, self.vdd_voltage, self.temperature) = corner
def set_load_slew(self,load,slew): def set_load_slew(self,load,slew):
""" Set the load and slew """ """ Set the load and slew """
self.load = load self.load = load
@ -113,9 +73,9 @@ class delay():
debug.error("Given probe_data is not an integer to specify a data bit",1) debug.error("Given probe_data is not an integer to specify a data bit",1)
#Adding port options here which the characterizer cannot handle. Some may be added later like ROM #Adding port options here which the characterizer cannot handle. Some may be added later like ROM
if len(self.read_ports) == 0: if len(self.read_index) == 0:
debug.error("Characterizer does not currently support SRAMs without read ports.",1) debug.error("Characterizer does not currently support SRAMs without read ports.",1)
if len(self.write_ports) == 0: if len(self.write_index) == 0:
debug.error("Characterizer does not currently support SRAMs without write ports.",1) debug.error("Characterizer does not currently support SRAMs without write ports.",1)
def write_generic_stimulus(self): def write_generic_stimulus(self):
@ -129,12 +89,12 @@ class delay():
self.sf.write("\n* Instantiation of the SRAM\n") self.sf.write("\n* Instantiation of the SRAM\n")
self.stim.inst_sram(sram=self.sram, self.stim.inst_sram(sram=self.sram,
port_signal_names=(self.addr_name,self.din_name,self.dout_name), port_signal_names=(self.addr_name,self.din_name,self.dout_name),
port_info=(self.total_port_num,self.write_ports,self.read_ports), port_info=(self.total_ports,self.write_index,self.read_index),
abits=self.addr_size, abits=self.addr_size,
dbits=self.word_size, dbits=self.word_size,
sram_name=self.name) sram_name=self.name)
self.sf.write("\n* SRAM output loads\n") self.sf.write("\n* SRAM output loads\n")
for port in self.read_ports: for port in self.read_index:
for i in range(self.word_size): for i in range(self.word_size):
self.sf.write("CD{0}{1} {2}{0}_{1} 0 {3}f\n".format(port,i,self.dout_name,self.load)) self.sf.write("CD{0}{1} {2}{0}_{1} 0 {3}f\n".format(port,i,self.dout_name,self.load))
@ -172,7 +132,7 @@ class delay():
self.gen_control() self.gen_control()
self.sf.write("\n* Generation of Port clock signal\n") self.sf.write("\n* Generation of Port clock signal\n")
for port in range(self.total_port_num): for port in range(self.total_ports):
self.stim.gen_pulse(sig_name="CLK{0}".format(port), self.stim.gen_pulse(sig_name="CLK{0}".format(port),
v1=0, v1=0,
v2=self.vdd_voltage, v2=self.vdd_voltage,
@ -214,24 +174,24 @@ class delay():
# generate data and addr signals # generate data and addr signals
self.sf.write("\n* Generation of data and address signals\n") self.sf.write("\n* Generation of data and address signals\n")
for write_port in self.write_ports: for write_port in self.write_index:
for i in range(self.word_size): for i in range(self.word_size):
self.stim.gen_constant(sig_name="{0}{1}_{2} ".format(self.din_name,write_port, i), self.stim.gen_constant(sig_name="{0}{1}_{2} ".format(self.din_name,write_port, i),
v_val=0) v_val=0)
for port in range(self.total_port_num): for port in range(self.total_ports):
for i in range(self.addr_size): for i in range(self.addr_size):
self.stim.gen_constant(sig_name="{0}{1}_{2}".format(self.addr_name,port, i), self.stim.gen_constant(sig_name="{0}{1}_{2}".format(self.addr_name,port, i),
v_val=0) v_val=0)
# generate control signals # generate control signals
self.sf.write("\n* Generation of control signals\n") self.sf.write("\n* Generation of control signals\n")
for port in range(self.total_port_num): for port in range(self.total_ports):
self.stim.gen_constant(sig_name="CSB{0}".format(port), v_val=self.vdd_voltage) self.stim.gen_constant(sig_name="CSB{0}".format(port), v_val=self.vdd_voltage)
if port in self.write_ports and port in self.read_ports: if port in self.write_index and port in self.read_index:
self.stim.gen_constant(sig_name="WEB{0}".format(port), v_val=self.vdd_voltage) self.stim.gen_constant(sig_name="WEB{0}".format(port), v_val=self.vdd_voltage)
self.sf.write("\n* Generation of global clock signal\n") self.sf.write("\n* Generation of global clock signal\n")
for port in range(self.total_port_num): for port in range(self.total_ports):
self.stim.gen_constant(sig_name="CLK{0}".format(port), v_val=0) self.stim.gen_constant(sig_name="CLK{0}".format(port), v_val=0)
self.write_power_measures() self.write_power_measures()
@ -360,10 +320,9 @@ class delay():
double the period until we find a valid period to use as a double the period until we find a valid period to use as a
starting point. starting point.
""" """
debug.check(port in self.read_ports, "Characterizer requires a read port to determine a period.") debug.check(port in self.read_index, "Characterizer requires a read port to determine a period.")
feasible_period = float(tech.spice["feasible_period"]) feasible_period = float(tech.spice["feasible_period"])
#feasible_period = float(2.5)#What happens if feasible starting point is wrong?
time_out = 9 time_out = 9
while True: while True:
time_out -= 1 time_out -= 1
@ -406,19 +365,18 @@ class delay():
Loops through all read ports determining the feasible period and collecting Loops through all read ports determining the feasible period and collecting
delay information from each port. delay information from each port.
""" """
feasible_delays = [{} for i in range(self.total_port_num)] feasible_delays = [{} for i in range(self.total_ports)]
self.period = float(tech.spice["feasible_period"])
#Get initial feasible delays from first port #Get initial feasible delays from first port
feasible_delays[self.read_ports[0]] = self.find_feasible_period_one_port(self.read_ports[0]) feasible_delays[self.read_index[0]] = self.find_feasible_period_one_port(self.read_index[0])
previous_period = self.period previous_period = self.period
#Loops through all the ports checks if the feasible period works. Everything restarts it if does not. #Loops through all the ports checks if the feasible period works. Everything restarts it if does not.
#Write ports do not produce delays which is why they are not included here. #Write ports do not produce delays which is why they are not included here.
i = 1 i = 1
while i < len(self.read_ports): while i < len(self.read_index):
port = self.read_ports[i] port = self.read_index[i]
#Only extract port values from the specified port, not the entire results. #Only extract port values from the specified port, not the entire results.
feasible_delays[port].update(self.find_feasible_period_one_port(port)) feasible_delays[port].update(self.find_feasible_period_one_port(port))
#Function sets the period. Restart the entire process if period changes to collect accurate delays #Function sets the period. Restart the entire process if period changes to collect accurate delays
@ -461,7 +419,7 @@ class delay():
#Sanity Check #Sanity Check
debug.check(self.period > 0, "Target simulation period non-positive") debug.check(self.period > 0, "Target simulation period non-positive")
result = [{} for i in range(self.total_port_num)] result = [{} for i in range(self.total_ports)]
# Checking from not data_value to data_value # Checking from not data_value to data_value
self.write_delay_stimulus() self.write_delay_stimulus()
@ -563,7 +521,7 @@ class delay():
#Find the minimum period for all ports. Start at one port and perform binary search then use that delay as a starting position. #Find the minimum period for all ports. Start at one port and perform binary search then use that delay as a starting position.
#For testing purposes, only checks read ports. #For testing purposes, only checks read ports.
for port in self.read_ports: for port in self.read_index:
target_period = self.find_min_period_one_port(feasible_delays, port, lb_period, ub_period, target_period) target_period = self.find_min_period_one_port(feasible_delays, port, lb_period, ub_period, target_period)
#The min period of one port becomes the new lower bound. Reset the upper_bound. #The min period of one port becomes the new lower bound. Reset the upper_bound.
lb_period = target_period lb_period = target_period
@ -728,8 +686,8 @@ class delay():
"""Simulate all specified output loads and input slews pairs of all ports""" """Simulate all specified output loads and input slews pairs of all ports"""
measure_data = self.get_empty_measure_data_dict() measure_data = self.get_empty_measure_data_dict()
#Set the target simulation ports to all available ports. This make sims slower but failed sims exit anyways. #Set the target simulation ports to all available ports. This make sims slower but failed sims exit anyways.
self.targ_read_ports = self.read_ports self.targ_read_ports = self.read_index
self.targ_write_ports = self.write_ports self.targ_write_ports = self.write_index
for slew in slews: for slew in slews:
for load in loads: for load in loads:
self.set_load_slew(load,slew) self.set_load_slew(load,slew)
@ -738,7 +696,7 @@ class delay():
debug.check(success,"Couldn't run a simulation. slew={0} load={1}\n".format(self.slew,self.load)) debug.check(success,"Couldn't run a simulation. slew={0} load={1}\n".format(self.slew,self.load))
debug.info(1, "Simulation Passed: Port {0} slew={1} load={2}".format("All", self.slew,self.load)) debug.info(1, "Simulation Passed: Port {0} slew={1} load={2}".format("All", self.slew,self.load))
#The results has a dict for every port but dicts can be empty (e.g. ports were not targeted). #The results has a dict for every port but dicts can be empty (e.g. ports were not targeted).
for port in range(self.total_port_num): for port in range(self.total_ports):
for mname,value in delay_results[port].items(): for mname,value in delay_results[port].items():
if "power" in mname: if "power" in mname:
# Subtract partial array leakage and add full array leakage for the power measures # Subtract partial array leakage and add full array leakage for the power measures
@ -747,118 +705,7 @@ class delay():
measure_data[port][mname].append(value) measure_data[port][mname].append(value)
return measure_data return measure_data
def add_data(self, data, port):
""" Add the array of data values """
debug.check(len(data)==self.word_size, "Invalid data word size.")
debug.check(port < len(self.data_values), "Port number cannot index data values.")
index = 0
for c in data:
if c=="0":
self.data_values[port][index].append(0)
elif c=="1":
self.data_values[port][index].append(1)
else:
debug.error("Non-binary data string",1)
index += 1
def add_address(self, address, port):
""" Add the array of address values """
debug.check(len(address)==self.addr_size, "Invalid address size.")
index = 0
for c in address:
if c=="0":
self.addr_values[port][index].append(0)
elif c=="1":
self.addr_values[port][index].append(1)
else:
debug.error("Non-binary address string",1)
index += 1
def add_noop_one_port(self, address, data, port):
""" Add the control values for a noop to a single port. """
#This is to be used as a helper function for the other add functions. Cycle and comments are omitted.
self.add_control_one_port(port, "noop")
if port in self.write_ports:
self.add_data(data,port)
self.add_address(address, port)
def add_noop_all_ports(self, comment, address, data):
""" Add the control values for a noop to all ports. """
self.add_comment("All", comment)
self.cycle_times.append(self.t_current)
self.t_current += self.period
for port in range(self.total_port_num):
self.add_noop_one_port(address, data, port)
def add_read(self, comment, address, data, port):
""" Add the control values for a read cycle. """
debug.check(port in self.read_ports, "Cannot add read cycle to a write port.")
self.add_comment(port, comment)
self.cycle_times.append(self.t_current)
self.t_current += self.period
self.add_control_one_port(port, "read")
#If the port is also a readwrite then add data.
if port in self.write_ports:
self.add_data(data,port)
self.add_address(address, 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 range(self.total_port_num):
if unselected_port != port:
self.add_noop_one_port(address, noop_data, unselected_port)
def add_write(self, comment, address, data, port):
""" Add the control values for a write cycle. """
debug.check(port in self.write_ports, "Cannot add read cycle to a read port.")
self.add_comment(port, comment)
self.cycle_times.append(self.t_current)
self.t_current += self.period
self.add_control_one_port(port, "write")
self.add_data(data,port)
self.add_address(address,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 range(self.total_port_num):
if unselected_port != port:
self.add_noop_one_port(address, noop_data, unselected_port)
def add_control_one_port(self, port, op):
"""Appends control signals for operation to a given port"""
#Determine values to write to port
web_val = 1
csb_val = 1
if op == "read":
csb_val = 0
elif op == "write":
csb_val = 0
web_val = 0
elif op != "noop":
debug.error("Could not add control signals for port {0}. Command {1} not recognized".format(port,op),1)
#Append the values depending on the type of port
self.csb_values[port].append(csb_val)
#If port is in both lists, add rw control signal. Condition indicates its a RW port.
if port in self.write_ports and port in self.read_ports:
self.web_values[port].append(web_val)
def add_comment(self, port, comment):
"""Add comment to list to be printed in stimulus file"""
#Clean up time before appending. Make spacing dynamic as well.
time = "{0:.2f} ns:".format(self.t_current)
time_spacing = len(time)+6
self.cycle_comments.append("Cycle {0:<6d} Port {1:<6} {2:<{3}}: {4}".format(len(self.cycle_times),
port,
time,
time_spacing,
comment))
def gen_test_cycles_one_port(self, read_port, write_port): def gen_test_cycles_one_port(self, read_port, write_port):
"""Intended but not implemented: Returns a list of key time-points [ns] of the waveform (each rising edge) """Intended but not implemented: Returns a list of key time-points [ns] of the waveform (each rising edge)
of the cycles to do a timing evaluation of a single port. Current: Values overwritten for multiple calls""" of the cycles to do a timing evaluation of a single port. Current: Values overwritten for multiple calls"""
@ -925,43 +772,29 @@ class delay():
def get_available_port(self,get_read_port): def get_available_port(self,get_read_port):
"""Returns the first accessible read or write port. """ """Returns the first accessible read or write port. """
if get_read_port and len(self.read_ports) > 0: if get_read_port and len(self.read_index) > 0:
return self.read_ports[0] return self.read_index[0]
elif not get_read_port and len(self.write_ports) > 0: elif not get_read_port and len(self.write_index) > 0:
return self.write_ports[0] return self.write_index[0]
return None return None
def set_stimulus_variables(self):
simulation.set_stimulus_variables(self)
self.measure_cycles = {}
def create_test_cycles(self): def create_test_cycles(self):
"""Returns a list of key time-points [ns] of the waveform (each rising edge) """Returns a list of key time-points [ns] of the waveform (each rising edge)
of the cycles to do a timing evaluation. The last time is the end of the simulation of the cycles to do a timing evaluation. The last time is the end of the simulation
and does not need a rising edge.""" and does not need a rising edge."""
#Using this requires setting at least one port to target for simulation. #Using this requires setting at least one port to target for simulation.
if len(self.targ_write_ports) == 0 and len(self.targ_read_ports) == 0: if len(self.targ_write_ports) == 0 and len(self.targ_read_ports) == 0:
debug.error("No ports selected for characterization.",1) debug.error("No port selected for characterization.",1)
self.set_stimulus_variables()
# Start at time 0
self.t_current = 0
# Cycle times (positive edge) with comment
self.cycle_comments = []
self.cycle_times = []
self.measure_cycles = {}
# Control signals for ports. These are not the final signals and will likely be changed later.
#web is the enable for write ports. Dicts used for simplicity as ports are not necessarily incremental.
self.web_values = {port:[] for port in self.write_ports}
#csb acts as an enable for the read ports.
self.csb_values = {port:[] for port in range(self.total_port_num)}
# Address and data values for each address/data bit. A 3d list of size #ports x bits x cycles.
self.data_values=[[[] for bit in range(self.word_size)] for port in range(len(self.write_ports))]
self.addr_values=[[[] for bit in range(self.addr_size)] for port in range(self.total_port_num)]
#Get any available read/write port in case only a single write or read ports is being characterized. #Get any available read/write port in case only a single write or read ports is being characterized.
cur_read_port = self.get_available_port(get_read_port=True) cur_read_port = self.get_available_port(get_read_port=True)
cur_write_port = self.get_available_port(get_read_port=False) cur_write_port = self.get_available_port(get_read_port=False)
#These checks should be superceded by check_arguments which should have been called earlier, so this is a double check.
debug.check(cur_read_port != None, "Characterizer requires at least 1 read port") debug.check(cur_read_port != None, "Characterizer requires at least 1 read port")
debug.check(cur_write_port != None, "Characterizer requires at least 1 write port") debug.check(cur_write_port != None, "Characterizer requires at least 1 write port")
@ -1026,7 +859,7 @@ class delay():
def gen_data(self): def gen_data(self):
""" Generates the PWL data inputs for a simulation timing test. """ """ Generates the PWL data inputs for a simulation timing test. """
for write_port in self.write_ports: for write_port in self.write_index:
for i in range(self.word_size): for i in range(self.word_size):
sig_name="{0}{1}_{2} ".format(self.din_name,write_port, i) sig_name="{0}{1}_{2} ".format(self.din_name,write_port, i)
self.stim.gen_pwl(sig_name, self.cycle_times, self.data_values[write_port][i], self.period, self.slew, 0.05) self.stim.gen_pwl(sig_name, self.cycle_times, self.data_values[write_port][i], self.period, self.slew, 0.05)
@ -1036,16 +869,16 @@ class delay():
Generates the address inputs for a simulation timing test. Generates the address inputs for a simulation timing test.
This alternates between all 1's and all 0's for the address. This alternates between all 1's and all 0's for the address.
""" """
for port in range(self.total_port_num): for port in range(self.total_ports):
for i in range(self.addr_size): for i in range(self.addr_size):
sig_name = "{0}{1}_{2}".format(self.addr_name,port,i) sig_name = "{0}{1}_{2}".format(self.addr_name,port,i)
self.stim.gen_pwl(sig_name, self.cycle_times, self.addr_values[port][i], self.period, self.slew, 0.05) self.stim.gen_pwl(sig_name, self.cycle_times, self.addr_values[port][i], self.period, self.slew, 0.05)
def gen_control(self): def gen_control(self):
""" Generates the control signals """ """ Generates the control signals """
for port in range(self.total_port_num): for port in range(self.total_ports):
self.stim.gen_pwl("CSB{0}".format(port), self.cycle_times, self.csb_values[port], self.period, self.slew, 0.05) self.stim.gen_pwl("CSB{0}".format(port), self.cycle_times, self.csb_values[port], self.period, self.slew, 0.05)
if port in self.read_ports and port in self.write_ports: if port in self.read_index and port in self.write_index:
self.stim.gen_pwl("WEB{0}".format(port), self.cycle_times, self.web_values[port], self.period, self.slew, 0.05) self.stim.gen_pwl("WEB{0}".format(port), self.cycle_times, self.web_values[port], self.period, self.slew, 0.05)
@ -1053,5 +886,5 @@ class delay():
"""Make a dict of lists for each type of delay and power measurement to append results to""" """Make a dict of lists for each type of delay and power measurement to append results to"""
measure_names = self.delay_meas_names + self.power_meas_names measure_names = self.delay_meas_names + self.power_meas_names
#Create list of dicts. List lengths is # of ports. Each dict maps the measurement names to lists. #Create list of dicts. List lengths is # of ports. Each dict maps the measurement names to lists.
measure_data = [{mname:[] for mname in measure_names} for i in range(self.total_port_num)] measure_data = [{mname:[] for mname in measure_names} for i in range(self.total_ports)]
return measure_data return measure_data

View File

@ -81,7 +81,6 @@ class simulation():
def add_data(self, data, port): def add_data(self, data, port):
""" Add the array of data values """ """ Add the array of data values """
debug.check(len(data)==self.word_size, "Invalid data word size.") debug.check(len(data)==self.word_size, "Invalid data word size.")
#debug.check(port < len(self.data_values), "Port number cannot index data values.")
bit = self.word_size - 1 bit = self.word_size - 1
for c in data: for c in data:
@ -109,12 +108,9 @@ class simulation():
def add_write(self, comment, address, data, port): def add_write(self, comment, address, data, port):
""" Add the control values for a write cycle. """ """ Add the control values for a write cycle. """
debug.info(1, comment) debug.info(2, comment)
debug.check(port in self.write_index, "Cannot add write cycle to a read port. Port {0}, Write Ports {1}".format(port, self.write_index)) debug.check(port in self.write_index, "Cannot add write cycle to a read port. Port {0}, Write Ports {1}".format(port, self.write_index))
self.cycle_comments.append("Cycle {0:2d}\tPort {3}\t{1:5.2f}ns:\t{2}".format(len(self.cycle_comments), self.append_cycle_comment(port, comment)
self.t_current,
comment,
port))
self.cycle_times.append(self.t_current) self.cycle_times.append(self.t_current)
self.t_current += self.period self.t_current += self.period
@ -131,12 +127,9 @@ class simulation():
def add_read(self, comment, address, data, port): def add_read(self, comment, address, data, port):
""" Add the control values for a read cycle. """ """ Add the control values for a read cycle. """
debug.info(1, comment) debug.info(2, comment)
debug.check(port in self.read_index, "Cannot add read cycle to a write port. Port {0}, Read Ports {1}".format(port, self.read_index)) debug.check(port in self.read_index, "Cannot add read cycle to a write port. Port {0}, Read Ports {1}".format(port, self.read_index))
self.cycle_comments.append("Cycle {0:2d}\tPort {3}\t{1:5.2f}ns:\t{2}".format(len(self.cycle_comments), self.append_cycle_comment(port, comment)
self.t_current,
comment,
port))
self.cycle_times.append(self.t_current) self.cycle_times.append(self.t_current)
self.t_current += self.period self.t_current += self.period
self.add_control_one_port(port, "read") self.add_control_one_port(port, "read")
@ -153,12 +146,21 @@ class simulation():
if unselected_port != port: if unselected_port != port:
self.add_noop_one_port(address, noop_data, unselected_port) self.add_noop_one_port(address, noop_data, unselected_port)
def append_cycle_comment(self, port, comment):
"""Add comment to list to be printed in stimulus file"""
#Clean up time before appending. Make spacing dynamic as well.
time = "{0:.2f} ns:".format(self.t_current)
time_spacing = len(time)+6
self.cycle_comments.append("Cycle {0:<6d} Port {1:<6} {2:<{3}}: {4}".format(len(self.cycle_times),
port,
time,
time_spacing,
comment))
def add_noop_all_ports(self, comment, address, data): def add_noop_all_ports(self, comment, address, data):
""" Add the control values for a noop to all ports. """ """ Add the control values for a noop to all ports. """
debug.info(1, comment) debug.info(2, comment)
self.cycle_comments.append("Cycle {0:2d}\tPort All\t{1:5.2f}ns:\t{2}".format(len(self.cycle_times), self.append_cycle_comment("All", comment)
self.t_current,
comment))
self.cycle_times.append(self.t_current) self.cycle_times.append(self.t_current)
self.t_current += self.period self.t_current += self.period

View File

@ -43,8 +43,8 @@ class worst_case(delay):
test_bits = self.get_test_bits() test_bits = self.get_test_bits()
bit_delays = self.simulate_for_bit_delays(test_bits) bit_delays = self.simulate_for_bit_delays(test_bits)
for delay in bit_delays: for i in range(len(test_bits)):
debug.info(1, "{}".format(delay)) debug.info(1, "Bit tested: addr {0[0]} data_pos {0[1]}\n Values {1}".format(test_bits[i], bit_delays[i]))
def simulate_for_bit_delays(self, test_bits): def simulate_for_bit_delays(self, test_bits):
"""Simulates the delay of the sram of over several bits.""" """Simulates the delay of the sram of over several bits."""

View File

@ -11,9 +11,9 @@ output_path = "temp"
output_name = "sram_{0}_{1}_{2}_{3}".format(word_size,num_words,num_banks,tech_name) output_name = "sram_{0}_{1}_{2}_{3}".format(word_size,num_words,num_banks,tech_name)
#Setting for multiport #Setting for multiport
# netlist_only = True netlist_only = True
# bitcell = "pbitcell" bitcell = "pbitcell"
# replica_bitcell="replica_pbitcell" replica_bitcell="replica_pbitcell"
# num_rw_ports = 1 num_rw_ports = 1
# num_r_ports = 1 num_r_ports = 1
# num_w_ports = 0 num_w_ports = 0

View File

@ -31,14 +31,14 @@ class worst_case_timing_sram_test(openram_test):
if not OPTS.spice_exe: if not OPTS.spice_exe:
debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1) debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1)
word_size, num_words, num_banks = 32, 32, 1 word_size, num_words, num_banks = 2, 16, 1
from sram import sram from sram import sram
from sram_config import sram_config from sram_config import sram_config
c = sram_config(word_size=word_size, c = sram_config(word_size=word_size,
num_words=num_words, num_words=num_words,
num_banks=num_banks) num_banks=num_banks)
#c.words_per_row=1 c.words_per_row=1
c.compute_sizes() #c.compute_sizes()
debug.info(1, "Testing the timing different bitecells inside a {}bit, {} words SRAM with {} bank".format( debug.info(1, "Testing the timing different bitecells inside a {}bit, {} words SRAM with {} bank".format(
word_size, num_words, num_banks)) word_size, num_words, num_banks))
s = sram(c, name="sram1") s = sram(c, name="sram1")
@ -56,8 +56,10 @@ class worst_case_timing_sram_test(openram_test):
sp_pex_file = OPTS.output_path + s.name + "_pex.sp" sp_pex_file = OPTS.output_path + s.name + "_pex.sp"
verify.run_pex(s.name, gdsname, sp_netlist_file, output=sp_pex_file) verify.run_pex(s.name, gdsname, sp_netlist_file, output=sp_pex_file)
sp_sim_file = sp_pex_file sp_sim_file = sp_pex_file
debug.info(1, "Performing spice simulations with backannotated spice file.")
else: else:
sp_sim_file = sp_netlist_file sp_sim_file = sp_netlist_file
debug.info(1, "Performing spice simulations with spice netlist.")
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
wc = worst_case(s.s, sp_sim_file, corner) wc = worst_case(s.s, sp_sim_file, corner)