Convert port index lists to three simple lists.

This commit is contained in:
Matt Guthaus 2018-11-08 12:19:40 -08:00
parent b25650eb07
commit 7b10e3bfec
8 changed files with 350 additions and 300 deletions

View File

@ -50,31 +50,36 @@ class design(hierarchy_design):
self.implant_space = drc("implant_to_implant") self.implant_space = drc("implant_to_implant")
def setup_multiport_constants(self): def setup_multiport_constants(self):
""" These are contants and lists that aid multiport design """ """
self.total_write = OPTS.num_rw_ports + OPTS.num_w_ports These are contants and lists that aid multiport design.
self.total_read = OPTS.num_rw_ports + OPTS.num_r_ports Ports are always in the order RW, W, R.
self.total_ports = OPTS.num_rw_ports + OPTS.num_w_ports + OPTS.num_r_ports Port indices start from 0 and increment.
self.num_rw_ports = OPTS.num_rw_ports A first RW port will have clk0, csb0, web0, addr0, data0
A first W port (with no RW ports) will be: clk0, csb0, addr0, data0
"""
total_ports = OPTS.num_rw_ports + OPTS.num_w_ports + OPTS.num_r_ports
# These are the read/write port indices.
self.readwrite_ports = []
# These are the read/write and write-only port indices
self.write_ports = []
# These are teh read/write and read-only port indice
self.read_ports = []
# These are all the ports
self.all_ports = list(range(total_ports))
# Port indices used for data, address, and control signals
# Port IDs used to identify port type
self.write_index = []
self.read_index = []
self.port_id = []
port_number = 0 port_number = 0
for port in range(OPTS.num_rw_ports): for port in range(OPTS.num_rw_ports):
self.write_index.append(port_number) self.readwrite_ports.append(port_number)
self.read_index.append(port_number) self.write_ports.append(port_number)
self.port_id.append("rw") self.read_ports.append(port_number)
port_number += 1 port_number += 1
for port in range(OPTS.num_w_ports): for port in range(OPTS.num_w_ports):
self.write_index.append(port_number) self.write_ports.append(port_number)
self.port_id.append("w")
port_number += 1 port_number += 1
for port in range(OPTS.num_r_ports): for port in range(OPTS.num_r_ports):
self.read_index.append(port_number) self.read_ports.append(port_number)
self.port_id.append("r")
port_number += 1 port_number += 1
def analytical_power(self, proc, vdd, temp, load): def analytical_power(self, proc, vdd, temp, load):

View File

@ -73,9 +73,9 @@ class delay(simulation):
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_index) == 0: if len(self.read_ports) == 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_index) == 0: if len(self.write_ports) == 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):
@ -89,12 +89,12 @@ class delay(simulation):
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_ports,self.write_index,self.read_index), port_info=(len(self.all_ports),self.write_ports,self.read_ports),
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_index: for port in self.read_ports:
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))
@ -132,7 +132,7 @@ class delay(simulation):
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_ports): for port in self.all_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,
@ -171,24 +171,24 @@ class delay(simulation):
# 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_index: for write_port in self.write_ports:
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_ports): for port in self.all_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_ports): for port in self.all_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_index and port in self.read_index: if port in self.readwrite_ports:
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_ports): for port in self.all_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()
@ -317,7 +317,7 @@ class delay(simulation):
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_index, "Characterizer requires a read port to determine a period.") debug.check(port in self.read_ports, "Characterizer requires a read port to determine a period.")
feasible_period = float(tech.spice["feasible_period"]) feasible_period = float(tech.spice["feasible_period"])
time_out = 9 time_out = 9
@ -362,18 +362,18 @@ class delay(simulation):
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_ports)] feasible_delays = [{} for i in self.all_ports]
#Get initial feasible delays from first port #Get initial feasible delays from first port
feasible_delays[self.read_index[0]] = self.find_feasible_period_one_port(self.read_index[0]) feasible_delays[self.read_ports[0]] = self.find_feasible_period_one_port(self.read_ports[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_index): while i < len(self.read_ports):
port = self.read_index[i] port = self.read_ports[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
@ -416,7 +416,7 @@ class delay(simulation):
#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_ports)] result = [{} for i in self.all_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()
@ -518,7 +518,7 @@ class delay(simulation):
#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_index: for port in self.read_ports:
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
@ -683,8 +683,8 @@ class delay(simulation):
"""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_index self.targ_read_ports = self.read_ports
self.targ_write_ports = self.write_index self.targ_write_ports = self.write_ports
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)
@ -693,7 +693,7 @@ class delay(simulation):
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_ports): for port in self.all_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
@ -763,15 +763,15 @@ class delay(simulation):
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_index) > 0: if get_read_port and len(self.read_ports) > 0:
return self.read_index[0] return self.read_ports[0]
elif not get_read_port and len(self.write_index) > 0: elif not get_read_port and len(self.write_ports) > 0:
return self.write_index[0] return self.write_ports[0]
return None return None
def set_stimulus_variables(self): def set_stimulus_variables(self):
simulation.set_stimulus_variables(self) simulation.set_stimulus_variables(self)
self.measure_cycles = [{} for port in range(self.total_ports)] self.measure_cycles = [{} for port in self.all_ports]
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)
@ -819,7 +819,7 @@ class delay(simulation):
for load in loads: for load in loads:
self.set_load_slew(load,slew) self.set_load_slew(load,slew)
bank_delay = self.sram.analytical_delay(self.vdd_voltage, self.slew,self.load) bank_delay = self.sram.analytical_delay(self.vdd_voltage, self.slew,self.load)
for port in range(self.total_ports): for port in self.all_ports:
for mname in self.delay_meas_names+self.power_meas_names: for mname in self.delay_meas_names+self.power_meas_names:
if "power" in mname: if "power" in mname:
port_data[port][mname].append(power.dynamic) port_data[port][mname].append(power.dynamic)
@ -877,7 +877,7 @@ class delay(simulation):
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_index: for write_port in self.write_ports:
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)
@ -887,16 +887,16 @@ class delay(simulation):
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_ports): for port in self.all_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_ports): for port in self.all_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_index and port in self.write_index: if port in self.readwrite_ports:
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)
@ -904,5 +904,5 @@ class delay(simulation):
"""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_ports)] measure_data = [{mname:[] for mname in measure_names} for i in self.all_ports]
return measure_data return measure_data

View File

