diff --git a/compiler/globals.py b/compiler/globals.py index 991ec1ad..3bdc5f92 100644 --- a/compiler/globals.py +++ b/compiler/globals.py @@ -116,6 +116,11 @@ def init_openram(config_file, is_unit_test=True): import_tech() + init_paths() + + # This depends on the tech, so do it after tech is loaded + init_config() + # Reset the static duplicate name checker for unit tests. import hierarchy_design hierarchy_design.hierarchy_design.name_map=[] @@ -229,15 +234,6 @@ def read_config(config_file, is_unit_test=True): OPTS.num_r_ports, OPTS.tech_name) - # Don't delete the output dir, it may have other files! - # make the directory if it doesn't exist - try: - os.makedirs(OPTS.output_path, 0o750) - except OSError as e: - if e.errno == 17: # errno.EEXIST - os.chmod(OPTS.output_path, 0o750) - except: - debug.error("Unable to make output directory.",-1) def end_openram(): @@ -299,12 +295,6 @@ def setup_paths(): cleanup_paths() - # make the directory if it doesn't exist - try: - os.makedirs(OPTS.openram_temp, 0o750) - except OSError as e: - if e.errno == 17: # errno.EEXIST - os.chmod(OPTS.openram_temp, 0o750) def is_exe(fpath): @@ -320,7 +310,37 @@ def find_exe(check_exe): if is_exe(exe): return exe return None - + +def init_paths(): + """ Create the temp and output directory if it doesn't exist """ + + # make the directory if it doesn't exist + try: + os.makedirs(OPTS.openram_temp, 0o750) + except OSError as e: + if e.errno == 17: # errno.EEXIST + os.chmod(OPTS.openram_temp, 0o750) + + # Don't delete the output dir, it may have other files! + # make the directory if it doesn't exist + try: + os.makedirs(OPTS.output_path, 0o750) + except OSError as e: + if e.errno == 17: # errno.EEXIST + os.chmod(OPTS.output_path, 0o750) + except: + debug.error("Unable to make output directory.",-1) + +def init_config(): + """ Initialize the SRAM configurations. """ + # Create the SRAM configuration + from sram_config import sram_config + OPTS.sram_config = sram_config(OPTS.word_size, + OPTS.num_words, + OPTS.num_banks) + + + # imports correct technology directories for testing def import_tech(): global OPTS diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 6c22070a..f8e76a8b 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -29,6 +29,10 @@ class bank(design.design): design.design.__init__(self, name) debug.info(2, "create sram of size {0} with {1} words".format(self.word_size,self.num_words)) + + self.total_write = OPTS.num_rw_ports + OPTS.num_w_ports + self.total_read = OPTS.num_rw_ports + OPTS.num_r_ports + self.total_ports = OPTS.num_rw_ports + OPTS.num_w_ports + OPTS.num_r_ports # The local control signals are gated when we have bank select logic, # so this prefix will be added to all of the input signals to create diff --git a/compiler/modules/bitcell.py b/compiler/modules/bitcell.py index 38fd8823..4e741e24 100644 --- a/compiler/modules/bitcell.py +++ b/compiler/modules/bitcell.py @@ -50,16 +50,6 @@ class bitcell(design.design): row_pins = ["wl"] return row_pins - def list_read_wl_names(self): - """ Creates a list of wordline pin names associated with read ports """ - row_pins = ["wl"] - return row_pins - - def list_write_wl_names(self): - """ Creates a list of wordline pin names associated with write ports """ - row_pins = ["wl"] - return row_pins - def list_all_bitline_names(self): """ Creates a list of all bitline pin names (both bl and br) """ column_pins = ["bl", "br"] diff --git a/compiler/modules/delay_chain.py b/compiler/modules/delay_chain.py index b8a57f15..90175743 100644 --- a/compiler/modules/delay_chain.py +++ b/compiler/modules/delay_chain.py @@ -53,11 +53,6 @@ class delay_chain(design.design): self.add_pin("gnd") def add_modules(self): - from importlib import reload - c = reload(__import__(OPTS.bitcell)) - self.mod_bitcell = getattr(c, OPTS.bitcell) - self.bitcell = self.mod_bitcell() - self.inv = pinv(route_output=False) self.add_mod(self.inv) diff --git a/compiler/modules/hierarchical_decoder.py b/compiler/modules/hierarchical_decoder.py index 38136b62..0b44c8fc 100644 --- a/compiler/modules/hierarchical_decoder.py +++ b/compiler/modules/hierarchical_decoder.py @@ -24,7 +24,8 @@ class hierarchical_decoder(design.design): from importlib import reload c = reload(__import__(OPTS.bitcell)) self.mod_bitcell = getattr(c, OPTS.bitcell) - self.bitcell_height = self.mod_bitcell.height + b = self.mod_bitcell() + self.bitcell_height = b.height self.NAND_FORMAT = "DEC_NAND[{0}]" self.INV_FORMAT = "DEC_INV_[{0}]" @@ -130,7 +131,7 @@ class hierarchical_decoder(design.design): self.total_number_of_predecoder_outputs = 4*self.no_of_pre2x4 + 8*self.no_of_pre3x8 else: self.total_number_of_predecoder_outputs = 0 - debug.error("Not enough rows for a hierarchical decoder. Non-hierarchical not supported yet.",-1) + debug.error("Not enough rows ({}) for a hierarchical decoder. Non-hierarchical not supported yet.".format(self.num_inputs),-1) # Calculates height and width of pre-decoder, if self.no_of_pre3x8 > 0: diff --git a/compiler/modules/replica_bitcell.py b/compiler/modules/replica_bitcell.py index 5ec524f4..7bbdbe06 100644 --- a/compiler/modules/replica_bitcell.py +++ b/compiler/modules/replica_bitcell.py @@ -10,7 +10,7 @@ class replica_bitcell(design.design): is a hand-made cell, so the layout and netlist should be available in the technology library. """ - pin_names = ["BL", "BR", "WL", "vdd", "gnd"] + pin_names = ["bl", "br", "wl", "vdd", "gnd"] (width,height) = utils.get_libcell_size("replica_cell_6t", GDS["unit"], layer["boundary"]) pin_map = utils.get_libcell_pins(pin_names, "replica_cell_6t", GDS["unit"], layer["boundary"]) diff --git a/compiler/modules/replica_bitline.py b/compiler/modules/replica_bitline.py index b15f4515..6ca4a829 100644 --- a/compiler/modules/replica_bitline.py +++ b/compiler/modules/replica_bitline.py @@ -228,7 +228,7 @@ class replica_bitline(design.design): # 3. Route the contact of previous route to the bitcell WL # route bend of previous net to bitcell WL - wl_offset = self.rbc_inst.get_pin("WL").lc() + wl_offset = self.rbc_inst.get_pin("wl").lc() xmid_point= 0.5*(wl_offset.x+contact_offset.x) wl_mid1 = vector(xmid_point,contact_offset.y) wl_mid2 = vector(xmid_point,wl_offset.y) @@ -247,7 +247,7 @@ class replica_bitline(design.design): # Route the connection of the source route to the RBL bitline (left) # Via will go halfway down from the bitcell - bl_offset = self.rbc_inst.get_pin("BL").bc() + bl_offset = self.rbc_inst.get_pin("bl").bc() # Route down a pitch so we can use M2 routing bl_down_offset = bl_offset - vector(0, self.m2_pitch) self.add_path("metal2",[source_offset, bl_down_offset, bl_offset]) diff --git a/compiler/modules/sense_amp_array.py b/compiler/modules/sense_amp_array.py index a02ffd9d..c48d280d 100644 --- a/compiler/modules/sense_amp_array.py +++ b/compiler/modules/sense_amp_array.py @@ -57,10 +57,11 @@ class sense_amp_array(design.design): self.amp = self.mod_sense_amp("sense_amp") self.add_mod(self.amp) + # This is just used for measurements, + # so don't add the module c = reload(__import__(OPTS.bitcell)) self.mod_bitcell = getattr(c, OPTS.bitcell) self.bitcell = self.mod_bitcell() - self.add_mod(self.bitcell) def create_sense_amp_array(self): self.local_insts = [] diff --git a/compiler/modules/wordline_driver.py b/compiler/modules/wordline_driver.py index 87b0430e..3deac4e1 100644 --- a/compiler/modules/wordline_driver.py +++ b/compiler/modules/wordline_driver.py @@ -50,6 +50,13 @@ class wordline_driver(design.design): def add_modules(self): + # This is just used for measurements, + # so don't add the module + from importlib import reload + c = reload(__import__(OPTS.bitcell)) + self.mod_bitcell = getattr(c, OPTS.bitcell) + self.bitcell = self.mod_bitcell() + self.inv = pinv() self.add_mod(self.inv) @@ -59,11 +66,6 @@ class wordline_driver(design.design): self.nand2 = pnand2() self.add_mod(self.nand2) - from importlib import reload - c = reload(__import__(OPTS.bitcell)) - self.mod_bitcell = getattr(c, OPTS.bitcell) - self.bitcell = self.mod_bitcell() - self.add_mod(self.bitcell) def route_vdd_gnd(self): """ Add a pin for each row of vdd/gnd which are must-connects next level up. """ diff --git a/compiler/modules/write_driver_array.py b/compiler/modules/write_driver_array.py index 88d40c86..eff0c8d8 100644 --- a/compiler/modules/write_driver_array.py +++ b/compiler/modules/write_driver_array.py @@ -58,11 +58,12 @@ class write_driver_array(design.design): self.mod_write_driver = getattr(c, OPTS.write_driver) self.driver = self.mod_write_driver("write_driver") self.add_mod(self.driver) - + + # This is just used for measurements, + # so don't add the module c = reload(__import__(OPTS.bitcell)) self.mod_bitcell = getattr(c, OPTS.bitcell) self.bitcell = self.mod_bitcell() - self.add_mod(self.bitcell) def create_write_array(self): self.driver_insts = {} diff --git a/compiler/openram.py b/compiler/openram.py index a6db154d..e4ab593e 100755 --- a/compiler/openram.py +++ b/compiler/openram.py @@ -52,14 +52,13 @@ print(*output_files,sep="\n") start_time = datetime.datetime.now() print_time("Start",start_time) +# Configure the SRAM organization c = sram_config(word_size=OPTS.word_size, - num_words=OPTS.num_words, - num_rw_ports=OPTS.num_rw_ports, - num_w_ports=OPTS.num_w_ports, - num_r_ports=OPTS.num_r_ports) + num_words=OPTS.num_words) # import SRAM test generation -s = sram(c, OPTS.output_name) +s = sram(sram_config=c, + name=OPTS.output_name) # Output the files for the resulting SRAM s.save() diff --git a/compiler/options.py b/compiler/options.py index a81f7fae..5298c00f 100644 --- a/compiler/options.py +++ b/compiler/options.py @@ -55,11 +55,17 @@ class options(optparse.Values): num_rw_ports = 1 num_r_ports = 0 num_w_ports = 0 + # These will get initialized by the the file supply_voltages = "" temperatures = "" process_corners = "" - + + # These are the main configuration parameters that should be over-ridden + # in a configuration file. + #num_words = 0 + #num_banks = 1 + #word_size = 0 # These are the default modules that can be over-riden decoder = "hierarchical_decoder" diff --git a/compiler/pgates/pbitcell.py b/compiler/pgates/pbitcell.py index eb3ccf91..24fdfb60 100644 --- a/compiler/pgates/pbitcell.py +++ b/compiler/pgates/pbitcell.py @@ -1,5 +1,4 @@ import contact -import pgate import design import debug from tech import drc, parameter, spice @@ -7,47 +6,42 @@ from vector import vector from ptx import ptx from globals import OPTS -class pbitcell(pgate.pgate): +class pbitcell(design.design): """ This module implements a parametrically sized multi-port bitcell, with a variable number of read/write, write, and read ports """ - - width = None - height = None - unique_id = 1 - - def __init__(self, num_readwrite=OPTS.num_rw_ports, num_write=OPTS.num_w_ports, num_read=OPTS.num_r_ports): - name = "pbitcell_{0}RW_{1}W_{2}R_{3}".format(num_readwrite, num_write, num_read, pbitcell.unique_id) - pbitcell.unique_id += 1 - pgate.pgate.__init__(self, name) - debug.info(2, "create a multi-port bitcell with {0} write ports and {1} read ports".format(num_write, num_read)) + def __init__(self): - self.num_readwrite = num_readwrite - self.num_write = num_write - self.num_read = num_read - self.total_ports = num_readwrite + num_write + num_read + self.num_rw_ports = OPTS.num_rw_ports + self.num_w_ports = OPTS.num_w_ports + self.num_r_ports = OPTS.num_r_ports + self.total_ports = self.num_rw_ports + self.num_w_ports + self.num_r_ports + + name = "pbitcell_{0}RW_{1}W_{2}R".format(self.num_rw_ports, self.num_w_ports, self.num_r_ports) + # This is not a pgate because pgates depend on the bitcell height! + design.design.__init__(self, name) + debug.info(2, "create a multi-port bitcell with {0} rw ports, {1} w ports and {2} r ports".format(self.num_rw_ports, + self.num_w_ports, + self.num_r_ports)) self.create_netlist() - if not OPTS.netlist_only: - self.create_layout() + # We must always create the bitcell layout because + # some transistor sizes in the other netlists depend on it + self.create_layout() - # Since since pbitcell's size is dependent on port choice, class width and height are set after layout creation - # class width and height are necessary for modules that load bitcell attributes - pbitcell.width = self.width - pbitcell.height = self.height def create_netlist(self): self.add_pins() self.add_modules() self.create_storage() - if(self.num_readwrite > 0): + if(self.num_rw_ports > 0): self.create_readwrite_ports() - if(self.num_write > 0): + if(self.num_w_ports > 0): self.create_write_ports() - if(self.num_read > 0): + if(self.num_r_ports > 0): self.create_read_ports() def create_layout(self): @@ -58,18 +52,18 @@ class pbitcell(pgate.pgate): self.route_storage() self.route_rails() - if(self.num_readwrite > 0): + if(self.num_rw_ports > 0): self.place_readwrite_ports() self.route_readwrite_wordlines() self.route_readwrite_bitlines() - if(self.num_write == 0): # routing for write to storage is the same as read/write to storage + if(self.num_w_ports == 0): # routing for write to storage is the same as read/write to storage self.route_readwrite_access() - if(self.num_write > 0): + if(self.num_w_ports > 0): self.place_write_ports() self.route_write_wordlines() self.route_write_bitlines() self.route_write_access() - if(self.num_read > 0): + if(self.num_r_ports > 0): self.place_read_ports() self.route_read_wordlines() self.route_read_bitlines() @@ -86,22 +80,24 @@ class pbitcell(pgate.pgate): self.w_br_names = [] self.r_bl_names = [] self.r_br_names = [] - self.wl_names = [] + self.rw_wl_names = [] + self.w_wl_names = [] + self.r_wl_names = [] port = 0 - for k in range(self.num_readwrite): + for k in range(self.num_rw_ports): self.add_pin("bl{}".format(port)) self.add_pin("br{}".format(port)) self.rw_bl_names.append("bl{}".format(port)) self.rw_br_names.append("br{}".format(port)) port += 1 - for k in range(self.num_write): + for k in range(self.num_w_ports): self.add_pin("bl{}".format(port)) self.add_pin("br{}".format(port)) self.w_bl_names.append("bl{}".format(port)) self.w_br_names.append("br{}".format(port)) port += 1 - for k in range(self.num_read): + for k in range(self.num_r_ports): self.add_pin("bl{}".format(port)) self.add_pin("br{}".format(port)) self.r_bl_names.append("bl{}".format(port)) @@ -109,20 +105,30 @@ class pbitcell(pgate.pgate): port += 1 port = 0 - for k in range(self.total_ports): + for k in range(self.num_rw_ports): self.add_pin("wl{}".format(port)) - self.wl_names.append("wl{}".format(port)) + self.rw_wl_names.append("wl{}".format(port)) + port += 1 + for k in range(self.num_w_ports): + self.add_pin("wl{}".format(port)) + self.w_wl_names.append("wl{}".format(port)) + port += 1 + for k in range(self.num_r_ports): + self.add_pin("wl{}".format(port)) + self.r_wl_names.append("wl{}".format(port)) + port += 1 self.add_pin("vdd") self.add_pin("gnd") + def add_modules(self): """ Determine size of transistors and add ptx modules """ # if there are any read/write ports, then the inverter nmos is sized based the number of read/write ports - if(self.num_readwrite > 0): - inverter_nmos_width = self.num_readwrite*3*parameter["min_tx_size"] + if(self.num_rw_ports > 0): + inverter_nmos_width = self.num_rw_ports*3*parameter["min_tx_size"] inverter_pmos_width = parameter["min_tx_size"] readwrite_nmos_width = 1.5*parameter["min_tx_size"] write_nmos_width = parameter["min_tx_size"] @@ -197,7 +203,7 @@ class pbitcell(pgate.pgate): # write to read transistor spacing (also acts as readwrite to read transistor spacing) # calculation is dependent on whether the read transistor is adjacent to a write transistor or a readwrite transistor - if(self.num_write > 0): + if(self.num_w_ports > 0): if(self.write_nmos_contact_extension > self.gate_contact_thres): write_portion = drc["minwidth_metal2"] + self.write_nmos_contact_extension else: @@ -236,23 +242,23 @@ class pbitcell(pgate.pgate): Calculate positions that describe the edges and dimensions of the cell """ # create flags for excluding readwrite, write, or read port calculations if they are not included in the bitcell - if(self.num_readwrite > 0): + if(self.num_rw_ports > 0): self.readwrite_port_flag = True else: self.readwrite_port_flag = False - if(self.num_write > 0): + if(self.num_w_ports > 0): self.write_port_flag = True else: self.write_port_flag = False - if(self.num_read > 0): + if(self.num_r_ports > 0): self.read_port_flag = True else: self.read_port_flag = False # determine the distance of the leftmost/rightmost transistor gate connection - if (self.num_read > 0): + if (self.num_r_ports > 0): if(self.read_nmos_contact_extension > self.gate_contact_thres): end_connection = drc["minwidth_metal2"] + self.read_nmos_contact_extension + contact.m1m2.height else: @@ -266,11 +272,11 @@ class pbitcell(pgate.pgate): # leftmost position = storage width + read/write ports width + write ports width + read ports width + end transistor gate connections + metal spacing necessary for tiling the bitcell self.leftmost_xpos = -self.inverter_tile_width \ - self.inverter_to_write_spacing \ - - self.readwrite_port_flag*(self.readwrite_nmos.active_height + (self.num_readwrite-1)*self.readwrite_tile_width) \ + - self.readwrite_port_flag*(self.readwrite_nmos.active_height + (self.num_rw_ports-1)*self.readwrite_tile_width) \ - self.write_port_flag*self.readwrite_port_flag*self.write_to_write_spacing \ - - self.write_port_flag*(self.write_nmos.active_height + (self.num_write-1)*self.write_tile_width) \ + - self.write_port_flag*(self.write_nmos.active_height + (self.num_w_ports-1)*self.write_tile_width) \ - self.read_port_flag*self.write_to_read_spacing \ - - self.read_port_flag*(self.read_nmos.active_height + (self.num_read-1)*self.read_tile_width) \ + - self.read_port_flag*(self.read_nmos.active_height + (self.num_r_ports-1)*self.read_tile_width) \ - end_connection \ - 0.5*drc["poly_to_polycontact"] @@ -279,9 +285,9 @@ class pbitcell(pgate.pgate): # bottommost position = gnd height + rwwl height + wwl height + rwl height + space needed between tiled bitcells array_tiling_offset = 0.5*drc["minwidth_metal2"] self.botmost_ypos = -self.rail_tile_height \ - - self.num_readwrite*self.rowline_tile_height \ - - self.num_write*self.rowline_tile_height \ - - self.num_read*self.rowline_tile_height \ + - self.num_rw_ports*self.rowline_tile_height \ + - self.num_w_ports*self.rowline_tile_height \ + - self.num_r_ports*self.rowline_tile_height \ - array_tiling_offset # topmost position = height of the inverter + height of vdd @@ -420,19 +426,19 @@ class pbitcell(pgate.pgate): """ # define write transistor variables as empty arrays based on the number of write ports - self.readwrite_nmos_left = [None] * self.num_readwrite - self.readwrite_nmos_right = [None] * self.num_readwrite + self.readwrite_nmos_left = [None] * self.num_rw_ports + self.readwrite_nmos_right = [None] * self.num_rw_ports # iterate over the number of read/write ports - for k in range(0,self.num_readwrite): + for k in range(0,self.num_rw_ports): # add read/write transistors self.readwrite_nmos_left[k] = self.add_inst(name="readwrite_nmos_left{}".format(k), mod=self.readwrite_nmos) - self.connect_inst(["Q", "rwwl{}".format(k), "rwbl{}".format(k), "gnd"]) + self.connect_inst(["Q", self.rw_wl_names[k], self.rw_bl_names[k], "gnd"]) self.readwrite_nmos_right[k] = self.add_inst(name="readwrite_nmos_right{}".format(k), mod=self.readwrite_nmos) - self.connect_inst(["Q_bar", "rwwl{}".format(k), "rwbl_bar{}".format(k), "gnd"]) + self.connect_inst(["Q_bar", self.rw_wl_names[k], self.rw_br_names[k], "gnd"]) def place_readwrite_ports(self): @@ -441,15 +447,15 @@ class pbitcell(pgate.pgate): """ # Define variables relevant to write transistors - self.rwwl_positions = [None] * self.num_readwrite - self.rwbl_positions = [None] * self.num_readwrite - self.rwbl_bar_positions = [None] * self.num_readwrite + self.rwwl_positions = [None] * self.num_rw_ports + self.rwbl_positions = [None] * self.num_rw_ports + self.rwbl_bar_positions = [None] * self.num_rw_ports # define offset correction due to rotation of the ptx module readwrite_rotation_correct = self.readwrite_nmos.active_height # iterate over the number of read/write ports - for k in range(0,self.num_readwrite): + for k in range(0,self.num_rw_ports): # Add transistors # calculate read/write transistor offsets left_readwrite_transistor_xpos = self.left_building_edge \ @@ -504,14 +510,14 @@ class pbitcell(pgate.pgate): """ Routes read/write trnasistors to their respective wordlines """ - for k in range(0,self.num_readwrite): + for k in range(0,self.num_rw_ports): # Gate/RWWL connections # add poly-to-meltal2 contacts to connect gate of read/write transistors to RWWL (contact next to gate) # contact must be placed a metal1 width below the source pin to avoid drc from source pin routings if(self.readwrite_nmos_contact_extension > self.gate_contact_thres): contact_xpos = self.readwrite_nmos_left[k].get_pin("S").lc().x - drc["minwidth_metal2"] - 0.5*contact.m1m2.width else: - contact_xpos = left_readwrite_transistor_xpos - self.readwrite_nmos.active_height - drc["poly_to_active"] - 0.5*contact.poly.width + contact_xpos = self.readwrite_nmos_left[k].offset.x - self.readwrite_nmos.active_height - drc["poly_to_active"] - 0.5*contact.poly.width contact_ypos = self.readwrite_nmos_left[k].get_pin("D").bc().y - drc["minwidth_metal1"] - 0.5*contact.m1m2.height left_gate_contact = vector(contact_xpos, contact_ypos) @@ -523,7 +529,7 @@ class pbitcell(pgate.pgate): if(self.readwrite_nmos_contact_extension > self.gate_contact_thres): contact_xpos = self.readwrite_nmos_right[k].get_pin("S").rc().x + drc["minwidth_metal2"] + 0.5*contact.m1m2.width else: - contact_xpos = right_readwrite_transistor_xpos + drc["poly_to_active"] + 0.5*contact.poly.width + contact_xpos = self.readwrite_nmos_right[k].offset.x + drc["poly_to_active"] + 0.5*contact.poly.width contact_ypos = self.readwrite_nmos_right[k].get_pin("D").bc().y - drc["minwidth_metal1"] - 0.5*contact.m1m2.height right_gate_contact = vector(contact_xpos, contact_ypos) @@ -559,7 +565,7 @@ class pbitcell(pgate.pgate): """ Routes read/write transistors to their respective bitlines """ - for k in range(0,self.num_readwrite): + for k in range(0,self.num_rw_ports): # Source/RWBL/RWBL_bar connections # add metal1-to-metal2 contacts on top of read/write transistor source pins for connection to WBL and WBL_bar offset_left = self.readwrite_nmos_left[k].get_pin("S").center() @@ -577,7 +583,7 @@ class pbitcell(pgate.pgate): """ Routes read/write transistors to the storage component of the bitcell """ - last_inst = self.num_readwrite - 1 + last_inst = self.num_rw_ports - 1 # Drain/Storage connections # this path only needs to be drawn once on the last iteration of the loop @@ -624,19 +630,19 @@ class pbitcell(pgate.pgate): write_rotation_correct = self.write_nmos.active_height # define write transistor variables as empty arrays based on the number of write ports - self.write_nmos_left = [None] * self.num_write - self.write_nmos_right = [None] * self.num_write + self.write_nmos_left = [None] * self.num_w_ports + self.write_nmos_right = [None] * self.num_w_ports # iterate over the number of write ports - for k in range(0,self.num_write): + for k in range(0,self.num_w_ports): # add write transistors self.write_nmos_left[k] = self.add_inst(name="write_nmos_left{}".format(k), mod=self.write_nmos) - self.connect_inst(["Q", "wwl{}".format(k), "wbl{}".format(k), "gnd"]) + self.connect_inst(["Q", self.w_wl_names[k], self.w_bl_names[k], "gnd"]) self.write_nmos_right[k] = self.add_inst(name="write_nmos_right{}".format(k), mod=self.write_nmos) - self.connect_inst(["Q_bar", "wwl{}".format(k), "wbl_bar{}".format(k), "gnd"]) + self.connect_inst(["Q_bar", self.w_wl_names[k], self.w_br_names[k], "gnd"]) def place_write_ports(self): @@ -644,15 +650,15 @@ class pbitcell(pgate.pgate): Places write ports in the bit cell. """ # Define variables relevant to write transistors - self.wwl_positions = [None] * self.num_write - self.wbl_positions = [None] * self.num_write - self.wbl_bar_positions = [None] * self.num_write + self.wwl_positions = [None] * self.num_w_ports + self.wbl_positions = [None] * self.num_w_ports + self.wbl_bar_positions = [None] * self.num_w_ports # define offset correction due to rotation of the ptx module write_rotation_correct = self.write_nmos.active_height # iterate over the number of write ports - for k in range(0,self.num_write): + for k in range(0,self.num_w_ports): # Add transistors # calculate write transistor offsets left_write_transistor_xpos = self.left_building_edge \ @@ -677,7 +683,7 @@ class pbitcell(pgate.pgate): # Add WWL lines # calculate WWL position wwl_ypos = self.gnd_position.y \ - - self.num_readwrite*self.rowline_tile_height \ + - self.num_rw_ports*self.rowline_tile_height \ - (k+1)*self.rowline_tile_height self.wwl_positions[k] = vector(self.leftmost_xpos, wwl_ypos) @@ -711,14 +717,14 @@ class pbitcell(pgate.pgate): """ Routes write transistors to their respective wordlines """ - for k in range(0,self.num_write): + for k in range(0,self.num_w_ports): # Gate/WWL connections # add poly-to-meltal2 contacts to connect gate of write transistors to WWL (contact next to gate) # contact must be placed a metal width below the source pin to avoid drc from source pin routings if(self.write_nmos_contact_extension > self.gate_contact_thres): contact_xpos = self.write_nmos_left[k].get_pin("S").lc().x - drc["minwidth_metal2"] - 0.5*contact.m1m2.width else: - contact_xpos = left_write_transistor_xpos - self.write_nmos.active_height - drc["poly_to_active"] - 0.5*contact.poly.width + contact_xpos = self.write_nmos_left[k].offset.x - self.write_nmos.active_height - drc["poly_to_active"] - 0.5*contact.poly.width contact_ypos = self.write_nmos_left[k].get_pin("D").bc().y - drc["minwidth_metal1"] - 0.5*contact.m1m2.height left_gate_contact = vector(contact_xpos, contact_ypos) @@ -730,7 +736,7 @@ class pbitcell(pgate.pgate): if(self.write_nmos_contact_extension > self.gate_contact_thres): contact_xpos = self.write_nmos_right[k].get_pin("S").rc().x + drc["minwidth_metal2"] + 0.5*contact.m1m2.width else: - contact_xpos = right_write_transistor_xpos + drc["poly_to_active"] + 0.5*contact.poly.width + contact_xpos = self.write_nmos_right[k].offset.x + drc["poly_to_active"] + 0.5*contact.poly.width contact_ypos = self.write_nmos_right[k].get_pin("D").bc().y - drc["minwidth_metal1"] - 0.5*contact.m1m2.height right_gate_contact = vector(contact_xpos, contact_ypos) @@ -765,7 +771,7 @@ class pbitcell(pgate.pgate): """ Routes write transistors to their respective bitlines """ - for k in range(0,self.num_write): + for k in range(0,self.num_w_ports): # Source/WBL/WBL_bar connections # add metal1-to-metal2 contacts on top of write transistor source pins for connection to WBL and WBL_bar offset_left = self.write_nmos_left[k].get_pin("S").center() @@ -782,7 +788,7 @@ class pbitcell(pgate.pgate): """ Routes write transistors to the storage component of the bitcell """ - last_inst = self.num_write - 1 + last_inst = self.num_w_ports - 1 # Drain/Storage connections # this path only needs to be drawn once on the last iteration of the loop @@ -829,13 +835,13 @@ class pbitcell(pgate.pgate): """ # define read transistor variables as empty arrays based on the number of read ports - self.read_nmos_left = [None] * self.num_read - self.read_nmos_right = [None] * self.num_read - self.read_access_nmos_left = [None] * self.num_read - self.read_access_nmos_right = [None] * self.num_read + self.read_nmos_left = [None] * self.num_r_ports + self.read_nmos_right = [None] * self.num_r_ports + self.read_access_nmos_left = [None] * self.num_r_ports + self.read_access_nmos_right = [None] * self.num_r_ports # iterate over the number of read ports - for k in range(0,self.num_read): + for k in range(0,self.num_r_ports): # add read-access transistors self.read_access_nmos_left[k] = self.add_inst(name="read_access_nmos_left{}".format(k), mod=self.read_nmos) @@ -848,20 +854,20 @@ class pbitcell(pgate.pgate): # add read transistors self.read_nmos_left[k] = self.add_inst(name="read_nmos_left{}".format(k), mod=self.read_nmos) - self.connect_inst(["rbl{}".format(k), "rwl{}".format(k), "RA_to_R_left{}".format(k), "gnd"]) + self.connect_inst([self.r_bl_names[k], self.r_wl_names[k], "RA_to_R_left{}".format(k), "gnd"]) self.read_nmos_right[k] = self.add_inst(name="read_nmos_right{}".format(k), mod=self.read_nmos) - self.connect_inst(["rbl_bar{}".format(k), "rwl{}".format(k), "RA_to_R_right{}".format(k), "gnd"]) + self.connect_inst([self.r_br_names[k], self.r_wl_names[k], "RA_to_R_right{}".format(k), "gnd"]) def place_read_ports(self): """ Places the read ports in the bit cell. """ # Define variables relevant to read transistors - self.rwl_positions = [None] * self.num_read - self.rbl_positions = [None] * self.num_read - self.rbl_bar_positions = [None] * self.num_read + self.rwl_positions = [None] * self.num_r_ports + self.rbl_positions = [None] * self.num_r_ports + self.rbl_bar_positions = [None] * self.num_r_ports # define offset correction due to rotation of the ptx module read_rotation_correct = self.read_nmos.active_height @@ -870,7 +876,7 @@ class pbitcell(pgate.pgate): overlap_offset = self.read_nmos.get_pin("D").ll() - self.read_nmos.get_pin("S").ll() # iterate over the number of read ports - for k in range(0,self.num_read): + for k in range(0,self.num_r_ports): # Add transistors # calculate transistor offsets left_read_transistor_xpos = self.left_building_edge \ @@ -900,8 +906,8 @@ class pbitcell(pgate.pgate): # Add RWL lines # calculate RWL position rwl_ypos = self.gnd_position.y \ - - self.num_readwrite*self.rowline_tile_height \ - - self.num_write*self.rowline_tile_height \ + - self.num_rw_ports*self.rowline_tile_height \ + - self.num_w_ports*self.rowline_tile_height \ - (k+1)*self.rowline_tile_height self.rwl_positions[k] = vector(self.leftmost_xpos, rwl_ypos) @@ -931,13 +937,13 @@ class pbitcell(pgate.pgate): """ Routes read transistors to their respective worlines """ - for k in range(0,self.num_read): + for k in range(0,self.num_r_ports): # Gate of read transistor / RWL connection # add poly-to-meltal2 contacts to connect gate of read transistors to RWL (contact next to gate) if(self.read_nmos_contact_extension > self.gate_contact_thres): contact_xpos = self.read_nmos_left[k].get_pin("S").lc().x - drc["minwidth_metal2"] - 0.5*contact.m1m2.width else: - contact_xpos = left_read_transistor_xpos - self.read_nmos.active_height - drc["poly_to_active"] - 0.5*contact.poly.width + contact_xpos = self.read_nmos_left[k].offset.x - self.read_nmos.active_height - drc["poly_to_active"] - 0.5*contact.poly.width contact_ypos = self.read_nmos_left[k].get_pin("G").lc().y left_gate_contact = vector(contact_xpos, contact_ypos) @@ -949,7 +955,7 @@ class pbitcell(pgate.pgate): if(self.read_nmos_contact_extension > self.gate_contact_thres): contact_xpos = self.read_nmos_right[k].get_pin("S").rc().x + drc["minwidth_metal2"] + 0.5*contact.m1m2.width else: - contact_xpos = right_read_transistor_xpos + drc["poly_to_active"] + 0.5*contact.poly.width + contact_xpos = self.read_nmos_right[k].offset.x + drc["poly_to_active"] + 0.5*contact.poly.width contact_ypos = self.read_nmos_right[k].get_pin("G").rc().y right_gate_contact = vector(contact_xpos, contact_ypos) @@ -989,7 +995,7 @@ class pbitcell(pgate.pgate): """ Routes read transistors to their respective bitlines """ - for k in range(0,self.num_read): + for k in range(0,self.num_r_ports): # Drain of read transistor / RBL & RBL_bar connection # add metal1-to-metal2 contacts on top of read transistor drain pins for connection to RBL and RBL_bar offset_left = self.read_nmos_left[k].get_pin("D").center() @@ -1006,13 +1012,13 @@ class pbitcell(pgate.pgate): """ Routes read access transistors to the storage component of the bitcell """ - for k in range(0,self.num_read): + for k in range(0,self.num_r_ports): # Gate of read-access transistor / storage connection # add poly-to-metal1 contacts to connect gate of read-access transistors to output of inverters (contact next to gate) if(self.read_nmos_contact_extension > self.gate_contact_thres): contact_xpos = self.read_nmos_left[k].get_pin("S").rc().x + drc["minwidth_metal2"] + 0.5*contact.m1m2.width else: - contact_xpos = left_read_transistor_xpos + drc["poly_to_active"] + 0.5*contact.poly.width + contact_xpos = self.read_nmos_left[k].offset.x + drc["poly_to_active"] + 0.5*contact.poly.width contact_ypos = self.read_access_nmos_left[k].get_pin("G").rc().y left_gate_contact = vector(contact_xpos, contact_ypos) @@ -1022,7 +1028,7 @@ class pbitcell(pgate.pgate): if(self.read_nmos_contact_extension > self.gate_contact_thres): contact_xpos = self.read_nmos_right[k].get_pin("S").lc().x - drc["minwidth_metal2"] - 0.5*contact.m1m2.width else: - contact_xpos = right_read_transistor_xpos - self.read_nmos.active_height - drc["poly_to_active"] - 0.5*contact.poly.width + contact_xpos = self.read_nmos_right[k].offset.x - self.read_nmos.active_height - drc["poly_to_active"] - 0.5*contact.poly.width contact_ypos = self.read_access_nmos_right[k].get_pin("G").lc().y right_gate_contact = vector(contact_xpos, contact_ypos) @@ -1073,7 +1079,7 @@ class pbitcell(pgate.pgate): # extend pwell over read/write and write transistors to the # height of the write transistor well (read/write and write # transistors are the same height) - if(self.num_write > 0): + if(self.num_w_ports > 0): # calculate the edge of the write transistor well closest to the center left_write_well_xpos = self.write_nmos_left[0].offset.x + drc["well_enclosure_active"] right_write_well_xpos = self.write_nmos_right[0].offset.x - self.write_nmos.active_height - drc["well_enclosure_active"] @@ -1099,7 +1105,7 @@ class pbitcell(pgate.pgate): height=write_well_height) # extend pwell over the read transistors to the height of the bitcell - if(self.num_read > 0): + if(self.num_r_ports > 0): # calculate the edge of the read transistor well clostest to the center left_read_well_xpos = self.read_nmos_left[0].offset.x + drc["well_enclosure_active"] right_read_well_xpos = self.read_nmos_right[0].offset.x - self.read_nmos.active_height - drc["well_enclosure_active"] @@ -1168,43 +1174,44 @@ class pbitcell(pgate.pgate): return bitcell_pins def list_all_wl_names(self): - """ Creates a list of all wordline pin names """ - return self.wl_names + """ Creates a list of all wordline pin names """ + wordline_names = self.rw_wl_names + self.w_wl_names + self.r_wl_names + return wordline_names def list_all_bitline_names(self): """ Creates a list of all bitline pin names (both bl and br) """ bitline_pins = [] for port in range(self.total_ports): - column_pins.append("bl{0}".format(port)) - column_pins.append("br{0}".format(port)) + bitline_pins.append("bl{0}".format(port)) + bitline_pins.append("br{0}".format(port)) return bitline_pins def list_all_bl_names(self): """ Creates a list of all bl pins names """ - bl_pins = [self.rw_bl_names, self.w_bl_names, self.r_bl_names] + bl_pins = self.rw_bl_names + self.w_bl_names + self.r_bl_names return bl_pins def list_all_br_names(self): """ Creates a list of all br pins names """ - br_pins = [self.rw_br_names, self.w_br_names, self.r_br_names] + br_pins = self.rw_br_names + self.w_br_names + self.r_br_names return br_pins def list_read_bl_names(self): """ Creates a list of bl pin names associated with read ports """ - bl_pins = [self.rw_bl_names, self.r_bl_names] + bl_pins = self.rw_bl_names + self.r_bl_names return bl_pins def list_read_br_names(self): """ Creates a list of br pin names associated with read ports """ - br_pins = [self.rw_br_names, self.r_br_names] + br_pins = self.rw_br_names + self.r_br_names return br_pins def list_write_bl_names(self): """ Creates a list of bl pin names associated with write ports """ - bl_pins = [self.rw_bl_names, self.w_bl_names] + bl_pins = self.rw_bl_names + self.w_bl_names return bl_pins def list_write_br_names(self): """ Creates a list of br pin names asscociated with write ports""" - br_pins = [self.rw_br_names, self.w_br_names] + br_pins = self.rw_br_names + self.w_br_names return br_pins diff --git a/compiler/pgates/pgate.py b/compiler/pgates/pgate.py index 4e47934d..ec3bed0c 100644 --- a/compiler/pgates/pgate.py +++ b/compiler/pgates/pgate.py @@ -11,10 +11,19 @@ class pgate(design.design): This is a module that implements some shared functions for parameterized gates. """ - def __init__(self, name): + def __init__(self, name, height=None): """ Creates a generic cell """ design.design.__init__(self, name) + if height: + self.height = height + elif not height: + from importlib import reload + c = reload(__import__(OPTS.bitcell)) + bitcell = getattr(c, OPTS.bitcell) + b = bitcell() + self.height = b.height + def connect_pin_to_rail(self,inst,pin,supply): """ Conencts a ptx pin to a supply rail. """ diff --git a/compiler/pgates/pinv.py b/compiler/pgates/pinv.py index e2e87053..f0df378d 100644 --- a/compiler/pgates/pinv.py +++ b/compiler/pgates/pinv.py @@ -17,26 +17,22 @@ class pinv(pgate.pgate): from center of rail to rail.. The route_output will route the output to the right side of the cell for easier access. """ - from importlib import reload - c = reload(__import__(OPTS.bitcell)) - bitcell = getattr(c, OPTS.bitcell) unique_id = 1 - def __init__(self, size=1, beta=parameter["beta"], height=bitcell.height, route_output=True): + def __init__(self, size=1, beta=parameter["beta"], height=None, route_output=True): # We need to keep unique names because outputting to GDSII # will use the last record with a given name. I.e., you will # over-write a design in GDS if one has and the other doesn't # have poly connected, for example. name = "pinv_{}".format(pinv.unique_id) pinv.unique_id += 1 - pgate.pgate.__init__(self, name) + pgate.pgate.__init__(self, name, height) debug.info(2, "create pinv structure {0} with size of {1}".format(name, size)) self.nmos_size = size self.pmos_size = beta*size self.beta = beta - self.height = height # Maybe minimize height if not defined in future? self.route_output = False diff --git a/compiler/pgates/pinvbuf.py b/compiler/pgates/pinvbuf.py index e55fb649..328836dc 100644 --- a/compiler/pgates/pinvbuf.py +++ b/compiler/pgates/pinvbuf.py @@ -11,13 +11,9 @@ class pinvbuf(design.design): This is a simple inverter/buffer used for driving loads. It is used in the column decoder for 1:2 decoding and as the clock buffer. """ - from importlib import reload - c = reload(__import__(OPTS.bitcell)) - bitcell = getattr(c, OPTS.bitcell) - unique_id = 1 - def __init__(self, driver_size=4, height=bitcell.height, name=""): + def __init__(self, driver_size=4, height=None, name=""): self.stage_effort = 4 self.row_height = height @@ -32,7 +28,7 @@ class pinvbuf(design.design): name = "pinvbuf_{0}_{1}_{2}".format(self.predriver_size, self.driver_size, pinvbuf.unique_id) pinvbuf.unique_id += 1 - design.design.__init__(self, name) + design.design.__init__(self, name) debug.info(1, "Creating {}".format(self.name)) self.create_netlist() diff --git a/compiler/pgates/pnand2.py b/compiler/pgates/pnand2.py index 99ae9f02..d38c7de4 100644 --- a/compiler/pgates/pnand2.py +++ b/compiler/pgates/pnand2.py @@ -12,24 +12,19 @@ class pnand2(pgate.pgate): This model use ptx to generate a 2-input nand within a cetrain height. """ - from importlib import reload - c = reload(__import__(OPTS.bitcell)) - bitcell = getattr(c, OPTS.bitcell) - unique_id = 1 - def __init__(self, size=1, height=bitcell.height): + def __init__(self, size=1, height=None): """ Creates a cell for a simple 2 input nand """ name = "pnand2_{0}".format(pnand2.unique_id) pnand2.unique_id += 1 - pgate.pgate.__init__(self, name) + pgate.pgate.__init__(self, name, height) debug.info(2, "create pnand2 structure {0} with size of {1}".format(name, size)) self.nmos_size = 2*size self.pmos_size = parameter["beta"]*size self.nmos_width = self.nmos_size*drc["minwidth_tx"] self.pmos_width = self.pmos_size*drc["minwidth_tx"] - self.height = height # FIXME: Allow these to be sized debug.check(size==1,"Size 1 pnand2 is only supported now.") diff --git a/compiler/pgates/pnand3.py b/compiler/pgates/pnand3.py index 984ee417..b4e11b32 100644 --- a/compiler/pgates/pnand3.py +++ b/compiler/pgates/pnand3.py @@ -12,18 +12,13 @@ class pnand3(pgate.pgate): This model use ptx to generate a 2-input nand within a cetrain height. """ - from importlib import reload - c = reload(__import__(OPTS.bitcell)) - mod_bitcell = getattr(c, OPTS.bitcell) - bitcell = mod_bitcell() - unique_id = 1 - def __init__(self, size=1, height=bitcell.height): + def __init__(self, size=1, height=None): """ Creates a cell for a simple 3 input nand """ name = "pnand3_{0}".format(pnand3.unique_id) pnand3.unique_id += 1 - pgate.pgate.__init__(self, name) + pgate.pgate.__init__(self, name, height) debug.info(2, "create pnand3 structure {0} with size of {1}".format(name, size)) # We have trouble pitch matching a 3x sizes to the bitcell... @@ -32,7 +27,6 @@ class pnand3(pgate.pgate): self.pmos_size = parameter["beta"]*size self.nmos_width = self.nmos_size*drc["minwidth_tx"] self.pmos_width = self.pmos_size*drc["minwidth_tx"] - self.height = height # FIXME: Allow these to be sized debug.check(size==1,"Size 1 pnand3 is only supported now.") diff --git a/compiler/pgates/pnor2.py b/compiler/pgates/pnor2.py index e19f03cf..8f7dcea4 100644 --- a/compiler/pgates/pnor2.py +++ b/compiler/pgates/pnor2.py @@ -12,17 +12,13 @@ class pnor2(pgate.pgate): This model use ptx to generate a 2-input nor within a cetrain height. """ - from importlib import reload - c = reload(__import__(OPTS.bitcell)) - bitcell = getattr(c, OPTS.bitcell) - unique_id = 1 - def __init__(self, size=1, height=bitcell.height): + def __init__(self, size=1, height=None): """ Creates a cell for a simple 2 input nor """ name = "pnor2_{0}".format(pnor2.unique_id) pnor2.unique_id += 1 - pgate.pgate.__init__(self, name) + pgate.pgate.__init__(self, name, height) debug.info(2, "create pnor2 structure {0} with size of {1}".format(name, size)) self.nmos_size = size @@ -30,7 +26,6 @@ class pnor2(pgate.pgate): self.pmos_size = 1.5*parameter["beta"]*size self.nmos_width = self.nmos_size*drc["minwidth_tx"] self.pmos_width = self.pmos_size*drc["minwidth_tx"] - self.height = height # FIXME: Allow these to be sized debug.check(size==1,"Size 1 pnor2 is only supported now.") diff --git a/compiler/pgates/single_level_column_mux.py b/compiler/pgates/single_level_column_mux.py index 604c9312..015b434a 100644 --- a/compiler/pgates/single_level_column_mux.py +++ b/compiler/pgates/single_level_column_mux.py @@ -39,6 +39,8 @@ class single_level_column_mux(design.design): self.add_wells() def add_modules(self): + # This is just used for measurements, + # so don't add the module from importlib import reload c = reload(__import__(OPTS.bitcell)) self.mod_bitcell = getattr(c, OPTS.bitcell) diff --git a/compiler/sram.py b/compiler/sram.py index 3891150b..0feea1b3 100644 --- a/compiler/sram.py +++ b/compiler/sram.py @@ -12,8 +12,9 @@ class sram(): results. We can later add visualizer and other high-level functions as needed. """ - def __init__(self, sram_config, name="sram"): + def __init__(self, sram_config, name): + sram_config.compute_sizes() sram_config.set_local_config(self) # reset the static duplicate name checker for unit tests @@ -27,6 +28,8 @@ class sram(): start_time = datetime.datetime.now() self.name = name + + if self.num_banks == 1: from sram_1bank import sram_1bank as sram elif self.num_banks == 2: @@ -35,8 +38,8 @@ class sram(): from sram_4bank import sram_4bank as sram else: debug.error("Invalid number of banks.",-1) - - self.s = sram(sram_config, name) + + self.s = sram(name, sram_config) self.s.create_netlist() if not OPTS.netlist_only: self.s.create_layout() diff --git a/compiler/sram_1bank.py b/compiler/sram_1bank.py index d7ea47fb..03791089 100644 --- a/compiler/sram_1bank.py +++ b/compiler/sram_1bank.py @@ -18,12 +18,11 @@ class sram_1bank(sram_base): """ Procedures specific to a one bank SRAM. """ - def __init__(self, sram_config, name): - sram_base.__init__(self, sram_config, name) + def __init__(self, name, sram_config): + sram_base.__init__(self, name, sram_config) def create_netlist(self): - self.compute_sizes() sram_base.create_netlist(self) self.create_modules() diff --git a/compiler/sram_2bank.py b/compiler/sram_2bank.py index ff0d7868..daf02563 100644 --- a/compiler/sram_2bank.py +++ b/compiler/sram_2bank.py @@ -16,8 +16,8 @@ class sram_2bank(sram_base): """ Procedures specific to a two bank SRAM. """ - def __init__(self, sram_config, name): - sram_base.__init__(self, sram_config, name) + def __init__(self, name, sram_config): + sram_base.__init__(self, name, sram_config) def compute_bank_offsets(self): """ Compute the overall offsets for a two bank SRAM """ diff --git a/compiler/sram_4bank.py b/compiler/sram_4bank.py index 64163e9f..44b8ba87 100644 --- a/compiler/sram_4bank.py +++ b/compiler/sram_4bank.py @@ -16,8 +16,8 @@ class sram_4bank(sram_base): """ Procedures specific to a four bank SRAM. """ - def __init__(self, sram_config, name): - sram_base.__init__(self, sram_config, name) + def __init__(self, name, sram_config): + sram_base.__init__(self, name, sram_config) def compute_bank_offsets(self): """ Compute the overall offsets for a four bank SRAM """ diff --git a/compiler/sram_base.py b/compiler/sram_base.py index d3122063..ca3351b5 100644 --- a/compiler/sram_base.py +++ b/compiler/sram_base.py @@ -3,7 +3,6 @@ import datetime import getpass import debug from importlib import reload -from math import log,sqrt,ceil from vector import vector from globals import OPTS, print_time @@ -14,85 +13,18 @@ class sram_base(design): Dynamically generated SRAM by connecting banks to control logic. The number of banks should be 1 , 2 or 4 """ - def __init__(self, sram_config, name): + def __init__(self, name, sram_config): design.__init__(self, name) - - # This is used to compute the sizes of the SRAM - # and must be loaded before netlist creation - c = reload(__import__(OPTS.bitcell)) - self.mod_bitcell = getattr(c, OPTS.bitcell) - self.bitcell = self.mod_bitcell() - - self.sram_config = sram_config - self.sram_config.set_local_config(self) + self.sram_config = sram_config + sram_config.set_local_config(self) + + self.total_write = OPTS.num_rw_ports + OPTS.num_w_ports + self.total_read = OPTS.num_rw_ports + OPTS.num_r_ports + self.total_ports = OPTS.num_rw_ports + OPTS.num_w_ports + OPTS.num_r_ports + self.bank_insts = [] - def compute_sizes(self): - """ Computes the organization of the memory using bitcell size by trying to make it square.""" - - debug.check(self.num_banks in [1,2,4], "Valid number of banks are 1 , 2 and 4.") - - self.num_words_per_bank = self.num_words/self.num_banks - self.num_bits_per_bank = self.word_size*self.num_words_per_bank - - # If this was hard coded, don't dynamically compute it! - if self.sram_config.words_per_row: - self.words_per_row = self.sram_config.words_per_row - else: - # Compute the area of the bitcells and estimate a square bank (excluding auxiliary circuitry) - self.bank_area = self.bitcell.width*self.bitcell.height*self.num_bits_per_bank - self.bank_side_length = sqrt(self.bank_area) - - # Estimate the words per row given the height of the bitcell and the square side length - self.tentative_num_cols = int(self.bank_side_length/self.bitcell.width) - self.words_per_row = self.estimate_words_per_row(self.tentative_num_cols, self.word_size) - - # Estimate the number of rows given the tentative words per row - self.tentative_num_rows = self.num_bits_per_bank / (self.words_per_row*self.word_size) - self.words_per_row = self.amend_words_per_row(self.tentative_num_rows, self.words_per_row) - - # Fix the number of columns and rows - self.num_cols = int(self.words_per_row*self.word_size) - self.num_rows = int(self.num_words_per_bank/self.words_per_row) - - # Compute the address and bank sizes - self.row_addr_size = int(log(self.num_rows, 2)) - self.col_addr_size = int(log(self.words_per_row, 2)) - self.bank_addr_size = self.col_addr_size + self.row_addr_size - self.addr_size = self.bank_addr_size + int(log(self.num_banks, 2)) - - self.sram_config.words_per_row = self.words_per_row - debug.info(1,"Words per row: {}".format(self.words_per_row)) - - def estimate_words_per_row(self,tentative_num_cols, word_size): - """ - This provides a heuristic rounded estimate for the number of words - per row. - """ - - if tentative_num_cols < 1.5*word_size: - return 1 - elif tentative_num_cols > 3*word_size: - return 4 - else: - return 2 - - def amend_words_per_row(self,tentative_num_rows, words_per_row): - """ - This picks the number of words per row more accurately by limiting - it to a minimum and maximum. - """ - # Recompute the words per row given a hard max - if(tentative_num_rows > 512): - debug.check(tentative_num_rows*words_per_row <= 2048, "Number of words exceeds 2048") - return int(words_per_row*tentative_num_rows/512) - # Recompute the words per row given a hard min - if(tentative_num_rows < 16): - debug.check(tentative_num_rows*words_per_row >= 16, "Minimum number of rows is 16, but given {0}".format(tentative_num_rows)) - return int(words_per_row*tentative_num_rows/16) - - return words_per_row def add_pins(self): """ Add pins for entire SRAM. """ @@ -274,6 +206,9 @@ class sram_base(design): def add_modules(self): """ Create all the modules that will be used """ + c = reload(__import__(OPTS.bitcell)) + self.mod_bitcell = getattr(c, OPTS.bitcell) + self.bitcell = self.mod_bitcell() c = reload(__import__(OPTS.control_logic)) self.mod_control_logic = getattr(c, OPTS.control_logic) diff --git a/compiler/sram_config.py b/compiler/sram_config.py index e7c58905..e7c80fd8 100644 --- a/compiler/sram_config.py +++ b/compiler/sram_config.py @@ -1,36 +1,96 @@ +import debug +from math import log,sqrt,ceil +from importlib import reload from globals import OPTS class sram_config: """ This is a structure that is used to hold the SRAM configuration options. """ - def __init__(self, word_size, num_words, num_banks=1, num_rw_ports=OPTS.num_rw_ports, num_w_ports=OPTS.num_w_ports, num_r_ports=OPTS.num_r_ports): + def __init__(self, word_size, num_words, num_banks=1): self.word_size = word_size self.num_words = num_words self.num_banks = num_banks - self.num_rw_ports = num_rw_ports - self.num_w_ports = num_w_ports - self.num_r_ports = num_r_ports # This will get over-written when we determine the organization - self.num_banks = 1 self.words_per_row = None - - self.total_write = num_rw_ports + num_w_ports - self.total_read = num_rw_ports + num_r_ports - self.total_ports = num_rw_ports + num_w_ports + num_r_ports + # Move the module names to this? + def set_local_config(self, module): - module.word_size = self.word_size - module.num_words = self.num_words - module.num_banks = self.num_banks - module.num_rw_ports = self.num_rw_ports - module.num_w_ports = self.num_w_ports - module.num_r_ports = self.num_r_ports + """ Copy all of the member variables to the given module for convenience """ - module.words_per_row = self.words_per_row - - module.total_write = self.total_write - module.total_read = self.total_read - module.total_ports = self.total_ports + members = [attr for attr in dir(self) if not callable(getattr(self, attr)) and not attr.startswith("__")] + # Copy all the variables to the local module + for member in members: + setattr(module,member,getattr(self,member)) + + def compute_sizes(self): + """ Computes the organization of the memory using bitcell size by trying to make it square.""" + + c = reload(__import__(OPTS.bitcell)) + self.mod_bitcell = getattr(c, OPTS.bitcell) + # pass a copy of myself for the port numbers + self.bitcell = self.mod_bitcell() + + + debug.check(self.num_banks in [1,2,4], "Valid number of banks are 1 , 2 and 4.") + + self.num_words_per_bank = self.num_words/self.num_banks + self.num_bits_per_bank = self.word_size*self.num_words_per_bank + + # If this was hard coded, don't dynamically compute it! + if not self.words_per_row: + # Compute the area of the bitcells and estimate a square bank (excluding auxiliary circuitry) + self.bank_area = self.bitcell.width*self.bitcell.height*self.num_bits_per_bank + self.bank_side_length = sqrt(self.bank_area) + + # Estimate the words per row given the height of the bitcell and the square side length + self.tentative_num_cols = int(self.bank_side_length/self.bitcell.width) + self.words_per_row = self.estimate_words_per_row(self.tentative_num_cols, self.word_size) + + # Estimate the number of rows given the tentative words per row + self.tentative_num_rows = self.num_bits_per_bank / (self.words_per_row*self.word_size) + self.words_per_row = self.amend_words_per_row(self.tentative_num_rows, self.words_per_row) + + # Fix the number of columns and rows + self.num_cols = int(self.words_per_row*self.word_size) + self.num_rows = int(self.num_words_per_bank/self.words_per_row) + + # Compute the address and bank sizes + self.row_addr_size = int(log(self.num_rows, 2)) + self.col_addr_size = int(log(self.words_per_row, 2)) + self.bank_addr_size = self.col_addr_size + self.row_addr_size + self.addr_size = self.bank_addr_size + int(log(self.num_banks, 2)) + + debug.info(1,"Words per row: {}".format(self.words_per_row)) + + def estimate_words_per_row(self,tentative_num_cols, word_size): + """ + This provides a heuristic rounded estimate for the number of words + per row. + """ + + if tentative_num_cols < 1.5*word_size: + return 1 + elif tentative_num_cols > 3*word_size: + return 4 + else: + return 2 + + def amend_words_per_row(self,tentative_num_rows, words_per_row): + """ + This picks the number of words per row more accurately by limiting + it to a minimum and maximum. + """ + # Recompute the words per row given a hard max + if(not OPTS.is_unit_test and tentative_num_rows > 512): + debug.check(tentative_num_rows*words_per_row <= 2048, "Number of words exceeds 2048") + return int(words_per_row*tentative_num_rows/512) + # Recompute the words per row given a hard min + if(not OPTS.is_unit_test and tentative_num_rows < 16): + debug.check(tentative_num_rows*words_per_row >= 16, "Minimum number of rows is 16, but given {0}".format(tentative_num_rows)) + return int(words_per_row*tentative_num_rows/16) + + return words_per_row diff --git a/compiler/tests/04_pbitcell_test.py b/compiler/tests/04_pbitcell_test.py index 070637f9..0b6bd8f5 100755 --- a/compiler/tests/04_pbitcell_test.py +++ b/compiler/tests/04_pbitcell_test.py @@ -18,47 +18,76 @@ class pbitcell_test(openram_test): def runTest(self): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) - import pbitcell + from pbitcell import pbitcell import tech - + OPTS.num_rw_ports=1 + OPTS.num_w_ports=1 + OPTS.num_r_ports=1 debug.info(2, "Bitcell with 1 of each port: read/write, write, and read") - tx = pbitcell.pbitcell(num_rw_ports=1,num_w_ports=1,num_r_ports=1) + tx = pbitcell() self.local_check(tx) + OPTS.num_rw_ports=0 + OPTS.num_w_ports=1 + OPTS.num_r_ports=1 debug.info(2, "Bitcell with 0 read/write ports") - tx = pbitcell.pbitcell(num_rw_ports=0,num_w_ports=1,num_r_ports=1) + tx = pbitcell() self.local_check(tx) + OPTS.num_rw_ports=1 + OPTS.num_w_ports=0 + OPTS.num_r_ports=1 debug.info(2, "Bitcell with 0 write ports") - tx = pbitcell.pbitcell(num_rw_ports=1,num_w_ports=0,num_r_ports=1) + tx = pbitcell() self.local_check(tx) + OPTS.num_rw_ports=1 + OPTS.num_w_ports=1 + OPTS.num_r_ports=0 debug.info(2, "Bitcell with 0 read ports") - tx = pbitcell.pbitcell(num_rw_ports=1,num_w_ports=1,num_r_ports=0) + tx = pbitcell() self.local_check(tx) + OPTS.num_rw_ports=1 + OPTS.num_w_ports=0 + OPTS.num_r_ports=0 debug.info(2, "Bitcell with 0 read ports and 0 write ports") - tx = pbitcell.pbitcell(num_rw_ports=1,num_w_ports=0,num_r_ports=0) + tx = pbitcell() self.local_check(tx) + OPTS.num_rw_ports=2 + OPTS.num_w_ports=2 + OPTS.num_r_ports=2 debug.info(2, "Bitcell with 2 of each port: read/write, write, and read") - tx = pbitcell.pbitcell(num_rw_ports=2,num_w_ports=2,num_r_ports=2) + tx = pbitcell() self.local_check(tx) + OPTS.num_rw_ports=0 + OPTS.num_w_ports=2 + OPTS.num_r_ports=2 debug.info(2, "Bitcell with 0 read/write ports") - tx = pbitcell.pbitcell(num_rw_ports=0,num_w_ports=2,num_r_ports=2) + tx = pbitcell() self.local_check(tx) + OPTS.num_rw_ports=2 + OPTS.num_w_ports=0 + OPTS.num_r_ports=2 debug.info(2, "Bitcell with 0 write ports") - tx = pbitcell.pbitcell(num_rw_ports=2,num_w_ports=0,num_r_ports=2) + tx = pbitcell() self.local_check(tx) + OPTS.num_rw_ports=2 + OPTS.num_w_ports=2 + OPTS.num_r_ports=0 debug.info(2, "Bitcell with 0 read ports") - tx = pbitcell.pbitcell(num_rw_ports=2,num_w_ports=2,num_r_ports=0) + tx = pbitcell() self.local_check(tx) + OPTS.num_rw_ports=2 + OPTS.num_w_ports=0 + OPTS.num_r_ports=0 debug.info(2, "Bitcell with 0 read ports and 0 write ports") - tx = pbitcell.pbitcell(num_rw_ports=2,num_w_ports=0,num_r_ports=0) + tx = pbitcell() self.local_check(tx) globals.end_openram() diff --git a/compiler/tests/04_precharge_test.py b/compiler/tests/04_precharge_test.py index 8e44aa52..3bc44c47 100755 --- a/compiler/tests/04_precharge_test.py +++ b/compiler/tests/04_precharge_test.py @@ -27,13 +27,13 @@ class precharge_test(openram_test): OPTS.num_rw_ports = 2 OPTS.num_r_ports = 2 OPTS.num_w_ports = 2 - tx = precharge.precharge(name="precharge_driver", size=1, bitcell_bl="rwbl0", bitcell_br="rwbl_bar0") + tx = precharge.precharge(name="precharge_driver", size=1, bitcell_bl="bl0", bitcell_br="br0") self.local_check(tx) - tx = precharge.precharge(name="precharge_driver", size=1, bitcell_bl="wbl0", bitcell_br="wbl_bar0") + tx = precharge.precharge(name="precharge_driver", size=1, bitcell_bl="bl2", bitcell_br="br2") self.local_check(tx) - tx = precharge.precharge(name="precharge_driver", size=1, bitcell_bl="rbl0", bitcell_br="rbl_bar0") + tx = precharge.precharge(name="precharge_driver", size=1, bitcell_bl="bl4", bitcell_br="br4") self.local_check(tx) globals.end_openram() diff --git a/compiler/tests/08_precharge_array_test.py b/compiler/tests/08_precharge_array_test.py index 49530410..0549cd52 100755 --- a/compiler/tests/08_precharge_array_test.py +++ b/compiler/tests/08_precharge_array_test.py @@ -28,13 +28,13 @@ class precharge_test(openram_test): OPTS.num_r_ports = 2 OPTS.num_w_ports = 2 - pc = precharge_array.precharge_array(columns=3, bitcell_bl="rwbl0", bitcell_br="rwbl_bar0") + pc = precharge_array.precharge_array(columns=3, bitcell_bl="bl0", bitcell_br="br0") self.local_check(pc) - pc = precharge_array.precharge_array(columns=3, bitcell_bl="wbl0", bitcell_br="wbl_bar0") + pc = precharge_array.precharge_array(columns=3, bitcell_bl="bl2", bitcell_br="br2") self.local_check(pc) - pc = precharge_array.precharge_array(columns=3, bitcell_bl="rbl0", bitcell_br="rbl_bar0") + pc = precharge_array.precharge_array(columns=3, bitcell_bl="bl4", bitcell_br="br4") self.local_check(pc) globals.end_openram() diff --git a/compiler/tests/08_wordline_driver_test.py b/compiler/tests/08_wordline_driver_test.py old mode 100644 new mode 100755 diff --git a/compiler/tests/09_sense_amp_array_test.py b/compiler/tests/09_sense_amp_array_test.py old mode 100644 new mode 100755 diff --git a/compiler/tests/10_write_driver_array_test.py b/compiler/tests/10_write_driver_array_test.py old mode 100644 new mode 100755 diff --git a/compiler/tests/19_psingle_bank_test.py b/compiler/tests/19_psingle_bank_test.py old mode 100644 new mode 100755 index bdb64f9e..f377a3db --- a/compiler/tests/19_psingle_bank_test.py +++ b/compiler/tests/19_psingle_bank_test.py @@ -11,7 +11,7 @@ import globals from globals import OPTS import debug -@unittest.skip("SKIPPING 19_psingle_bank_test") +#@unittest.skip("SKIPPING 19_psingle_bank_test") class psingle_bank_test(openram_test): def runTest(self): diff --git a/compiler/tests/20_sram_1bank_test.py b/compiler/tests/20_sram_1bank_test.py index ad5732a6..ce482b6d 100755 --- a/compiler/tests/20_sram_1bank_test.py +++ b/compiler/tests/20_sram_1bank_test.py @@ -21,27 +21,28 @@ class sram_1bank_test(openram_test): num_words=16, num_banks=1) + c.words_per_row=1 debug.info(1, "Single bank, no column mux with control logic") - a = sram(c, name="sram1") + a = sram(c, "sram1") self.local_check(a, final_verification=True) c.num_words=32 c.words_per_row=2 debug.info(1, "Single bank two way column mux with control logic") - a = sram(c, name="sram2") + a = sram(c, "sram2") self.local_check(a, final_verification=True) c.num_words=64 c.words_per_row=4 debug.info(1, "Single bank, four way column mux with control logic") - a = sram(c, name="sram3") + a = sram(c, "sram3") self.local_check(a, final_verification=True) c.word_size=2 c.num_words=128 c.words_per_row=8 debug.info(1, "Single bank, eight way column mux with control logic") - a = sram(c, name="sram4") + a = sram(c, "sram4") self.local_check(a, final_verification=True) globals.end_openram() diff --git a/compiler/tests/20_sram_2bank_test.py b/compiler/tests/20_sram_2bank_test.py index fd701860..ff9fbaea 100755 --- a/compiler/tests/20_sram_2bank_test.py +++ b/compiler/tests/20_sram_2bank_test.py @@ -22,27 +22,28 @@ class sram_2bank_test(openram_test): num_words=32, num_banks=2) + c.words_per_row=1 debug.info(1, "Two bank, no column mux with control logic") - a = sram(c, name="sram1") + a = sram(c, "sram1") self.local_check(a, final_verification=True) c.num_words=64 c.words_per_row=2 debug.info(1, "Two bank two way column mux with control logic") - a = sram(c, name="sram2") + a = sram(c, "sram2") self.local_check(a, final_verification=True) c.num_words=128 c.words_per_row=4 debug.info(1, "Two bank, four way column mux with control logic") - a = sram(c, name="sram3") + a = sram(c, "sram3") self.local_check(a, final_verification=True) c.word_size=2 c.num_words=256 c.words_per_row=8 debug.info(1, "Two bank, eight way column mux with control logic") - a = sram(c, name="sram4") + a = sram(c, "sram4") self.local_check(a, final_verification=True) globals.end_openram() diff --git a/compiler/tests/20_sram_4bank_test.py b/compiler/tests/20_sram_4bank_test.py index 19937d04..fb34d3b0 100755 --- a/compiler/tests/20_sram_4bank_test.py +++ b/compiler/tests/20_sram_4bank_test.py @@ -23,26 +23,26 @@ class sram_4bank_test(openram_test): num_banks=4) debug.info(1, "Four bank, no column mux with control logic") - a = sram(c, name="sram1") + a = sram(c, "sram1") self.local_check(a, final_verification=True) c.num_words=128 c.words_per_row=2 debug.info(1, "Four bank two way column mux with control logic") - a = sram(c, name="sram2") + a = sram(c, "sram2") self.local_check(a, final_verification=True) c.num_words=256 c.words_per_row=4 debug.info(1, "Four bank, four way column mux with control logic") - a = sram(word_size=16, num_words=256, num_banks=4, name="sram3") + a = sram(c, "sram3") self.local_check(a, final_verification=True) c.word_size=2 c.num_words=256 c.words_per_row=8 debug.info(1, "Four bank, eight way column mux with control logic") - a = sram.sram(word_size=2, num_words=256, num_banks=4, name="sram4") + a = sram.sram(c, "sram4") self.local_check(a, final_verification=True) globals.end_openram() diff --git a/compiler/tests/21_hspice_delay_test.py b/compiler/tests/21_hspice_delay_test.py index cfcf3173..93fc8413 100755 --- a/compiler/tests/21_hspice_delay_test.py +++ b/compiler/tests/21_hspice_delay_test.py @@ -32,7 +32,7 @@ class timing_sram_test(openram_test): c = sram_config(word_size=1, num_words=16, num_banks=1) - + c.words_per_row=1 debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank") s = sram(c, name="sram1") diff --git a/compiler/tests/21_ngspice_delay_test.py b/compiler/tests/21_ngspice_delay_test.py index 02557d96..d54cdf54 100755 --- a/compiler/tests/21_ngspice_delay_test.py +++ b/compiler/tests/21_ngspice_delay_test.py @@ -32,7 +32,7 @@ class timing_sram_test(openram_test): c = sram_config(word_size=1, num_words=16, num_banks=1) - + c.words_per_row=1 debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank") s = sram(c, name="sram1") diff --git a/compiler/tests/23_lib_sram_model_test.py b/compiler/tests/23_lib_sram_model_test.py index cec8b85a..8d5064d5 100755 --- a/compiler/tests/23_lib_sram_model_test.py +++ b/compiler/tests/23_lib_sram_model_test.py @@ -22,10 +22,9 @@ class lib_test(openram_test): c = sram_config(word_size=2, num_words=16, num_banks=1) - + c.words_per_row=1 debug.info(1, "Testing analytical timing for sample 2 bit, 16 words SRAM with 1 bank") s = sram(c, "sram_2_16_1_{0}".format(OPTS.tech_name)) - tempspice = OPTS.openram_temp + "temp.sp" s.sp_write(tempspice) diff --git a/compiler/tests/23_lib_sram_prune_test.py b/compiler/tests/23_lib_sram_prune_test.py index 37974bf7..952072aa 100755 --- a/compiler/tests/23_lib_sram_prune_test.py +++ b/compiler/tests/23_lib_sram_prune_test.py @@ -31,7 +31,7 @@ class lib_test(openram_test): c = sram_config(word_size=2, num_words=16, num_banks=1) - + c.words_per_row=1 debug.info(1, "Testing pruned timing for sample 2 bit, 16 words SRAM with 1 bank") s = sram(c, "sram_2_16_1_{0}".format(OPTS.tech_name)) diff --git a/compiler/tests/23_lib_sram_test.py b/compiler/tests/23_lib_sram_test.py index 5e6aa060..1b2d317c 100755 --- a/compiler/tests/23_lib_sram_test.py +++ b/compiler/tests/23_lib_sram_test.py @@ -31,7 +31,7 @@ class lib_test(openram_test): c = sram_config(word_size=2, num_words=16, num_banks=1) - + c.words_per_row=1 debug.info(1, "Testing timing for sample 2 bit, 16 words SRAM with 1 bank") s = sram(c, "sram_2_16_1_{0}".format(OPTS.tech_name)) diff --git a/compiler/tests/24_lef_sram_test.py b/compiler/tests/24_lef_sram_test.py index b2566b84..f66104b6 100755 --- a/compiler/tests/24_lef_sram_test.py +++ b/compiler/tests/24_lef_sram_test.py @@ -22,7 +22,7 @@ class lef_test(openram_test): c = sram_config(word_size=2, num_words=16, num_banks=1) - + c.words_per_row=1 debug.info(1, "Testing LEF for sample 2 bit, 16 words SRAM with 1 bank") s = sram(c, "sram_2_16_1_{0}".format(OPTS.tech_name)) diff --git a/compiler/tests/25_verilog_sram_test.py b/compiler/tests/25_verilog_sram_test.py index 9412e8e8..48ba29e8 100755 --- a/compiler/tests/25_verilog_sram_test.py +++ b/compiler/tests/25_verilog_sram_test.py @@ -21,7 +21,7 @@ class verilog_test(openram_test): c = sram_config(word_size=2, num_words=16, num_banks=1) - + c.words_per_row=1 debug.info(1, "Testing Verilog for sample 2 bit, 16 words SRAM with 1 bank") s = sram(c, "sram_2_16_1_{0}".format(OPTS.tech_name)) diff --git a/technology/freepdk45/gds_lib/replica_cell_6t.gds b/technology/freepdk45/gds_lib/replica_cell_6t.gds index 9b301c08..2881a883 100644 Binary files a/technology/freepdk45/gds_lib/replica_cell_6t.gds and b/technology/freepdk45/gds_lib/replica_cell_6t.gds differ diff --git a/technology/scn3me_subm/gds_lib/cell_6t.gds b/technology/scn3me_subm/gds_lib/cell_6t.gds index ec926456..20e5367e 100644 Binary files a/technology/scn3me_subm/gds_lib/cell_6t.gds and b/technology/scn3me_subm/gds_lib/cell_6t.gds differ diff --git a/technology/scn3me_subm/gds_lib/dff.gds b/technology/scn3me_subm/gds_lib/dff.gds index b96235c7..07c37298 100644 Binary files a/technology/scn3me_subm/gds_lib/dff.gds and b/technology/scn3me_subm/gds_lib/dff.gds differ diff --git a/technology/scn3me_subm/gds_lib/ms_flop.gds b/technology/scn3me_subm/gds_lib/ms_flop.gds index 0e06e532..e1c071be 100644 Binary files a/technology/scn3me_subm/gds_lib/ms_flop.gds and b/technology/scn3me_subm/gds_lib/ms_flop.gds differ diff --git a/technology/scn3me_subm/gds_lib/replica_cell_6t.gds b/technology/scn3me_subm/gds_lib/replica_cell_6t.gds index af9bd1b8..12d97796 100644 Binary files a/technology/scn3me_subm/gds_lib/replica_cell_6t.gds and b/technology/scn3me_subm/gds_lib/replica_cell_6t.gds differ diff --git a/technology/scn3me_subm/gds_lib/sense_amp.gds b/technology/scn3me_subm/gds_lib/sense_amp.gds index d5ddd7d4..0fc7eb56 100644 Binary files a/technology/scn3me_subm/gds_lib/sense_amp.gds and b/technology/scn3me_subm/gds_lib/sense_amp.gds differ diff --git a/technology/scn3me_subm/gds_lib/tri_gate.gds b/technology/scn3me_subm/gds_lib/tri_gate.gds index b3d696d0..a3f25a39 100644 Binary files a/technology/scn3me_subm/gds_lib/tri_gate.gds and b/technology/scn3me_subm/gds_lib/tri_gate.gds differ diff --git a/technology/scn3me_subm/gds_lib/write_driver.gds b/technology/scn3me_subm/gds_lib/write_driver.gds index bf497a25..fdd3ad88 100644 Binary files a/technology/scn3me_subm/gds_lib/write_driver.gds and b/technology/scn3me_subm/gds_lib/write_driver.gds differ diff --git a/technology/scn3me_subm/mag_lib/cell_6t.gds b/technology/scn3me_subm/mag_lib/cell_6t.gds deleted file mode 100644 index c6fdb0e8..00000000 Binary files a/technology/scn3me_subm/mag_lib/cell_6t.gds and /dev/null differ diff --git a/technology/scn3me_subm/mag_lib/cell_6t.mag b/technology/scn3me_subm/mag_lib/cell_6t.mag index b38f7488..f2e9906a 100644 --- a/technology/scn3me_subm/mag_lib/cell_6t.mag +++ b/technology/scn3me_subm/mag_lib/cell_6t.mag @@ -1,6 +1,6 @@ magic tech scmos -timestamp 1521677056 +timestamp 1536091415 << nwell >> rect -8 29 42 51 << pwell >> @@ -105,13 +105,13 @@ rect 6 2 10 48 rect 24 -2 28 48 rect 32 33 36 48 rect 32 -2 36 29 -<< m3p >> +<< bb >> rect 0 0 34 46 << labels >> rlabel metal2 0 0 0 0 1 gnd rlabel metal2 34 0 34 0 1 gnd rlabel m2contact 17 46 17 46 5 vdd -rlabel metal1 4 7 4 7 1 WL -rlabel metal2 8 43 8 43 1 BL -rlabel metal2 26 43 26 43 1 BR +rlabel metal2 8 43 8 43 1 bl +rlabel metal2 26 43 26 43 1 br +rlabel metal1 4 7 4 7 1 wl << end >> diff --git a/technology/scn3me_subm/mag_lib/dff.mag b/technology/scn3me_subm/mag_lib/dff.mag index 19825153..46d22c84 100644 --- a/technology/scn3me_subm/mag_lib/dff.mag +++ b/technology/scn3me_subm/mag_lib/dff.mag @@ -1,6 +1,6 @@ magic tech scmos -timestamp 1518823399 +timestamp 1536089597 << nwell >> rect 0 48 109 103 << pwell >> @@ -266,7 +266,7 @@ rect 6 30 10 50 rect 22 20 26 57 rect 70 44 74 70 rect 70 20 74 40 -<< m3p >> +<< bb >> rect 0 0 109 100 << labels >> rlabel m2contact 15 34 15 34 4 clk diff --git a/technology/scn3me_subm/mag_lib/ms_flop.mag b/technology/scn3me_subm/mag_lib/ms_flop.mag index 8b3b1d40..713d264f 100644 --- a/technology/scn3me_subm/mag_lib/ms_flop.mag +++ b/technology/scn3me_subm/mag_lib/ms_flop.mag @@ -1,6 +1,6 @@ magic tech scmos -timestamp 1523479368 +timestamp 1536089622 << nwell >> rect -2 0 18 200 << pwell >> @@ -280,7 +280,7 @@ rect 14 8 20 9 rect 14 4 15 8 rect 19 4 20 8 rect 14 3 20 4 -<< m3p >> +<< bb >> rect 0 0 34 200 << labels >> rlabel metal1 0 8 0 8 2 clk diff --git a/technology/scn3me_subm/mag_lib/replica_cell_6t.mag b/technology/scn3me_subm/mag_lib/replica_cell_6t.mag index 52dd6265..d0dc472f 100644 --- a/technology/scn3me_subm/mag_lib/replica_cell_6t.mag +++ b/technology/scn3me_subm/mag_lib/replica_cell_6t.mag @@ -1,6 +1,6 @@ magic tech scmos -timestamp 1521677136 +timestamp 1536091380 << nwell >> rect -8 29 42 51 << pwell >> @@ -106,13 +106,13 @@ rect 6 2 10 48 rect 24 -2 28 48 rect 32 33 36 48 rect 32 -2 36 29 -<< m3p >> +<< bb >> rect 0 0 34 46 << labels >> rlabel metal2 0 0 0 0 1 gnd rlabel metal2 34 0 34 0 1 gnd rlabel m2contact 17 46 17 46 5 vdd -rlabel metal1 4 7 4 7 1 WL -rlabel metal2 8 43 8 43 1 BL -rlabel metal2 26 43 26 43 1 BR +rlabel metal2 8 43 8 43 1 bl +rlabel metal2 26 43 26 43 1 br +rlabel metal1 4 7 4 7 1 wl << end >> diff --git a/technology/scn3me_subm/mag_lib/sense_amp.mag b/technology/scn3me_subm/mag_lib/sense_amp.mag index b29f7da0..e5fa4373 100644 --- a/technology/scn3me_subm/mag_lib/sense_amp.mag +++ b/technology/scn3me_subm/mag_lib/sense_amp.mag @@ -1,6 +1,6 @@ magic tech scmos -timestamp 1524065550 +timestamp 1536089670 << nwell >> rect 0 0 40 102 << pwell >> @@ -122,7 +122,7 @@ rect 20 44 22 48 rect 3 0 7 11 rect 10 0 14 44 rect 20 0 24 44 -<< m3p >> +<< bb >> rect 0 0 34 163 << labels >> flabel metal1 0 149 0 149 4 FreeSans 26 0 0 0 en diff --git a/technology/scn3me_subm/mag_lib/tri_gate.mag b/technology/scn3me_subm/mag_lib/tri_gate.mag index a393074b..bda635c7 100644 --- a/technology/scn3me_subm/mag_lib/tri_gate.mag +++ b/technology/scn3me_subm/mag_lib/tri_gate.mag @@ -1,6 +1,6 @@ magic tech scmos -timestamp 1524499924 +timestamp 1536089695 << nwell >> rect -2 45 38 73 << pwell >> @@ -86,7 +86,7 @@ rect 24 19 28 23 << metal2 >> rect 15 34 25 38 rect 15 0 19 34 -<< m3p >> +<< bb >> rect 0 0 34 73 << labels >> rlabel metal1 0 12 0 12 3 en diff --git a/technology/scn3me_subm/mag_lib/write_driver.mag b/technology/scn3me_subm/mag_lib/write_driver.mag index 80e09d11..ab2014aa 100644 --- a/technology/scn3me_subm/mag_lib/write_driver.mag +++ b/technology/scn3me_subm/mag_lib/write_driver.mag @@ -1,6 +1,6 @@ magic tech scmos -timestamp 1524499497 +timestamp 1536089714 << nwell >> rect -3 101 37 138 rect -3 0 37 51 @@ -209,7 +209,7 @@ rect 10 196 14 202 rect 20 193 24 202 rect 20 177 24 189 rect 15 0 19 6 -<< m3p >> +<< bb >> rect 0 0 34 202 << labels >> rlabel metal2 15 1 15 1 1 din diff --git a/technology/scn3me_subm/tech/SCN3ME_SUBM.30.tech b/technology/scn3me_subm/tech/SCN3ME_SUBM.30.tech index bf6ce64b..be511001 100644 --- a/technology/scn3me_subm/tech/SCN3ME_SUBM.30.tech +++ b/technology/scn3me_subm/tech/SCN3ME_SUBM.30.tech @@ -276,6 +276,11 @@ cifoutput style lambda=0.30(p) scalefactor 30 15 + # This is a custom section to add bounding boxes in OpenRAM + layer BB bb + labels bb + calma 63 0 + layer CWN nwell,rnw bloat-or pdiff,rpd,pdc/a,pfet * 180 bloat-or nsd,nsc/a * 90 @@ -1506,7 +1511,12 @@ cifinput style lambda=0.30(p) scalefactor 30 - layer nwell CWN + # This is a custom section to add bounding boxes in OpenRAM + layer bb BB + labels BB + calma 63 0 + +layer nwell CWN and-not CWNR and-not CTA labels CWN diff --git a/technology/scn3me_subm/tech/tech.py b/technology/scn3me_subm/tech/tech.py index d69a7d7f..4998c5b6 100755 --- a/technology/scn3me_subm/tech/tech.py +++ b/technology/scn3me_subm/tech/tech.py @@ -39,8 +39,8 @@ layer["via1"] = 50 layer["metal2"] = 51 layer["via2"] = 61 layer["metal3"] = 62 -layer["text"] = 83 -layer["boundary"] = 83 +layer["text"] = 63 +layer["boundary"] = 63 ################################################### ##END GDS Layer Map diff --git a/technology/scn3me_subm/tf/layers.map b/technology/scn3me_subm/tf/layers.map index d10d5f2d..b5440f23 100644 --- a/technology/scn3me_subm/tf/layers.map +++ b/technology/scn3me_subm/tf/layers.map @@ -13,4 +13,4 @@ Metal2 drawing 51 0 Via2 drawing 61 0 Metal3 drawing 62 0 Glass drawing 52 0 -text drawing 83 0 +comment drawing 63 0