diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index a3255075..98b1fbac 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -976,7 +976,7 @@ class layout(): (horizontal_layer, via_layer, vertical_layer) = layer_stack if horizontal: route_layer = vertical_layer - bys_layer = horizontal_layer + bus_layer = horizontal_layer else: route_layer = horizontal_layer bus_layer = vertical_layer diff --git a/compiler/base/pin_layout.py b/compiler/base/pin_layout.py index 40e3c2f5..21bad6bc 100644 --- a/compiler/base/pin_layout.py +++ b/compiler/base/pin_layout.py @@ -380,11 +380,19 @@ class pin_layout: label_purpose = purpose newLayout.addBox(layerNumber=layer_num, - purposeNumber=pin_purpose, + purposeNumber=purpose, offsetInMicrons=self.ll(), width=self.width(), height=self.height(), center=False) + # Draw a second pin shape too + if pin_purpose != purpose: + newLayout.addBox(layerNumber=layer_num, + purposeNumber=pin_purpose, + offsetInMicrons=self.ll(), + width=self.width(), + height=self.height(), + center=False) # Add the tet in the middle of the pin. # This fixes some pin label offsetting when GDS gets # imported into Magic. diff --git a/compiler/bitcells/col_cap_bitcell_1port.py b/compiler/bitcells/col_cap_bitcell_1port.py new file mode 100644 index 00000000..5d34e2f5 --- /dev/null +++ b/compiler/bitcells/col_cap_bitcell_1port.py @@ -0,0 +1,22 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2019 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import debug +from tech import cell_properties as props +import bitcell_base + + +class col_cap_bitcell_1port(bitcell_base.bitcell_base): + """ + Column end cap cell. + """ + + def __init__(self, name="col_cap_bitcell_1port"): + bitcell_base.bitcell_base.__init__(self, name, prop=props.col_cap_1port) + debug.info(2, "Create col_cap bitcell 1 port object") + + self.no_instances = True diff --git a/compiler/bitcells/row_cap_bitcell_1port.py b/compiler/bitcells/row_cap_bitcell_1port.py new file mode 100644 index 00000000..c82b3782 --- /dev/null +++ b/compiler/bitcells/row_cap_bitcell_1port.py @@ -0,0 +1,22 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2019 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import debug +from tech import cell_properties as props +import bitcell_base + + +class row_cap_bitcell_1port(bitcell_base.bitcell_base): + """ + Row end cap cell. + """ + + def __init__(self, name="row_cap_bitcell_1port"): + bitcell_base.bitcell_base.__init__(self, name, prop=props.row_cap_1port) + debug.info(2, "Create row_cap bitcell 1 port object") + + self.no_instances = True diff --git a/compiler/gdsMill/gdsMill/gds2reader.py b/compiler/gdsMill/gdsMill/gds2reader.py index 2f9976a5..448355a8 100644 --- a/compiler/gdsMill/gdsMill/gds2reader.py +++ b/compiler/gdsMill/gdsMill/gds2reader.py @@ -79,7 +79,8 @@ class Gds2reader: recordLength = struct.unpack(">h",recordLengthAscii) #gives us a tuple with a short int inside offset_int = int(recordLength[0]) # extract length offset += offset_int # count offset - #print(offset) #print out the record numbers for de-bugging + if(self.debugToTerminal==1): + print("Offset: " + str(offset)) #print out the record numbers for de-bugging record = self.fileHandle.read(recordLength[0]-2) #read the rest of it (first 2 bytes were already read) return record @@ -176,7 +177,7 @@ class Gds2reader: def readBoundary(self): ##reads in a boundary type structure = a filled polygon if(self.debugToTerminal==1): - print("\t\t\tBeginBoundary") + print("\t\tBeginBoundary") thisBoundary=GdsBoundary() while 1: record = self.readNextRecord() @@ -214,13 +215,13 @@ class Gds2reader: print("\t\t\tXY Point: "+str(x)+","+str(y)) elif(idBits==b'\x11\x00'): #End Of Element if(self.debugToTerminal==1): - print("\t\t\tEndBoundary") + print("\t\tEndBoundary") break; return thisBoundary def readPath(self): #reads in a path structure if(self.debugToTerminal==1): - print("\t\t\tBeginPath") + print("\t\tBeginPath") thisPath=GdsPath() while 1: @@ -274,7 +275,7 @@ class Gds2reader: print("\t\t\tXY Point: "+str(x)+","+str(y)) elif(idBits==b'\x11\x00'): #End Of Element if(self.debugToTerminal==1): - print("\t\t\tEndPath") + print("\t\tEndPath") break; return thisPath diff --git a/compiler/globals.py b/compiler/globals.py index b1cc92c4..6d0c1d9c 100644 --- a/compiler/globals.py +++ b/compiler/globals.py @@ -361,6 +361,21 @@ def end_openram(): verify.print_lvs_stats() verify.print_pex_stats() + +def purge_temp(): + """ Remove the temp directory. """ + debug.info(1, + "Purging temp directory: {}".format(OPTS.openram_temp)) + # This annoyingly means you have to re-cd into + # the directory each debug iteration + # shutil.rmtree(OPTS.openram_temp, ignore_errors=True) + contents = [os.path.join(OPTS.openram_temp, i) for i in os.listdir(OPTS.openram_temp)] + for i in contents: + if os.path.isfile(i) or os.path.islink(i): + os.remove(i) + else: + shutil.rmtree(i) + def cleanup_paths(): """ @@ -372,19 +387,9 @@ def cleanup_paths(): "Preserving temp directory: {}".format(OPTS.openram_temp)) return elif os.path.exists(OPTS.openram_temp): - debug.info(1, - "Purging temp directory: {}".format(OPTS.openram_temp)) - # This annoyingly means you have to re-cd into - # the directory each debug iteration - # shutil.rmtree(OPTS.openram_temp, ignore_errors=True) - contents = [os.path.join(OPTS.openram_temp, i) for i in os.listdir(OPTS.openram_temp)] - for i in contents: - if os.path.isfile(i) or os.path.islink(i): - os.remove(i) - else: - shutil.rmtree(i) - + purge_temp() + def setup_paths(): """ Set up the non-tech related paths. """ debug.info(2, "Setting up paths...") @@ -413,7 +418,7 @@ def setup_paths(): OPTS.openram_temp += "/" debug.info(1, "Temporary files saved in " + OPTS.openram_temp) - + def is_exe(fpath): """ Return true if the given is an executable file that exists. """ return os.path.exists(fpath) and os.access(fpath, os.X_OK) @@ -435,15 +440,17 @@ def find_exe(check_exe): def init_paths(): """ Create the temp and output directory if it doesn't exist """ - - # make the directory if it doesn't exist - try: - debug.info(1, - "Creating temp directory: {}".format(OPTS.openram_temp)) - os.makedirs(OPTS.openram_temp, 0o750) - except OSError as e: - if e.errno == 17: # errno.EEXIST - os.chmod(OPTS.openram_temp, 0o750) + if os.path.exists(OPTS.openram_temp): + purge_temp() + else: + # make the directory if it doesn't exist + try: + debug.info(1, + "Creating temp directory: {}".format(OPTS.openram_temp)) + 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 diff --git a/compiler/modules/col_cap_array.py b/compiler/modules/col_cap_array.py index 1b7a1f49..1be29327 100644 --- a/compiler/modules/col_cap_array.py +++ b/compiler/modules/col_cap_array.py @@ -100,7 +100,7 @@ class col_cap_array(bitcell_base_array): inst = self.cell_inst[row, col] for pin_name in ["vdd", "gnd"]: for pin in inst.get_pins(pin_name): - self.add_power_pin(name=pin.name, + self.add_power_pin(name=pin_name, loc=pin.center(), start_layer=pin.layer) diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index 75d47670..fb51b252 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -390,20 +390,19 @@ class replica_bitcell_array(bitcell_base_array): # These grow up, away from the array for bit in range(self.rbl[1]): dummy_offset = self.bitcell_offset.scale(0, bit + bit % 2) + self.bitcell_array_inst.ul() + import pdb; pdb.set_trace() self.dummy_row_replica_insts[self.rbl[0] + bit].place(offset=dummy_offset, - mirror="MX" if bit % 2 else "R0") + mirror="MX" if (self.row_size + bit) % 2 else "R0") def add_end_caps(self): """ Add dummy cells or end caps around the array """ - # FIXME: These depend on the array size itself - # Far top dummy row (first row above array is NOT flipped) - flip_dummy = self.rbl[1] % 2 + # Far top dummy row (first row above array is NOT flipped if even number of rows) + flip_dummy = (self.row_size + self.rbl[1]) % 2 dummy_row_offset = self.bitcell_offset.scale(0, self.rbl[1] + flip_dummy) + self.bitcell_array_inst.ul() self.dummy_row_insts[1].place(offset=dummy_row_offset, mirror="MX" if flip_dummy else "R0") - # FIXME: These depend on the array size itself # Far bottom dummy row (first row below array IS flipped) flip_dummy = (self.rbl[0] + 1) % 2 dummy_row_offset = self.bitcell_offset.scale(0, -self.rbl[0] - 1 + flip_dummy) + self.unused_offset @@ -422,9 +421,8 @@ class replica_bitcell_array(bitcell_base_array): def add_layout_pins(self): """ Add the layout pins """ - #All wordlines - #Main array wl and bl/br - + # All wordlines + # Main array wl and bl/br for pin_name in self.all_wordline_names: pin_list = self.bitcell_array_inst.get_pins(pin_name) for pin in pin_list: diff --git a/compiler/modules/row_cap_array.py b/compiler/modules/row_cap_array.py index 5cee866a..850dd5f9 100644 --- a/compiler/modules/row_cap_array.py +++ b/compiler/modules/row_cap_array.py @@ -113,7 +113,7 @@ class row_cap_array(bitcell_base_array): inst = self.cell_inst[row, col] for pin_name in ["vdd", "gnd"]: for pin in inst.get_pins(pin_name): - self.add_power_pin(name=pin.name, + self.add_power_pin(name=pin_name, loc=pin.center(), start_layer=pin.layer) diff --git a/compiler/printGDS.py b/compiler/printGDS.py new file mode 100755 index 00000000..b0683203 --- /dev/null +++ b/compiler/printGDS.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 + +import sys +from gdsMill import gdsMill + +if len(sys.argv) < 2: + print("Usage: {0} file.gds".format(sys.argv[0])) + sys.exit(1) + +gds_file = sys.argv[1] +arrayCellLayout = gdsMill.VlsiLayout() +reader = gdsMill.Gds2reader(arrayCellLayout,debugToTerminal = 1) +reader.loadFromFile(gds_file) + diff --git a/compiler/tests/14_replica_bitcell_array_test.py b/compiler/tests/14_replica_bitcell_array_test.py index 98ee0a43..c06819c4 100755 --- a/compiler/tests/14_replica_bitcell_array_test.py +++ b/compiler/tests/14_replica_bitcell_array_test.py @@ -25,7 +25,7 @@ class replica_bitcell_array_test(openram_test): factory.reset() debug.info(2, "Testing 4x4 array for bitcell") - a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, rbl=[1, 0]) + a = factory.create(module_type="replica_bitcell_array", cols=7, rows=5, rbl=[1, 0]) self.local_check(a) globals.end_openram() diff --git a/compiler/verify/calibre.py b/compiler/verify/calibre.py index a6376a16..9d079c2a 100644 --- a/compiler/verify/calibre.py +++ b/compiler/verify/calibre.py @@ -103,10 +103,10 @@ def write_lvs_script(cell_name, gds_name, sp_name, final_verification=False, out 'cmnTranscriptEchoToFile': 1, 'lvsRecognizeGates': 'NONE', } - # FIXME: Remove when vdd/gnd connected - #'cmnVConnectNamesState' : 'ALL', #connects all nets with the same namee - # FIXME: Remove when vdd/gnd connected - #'lvsAbortOnSupplyError' : 0 + # FIXME: Remove when vdd/gnd connected + # 'cmnVConnectNamesState' : 'ALL', #connects all nets with the same namee + # FIXME: Remove when vdd/gnd connected + # 'lvsAbortOnSupplyError' : 0 if not final_verification or not OPTS.route_supplies: lvs_runset['cmnVConnectReport']=1 @@ -115,8 +115,6 @@ def write_lvs_script(cell_name, gds_name, sp_name, final_verification=False, out else: lvs_runset['lvsAbortOnSupplyError']=1 - - # write the runset file f = open(output_path + "lvs_runset", "w") for k in sorted(iter(lvs_runset.keys())): diff --git a/compiler/verify/magic.py b/compiler/verify/magic.py index 36acaf5a..07a2efab 100644 --- a/compiler/verify/magic.py +++ b/compiler/verify/magic.py @@ -89,6 +89,7 @@ def write_drc_script(cell_name, gds_name, extract, final_verification, output_pa f.write("gds warning default\n") f.write("gds flatten true\n") f.write("gds readonly true\n") + f.write("gds ordering true\n") f.write("gds read {}\n".format(gds_name)) f.write('puts "Finished reading gds {}"\n'.format(gds_name)) f.write("load {}\n".format(cell_name)) @@ -218,7 +219,7 @@ def write_lvs_script(cell_name, gds_name, sp_name, final_verification=False, out f = open(run_file, "w") f.write("#!/bin/sh\n") f.write('export OPENRAM_TECH="{}"\n'.format(os.environ['OPENRAM_TECH'])) - f.write('echo "$(date): Starting LVS using Magic {}"\n'.format(OPTS.drc_exe[1])) + f.write('echo "$(date): Starting LVS using Netgen {}"\n'.format(OPTS.lvs_exe[1])) f.write("{} -noconsole << EOF\n".format(OPTS.lvs_exe[1])) # f.write("readnet spice {0}.spice\n".format(cell_name)) # f.write("readnet spice {0}\n".format(sp_name)) @@ -226,7 +227,7 @@ def write_lvs_script(cell_name, gds_name, sp_name, final_verification=False, out f.write("quit\n") f.write("EOF\n") f.write("magic_retcode=$?\n") - f.write('echo "$(date): Finished ($magic_retcode) LVS using Magic {}"\n'.format(OPTS.drc_exe[1])) + f.write('echo "$(date): Finished ($magic_retcode) LVS using Netgen {}"\n'.format(OPTS.lvs_exe[1])) f.write("exit $magic_retcode\n") f.close() os.system("chmod u+x {}".format(run_file))