@ -80,8 +80,8 @@ class functional(simulation):
# 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. # 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. # This will test the viablilty of the transistor sizing in the bitcell.
for port in range(self.total_ports): for port in self.all_ports:
if self.port_id[port] == "w": 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, port)
else: else:
comment = self.gen_cycle_comment("read", word, addr, port, self.t_current) comment = self.gen_cycle_comment("read", word, addr, port, self.t_current)
@ -94,10 +94,10 @@ class functional(simulation):
# Perform a random sequence of writes and reads on random ports, using random addresses and random words # Perform a random sequence of writes and reads on random ports, using random addresses and random words
for i in range(self.num_cycles): for i in range(self.num_cycles):
w_addrs = [] w_addrs = []
for port in range(self.total_ports): for port in self.all_ports:
if self.port_id[port] == "rw": if port in self.readwrite_ports:
op = random.choice(rw_ops) op = random.choice(rw_ops)
elif self.port_id[port] == "w": elif port in self.write_ports:
op = random.choice(w_ops) op = random.choice(w_ops)
else: else:
op = random.choice(r_ops) op = random.choice(r_ops)
@ -225,17 +225,17 @@ class functional(simulation):
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_ports, self.write_index, self.read_index), port_info=(len(self.all_ports), self.write_ports, self.read_ports),
abits=self.addr_size, abits=self.addr_size,
dbits=self.word_size, dbits=self.word_size,
sram_name=self.name) sram_name=self.name)
# Add load capacitance to each of the read ports # Add load capacitance to each of the read ports
self.sf.write("\n* SRAM output loads\n") self.sf.write("\n* SRAM output loads\n")
for port in range(self.total_read): for port in self.read_ports:
for bit in range(self.word_size): for bit in range(self.word_size):
sig_name="{0}{1}_{2} ".format(self.dout_name, self.read_index[port], bit) sig_name="{0}{1}_{2} ".format(self.dout_name, port, bit)
self.sf.write("CD{0}{1} {2} 0 {3}f\n".format(self.read_index[port], bit, sig_name, self.load)) self.sf.write("CD{0}{1} {2} 0 {3}f\n".format(port, bit, sig_name, self.load))
# Write debug comments to stim file # Write debug comments to stim file
self.sf.write("\n\n * Sequence of operations\n") self.sf.write("\n\n * Sequence of operations\n")
@ -244,27 +244,27 @@ class functional(simulation):
# Generate data input bits # Generate data input bits
self.sf.write("\n* Generation of data and address signals\n") self.sf.write("\n* Generation of data and address signals\n")
for port in range(self.total_write): for port in self.write_ports:
for bit in range(self.word_size): for bit in range(self.word_size):
sig_name="{0}{1}_{2} ".format(self.din_name, port, bit) sig_name="{0}{1}_{2} ".format(self.din_name, 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.data_values[port][bit], self.period, self.slew, 0.05)
# Generate address bits # Generate address bits
for port in range(self.total_ports): for port in self.all_ports:
for bit in range(self.addr_size): for bit in range(self.addr_size):
sig_name="{0}{1}_{2} ".format(self.addr_name, port, bit) sig_name="{0}{1}_{2} ".format(self.addr_name, port, bit)
self.stim.gen_pwl(sig_name, self.cycle_times, self.addr_values[port][bit], self.period, self.slew, 0.05) self.stim.gen_pwl(sig_name, self.cycle_times, self.addr_values[port][bit], self.period, self.slew, 0.05)
# 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_ports): for port in self.all_ports:
self.stim.gen_pwl("CSB{}".format(port), self.cycle_times , self.csb_values[port], self.period, self.slew, 0.05) self.stim.gen_pwl("CSB{}".format(port), self.cycle_times , self.csb_values[port], self.period, self.slew, 0.05)
for port in range(self.num_rw_ports): 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) self.stim.gen_pwl("WEB{}".format(port), self.cycle_times , self.web_values[port], self.period, self.slew, 0.05)
# Generate CLK signals # Generate CLK signals
for port in range(self.total_ports): for port in self.all_ports:
self.stim.gen_pulse(sig_name="{0}{1}".format(tech.spice["clk"], port), self.stim.gen_pulse(sig_name="{0}{1}".format(tech.spice["clk"], port),
v1=self.gnd_voltage, v1=self.gnd_voltage,
v2=self.vdd_voltage, v2=self.vdd_voltage,

View File

@ -22,13 +22,10 @@ class simulation():
self.num_banks = self.sram.num_banks self.num_banks = self.sram.num_banks
self.sp_file = spfile self.sp_file = spfile
self.total_ports = self.sram.total_ports self.all_ports = self.sram.all_ports
self.total_write = self.sram.total_write self.readwrite_ports = self.sram.readwrite_ports
self.total_read = self.sram.total_read self.read_ports = self.sram.read_ports
self.read_index = self.sram.read_index self.write_ports = self.sram.write_ports
self.write_index = self.sram.write_index
self.num_rw_ports = self.sram.num_rw_ports
self.port_id = self.sram.port_id
def set_corner(self,corner): def set_corner(self,corner):
""" Set the corner values """ """ Set the corner values """
@ -48,12 +45,12 @@ class simulation():
self.t_current = 0 self.t_current = 0
# control signals: only one cs_b for entire multiported sram, one we_b for each write port # control signals: only one cs_b for entire multiported sram, one we_b for each write port
self.csb_values = [[] for port in range(self.total_ports)] self.csb_values = [[] for port in self.all_ports]
self.web_values = [[] for port in range(self.num_rw_ports)] self.web_values = [[] for port in self.readwrite_ports]
# Three dimensional list to handle each addr and data bits for wach port over the number of checks # 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 range(self.total_ports)] 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 range(self.total_write)] self.data_values = [[[] for bit in range(self.word_size)] for port in self.write_ports]
# For generating comments in SPICE stimulus # For generating comments in SPICE stimulus
self.cycle_comments = [] self.cycle_comments = []
@ -75,7 +72,7 @@ class simulation():
# Append the values depending on the type of port # Append the values depending on the type of port
self.csb_values[port].append(csb_val) 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 is in both lists, add rw control signal. Condition indicates its a RW port.
if port < self.num_rw_ports: if port in self.readwrite_ports:
self.web_values[port].append(web_val) self.web_values[port].append(web_val)
def add_data(self, data, port): def add_data(self, data, port):
@ -108,7 +105,7 @@ 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.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_ports, "Cannot add write cycle to a read port. Port {0}, Write Ports {1}".format(port, self.write_ports))
debug.info(2, comment) debug.info(2, comment)
self.fn_cycle_comments.append(comment) self.fn_cycle_comments.append(comment)
self.append_cycle_comment(port, comment) self.append_cycle_comment(port, comment)
@ -123,13 +120,13 @@ class simulation():
#This value is hard coded here. Possibly change to member variable or set in add_noop_one_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 noop_data = "0"*self.word_size
#Add noops to all other ports. #Add noops to all other ports.
for unselected_port in range(self.total_ports): for unselected_port in self.all_ports:
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 add_read(self, comment, address, din_data, port): def add_read(self, comment, address, din_data, port):
""" Add the control values for a read cycle. """ """ Add the control values for a read cycle. """
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_ports, "Cannot add read cycle to a write port. Port {0}, Read Ports {1}".format(port, self.read_ports))
debug.info(2, comment) debug.info(2, comment)
self.fn_cycle_comments.append(comment) self.fn_cycle_comments.append(comment)
self.append_cycle_comment(port, comment) self.append_cycle_comment(port, comment)
@ -139,14 +136,14 @@ class simulation():
self.add_control_one_port(port, "read") self.add_control_one_port(port, "read")
#If the port is also a readwrite then add data. #If the port is also a readwrite then add data.
if port in self.write_index: if port in self.write_ports:
self.add_data(din_data,port) self.add_data(din_data,port)
self.add_address(address, port) self.add_address(address, port)
#This value is hard coded here. Possibly change to member variable or set in add_noop_one_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 noop_data = "0"*self.word_size
#Add noops to all other ports. #Add noops to all other ports.
for unselected_port in range(self.total_ports): for unselected_port in self.all_ports:
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)
@ -159,12 +156,12 @@ class simulation():
self.cycle_times.append(self.t_current) self.cycle_times.append(self.t_current)
self.t_current += self.period self.t_current += self.period
for port in range(self.total_ports): for port in self.all_ports:
self.add_noop_one_port(address, data, port) self.add_noop_one_port(address, data, port)
def add_write_one_port(self, comment, address, data, port): def add_write_one_port(self, comment, address, data, port):
""" Add the control values for a write cycle. Does not increment the period. """ """ Add the control values for a write cycle. Does not increment the period. """
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_ports, "Cannot add write cycle to a read port. Port {0}, Write Ports {1}".format(port, self.write_ports))
debug.info(2, comment) debug.info(2, comment)
self.fn_cycle_comments.append(comment) self.fn_cycle_comments.append(comment)
@ -174,20 +171,20 @@ class simulation():
def add_read_one_port(self, comment, address, din_data, port): def add_read_one_port(self, comment, address, din_data, port):
""" Add the control values for a read cycle. Does not increment the period. """ """ Add the control values for a read cycle. Does not increment the period. """
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_ports, "Cannot add read cycle to a write port. Port {0}, Read Ports {1}".format(port, self.read_ports))
debug.info(2, comment) debug.info(2, comment)
self.fn_cycle_comments.append(comment) self.fn_cycle_comments.append(comment)
self.add_control_one_port(port, "read") self.add_control_one_port(port, "read")
#If the port is also a readwrite then add data. #If the port is also a readwrite then add data.
if port in self.write_index: if port in self.write_ports:
self.add_data(din_data,port) self.add_data(din_data,port)
self.add_address(address, port) self.add_address(address, port)
def add_noop_one_port(self, address, data, port): def add_noop_one_port(self, address, data, port):
""" Add the control values for a noop to a single port. Does not increment the period. """ """ Add the control values for a noop to a single port. Does not increment the period. """
self.add_control_one_port(port, "noop") self.add_control_one_port(port, "noop")
if port in self.write_index: if port in self.write_ports:
self.add_data(data,port) self.add_data(data,port)
self.add_address(address, port) self.add_address(address, port)

View File

@ -5,6 +5,7 @@ import design
import math import math
from math import log,sqrt,ceil from math import log,sqrt,ceil
import contact import contact
import pgates
from pinv import pinv from pinv import pinv
from pnand2 import pnand2 from pnand2 import pnand2
from pnor2 import pnor2 from pnor2 import pnor2
@ -66,26 +67,26 @@ class bank(design.design):
def add_pins(self): def add_pins(self):
""" Adding pins for Bank module""" """ Adding pins for Bank module"""
for port in range(self.total_read): for port in self.read_ports:
for bit in range(self.word_size): for bit in range(self.word_size):
self.add_pin("dout{0}_{1}".format(self.read_index[port],bit),"OUT") self.add_pin("dout{0}_{1}".format(port,bit),"OUT")
for port in range(self.total_write): for port in self.write_ports:
for bit in range(self.word_size): for bit in range(self.word_size):
self.add_pin("din{0}_{1}".format(port,bit),"IN") self.add_pin("din{0}_{1}".format(port,bit),"IN")
for port in range(self.total_ports): for port in self.all_ports:
for bit in range(self.addr_size): for bit in range(self.addr_size):
self.add_pin("addr{0}_{1}".format(port,bit),"INPUT") self.add_pin("addr{0}_{1}".format(port,bit),"INPUT")
# For more than one bank, we have a bank select and name # For more than one bank, we have a bank select and name
# the signals gated_*. # the signals gated_*.
if self.num_banks > 1: if self.num_banks > 1:
for port in range(self.total_ports): for port in self.all_ports:
self.add_pin("bank_sel{}".format(port),"INPUT") self.add_pin("bank_sel{}".format(port),"INPUT")
for port in range(self.total_read): for port in self.read_ports:
self.add_pin("s_en{0}".format(self.read_index[port]), "INPUT") self.add_pin("s_en{0}".format(port), "INPUT")
for port in range(self.total_write): for port in self.write_ports:
self.add_pin("w_en{0}".format(port), "INPUT") self.add_pin("w_en{0}".format(port), "INPUT")
for port in range(self.total_ports): for port in self.all_ports:
self.add_pin("clk_buf_bar{0}".format(port),"INPUT") self.add_pin("clk_buf_bar{0}".format(port),"INPUT")
self.add_pin("clk_buf{0}".format(port),"INPUT") self.add_pin("clk_buf{0}".format(port),"INPUT")
self.add_pin("vdd","POWER") self.add_pin("vdd","POWER")
@ -96,8 +97,8 @@ class bank(design.design):
""" Create routing amoung the modules """ """ Create routing amoung the modules """
self.route_central_bus() self.route_central_bus()
self.route_precharge_to_bitcell_array() self.route_precharge_to_bitcell_array()
self.route_col_mux_to_bitcell_array() self.route_col_mux_to_precharge_array()
self.route_sense_amp_to_col_mux_or_bitcell_array() self.route_sense_amp_to_col_mux_or_precharge_array()
self.route_sense_amp_out() self.route_sense_amp_out()
self.route_wordline_driver() self.route_wordline_driver()
self.route_write_driver() self.route_write_driver()
@ -127,26 +128,76 @@ class bank(design.design):
self.create_column_decoder() self.create_column_decoder()
self.create_bank_select() self.create_bank_select()
def place_modules(self): def compute_module_offsets(self):
""" Add modules. The order should not matter! """ """
Compute the module offsets.
# Above the bitcell array """
self.place_bitcell_array()
self.place_precharge_array()
# UPPER RIGHT QUADRANT
# Bitcell array is placed at (0,0)
self.bitcell_array_offset = vector(0,0)
# LOWER RIGHT QUADRANT
# Below the bitcell array # Below the bitcell array
self.place_column_mux_array() y_offset = self.precharge_array[0].height + self.m2_gap
self.place_sense_amp_array() self.precharge_offset = vector(0,-y_offset)
self.place_write_driver_array() if self.col_addr_size > 0:
y_offset += self.column_mux_array[0].height
self.column_mux_offset = vector(0,-y_offset)
y_offset += self.sense_amp_array.height
self.sense_amp_offset = vector(0,-y_offset)
y_offset += self.write_driver_array.height
self.write_driver_offset = vector(0,-y_offset)
# UPPER LEFT QUADRANT
# To the left of the bitcell array # To the left of the bitcell array
self.place_row_decoder() # The wordline driver is placed to the right of the main decoder width.
self.place_wordline_driver() x_offset = self.central_bus_width + self.wordline_driver.width - self.m2_pitch
self.place_column_decoder() self.wordline_driver_offset = vector(-x_offset,0)
x_offset += self.row_decoder.width + self.m2_pitch
self.row_decoder_offset = vector(-x_offset,0)
self.place_bank_select() # LOWER LEFT QUADRANT
# Place the col decoder right aligned with row decoder (x_offset doesn't change)
# Below the bitcell array
if self.col_addr_size > 0:
y_offset = self.col_decoder.height
else:
y_offset = 0
y_offset += 2*drc("well_to_well")
self.column_decoder_offset = vector(-x_offset,-y_offset)
# Bank select gets placed below the column decoder (x_offset doesn't change)
if self.col_addr_size > 0:
y_offset = min(self.column_decoder_offset.y, self.column_mux_offset.y)
else:
y_offset = self.row_decoder_offset.y
if self.num_banks > 1:
y_offset += self.bank_select.height + drc("well_to_well")
self.bank_select_offset = vector(-x_offset,-y_offset)
def place_modules(self):
""" Place the modules. """
self.compute_module_offsets()
# UPPER RIGHT QUADRANT
self.place_bitcell_array(self.bitcell_array_offset)
# LOWER RIGHT QUADRANT
self.place_precharge_array([self.precharge_offset]*len(self.read_ports))
self.place_column_mux_array([self.column_mux_offset]*len(self.all_ports))
self.place_sense_amp_array([self.sense_amp_offset]*len(self.read_ports))
self.place_write_driver_array([self.write_driver_offset]*len(self.write_ports))
# UPPER LEFT QUADRANT
self.place_row_decoder([self.row_decoder_offset]*len(self.all_ports))
self.place_wordline_driver([self.wordline_driver_offset]*len(self.all_ports))
# LOWER LEFT QUADRANT
self.place_column_decoder([self.column_decoder_offset]*len(self.all_ports))
self.place_bank_select([self.bank_select_offset]*len(self.all_ports))
def compute_sizes(self): def compute_sizes(self):
@ -184,7 +235,7 @@ class bank(design.design):
# These will be outputs of the gaters if this is multibank, if not, normal signals. # These will be outputs of the gaters if this is multibank, if not, normal signals.
self.control_signals = [] self.control_signals = []
for port in range(self.total_ports): for port in self.all_ports:
if self.num_banks > 1: if self.num_banks > 1:
self.control_signals.append(["gated_"+str for str in self.input_control_signals[port]]) self.control_signals.append(["gated_"+str for str in self.input_control_signals[port]])
else: else:
@ -226,30 +277,33 @@ class bank(design.design):
self.add_mod(self.bitcell_array) self.add_mod(self.bitcell_array)
# create arrays of bitline and bitline_bar names for read, write, or all ports # create arrays of bitline and bitline_bar names for read, write, or all ports
self.read_bl_list = self.bitcell.list_read_bl_names() self.read_bl_names = self.bitcell.list_read_bl_names()
self.read_br_list = self.bitcell.list_read_br_names() self.read_br_names = self.bitcell.list_read_br_names()
self.write_bl_list = self.bitcell.list_write_bl_names() self.write_bl_names = self.bitcell.list_write_bl_names()
self.write_br_list = self.bitcell.list_write_br_names() self.write_br_names = self.bitcell.list_write_br_names()
self.total_bl_list = self.bitcell.list_all_bl_names() self.total_bl_names = self.bitcell.list_all_bl_names()
self.total_br_list = self.bitcell.list_all_br_names() self.total_br_names = self.bitcell.list_all_br_names()
self.total_wl_list = self.bitcell.list_all_wl_names() self.total_wl_names = self.bitcell.list_all_wl_names()
self.total_bitline_list = self.bitcell.list_all_bitline_names() self.total_bitline_names = self.bitcell.list_all_bitline_names()
self.precharge_array = [] self.precharge_array = []
for port in range(self.total_read): for port in self.all_ports:
self.precharge_array.append(self.mod_precharge_array(columns=self.num_cols, bitcell_bl=self.read_bl_list[port], bitcell_br=self.read_br_list[port])) if port in self.read_ports:
self.add_mod(self.precharge_array[port]) self.precharge_array.append(self.mod_precharge_array(columns=self.num_cols, bitcell_bl=self.total_bl_names[port], bitcell_br=self.total_br_names[port]))
self.add_mod(self.precharge_array[port])
else:
self.precharge_array.append(None)
if self.col_addr_size > 0: if self.col_addr_size > 0:
self.column_mux_array = [] self.column_mux_array = []
for port in range(self.total_ports): for port in self.all_ports:
self.column_mux_array.append(self.mod_column_mux_array(columns=self.num_cols, self.column_mux_array.append(self.mod_column_mux_array(columns=self.num_cols,
word_size=self.word_size, word_size=self.word_size,
bitcell_bl=self.total_bl_list[port], bitcell_bl=self.total_bl_names[port],
bitcell_br=self.total_br_list[port])) bitcell_br=self.total_br_names[port]))
self.add_mod(self.column_mux_array[port]) self.add_mod(self.column_mux_array[port])
@ -284,151 +338,153 @@ class bank(design.design):
temp = [] temp = []
for col in range(self.num_cols): for col in range(self.num_cols):
for bitline in self.total_bitline_list: for bitline in self.total_bitline_names:
temp.append(bitline+"_{0}".format(col)) temp.append(bitline+"_{0}".format(col))
for row in range(self.num_rows): for row in range(self.num_rows):
for wordline in self.total_wl_list: for wordline in self.total_wl_names:
temp.append(wordline+"_{0}".format(row)) temp.append(wordline+"_{0}".format(row))
temp.append("vdd") temp.append("vdd")
temp.append("gnd") temp.append("gnd")
self.connect_inst(temp) self.connect_inst(temp)
def place_bitcell_array(self): def place_bitcell_array(self, offset):
""" Placing Bitcell Array """ """ Placing Bitcell Array """
self.bitcell_array_inst.place(vector(0,0)) self.bitcell_array_inst.place(offset)
def create_precharge_array(self): def create_precharge_array(self):
""" Creating Precharge """ """ Creating Precharge """
self.precharge_array_inst = [] self.precharge_array_inst = []
for port in range(self.total_read): for port in self.read_ports:
self.precharge_array_inst.append(self.add_inst(name="precharge_array{}".format(port), self.precharge_array_inst.append(self.add_inst(name="precharge_array{}".format(port),
mod=self.precharge_array[port])) mod=self.precharge_array[port]))
temp = [] temp = []
for i in range(self.num_cols): for i in range(self.num_cols):
temp.append(self.read_bl_list[port]+"_{0}".format(i)) temp.append(self.total_bl_names[port]+"_{0}".format(i))
temp.append(self.read_br_list[port]+"_{0}".format(i)) temp.append(self.total_br_names[port]+"_{0}".format(i))
temp.extend([self.prefix+"clk_buf_bar{0}".format(self.read_index[port]), "vdd"]) temp.extend([self.prefix+"clk_buf_bar{0}".format(port), "vdd"])
self.connect_inst(temp) self.connect_inst(temp)
def place_precharge_array(self): def place_precharge_array(self, offsets):
""" Placing Precharge """ """ Placing Precharge """
debug.check(len(offsets)>=len(self.all_ports), "Insufficient offsets to place precharge array.")
# FIXME: place for multiport # FIXME: place for multiport
for port in range(self.total_read): for port in self.read_ports:
# The wells must be far enough apart self.precharge_array_inst[port].place(offsets[port])
# The enclosure is for the well and the spacing is to the bitcell wells
y_offset = self.bitcell_array.height + self.m2_gap
self.precharge_array_inst[port].place(vector(0,y_offset))
def create_column_mux_array(self): def create_column_mux_array(self):
""" Creating Column Mux when words_per_row > 1 . """ """ Creating Column Mux when words_per_row > 1 . """
self.col_mux_array_inst = []
if self.col_addr_size == 0: if self.col_addr_size == 0:
return return
self.col_mux_array_inst = [] for port in self.all_ports:
for port in range(self.total_ports):
self.col_mux_array_inst.append(self.add_inst(name="column_mux_array{}".format(port), self.col_mux_array_inst.append(self.add_inst(name="column_mux_array{}".format(port),
mod=self.column_mux_array[port])) mod=self.column_mux_array[port]))
temp = [] temp = []
for col in range(self.num_cols): for col in range(self.num_cols):
temp.append(self.total_bl_list[port]+"_{0}".format(col)) temp.append(self.total_bl_names[port]+"_{0}".format(col))
temp.append(self.total_br_list[port]+"_{0}".format(col)) temp.append(self.total_br_names[port]+"_{0}".format(col))
for word in range(self.words_per_row): for word in range(self.words_per_row):
temp.append("sel{0}_{1}".format(port,word)) temp.append("sel{0}_{1}".format(port,word))
for bit in range(self.word_size): for bit in range(self.word_size):
temp.append(self.total_bl_list[port]+"_out_{0}".format(bit)) temp.append(self.total_bl_names[port]+"_out_{0}".format(bit))
temp.append(self.total_br_list[port]+"_out_{0}".format(bit)) temp.append(self.total_br_names[port]+"_out_{0}".format(bit))
temp.append("gnd") temp.append("gnd")
self.connect_inst(temp) self.connect_inst(temp)
def place_column_mux_array(self): def place_column_mux_array(self, offsets):
""" Placing Column Mux when words_per_row > 1 . """ """ Placing Column Mux when words_per_row > 1 . """
if self.col_addr_size > 0: if self.col_addr_size == 0:
self.column_mux_height = self.column_mux_array[0].height + self.m2_gap
else:
self.column_mux_height = 0
return return
for port in range(self.total_ports): debug.check(len(offsets)>=len(self.all_ports), "Insufficient offsets to place column mux array.")
y_offset = self.column_mux_height
self.col_mux_array_inst[port].place(vector(0,y_offset).scale(-1,-1)) for port in self.all_ports:
self.col_mux_array_inst[port].place(offsets[port])
def create_sense_amp_array(self): def create_sense_amp_array(self):
""" Creating Sense amp """ """ Creating Sense amp """
self.sense_amp_array_inst = [] self.sense_amp_array_inst = []
for port in range(self.total_read): for port in self.read_ports:
self.sense_amp_array_inst.append(self.add_inst(name="sense_amp_array{}".format(port), self.sense_amp_array_inst.append(self.add_inst(name="sense_amp_array{}".format(port),
mod=self.sense_amp_array)) mod=self.sense_amp_array))
temp = [] temp = []
for bit in range(self.word_size): for bit in range(self.word_size):
temp.append("dout{0}_{1}".format(self.read_index[port],bit)) temp.append("dout{0}_{1}".format(port,bit))
if self.words_per_row == 1: if self.words_per_row == 1:
temp.append(self.read_bl_list[port]+"_{0}".format(bit)) temp.append(self.total_bl_names[port]+"_{0}".format(bit))
temp.append(self.read_br_list[port]+"_{0}".format(bit)) temp.append(self.total_br_names[port]+"_{0}".format(bit))
else: else:
temp.append(self.read_bl_list[port]+"_out_{0}".format(bit)) temp.append(self.total_bl_names[port]+"_out_{0}".format(bit))
temp.append(self.read_br_list[port]+"_out_{0}".format(bit)) temp.append(self.total_br_names[port]+"_out_{0}".format(bit))
temp.extend([self.prefix+"s_en{}".format(self.read_index[port]), "vdd", "gnd"]) temp.extend([self.prefix+"s_en{}".format(port), "vdd", "gnd"])
self.connect_inst(temp) self.connect_inst(temp)
def place_sense_amp_array(self): def place_sense_amp_array(self, offsets):
""" Placing Sense amp """ """ Placing Sense amp """
debug.check(len(offsets)>=len(self.read_ports), "Insufficient offsets to place sense amp array.")
# FIXME: place for multiport # FIXME: place for multiport
for port in range(self.total_read): for port in self.read_ports:
y_offset = self.column_mux_height + self.sense_amp_array.height + self.m2_gap self.sense_amp_array_inst[port].place(offsets[port])
self.sense_amp_array_inst[port].place(vector(0,y_offset).scale(-1,-1))
def create_write_driver_array(self): def create_write_driver_array(self):
""" Creating Write Driver """ """ Creating Write Driver """
self.write_driver_array_inst = [] self.write_driver_array_inst = []
for port in range(self.total_write): for port in self.all_ports:
self.write_driver_array_inst.append(self.add_inst(name="write_driver_array{}".format(port), if port in self.write_ports:
mod=self.write_driver_array)) self.write_driver_array_inst.append(self.add_inst(name="write_driver_array{}".format(port),
mod=self.write_driver_array))
else:
self.write_driver_array_inst.append(None)
temp = [] temp = []
for bit in range(self.word_size): for bit in range(self.word_size):
temp.append("din{0}_{1}".format(port,bit)) temp.append("din{0}_{1}".format(port,bit))
for bit in range(self.word_size): for bit in range(self.word_size):
if (self.words_per_row == 1): if (self.words_per_row == 1):
temp.append(self.write_bl_list[port]+"_{0}".format(bit)) temp.append(self.total_bl_names[port]+"_{0}".format(bit))
temp.append(self.write_br_list[port]+"_{0}".format(bit)) temp.append(self.total_br_names[port]+"_{0}".format(bit))
else: else:
temp.append(self.write_bl_list[port]+"_out_{0}".format(bit)) temp.append(self.total_bl_names[port]+"_out_{0}".format(bit))
temp.append(self.write_br_list[port]+"_out_{0}".format(bit)) temp.append(self.total_br_names[port]+"_out_{0}".format(bit))
temp.extend([self.prefix+"w_en{0}".format(port), "vdd", "gnd"]) temp.extend([self.prefix+"w_en{0}".format(port), "vdd", "gnd"])
self.connect_inst(temp) self.connect_inst(temp)
def place_write_driver_array(self): def place_write_driver_array(self, offsets):
""" Placing Write Driver """ """ Placing Write Driver """
# FIXME: place for multiport debug.check(len(offsets)>=len(self.write_ports), "Insufficient offsets to place write driver array.")
for port in range(self.total_write):
y_offset = self.sense_amp_array.height + self.column_mux_height \ for port in self.write_ports:
+ self.m2_gap + self.write_driver_array.height self.write_driver_array_inst[port].place(offsets[port])
self.write_driver_array_inst[port].place(vector(0,y_offset).scale(-1,-1))
def create_row_decoder(self): def create_row_decoder(self):
""" Create the hierarchical row decoder """ """ Create the hierarchical row decoder """
self.row_decoder_inst = [] self.row_decoder_inst = []
for port in range(self.total_ports): for port in self.all_ports:
self.row_decoder_inst.append(self.add_inst(name="row_decoder{}".format(port), self.row_decoder_inst.append(self.add_inst(name="row_decoder{}".format(port),
mod=self.row_decoder)) mod=self.row_decoder))
@ -441,9 +497,11 @@ class bank(design.design):
self.connect_inst(temp) self.connect_inst(temp)
def place_row_decoder(self): def place_row_decoder(self, offsets):
""" Place the hierarchical row decoder """ """ Place the hierarchical row decoder """
debug.check(len(offsets)>=len(self.all_ports), "Insufficient offsets to place row decoder array.")
# The address and control bus will be in between decoder and the main memory array # The address and control bus will be in between decoder and the main memory array
# This bus will route address bits to the decoder input and column mux inputs. # This bus will route address bits to the decoder input and column mux inputs.
# The wires are actually routed after we placed the stuff on both sides. # The wires are actually routed after we placed the stuff on both sides.
@ -451,16 +509,15 @@ class bank(design.design):
# The address flop and decoder are aligned in the x coord. # The address flop and decoder are aligned in the x coord.
# FIXME: place for multiport # FIXME: place for multiport
for port in range(self.total_ports): for port in self.all_ports:
x_offset = -(self.row_decoder.width + self.central_bus_width + self.wordline_driver.width) self.row_decoder_inst[port].place(offsets[port])
self.row_decoder_inst[port].place(vector(x_offset,0))
def create_wordline_driver(self): def create_wordline_driver(self):
""" Create the Wordline Driver """ """ Create the Wordline Driver """
self.wordline_driver_inst = [] self.wordline_driver_inst = []
for port in range(self.total_ports): for port in self.all_ports:
self.wordline_driver_inst.append(self.add_inst(name="wordline_driver{}".format(port), self.wordline_driver_inst.append(self.add_inst(name="wordline_driver{}".format(port),
mod=self.wordline_driver)) mod=self.wordline_driver))
@ -468,21 +525,20 @@ class bank(design.design):
for row in range(self.num_rows): for row in range(self.num_rows):
temp.append("dec_out{0}_{1}".format(port,row)) temp.append("dec_out{0}_{1}".format(port,row))
for row in range(self.num_rows): for row in range(self.num_rows):
temp.append(self.total_wl_list[port]+"_{0}".format(row)) temp.append(self.total_wl_names[port]+"_{0}".format(row))
temp.append(self.prefix+"clk_buf{0}".format(port)) temp.append(self.prefix+"clk_buf{0}".format(port))
temp.append("vdd") temp.append("vdd")
temp.append("gnd") temp.append("gnd")
self.connect_inst(temp) self.connect_inst(temp)
def place_wordline_driver(self): def place_wordline_driver(self, offsets):
""" Place the Wordline Driver """ """ Place the Wordline Driver """
# FIXME: place for multiport debug.check(len(offsets)>=len(self.all_ports), "Insufficient offsets to place wordline driver array.")
for port in range(self.total_ports):
# The wordline driver is placed to the right of the main decoder width. for port in self.all_ports:
x_offset = -(self.central_bus_width + self.wordline_driver.width) + self.m2_pitch self.wordline_driver_inst[port].place(offsets[port])
self.wordline_driver_inst[port].place(vector(x_offset,0))
def create_column_decoder(self): def create_column_decoder(self):
@ -504,7 +560,7 @@ class bank(design.design):
debug.error("Invalid column decoder?",-1) debug.error("Invalid column decoder?",-1)
self.col_decoder_inst = [] self.col_decoder_inst = []
for port in range(self.total_ports): for port in self.all_ports:
self.col_decoder_inst.append(self.add_inst(name="col_address_decoder{}".format(port), self.col_decoder_inst.append(self.add_inst(name="col_address_decoder{}".format(port),
mod=self.col_decoder)) mod=self.col_decoder))
@ -517,21 +573,17 @@ class bank(design.design):
self.connect_inst(temp) self.connect_inst(temp)
def place_column_decoder(self): def place_column_decoder(self, offsets):
""" """
Place a 2:4 or 3:8 column address decoder. Place a 2:4 or 3:8 column address decoder.
""" """
if self.col_addr_size == 0: if self.col_addr_size == 0:
return return
# FIXME: place for multiport debug.check(len(offsets)>=len(self.all_ports), "Insufficient offsets to place column decoder.")
for port in range(self.total_ports):
col_decoder_inst = self.col_decoder_inst[port] for port in self.all_ports:
col_decoder_inst.place(offsets[port])
# Place the col decoder right aligned with row decoder
x_off = -(self.central_bus_width + self.wordline_driver.width + self.col_decoder.width)
y_off = -(self.col_decoder.height + 2*drc("well_to_well"))
col_decoder_inst.place(vector(x_off,y_off))
@ -542,7 +594,7 @@ class bank(design.design):
return return
self.bank_select_inst = [] self.bank_select_inst = []
for port in range(self.total_ports): for port in self.all_ports:
self.bank_select_inst.append(self.add_inst(name="bank_select{}".format(port), self.bank_select_inst.append(self.add_inst(name="bank_select{}".format(port),
mod=self.bank_select)) mod=self.bank_select))
@ -554,22 +606,16 @@ class bank(design.design):
self.connect_inst(temp) self.connect_inst(temp)
def place_bank_select(self): def place_bank_select(self, offsets):
""" Place the bank select logic. """ """ Place the bank select logic. """
if not self.num_banks > 1: if not self.num_banks > 1:
return return
# FIXME: place for multiport debug.check(len(offsets)>=len(self.all_ports), "Insufficient offsets to place bank select logic.")
for port in range(self.total_ports):
x_off = -(self.row_decoder.width + self.central_bus_width + self.wordline_driver.width) for port in self.all_ports:
if self.col_addr_size > 0: self.bank_select_inst[port].place(offsets[port])
y_off = min(self.col_decoder_inst[port].by(), self.col_mux_array_inst[port].by())
else:
y_off = self.row_decoder_inst[port].by()
y_off -= (self.bank_select.height + drc("well_to_well"))
self.bank_select_pos = vector(x_off,y_off)
self.bank_select_inst[port].place(self.bank_select_pos)
def route_supplies(self): def route_supplies(self):
@ -581,7 +627,7 @@ class bank(design.design):
def route_bank_select(self): def route_bank_select(self):
""" Route the bank select logic. """ """ Route the bank select logic. """
for port in range(self.total_ports): for port in self.all_ports:
if self.port_id[port] == "rw": if self.port_id[port] == "rw":
bank_sel_signals = ["clk_buf", "clk_buf_bar", "w_en", "s_en", "bank_sel"] bank_sel_signals = ["clk_buf", "clk_buf_bar", "w_en", "s_en", "bank_sel"]
gated_bank_sel_signals = ["gated_clk_buf", "gated_clk_buf_bar", "gated_w_en", "gated_s_en"] gated_bank_sel_signals = ["gated_clk_buf", "gated_clk_buf_bar", "gated_w_en", "gated_s_en"]
@ -641,7 +687,7 @@ class bank(design.design):
# The max point is always the top of the precharge bitlines # The max point is always the top of the precharge bitlines
# Add a vdd and gnd power rail above the array # Add a vdd and gnd power rail above the array
# FIXME: Update multiport # FIXME: Update multiport
self.max_y_offset = self.precharge_array_inst[0].uy() + 3*self.m1_width self.max_y_offset = self.bitcell_array_inst.ur().y + 3*self.m1_width
self.max_x_offset = self.bitcell_array_inst.ur().x + 3*self.m1_width self.max_x_offset = self.bitcell_array_inst.ur().x + 3*self.m1_width
self.min_x_offset = self.row_decoder_inst[0].lx() self.min_x_offset = self.row_decoder_inst[0].lx()
@ -661,7 +707,7 @@ class bank(design.design):
# and control lines. # and control lines.
# The bank is at (0,0), so this is to the left of the y-axis. # The bank is at (0,0), so this is to the left of the y-axis.
# 2 pitches on the right for vias/jogs to access the inputs # 2 pitches on the right for vias/jogs to access the inputs
for port in range(self.total_ports): for port in self.all_ports:
control_bus_offset = vector(-self.m2_pitch * self.num_control_lines - self.m2_width, self.min_y_offset) control_bus_offset = vector(-self.m2_pitch * self.num_control_lines - self.m2_width, self.min_y_offset)
control_bus_length = self.max_y_offset - self.min_y_offset control_bus_length = self.max_y_offset - self.min_y_offset
self.bus_xoffset = self.create_bus(layer="metal2", self.bus_xoffset = self.create_bus(layer="metal2",
@ -677,12 +723,12 @@ class bank(design.design):
""" Routing of BL and BR between pre-charge and bitcell array """ """ Routing of BL and BR between pre-charge and bitcell array """
# FIXME: Update for multiport # FIXME: Update for multiport
for port in range(self.total_read): for port in self.read_ports:
for col in range(self.num_cols): for col in range(self.num_cols):
precharge_bl = self.precharge_array_inst[port].get_pin("bl_{}".format(col)).bc() precharge_bl = self.precharge_array_inst[port].get_pin("bl_{}".format(col)).uc()
precharge_br = self.precharge_array_inst[port].get_pin("br_{}".format(col)).bc() precharge_br = self.precharge_array_inst[port].get_pin("br_{}".format(col)).uc()
bitcell_bl = self.bitcell_array_inst.get_pin(self.read_bl_list[port]+"_{}".format(col)).uc() bitcell_bl = self.bitcell_array_inst.get_pin(self.read_bl_names[port]+"_{}".format(col)).bc()
bitcell_br = self.bitcell_array_inst.get_pin(self.read_br_list[port]+"_{}".format(col)).uc() bitcell_br = self.bitcell_array_inst.get_pin(self.read_br_names[port]+"_{}".format(col)).bc()
yoffset = 0.5*(precharge_bl.y+bitcell_bl.y) yoffset = 0.5*(precharge_bl.y+bitcell_bl.y)
self.add_path("metal2",[precharge_bl, vector(precharge_bl.x,yoffset), self.add_path("metal2",[precharge_bl, vector(precharge_bl.x,yoffset),
@ -691,32 +737,32 @@ class bank(design.design):
vector(bitcell_br.x,yoffset), bitcell_br]) vector(bitcell_br.x,yoffset), bitcell_br])
def route_col_mux_to_bitcell_array(self): def route_col_mux_to_precharge_array(self):
""" Routing of BL and BR between col mux and bitcell array """ """ Routing of BL and BR between col mux and precharge array """
# Only do this if we have a column mux! # Only do this if we have a column mux!
if self.col_addr_size==0: if self.col_addr_size==0:
return return
# FIXME: Update for multiport # FIXME: Update for multiport
for port in range(self.total_ports): for port in self.all_ports:
for col in range(self.num_cols): for col in range(self.num_cols):
col_mux_bl = self.col_mux_array_inst[port].get_pin("bl_{}".format(col)).uc() col_mux_bl = self.col_mux_array_inst[port].get_pin("bl_{}".format(col)).uc()
col_mux_br = self.col_mux_array_inst[port].get_pin("br_{}".format(col)).uc() col_mux_br = self.col_mux_array_inst[port].get_pin("br_{}".format(col)).uc()
bitcell_bl = self.bitcell_array_inst.get_pin(self.total_bl_list[port]+"_{}".format(col)).bc() precharge_bl = self.precharge_array_inst[port].get_pin(self.total_bl_names[port]+"_{}".format(col)).bc()
bitcell_br = self.bitcell_array_inst.get_pin(self.total_br_list[port]+"_{}".format(col)).bc() precharge_br = self.precharge_array_inst[port].get_pin(self.total_br_names[port]+"_{}".format(col)).bc()
yoffset = 0.5*(col_mux_bl.y+bitcell_bl.y) yoffset = 0.5*(col_mux_bl.y+precharge_bl.y)
self.add_path("metal2",[col_mux_bl, vector(col_mux_bl.x,yoffset), self.add_path("metal2",[col_mux_bl, vector(col_mux_bl.x,yoffset),
vector(bitcell_bl.x,yoffset), bitcell_bl]) vector(precharge_bl.x,yoffset), precharge_bl])
self.add_path("metal2",[col_mux_br, vector(col_mux_br.x,yoffset), self.add_path("metal2",[col_mux_br, vector(col_mux_br.x,yoffset),
vector(bitcell_br.x,yoffset), bitcell_br]) vector(precharge_br.x,yoffset), precharge_br])
def route_sense_amp_to_col_mux_or_bitcell_array(self): def route_sense_amp_to_col_mux_or_precharge_array(self):
""" Routing of BL and BR between sense_amp and column mux or bitcell array """ """ Routing of BL and BR between sense_amp and column mux or precharge array """
for port in range(self.total_read): for port in self.read_ports:
for bit in range(self.word_size): for bit in range(self.word_size):
sense_amp_bl = self.sense_amp_array_inst[port].get_pin("bl_{}".format(bit)).uc() sense_amp_bl = self.sense_amp_array_inst[port].get_pin("bl_{}".format(bit)).uc()
sense_amp_br = self.sense_amp_array_inst[port].get_pin("br_{}".format(bit)).uc() sense_amp_br = self.sense_amp_array_inst[port].get_pin("br_{}".format(bit)).uc()
@ -726,9 +772,9 @@ class bank(design.design):
connect_bl = self.col_mux_array_inst[port].get_pin("bl_out_{}".format(bit)).bc() connect_bl = self.col_mux_array_inst[port].get_pin("bl_out_{}".format(bit)).bc()
connect_br = self.col_mux_array_inst[port].get_pin("br_out_{}".format(bit)).bc() connect_br = self.col_mux_array_inst[port].get_pin("br_out_{}".format(bit)).bc()
else: else:
# Sense amp is directly connected to the bitcell array # Sense amp is directly connected to the precharge array
connect_bl = self.bitcell_array_inst.get_pin(self.read_bl_list[port]+"_{}".format(bit)).bc() connect_bl = self.precharge_array_inst[port].get_pin(self.read_bl_names[port]+"_{}".format(bit)).bc()
connect_br = self.bitcell_array_inst.get_pin(self.read_br_list[port]+"_{}".format(bit)).bc() connect_br = self.precharge_array_inst[port].get_pin(self.read_br_names[port]+"_{}".format(bit)).bc()
yoffset = 0.5*(sense_amp_bl.y+connect_bl.y) yoffset = 0.5*(sense_amp_bl.y+connect_bl.y)
@ -742,10 +788,10 @@ class bank(design.design):
""" Add pins for the sense amp output """ """ Add pins for the sense amp output """
# FIXME: Update for multiport # FIXME: Update for multiport
for port in range(self.total_read): for port in self.read_ports:
for bit in range(self.word_size): for bit in range(self.word_size):
data_pin = self.sense_amp_array_inst[port].get_pin("data_{}".format(bit)) data_pin = self.sense_amp_array_inst[port].get_pin("data_{}".format(bit))
self.add_layout_pin_rect_center(text="dout{0}_{1}".format(self.read_index[port],bit), self.add_layout_pin_rect_center(text="dout{0}_{1}".format(self.read_ports[port],bit),
layer=data_pin.layer, layer=data_pin.layer,
offset=data_pin.center(), offset=data_pin.center(),
height=data_pin.height(), height=data_pin.height(),
@ -757,7 +803,7 @@ class bank(design.design):
# FIXME: Update for multiport # FIXME: Update for multiport
# Create inputs for the row address lines # Create inputs for the row address lines
for port in range(self.total_ports): for port in self.all_ports:
for row in range(self.row_addr_size): for row in range(self.row_addr_size):
addr_idx = row + self.col_addr_size addr_idx = row + self.col_addr_size
decoder_name = "addr_{}".format(row) decoder_name = "addr_{}".format(row)
@ -767,7 +813,7 @@ class bank(design.design):
def route_write_driver(self): def route_write_driver(self):
""" Connecting write driver """ """ Connecting write driver """
for port in range(self.total_ports): for port in self.all_ports:
for row in range(self.word_size): for row in range(self.word_size):
data_name = "data_{}".format(row) data_name = "data_{}".format(row)
din_name = "din{0}_{1}".format(port,row) din_name = "din{0}_{1}".format(port,row)
@ -776,7 +822,7 @@ class bank(design.design):
def route_wordline_driver(self): def route_wordline_driver(self):
""" Connecting Wordline driver output to Bitcell WL connection """ """ Connecting Wordline driver output to Bitcell WL connection """
for port in range(self.total_ports): for port in self.all_ports:
for row in range(self.num_rows): for row in range(self.num_rows):
# The pre/post is to access the pin from "outside" the cell to avoid DRCs # The pre/post is to access the pin from "outside" the cell to avoid DRCs
decoder_out_pos = self.row_decoder_inst[port].get_pin("decode_{}".format(row)).rc() decoder_out_pos = self.row_decoder_inst[port].get_pin("decode_{}".format(row)).rc()
@ -787,7 +833,7 @@ class bank(design.design):
# The mid guarantees we exit the input cell to the right. # The mid guarantees we exit the input cell to the right.
driver_wl_pos = self.wordline_driver_inst[port].get_pin("wl_{}".format(row)).rc() driver_wl_pos = self.wordline_driver_inst[port].get_pin("wl_{}".format(row)).rc()
bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.total_wl_list[port]+"_{}".format(row)).lc() bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.total_wl_names[port]+"_{}".format(row)).lc()
mid1 = driver_wl_pos.scale(0.5,1)+bitcell_wl_pos.scale(0.5,0) mid1 = driver_wl_pos.scale(0.5,1)+bitcell_wl_pos.scale(0.5,0)
mid2 = driver_wl_pos.scale(0.5,0)+bitcell_wl_pos.scale(0.5,1) mid2 = driver_wl_pos.scale(0.5,0)+bitcell_wl_pos.scale(0.5,1)
self.add_path("metal1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos]) self.add_path("metal1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos])
@ -798,7 +844,7 @@ class bank(design.design):
if not self.col_addr_size>0: if not self.col_addr_size>0:
return return
for port in range(self.total_ports): for port in self.all_ports:
if self.col_addr_size == 1: if self.col_addr_size == 1:
# Connect to sel[0] and sel[1] # Connect to sel[0] and sel[1]
@ -894,16 +940,16 @@ class bank(design.design):
read_inst = 0 read_inst = 0
# Control lines for RW ports # Control lines for RW ports
for port in range(self.total_ports): for port in self.all_ports:
connection = [] connection = []
if (self.port_id[port] == "rw") or (self.port_id[port] == "r"): if port in self.read_ports:
connection.append((self.prefix+"clk_buf_bar{}".format(port), self.precharge_array_inst[read_inst].get_pin("en").lc())) connection.append((self.prefix+"clk_buf_bar{}".format(port), self.precharge_array_inst[port].get_pin("en").lc()))
if (self.port_id[port] == "rw") or (self.port_id[port] == "w"):
connection.append((self.prefix+"w_en{}".format(port), self.write_driver_array_inst[write_inst].get_pin("en").lc())) if port in self.write_ports:
write_inst += 1 connection.append((self.prefix+"w_en{}".format(port), self.write_driver_array_inst[port].get_pin("en").lc()))
if (self.port_id[port] == "rw") or (self.port_id[port] == "r"):
connection.append((self.prefix+"s_en{}".format(port), self.sense_amp_array_inst[read_inst].get_pin("en").lc())) if port in self.read_ports:
read_inst += 1 connection.append((self.prefix+"s_en{}".format(port), self.sense_amp_array_inst[port].get_pin("en").lc()))
for (control_signal, pin_pos) in connection: for (control_signal, pin_pos) in connection:
control_pos = vector(self.bus_xoffset[control_signal].x ,pin_pos.y) control_pos = vector(self.bus_xoffset[control_signal].x ,pin_pos.y)
@ -937,7 +983,7 @@ class bank(design.design):
bitcell_array_delay = self.bitcell_array.analytical_delay(word_driver_delay.slew) bitcell_array_delay = self.bitcell_array.analytical_delay(word_driver_delay.slew)
#This also essentially creates the same delay for each port. Good structure, no substance #This also essentially creates the same delay for each port. Good structure, no substance
for port in range(self.total_ports): for port in self.all_ports:
if self.words_per_row > 1: if self.words_per_row > 1:
column_mux_delay = self.column_mux_array[port].analytical_delay(vdd, bitcell_array_delay.slew, column_mux_delay = self.column_mux_array[port].analytical_delay(vdd, bitcell_array_delay.slew,
self.sense_amp_array.input_load()) self.sense_amp_array.input_load())

View File

@ -125,10 +125,10 @@ class replica_bitline(design.design):
self.rbc_inst=self.add_inst(name="bitcell", self.rbc_inst=self.add_inst(name="bitcell",
mod=self.replica_bitcell) mod=self.replica_bitcell)
temp = [] temp = []
for port in range(self.total_ports): for port in self.all_ports:
temp.append("bl{}_0".format(port)) temp.append("bl{}_0".format(port))
temp.append("br{}_0".format(port)) temp.append("br{}_0".format(port))
for port in range(self.total_ports): for port in self.all_ports:
temp.append("delayed_en") temp.append("delayed_en")
temp.append("vdd") temp.append("vdd")
temp.append("gnd") temp.append("gnd")
@ -139,11 +139,11 @@ class replica_bitline(design.design):
mod=self.rbl) mod=self.rbl)
temp = [] temp = []
for port in range(self.total_ports): for port in self.all_ports:
temp.append("bl{}_0".format(port)) temp.append("bl{}_0".format(port))
temp.append("br{}_0".format(port)) temp.append("br{}_0".format(port))
for wl in range(self.bitcell_loads): for wl in range(self.bitcell_loads):
for port in range(self.total_ports): for port in self.all_ports:
temp.append("gnd") temp.append("gnd")
temp.append("vdd") temp.append("vdd")
temp.append("gnd") temp.append("gnd")
@ -195,7 +195,7 @@ class replica_bitline(design.design):
self.add_power_pin("gnd", pin_extension) self.add_power_pin("gnd", pin_extension)
# for multiport, need to short wordlines to each other so they all connect to gnd. # for multiport, need to short wordlines to each other so they all connect to gnd.
wl_last = self.wl_list[self.total_ports-1]+"_{}".format(row) wl_last = self.wl_list[-1]+"_{}".format(row)
pin_last = self.rbl_inst.get_pin(wl_last) pin_last = self.rbl_inst.get_pin(wl_last)
self.short_wordlines(pin, pin_last, "right", False, row, vector(self.m3_pitch,0)) self.short_wordlines(pin, pin_last, "right", False, row, vector(self.m3_pitch,0))
@ -203,7 +203,7 @@ class replica_bitline(design.design):
"""Connects the word lines together for a single bitcell. Also requires which side of the bitcell to short the pins.""" """Connects the word lines together for a single bitcell. Also requires which side of the bitcell to short the pins."""
#Assumes input pins are wordlines. Also assumes the word lines are horizontal in metal1. Also assumes pins have same x coord. #Assumes input pins are wordlines. Also assumes the word lines are horizontal in metal1. Also assumes pins have same x coord.
#This is my (Hunter) first time editing layout in openram so this function is likely not optimal. #This is my (Hunter) first time editing layout in openram so this function is likely not optimal.
if self.total_ports > 1: if len(self.all_ports) > 1:
#1. Create vertical metal for all the bitlines to connect to #1. Create vertical metal for all the bitlines to connect to
#m1 needs to be extended in the y directions, direction needs to be determined as every other cell is flipped #m1 needs to be extended in the y directions, direction needs to be determined as every other cell is flipped
correct_y = vector(0, 0.5*drc("minwidth_metal1")) correct_y = vector(0, 0.5*drc("minwidth_metal1"))
@ -234,7 +234,7 @@ class replica_bitline(design.design):
debug.error("Could not connect wordlines on specified input side={}".format(pin_side),1) debug.error("Could not connect wordlines on specified input side={}".format(pin_side),1)
#2. Connect word lines horizontally. Only replica cell needs. Bitline loads currently already do this. #2. Connect word lines horizontally. Only replica cell needs. Bitline loads currently already do this.
for port in range(self.total_ports): for port in self.all_ports:
if is_replica_cell: if is_replica_cell:
wl = self.wl_list[port] wl = self.wl_list[port]
pin = self.rbc_inst.get_pin(wl) pin = self.rbc_inst.get_pin(wl)
@ -319,7 +319,7 @@ class replica_bitline(design.design):
# 4. Short wodlines if multiport # 4. Short wodlines if multiport
wl = self.wl_list[0] wl = self.wl_list[0]
wl_last = self.wl_list[self.total_ports-1] wl_last = self.wl_list[-1]
pin = self.rbc_inst.get_pin(wl) pin = self.rbc_inst.get_pin(wl)
pin_last = self.rbc_inst.get_pin(wl_last) pin_last = self.rbc_inst.get_pin(wl_last)
x_offset = self.short_wordlines(pin, pin_last, "left", True) x_offset = self.short_wordlines(pin, pin_last, "left", True)

View File

@ -57,7 +57,7 @@ class sram_1bank(sram_base):
# the sense amps/column mux and cell array) # the sense amps/column mux and cell array)
# The x-coordinate is placed to allow a single clock wire (plus an extra pitch) # The x-coordinate is placed to allow a single clock wire (plus an extra pitch)
# up to the row address DFFs. # up to the row address DFFs.
for port in range(self.total_ports): for port in self.all_ports:
control_pos = vector(-self.control_logic.width - 2*self.m2_pitch, control_pos = vector(-self.control_logic.width - 2*self.m2_pitch,
self.bank.bank_center.y - self.control_logic.control_logic_center.y) self.bank.bank_center.y - self.control_logic.control_logic_center.y)
self.control_logic_inst[port].place(control_pos) self.control_logic_inst[port].place(control_pos)
@ -94,13 +94,14 @@ class sram_1bank(sram_base):
""" """
Add the top-level pins for a single bank SRAM with control. Add the top-level pins for a single bank SRAM with control.
""" """
for port in range(self.total_ports): for port in self.all_ports:
# Connect the control pins as inputs # Connect the control pins as inputs
for signal in self.control_logic_inputs[port] + ["clk"]: for signal in self.control_logic_inputs[port] + ["clk"]:
self.copy_layout_pin(self.control_logic_inst[port], signal, signal+"{}".format(port)) self.copy_layout_pin(self.control_logic_inst[port], signal, signal+"{}".format(port))
for bit in range(self.word_size): if port in self.read_ports:
self.copy_layout_pin(self.bank_inst, "dout{0}_{1}".format(port,bit), "DOUT{0}[{1}]".format(port,bit)) for bit in range(self.word_size):
self.copy_layout_pin(self.bank_inst, "dout{0}_{1}".format(port,bit), "DOUT{0}[{1}]".format(port,bit))
# Lower address bits # Lower address bits
for bit in range(self.col_addr_size): for bit in range(self.col_addr_size):
@ -109,8 +110,9 @@ class sram_1bank(sram_base):
for bit in range(self.row_addr_size): for bit in range(self.row_addr_size):
self.copy_layout_pin(self.row_addr_dff_inst[port], "din_{}".format(bit),"ADDR{0}[{1}]".format(port,bit+self.col_addr_size)) self.copy_layout_pin(self.row_addr_dff_inst[port], "din_{}".format(bit),"ADDR{0}[{1}]".format(port,bit+self.col_addr_size))
for bit in range(self.word_size): if port in self.write_ports:
self.copy_layout_pin(self.data_dff_inst[port], "din_{}".format(bit), "DIN{0}[{1}]".format(port,bit)) for bit in range(self.word_size):
self.copy_layout_pin(self.data_dff_inst[port], "din_{}".format(bit), "DIN{0}[{1}]".format(port,bit))
def route(self): def route(self):
""" Route a single bank SRAM """ """ Route a single bank SRAM """
@ -132,7 +134,7 @@ class sram_1bank(sram_base):
""" Route the clock network """ """ Route the clock network """
# This is the actual input to the SRAM # This is the actual input to the SRAM
for port in range(self.total_ports): for port in self.all_ports:
self.copy_layout_pin(self.control_logic_inst[port], "clk", "clk{}".format(port)) self.copy_layout_pin(self.control_logic_inst[port], "clk", "clk{}".format(port))
# Connect all of these clock pins to the clock in the central bus # Connect all of these clock pins to the clock in the central bus
@ -172,7 +174,7 @@ class sram_1bank(sram_base):
def route_control_logic(self): def route_control_logic(self):
""" Route the outputs from the control logic module """ """ Route the outputs from the control logic module """
for port in range(self.total_ports): for port in self.all_ports:
for signal in self.control_logic_outputs[port]: for signal in self.control_logic_outputs[port]:
src_pin = self.control_logic_inst[port].get_pin(signal) src_pin = self.control_logic_inst[port].get_pin(signal)
dest_pin = self.bank_inst.get_pin(signal+"{}".format(port)) dest_pin = self.bank_inst.get_pin(signal+"{}".format(port))
@ -184,7 +186,7 @@ class sram_1bank(sram_base):
def route_row_addr_dff(self): def route_row_addr_dff(self):
""" Connect the output of the row flops to the bank pins """ """ Connect the output of the row flops to the bank pins """
for port in range(self.total_ports): for port in self.all_ports:
for bit in range(self.row_addr_size): for bit in range(self.row_addr_size):
flop_name = "dout_{}".format(bit) flop_name = "dout_{}".format(bit)
bank_name = "addr{0}_{1}".format(port,bit+self.col_addr_size) bank_name = "addr{0}_{1}".format(port,bit+self.col_addr_size)
@ -200,7 +202,7 @@ class sram_1bank(sram_base):
def route_col_addr_dff(self): def route_col_addr_dff(self):
""" Connect the output of the row flops to the bank pins """ """ Connect the output of the row flops to the bank pins """
for port in range(self.total_ports): for port in self.all_ports:
bus_names = ["addr_{}".format(x) for x in range(self.col_addr_size)] bus_names = ["addr_{}".format(x) for x in range(self.col_addr_size)]
col_addr_bus_offsets = self.create_horizontal_bus(layer="metal1", col_addr_bus_offsets = self.create_horizontal_bus(layer="metal1",
pitch=self.m1_pitch, pitch=self.m1_pitch,
@ -220,7 +222,7 @@ class sram_1bank(sram_base):
def route_data_dff(self): def route_data_dff(self):
""" Connect the output of the data flops to the write driver """ """ Connect the output of the data flops to the write driver """
# This is where the channel will start (y-dimension at least) # This is where the channel will start (y-dimension at least)
for port in range(self.total_write): for port in self.write_ports:
offset = self.data_dff_inst[port].ul() + vector(0, self.m1_pitch) offset = self.data_dff_inst[port].ul() + vector(0, self.m1_pitch)
dff_names = ["dout_{}".format(x) for x in range(self.word_size)] dff_names = ["dout_{}".format(x) for x in range(self.word_size)]

View File

@ -24,38 +24,38 @@ class sram_base(design):
def add_pins(self): def add_pins(self):
""" Add pins for entire SRAM. """ """ Add pins for entire SRAM. """
for port in range(self.total_write): for port in self.write_ports:
for bit in range(self.word_size): for bit in range(self.word_size):
self.add_pin("DIN{0}[{1}]".format(port,bit),"INPUT") self.add_pin("DIN{0}[{1}]".format(port,bit),"INPUT")
for port in range(self.total_ports): for port in self.all_ports:
for bit in range(self.addr_size): for bit in range(self.addr_size):
self.add_pin("ADDR{0}[{1}]".format(port,bit),"INPUT") self.add_pin("ADDR{0}[{1}]".format(port,bit),"INPUT")
# These are used to create the physical pins # These are used to create the physical pins
self.control_logic_inputs = [] self.control_logic_inputs = []
self.control_logic_outputs = [] self.control_logic_outputs = []
for port in range(self.total_ports): for port in self.all_ports:
if self.port_id[port] == "rw": if port in self.readwrite_ports:
self.control_logic_inputs.append(self.control_logic_rw.get_inputs()) self.control_logic_inputs.append(self.control_logic_rw.get_inputs())
self.control_logic_outputs.append(self.control_logic_rw.get_outputs()) self.control_logic_outputs.append(self.control_logic_rw.get_outputs())
elif self.port_id[port] == "w": elif port in self.write_ports:
self.control_logic_inputs.append(self.control_logic_w.get_inputs()) self.control_logic_inputs.append(self.control_logic_w.get_inputs())
self.control_logic_outputs.append(self.control_logic_w.get_outputs()) self.control_logic_outputs.append(self.control_logic_w.get_outputs())
else: else:
self.control_logic_inputs.append(self.control_logic_r.get_inputs()) self.control_logic_inputs.append(self.control_logic_r.get_inputs())
self.control_logic_outputs.append(self.control_logic_r.get_outputs()) self.control_logic_outputs.append(self.control_logic_r.get_outputs())
for port in range(self.total_ports): for port in self.all_ports:
self.add_pin("csb{}".format(port),"INPUT") self.add_pin("csb{}".format(port),"INPUT")
for port in range(self.num_rw_ports): for port in self.readwrite_ports:
self.add_pin("web{}".format(port),"INPUT") self.add_pin("web{}".format(port),"INPUT")
for port in range(self.total_ports): for port in self.all_ports:
self.add_pin("clk{}".format(port),"INPUT") self.add_pin("clk{}".format(port),"INPUT")
for port in range(self.total_read): for port in self.read_ports:
for bit in range(self.word_size): for bit in range(self.word_size):
self.add_pin("DOUT{0}[{1}]".format(self.read_index[port],bit),"OUTPUT") self.add_pin("DOUT{0}[{1}]".format(port,bit),"OUTPUT")
self.add_pin("vdd","POWER") self.add_pin("vdd","POWER")
self.add_pin("gnd","GROUND") self.add_pin("gnd","GROUND")
@ -138,7 +138,7 @@ class sram_base(design):
# Vertical bus # Vertical bus
# The order of the control signals on the control bus: # The order of the control signals on the control bus:
self.control_bus_names = [] self.control_bus_names = []
for port in range(self.total_ports): for port in self.all_ports:
self.control_bus_names[port] = ["clk_buf{}".format(port), "clk_buf_bar{}".format(port)] self.control_bus_names[port] = ["clk_buf{}".format(port), "clk_buf_bar{}".format(port)]
if (self.port_id[port] == "rw") or (self.port_id[port] == "w"): if (self.port_id[port] == "rw") or (self.port_id[port] == "w"):
self.control_bus_names[port].append("w_en{}".format(port)) self.control_bus_names[port].append("w_en{}".format(port))
@ -268,23 +268,23 @@ class sram_base(design):
mod=self.bank)) mod=self.bank))
temp = [] temp = []
for port in range(self.total_read): for port in self.read_ports:
for bit in range(self.word_size): for bit in range(self.word_size):
temp.append("DOUT{0}[{1}]".format(self.read_index[port],bit)) temp.append("DOUT{0}[{1}]".format(port,bit))
for port in range(self.total_write): for port in self.write_ports:
for bit in range(self.word_size): for bit in range(self.word_size):
temp.append("BANK_DIN{0}[{1}]".format(port,bit)) temp.append("BANK_DIN{0}[{1}]".format(port,bit))
for port in range(self.total_ports): for port in self.all_ports:
for bit in range(self.bank_addr_size): for bit in range(self.bank_addr_size):
temp.append("A{0}[{1}]".format(port,bit)) temp.append("A{0}[{1}]".format(port,bit))
if(self.num_banks > 1): if(self.num_banks > 1):
for port in range(self.total_ports): for port in self.all_ports:
temp.append("bank_sel{0}[{1}]".format(port,bank_num)) temp.append("bank_sel{0}[{1}]".format(port,bank_num))
for port in range(self.total_read): for port in self.read_ports:
temp.append("s_en{0}".format(self.read_index[port])) temp.append("s_en{0}".format(port))
for port in range(self.total_write): for port in self.readwrite_ports:
temp.append("w_en{0}".format(port)) temp.append("w_en{0}".format(port))
for port in range(self.total_ports): for port in self.all_ports:
temp.append("clk_buf_bar{0}".format(port)) temp.append("clk_buf_bar{0}".format(port))
temp.append("clk_buf{0}".format(port)) temp.append("clk_buf{0}".format(port))
temp.extend(["vdd", "gnd"]) temp.extend(["vdd", "gnd"])
@ -327,7 +327,7 @@ class sram_base(design):
def create_row_addr_dff(self): def create_row_addr_dff(self):
""" Add all address flops for the main decoder """ """ Add all address flops for the main decoder """
insts = [] insts = []
for port in range(self.total_ports): for port in self.all_ports:
insts.append(self.add_inst(name="row_address{}".format(port), insts.append(self.add_inst(name="row_address{}".format(port),
mod=self.row_addr_dff)) mod=self.row_addr_dff))
@ -346,7 +346,7 @@ class sram_base(design):
def create_col_addr_dff(self): def create_col_addr_dff(self):
""" Add and place all address flops for the column decoder """ """ Add and place all address flops for the column decoder """
insts = [] insts = []
for port in range(self.total_ports): for port in self.all_ports:
insts.append(self.add_inst(name="col_address{}".format(port), insts.append(self.add_inst(name="col_address{}".format(port),
mod=self.col_addr_dff)) mod=self.col_addr_dff))
@ -365,7 +365,7 @@ class sram_base(design):
def create_data_dff(self): def create_data_dff(self):
""" Add and place all data flops """ """ Add and place all data flops """
insts = [] insts = []
for port in range(self.total_write): for port in self.write_ports:
insts.append(self.add_inst(name="data_dff{}".format(port), insts.append(self.add_inst(name="data_dff{}".format(port),
mod=self.data_dff)) mod=self.data_dff))
@ -384,10 +384,10 @@ class sram_base(design):
def create_control_logic(self): def create_control_logic(self):
""" Add and place control logic """ """ Add and place control logic """
insts = [] insts = []
for port in range(self.total_ports): for port in self.all_ports:
if self.port_id[port] == "rw": if port in self.readwrite_ports:
mod = self.control_logic_rw mod = self.control_logic_rw
elif self.port_id[port] == "w": elif port in self.write_ports:
mod = self.control_logic_w mod = self.control_logic_w
else: else:
mod = self.control_logic_r mod = self.control_logic_r
@ -396,12 +396,12 @@ class sram_base(design):
mod=mod)) mod=mod))
temp = ["csb{}".format(port)] temp = ["csb{}".format(port)]
if self.port_id[port] == "rw": if port in self.readwrite_ports:
temp.append("web{}".format(port)) temp.append("web{}".format(port))
temp.append("clk{}".format(port)) temp.append("clk{}".format(port))
if (self.port_id[port] == "rw") or (self.port_id[port] == "r"): if port in self.read_ports:
temp.append("s_en{}".format(port)) temp.append("s_en{}".format(port))
if (self.port_id[port] == "rw") or (self.port_id[port] == "w"): if port in self.write_ports:
temp.append("w_en{}".format(port)) temp.append("w_en{}".format(port))
temp.extend(["clk_buf_bar{}".format(port), "clk_buf{}".format(port), "vdd", "gnd"]) temp.extend(["clk_buf_bar{}".format(port), "clk_buf{}".format(port), "vdd", "gnd"])
self.connect_inst(temp) self.connect_inst(temp)