Merge branch 'dev' into cacti_model

This commit is contained in:
Hunter Nichols 2021-07-26 14:35:47 -07:00
commit 1e08005639
29 changed files with 873 additions and 112 deletions

View File

@ -93,9 +93,9 @@ class cell:
# It is assumed it is [nwell, pwell] # It is assumed it is [nwell, pwell]
self._body_bias = body_bias self._body_bias = body_bias
self._port_map['vnb'] = body_bias[0] self._port_map['vnb'] = body_bias[0]
self._port_types['vnb'] = "POWER" self._port_types['vnb'] = "GROUND"
self._port_map['vpb'] = body_bias[1] self._port_map['vpb'] = body_bias[1]
self._port_types['vpb'] = "GROUND" self._port_types['vpb'] = "POWER"
@property @property
def port_types(self): def port_types(self):

View File

@ -52,7 +52,7 @@ class pin_layout:
from tech import layer_override_name from tech import layer_override_name
if layer_override[name]: if layer_override[name]:
self.lpp = layer_override[name] self.lpp = layer_override[name]
self.layer = "m1" self.layer = "pwellp"
self._recompute_hash() self._recompute_hash()
return return
except: except:
@ -406,6 +406,13 @@ class pin_layout:
try: try:
from tech import label_purpose from tech import label_purpose
try:
from tech import layer_override_purpose
if pin_layer_num in layer_override_purpose:
layer_num = layer_override_purpose[pin_layer_num][0]
label_purpose = layer_override_purpose[pin_layer_num][1]
except:
pass
except ImportError: except ImportError:
label_purpose = purpose label_purpose = purpose

View File

@ -81,7 +81,11 @@ class functional(simulation):
self.create_graph() self.create_graph()
self.set_internal_spice_names() self.set_internal_spice_names()
self.q_name, self.qbar_name = self.get_bit_name() self.q_name, self.qbar_name = self.get_bit_name()
debug.info(2, "q name={0}\nqbar name={1}".format(self.q_name, self.qbar_name)) debug.info(2, "q:\t\t{0}".format(self.q_name))
debug.info(2, "qbar:\t{0}".format(self.qbar_name))
debug.info(2, "s_en:\t{0}".format(self.sen_name))
debug.info(2, "bl:\t{0}".format(self.bl_name))
debug.info(2, "br:\t{0}".format(self.br_name))
# Number of checks can be changed # Number of checks can be changed
self.num_cycles = cycles self.num_cycles = cycles
@ -141,23 +145,25 @@ class functional(simulation):
comment = self.gen_cycle_comment("noop", "0" * self.word_size, "0" * self.addr_size, "0" * self.num_wmasks, 0, self.t_current) comment = self.gen_cycle_comment("noop", "0" * self.word_size, "0" * self.addr_size, "0" * self.num_wmasks, 0, self.t_current)
self.add_noop_all_ports(comment) self.add_noop_all_ports(comment)
# 1. Write all the write ports first to seed a bunch of locations.
for port in self.write_ports:
addr = self.gen_addr()
(word, spare) = self.gen_data()
combined_word = self.combine_word(spare, word)
comment = self.gen_cycle_comment("write", combined_word, addr, "1" * self.num_wmasks, port, self.t_current)
self.add_write_one_port(comment, addr, spare + word, "1" * self.num_wmasks, port)
self.stored_words[addr] = word
self.stored_spares[addr[:self.addr_spare_index]] = spare
# All other read-only ports are noops. # 1. Write all the write ports 2x to seed a bunch of locations.
for port in self.read_ports: for i in range(3):
if port not in self.write_ports: for port in self.write_ports:
self.add_noop_one_port(port) addr = self.gen_addr()
self.cycle_times.append(self.t_current) (word, spare) = self.gen_data()
self.t_current += self.period combined_word = self.combine_word(spare, word)
self.check_lengths() comment = self.gen_cycle_comment("write", combined_word, addr, "1" * self.num_wmasks, port, self.t_current)
self.add_write_one_port(comment, addr, spare + word, "1" * self.num_wmasks, port)
self.stored_words[addr] = word
self.stored_spares[addr[:self.addr_spare_index]] = spare
# All other read-only ports are noops.
for port in self.read_ports:
if port not in self.write_ports:
self.add_noop_one_port(port)
self.cycle_times.append(self.t_current)
self.t_current += self.period
self.check_lengths()
# 2. Read at least once. For multiport, it is important that one # 2. Read at least once. For multiport, it is important that one
# read cycle uses all RW and R port to read from the same # read cycle uses all RW and R port to read from the same
@ -297,38 +303,6 @@ class functional(simulation):
self.read_results.append([sp_read_value, dout_port, eo_period, cycle]) self.read_results.append([sp_read_value, dout_port, eo_period, cycle])
return (1, "SUCCESS") return (1, "SUCCESS")
def combine_word(self, spare, word):
if len(spare) > 0:
return spare + "+" + word
return word
def format_value(self, value):
""" Format in better readable manner """
def delineate(word):
# Create list of chars in reverse order
split_word = list(reversed([x for x in word]))
# Add underscore every 4th char
split_word2 = [x + '_' * (n != 0 and n % 4 == 0) for n, x in enumerate(split_word)]
# Join the word unreversed back together
new_word = ''.join(reversed(split_word2))
return(new_word)
# Split extra cols
if self.num_spare_cols > 0:
vals = value[self.num_spare_cols:]
spare_vals = value[:self.num_spare_cols]
else:
vals = value
spare_vals = ""
# Insert underscores
vals = delineate(vals)
spare_vals = delineate(spare_vals)
return self.combine_word(spare_vals, vals)
def check_stim_results(self): def check_stim_results(self):
for i in range(len(self.read_check)): for i in range(len(self.read_check)):
if self.read_check[i][0] != self.read_results[i][0]: if self.read_check[i][0] != self.read_results[i][0]:
@ -372,7 +346,8 @@ class functional(simulation):
def gen_data(self): def gen_data(self):
""" Generates a random word to write. """ """ Generates a random word to write. """
random_value = random.randint(0, self.max_data) # Don't use 0 or max value
random_value = random.randint(1, self.max_data - 1)
data_bits = binary_repr(random_value, self.word_size) data_bits = binary_repr(random_value, self.word_size)
if self.num_spare_cols>0: if self.num_spare_cols>0:
random_value = random.randint(0, self.max_col_data) random_value = random.randint(0, self.max_col_data)
@ -431,11 +406,11 @@ class functional(simulation):
# Write important signals to stim file # Write important signals to stim file
self.sf.write("\n\n* Important signals for debug\n") self.sf.write("\n\n* Important signals for debug\n")
self.sf.write("* bl: {0}\n".format(self.bl_name.format(port))) self.sf.write("* bl:\t{0}\n".format(self.bl_name.format(port)))
self.sf.write("* br: {0}\n".format(self.br_name.format(port))) self.sf.write("* br:\t{0}\n".format(self.br_name.format(port)))
self.sf.write("* s_en: {0}\n".format(self.sen_name)) self.sf.write("* s_en:\t{0}\n".format(self.sen_name))
self.sf.write("* q: {0}\n".format(self.q_name)) self.sf.write("* q:\t{0}\n".format(self.q_name))
self.sf.write("* qbar: {0}\n".format(self.qbar_name)) self.sf.write("* qbar:\t{0}\n".format(self.qbar_name))
# 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")
@ -498,7 +473,7 @@ class functional(simulation):
for (word, dout_port, eo_period, cycle) in self.read_check: for (word, dout_port, eo_period, cycle) in self.read_check:
t_initial = eo_period t_initial = eo_period
t_final = eo_period t_final = eo_period + 0.01 * self.period
num_bits = self.word_size + self.num_spare_cols num_bits = self.word_size + self.num_spare_cols
for bit in range(num_bits): for bit in range(num_bits):
signal_name = "{0}_{1}".format(dout_port, bit) signal_name = "{0}_{1}".format(dout_port, bit)

View File

@ -372,6 +372,38 @@ class simulation():
time_spacing, time_spacing,
comment)) comment))
def combine_word(self, spare, word):
if len(spare) > 0:
return spare + "+" + word
return word
def format_value(self, value):
""" Format in better readable manner """
def delineate(word):
# Create list of chars in reverse order
split_word = list(reversed([x for x in word]))
# Add underscore every 4th char
split_word2 = [x + '_' * (n != 0 and n % 4 == 0) for n, x in enumerate(split_word)]
# Join the word unreversed back together
new_word = ''.join(reversed(split_word2))
return(new_word)
# Split extra cols
if self.num_spare_cols > 0:
vals = value[self.num_spare_cols:]
spare_vals = value[:self.num_spare_cols]
else:
vals = value
spare_vals = ""
# Insert underscores
vals = delineate(vals)
spare_vals = delineate(spare_vals)
return self.combine_word(spare_vals, vals)
def gen_cycle_comment(self, op, word, addr, wmask, port, t_current): def gen_cycle_comment(self, op, word, addr, wmask, port, t_current):
if op == "noop": if op == "noop":
str = "\tIdle during cycle {0} ({1}ns - {2}ns)" str = "\tIdle during cycle {0} ({1}ns - {2}ns)"
@ -483,8 +515,6 @@ class simulation():
self.sen_name = sen_with_port self.sen_name = sen_with_port
debug.warning("Error occurred while determining SEN name. Can cause faults in simulation.") debug.warning("Error occurred while determining SEN name. Can cause faults in simulation.")
debug.info(2, "s_en name = {}".format(self.sen_name))
column_addr = self.get_column_addr() column_addr = self.get_column_addr()
bl_name_port, br_name_port = self.get_bl_name(self.graph.all_paths, port) bl_name_port, br_name_port = self.get_bl_name(self.graph.all_paths, port)
port_pos = -1 - len(str(column_addr)) - len(str(port)) port_pos = -1 - len(str(column_addr)) - len(str(port))
@ -505,11 +535,12 @@ class simulation():
'{}{}_{}'.format(self.dout_name, port, self.probe_data)) '{}{}_{}'.format(self.dout_name, port, self.probe_data))
self.sen_name = self.get_sen_name(self.graph.all_paths) self.sen_name = self.get_sen_name(self.graph.all_paths)
debug.info(2, "s_en name = {}".format(self.sen_name)) #debug.info(2, "s_en {}".format(self.sen_name))
self.bl_name = "bl{0}_{1}".format(port, OPTS.word_size - 1) self.bl_name = "bl{0}_{1}".format(port, OPTS.word_size - 1)
self.br_name = "br{0}_{1}".format(port, OPTS.word_size - 1) self.br_name = "br{0}_{1}".format(port, OPTS.word_size - 1)
debug.info(2, "bl name={}, br name={}".format(self.bl_name, self.br_name)) # debug.info(2, "bl name={0}".format(self.bl_name))
# debug.info(2, "br name={0}".format(self.br_name))
def get_sen_name(self, paths, assumed_port=None): def get_sen_name(self, paths, assumed_port=None):
""" """

View File

@ -222,7 +222,7 @@ class stimuli():
def gen_meas_value(self, meas_name, dout, t_initial, t_final): def gen_meas_value(self, meas_name, dout, t_initial, t_final):
measure_string=".meas tran {0} FIND v({1}) AT={2}n\n\n".format(meas_name.lower(), dout, (t_initial + t_final) / 2) measure_string=".meas tran {0} FIND v({1}) AT={2}n\n\n".format(meas_name.lower(), dout, (t_initial + t_final) / 2)
# measure_string=".meas tran {0} AVG v({1}) FROM={2}n TO={3}n\n\n".format(meas_name.lower(), dout, t_initial, t_final) #measure_string=".meas tran {0} AVG v({1}) FROM={2}n TO={3}n\n\n".format(meas_name.lower(), dout, t_initial, t_final)
self.sf.write(measure_string) self.sf.write(measure_string)
def write_control(self, end_time, runlvl=4): def write_control(self, end_time, runlvl=4):
@ -237,12 +237,13 @@ class stimuli():
reltol = 0.005 # 0.5% reltol = 0.005 # 0.5%
else: else:
reltol = 0.001 # 0.1% reltol = 0.001 # 0.1%
timestep = 10 # ps, was 5ps but ngspice was complaining the timestep was too small in certain tests. timestep = 10 # ps
if OPTS.spice_name == "ngspice": if OPTS.spice_name == "ngspice":
self.sf.write(".TEMP {}\n".format(self.temperature)) self.sf.write(".TEMP {}\n".format(self.temperature))
# UIC is needed for ngspice to converge # UIC is needed for ngspice to converge
self.sf.write(".TRAN {0}p {1}n UIC\n".format(timestep, end_time)) # Format: .tran tstep tstop < tstart < tmax >>
self.sf.write(".TRAN {0}p {1}n 0n {0}p UIC\n".format(timestep, end_time))
# ngspice sometimes has convergence problems if not using gear method # ngspice sometimes has convergence problems if not using gear method
# which is more accurate, but slower than the default trapezoid method # which is more accurate, but slower than the default trapezoid method
# Do not remove this or it may not converge due to some "pa_00" nodes # Do not remove this or it may not converge due to some "pa_00" nodes
@ -268,7 +269,8 @@ class stimuli():
self.sf.write("simulator lang=spice\n") self.sf.write("simulator lang=spice\n")
elif OPTS.spice_name in ["hspice", "xa"]: elif OPTS.spice_name in ["hspice", "xa"]:
self.sf.write(".TEMP {}\n".format(self.temperature)) self.sf.write(".TEMP {}\n".format(self.temperature))
self.sf.write(".TRAN {0}p {1}n UIC\n".format(timestep, end_time)) # Format: .tran tstep tstop < tstart < tmax >>
self.sf.write(".TRAN {0}p {1}n 0n {0}p UIC\n".format(timestep, end_time))
self.sf.write(".OPTIONS POST=1 RUNLVL={0} PROBE\n".format(runlvl)) self.sf.write(".OPTIONS POST=1 RUNLVL={0} PROBE\n".format(runlvl))
self.sf.write(".OPTIONS PSF=1 \n") self.sf.write(".OPTIONS PSF=1 \n")
self.sf.write(".OPTIONS HIER_DELIM=1 \n") self.sf.write(".OPTIONS HIER_DELIM=1 \n")
@ -276,7 +278,9 @@ class stimuli():
self.sf.write(".OPTIONS DEVICE TEMP={}\n".format(self.temperature)) self.sf.write(".OPTIONS DEVICE TEMP={}\n".format(self.temperature))
self.sf.write(".OPTIONS MEASURE MEASFAIL=1\n") self.sf.write(".OPTIONS MEASURE MEASFAIL=1\n")
self.sf.write(".OPTIONS LINSOL type=klu\n") self.sf.write(".OPTIONS LINSOL type=klu\n")
self.sf.write(".TRAN {0}p {1}n\n".format(timestep, end_time)) self.sf.write(".OPTIONS TIMEINT RELTOL=1e-6 ABSTOL=1e-10 method=gear minorder=2\n")
# Format: .TRAN <initial step> <final time> <start time> <step ceiling>
self.sf.write(".TRAN {0}p {1}n 0n {0}p\n".format(timestep, end_time))
elif OPTS.spice_name: elif OPTS.spice_name:
debug.error("Unkown spice simulator {}".format(OPTS.spice_name), -1) debug.error("Unkown spice simulator {}".format(OPTS.spice_name), -1)

View File

@ -12,6 +12,7 @@ nominal_corner_only = True
route_supplies = "ring" route_supplies = "ring"
#route_supplies = "left" #route_supplies = "left"
check_lvsdrc = True check_lvsdrc = True
uniquify = True
#perimeter_pins = False #perimeter_pins = False
#netlist_only = True #netlist_only = True
#analytical_delay = False #analytical_delay = False

View File

@ -81,7 +81,7 @@ class VlsiLayout:
coordinatesRotate.extend((newX,newY)) coordinatesRotate.extend((newX,newY))
return coordinatesRotate return coordinatesRotate
def uniquify(self): def uniquify(self, prefix_name=None):
new_structures = {} new_structures = {}
if self.rootStructureName[-1] == "\x00": if self.rootStructureName[-1] == "\x00":
prefix = self.rootStructureName[0:-1] + "_" prefix = self.rootStructureName[0:-1] + "_"
@ -92,7 +92,10 @@ class VlsiLayout:
base_name = name[0:-1] base_name = name[0:-1]
else: else:
base_name = name base_name = name
if name != self.rootStructureName: # Don't do library cells
if prefix_name and base_name.startswith(prefix_name):
new_name = name
elif name != self.rootStructureName:
new_name = self.padText(prefix + base_name) new_name = self.padText(prefix + base_name)
else: else:
new_name = name new_name = name
@ -105,7 +108,11 @@ class VlsiLayout:
base_sref_name = sref.sName[0:-1] base_sref_name = sref.sName[0:-1]
else: else:
base_sref_name = sref.sName base_sref_name = sref.sName
new_sref_name = self.padText(prefix + base_sref_name) # Don't do library cells
if prefix_name and base_sref_name.startswith(prefix_name):
new_sref_name = sref.sName
else:
new_sref_name = self.padText(prefix + base_sref_name)
sref.sName = new_sref_name sref.sName = new_sref_name
#print("SREF: {0} -> {1}".format(base_sref_name, new_sref_name)) #print("SREF: {0} -> {1}".format(base_sref_name, new_sref_name))
self.structures = new_structures self.structures = new_structures
@ -770,7 +777,13 @@ class VlsiLayout:
from tech import layer_override from tech import layer_override
if layer_override[label_text]: if layer_override[label_text]:
shapes = self.getAllShapes((layer_override[label_text][0], None)) shapes = self.getAllShapes((layer_override[label_text][0], None))
lpp = layer_override[label_text] if not shapes:
shapes = self.getAllShapes(lpp)
else:
lpp = layer_override[label_text]
except: except:
pass pass
for boundary in shapes: for boundary in shapes:

View File

@ -620,7 +620,7 @@ class bank(design.design):
self.copy_power_pins(inst, "gnd", add_vias=False) self.copy_power_pins(inst, "gnd", add_vias=False)
if 'vpb' in self.bitcell_array_inst.mod.pins and 'vnb' in self.bitcell_array_inst.mod.pins: if 'vpb' in self.bitcell_array_inst.mod.pins and 'vnb' in self.bitcell_array_inst.mod.pins:
for pin_name, supply_name in zip(['vpb','vnb'],['gnd','vdd']): for pin_name, supply_name in zip(['vnb','vpb'],['gnd','vdd']):
self.copy_power_pins(self.bitcell_array_inst, pin_name, new_name=supply_name) self.copy_power_pins(self.bitcell_array_inst, pin_name, new_name=supply_name)
# If we use the pinvbuf as the decoder, we need to add power pins. # If we use the pinvbuf as the decoder, we need to add power pins.

View File

@ -162,9 +162,6 @@ class bitcell_base_array(design.design):
inst = self.cell_inst[row, col] inst = self.cell_inst[row, col]
for pin_name in ["vdd", "gnd"]: for pin_name in ["vdd", "gnd"]:
self.copy_layout_pin(inst, pin_name) self.copy_layout_pin(inst, pin_name)
if row == 2: #add only 1 label per col
for pin_name in ["vdd", "gnd"]:
self.copy_layout_pin(inst, pin_name)
def add_layout_pins(self): def add_layout_pins(self):
""" Add the layout pins """ """ Add the layout pins """

View File

@ -1,19 +0,0 @@
#!/usr/bin/env python3
import sys
from gdsMill import gdsMill
if len(sys.argv) < 3:
print("Script to prefix every instance and structure with the root cell name to provide unique namespace.")
print("Usage: {0} in.gds out.gds".format(sys.argv[0]))
sys.exit(1)
gds_file = sys.argv[1]
gds = gdsMill.VlsiLayout()
reader = gdsMill.Gds2reader(gds)
reader.loadFromFile(gds_file)
gds.uniquify()
writer = gdsMill.Gds2writer(gds)
writer.writeToFile(sys.argv[2])

View File

@ -69,7 +69,12 @@ class sram():
reader = gdsMill.Gds2reader(gds) reader = gdsMill.Gds2reader(gds)
reader.loadFromFile(name) reader.loadFromFile(name)
gds.uniquify() # Uniquify but skip the library cells since they are hard coded
try:
from tech import library_prefix_name
except ImportError:
library_prefix_name = None
gds.uniquify(library_prefix_name)
writer = gdsMill.Gds2writer(gds) writer = gdsMill.Gds2writer(gds)
unique_name = name.replace(".gds", "_unique.gds") unique_name = name.replace(".gds", "_unique.gds")

View File

@ -17,7 +17,11 @@ class sram_config:
def __init__(self, word_size, num_words, write_size=None, num_banks=1, words_per_row=None, num_spare_rows=0, num_spare_cols=0): def __init__(self, word_size, num_words, write_size=None, num_banks=1, words_per_row=None, num_spare_rows=0, num_spare_cols=0):
self.word_size = word_size self.word_size = word_size
self.num_words = num_words self.num_words = num_words
self.write_size = write_size # Don't add a write mask if it is the same size as the data word
if write_size and write_size==word_size:
self.write_size = None
else:
self.write_size = write_size
self.num_banks = num_banks self.num_banks = num_banks
self.num_spare_rows = num_spare_rows self.num_spare_rows = num_spare_rows
self.num_spare_cols = num_spare_cols self.num_spare_cols = num_spare_cols

View File

@ -23,7 +23,15 @@ class array_test(openram_test):
globals.init_openram(config_file) globals.init_openram(config_file)
debug.info(2, "Testing 8x8 array for 6t_cell") debug.info(2, "Testing 8x8 array for 6t_cell")
a = factory.create(module_type="bitcell_array", cols=8, rows=8)
if OPTS.tech_name == "sky130":
num_spare_rows = 1
num_spare_cols = 1
else:
num_spare_rows = 0
num_spare_cols = 0
a = factory.create(module_type="bitcell_array", cols=8 + num_spare_cols, rows=8 + num_spare_rows)
self.local_check(a) self.local_check(a)
globals.end_openram() globals.end_openram()

View File

@ -19,9 +19,19 @@ class replica_column_test(openram_test):
def runTest(self): def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file) globals.init_openram(config_file)
if OPTS.tech_name == "sky130":
num_spare_rows = 1
num_spare_cols = 1
else:
num_spare_rows = 0
num_spare_cols = 0
debug.info(2, "Testing replica column for single port") debug.info(2, "Testing replica column for single port")
a = factory.create(module_type="replica_column", rows=4, rbl=[1, 0], replica_bit=1) a = factory.create(module_type="replica_column",
rows=4 + num_spare_rows,
rbl=[1, 0],
replica_bit=1,
column_offset=num_spare_cols)
self.local_check(a) self.local_check(a)
globals.end_openram() globals.end_openram()

View File

@ -0,0 +1,64 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2021 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import unittest
from testutils import *
import sys, os
sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
from sram_factory import factory
import debug
@unittest.skip("SKIPPING 50_riscv_func_test")
class riscv_func_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
OPTS.analytical_delay = False
OPTS.netlist_only = True
OPTS.trim_netlist = False
#OPTS.local_array_size = 16
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
globals.setup_bitcell()
# This is a hack to reload the characterizer __init__ with the spice version
from importlib import reload
import characterizer
reload(characterizer)
from characterizer import functional
from sram_config import sram_config
c = sram_config(word_size=32,
write_size=8,
num_words=256,
num_banks=1)
debug.info(1, "Functional test RISC-V memory"
"{} bit words, {} words, {} words per row, {} banks".format(c.word_size,
c.num_words,
c.words_per_row,
c.num_banks))
s = factory.create(module_type="sram", sram_config=c)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
f = functional(s.s, corner=corner, cycles=100)
(fail, error) = f.run()
self.assertTrue(fail, error)
globals.end_openram()
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())

View File

@ -0,0 +1,66 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2021 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import unittest
from testutils import *
import sys, os
sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
from sram_factory import factory
import debug
@unittest.skip("SKIPPING 50_riscv_func_test")
class riscv_func_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
OPTS.analytical_delay = False
OPTS.netlist_only = True
OPTS.trim_netlist = False
#OPTS.local_array_size = 16
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 0
OPTS.num_w_ports = 0
globals.setup_bitcell()
# This is a hack to reload the characterizer __init__ with the spice version
from importlib import reload
import characterizer
reload(characterizer)
from characterizer import functional
from sram_config import sram_config
c = sram_config(word_size=32,
write_size=8,
num_words=256,
num_banks=1,
num_spare_rows=1,
num_spare_cols=1)
debug.info(1, "Functional test RISC-V memory"
"{} bit words, {} words, {} words per row, {} banks".format(c.word_size,
c.num_words,
c.words_per_row,
c.num_banks))
s = factory.create(module_type="sram", sram_config=c)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
f = functional(s.s, corner=corner, cycles=3)
(fail, error) = f.run()
self.assertTrue(fail, error)
globals.end_openram()
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())

View File

@ -16,7 +16,7 @@ from sram_factory import factory
import debug import debug
# @unittest.skip("SKIPPING 50_riscv_func_test") @unittest.skip("SKIPPING 50_riscv_func_test")
class riscv_func_test(openram_test): class riscv_func_test(openram_test):
def runTest(self): def runTest(self):
@ -24,6 +24,8 @@ class riscv_func_test(openram_test):
globals.init_openram(config_file) globals.init_openram(config_file)
OPTS.analytical_delay = False OPTS.analytical_delay = False
OPTS.netlist_only = True OPTS.netlist_only = True
OPTS.trim_netlist = False
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_w_ports = 0 OPTS.num_w_ports = 0
OPTS.num_r_ports = 1 OPTS.num_r_ports = 1
@ -48,7 +50,7 @@ class riscv_func_test(openram_test):
c.num_banks)) c.num_banks))
s = factory.create(module_type="sram", sram_config=c) s = factory.create(module_type="sram", sram_config=c)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
f = functional(s.s, corner=corner, cycles=50) f = functional(s.s, corner=corner, cycles=25)
(fail, error) = f.run() (fail, error) = f.run()
self.assertTrue(fail, error) self.assertTrue(fail, error)

View File

@ -16,7 +16,7 @@ from sram_factory import factory
import debug import debug
@unittest.skip("SKIPPING 50_riscv_phys_test") # @unittest.skip("SKIPPING 50_riscv_phys_test")
class riscv_phys_test(openram_test): class riscv_phys_test(openram_test):
def runTest(self): def runTest(self):

View File

@ -16,7 +16,7 @@ from sram_factory import factory
import debug import debug
# @unittest.skip("SKIPPING 50_riscv_func_test") @unittest.skip("SKIPPING 50_riscv_func_test")
class riscv_func_test(openram_test): class riscv_func_test(openram_test):
def runTest(self): def runTest(self):
@ -24,6 +24,15 @@ class riscv_func_test(openram_test):
globals.init_openram(config_file) globals.init_openram(config_file)
OPTS.analytical_delay = False OPTS.analytical_delay = False
OPTS.netlist_only = True OPTS.netlist_only = True
OPTS.trim_netlist = False
if OPTS.tech_name == "sky130":
num_spare_rows = 1
num_spare_cols = 1
else:
num_spare_rows = 0
num_spare_cols = 0
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_w_ports = 0 OPTS.num_w_ports = 0
OPTS.num_r_ports = 0 OPTS.num_r_ports = 0
@ -37,8 +46,10 @@ class riscv_func_test(openram_test):
from sram_config import sram_config from sram_config import sram_config
c = sram_config(word_size=32, c = sram_config(word_size=32,
write_size=8, write_size=8,
num_words=32, num_words=64,
num_banks=1) num_banks=1,
num_spare_cols=num_spare_cols,
num_spare_rows=num_spare_rows)
c.words_per_row=1 c.words_per_row=1
c.recompute_sizes() c.recompute_sizes()
debug.info(1, "Functional test RISC-V memory" debug.info(1, "Functional test RISC-V memory"
@ -48,7 +59,7 @@ class riscv_func_test(openram_test):
c.num_banks)) c.num_banks))
s = factory.create(module_type="sram", sram_config=c) s = factory.create(module_type="sram", sram_config=c)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
f = functional(s.s, corner=corner, cycles=50) f = functional(s.s, corner=corner, cycles=25)
(fail, error) = f.run() (fail, error) = f.run()
self.assertTrue(fail, error) self.assertTrue(fail, error)

View File

@ -0,0 +1,62 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2021 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import unittest
from testutils import *
import sys, os
sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
from sram_factory import factory
import debug
# @unittest.skip("SKIPPING 50_riscv_phys_test")
class riscv_phys_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
from sram_config import sram_config
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
OPTS.local_array_size = 16
globals.setup_bitcell()
OPTS.route_supplies = False
OPTS.perimeter_pins = False
c = sram_config(word_size=32,
write_size=8,
num_words=32,
num_banks=1,
num_spare_rows=1,
num_spare_cols=1)
c.words_per_row=2
c.recompute_sizes()
debug.info(1, "Layout test for {}rw,{}r,{}w sram "
"with {} bit words, {} words, {} words per "
"row, {} banks".format(OPTS.num_rw_ports,
OPTS.num_r_ports,
OPTS.num_w_ports,
c.word_size,
c.num_words,
c.words_per_row,
c.num_banks))
a = factory.create(module_type="sram", sram_config=c)
self.local_check(a, final_verification=True)
globals.end_openram()
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())

View File

@ -0,0 +1,64 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2021 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import unittest
from testutils import *
import sys, os
sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
from sram_factory import factory
import debug
@unittest.skip("SKIPPING 50_riscv_func_test")
class riscv_func_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
OPTS.analytical_delay = False
OPTS.netlist_only = True
OPTS.trim_netlist = False
#OPTS.local_array_size = 16
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
globals.setup_bitcell()
# This is a hack to reload the characterizer __init__ with the spice version
from importlib import reload
import characterizer
reload(characterizer)
from characterizer import functional
from sram_config import sram_config
c = sram_config(word_size=32,
write_size=8,
num_words=512,
num_banks=1)
debug.info(1, "Functional test RISC-V memory"
"{} bit words, {} words, {} words per row, {} banks".format(c.word_size,
c.num_words,
c.words_per_row,
c.num_banks))
s = factory.create(module_type="sram", sram_config=c)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
f = functional(s.s, corner=corner, cycles=100)
(fail, error) = f.run()
self.assertTrue(fail, error)
globals.end_openram()
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())

View File

@ -0,0 +1,66 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2021 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import unittest
from testutils import *
import sys, os
sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
from sram_factory import factory
import debug
@unittest.skip("SKIPPING 50_riscv_func_test")
class riscv_func_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
OPTS.analytical_delay = False
OPTS.netlist_only = True
OPTS.trim_netlist = False
#OPTS.local_array_size = 16
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 0
OPTS.num_w_ports = 0
globals.setup_bitcell()
# This is a hack to reload the characterizer __init__ with the spice version
from importlib import reload
import characterizer
reload(characterizer)
from characterizer import functional
from sram_config import sram_config
c = sram_config(word_size=32,
write_size=8,
num_words=512,
num_banks=1,
num_spare_rows=1,
num_spare_cols=1)
debug.info(1, "Functional test RISC-V memory"
"{} bit words, {} words, {} words per row, {} banks".format(c.word_size,
c.num_words,
c.words_per_row,
c.num_banks))
s = factory.create(module_type="sram", sram_config=c)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
f = functional(s.s, corner=corner, cycles=100)
(fail, error) = f.run()
self.assertTrue(fail, error)
globals.end_openram()
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())

View File

@ -0,0 +1,64 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2021 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import unittest
from testutils import *
import sys, os
sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
from sram_factory import factory
import debug
@unittest.skip("SKIPPING 50_riscv_func_test")
class riscv_func_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
OPTS.analytical_delay = False
OPTS.netlist_only = True
OPTS.trim_netlist = False
#OPTS.local_array_size = 16
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
globals.setup_bitcell()
# This is a hack to reload the characterizer __init__ with the spice version
from importlib import reload
import characterizer
reload(characterizer)
from characterizer import functional
from sram_config import sram_config
c = sram_config(word_size=32,
write_size=8,
num_words=1024,
num_banks=1)
debug.info(1, "Functional test RISC-V memory"
"{} bit words, {} words, {} words per row, {} banks".format(c.word_size,
c.num_words,
c.words_per_row,
c.num_banks))
s = factory.create(module_type="sram", sram_config=c)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
f = functional(s.s, corner=corner)
(fail, error) = f.run()
self.assertTrue(fail, error)
globals.end_openram()
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())

View File

@ -0,0 +1,66 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2021 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import unittest
from testutils import *
import sys, os
sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
from sram_factory import factory
import debug
@unittest.skip("SKIPPING 50_riscv_func_test")
class riscv_func_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
OPTS.analytical_delay = False
OPTS.netlist_only = True
OPTS.trim_netlist = False
#OPTS.local_array_size = 16
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 0
OPTS.num_w_ports = 0
globals.setup_bitcell()
# This is a hack to reload the characterizer __init__ with the spice version
from importlib import reload
import characterizer
reload(characterizer)
from characterizer import functional
from sram_config import sram_config
c = sram_config(word_size=32,
write_size=8,
num_words=1024,
num_banks=1,
num_spare_rows=1,
num_spare_cols=1)
debug.info(1, "Functional test RISC-V memory"
"{} bit words, {} words, {} words per row, {} banks".format(c.word_size,
c.num_words,
c.words_per_row,
c.num_banks))
s = factory.create(module_type="sram", sram_config=c)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
f = functional(s.s, corner=corner)
(fail, error) = f.run()
self.assertTrue(fail, error)
globals.end_openram()
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())

View File

@ -0,0 +1,64 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2021 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import unittest
from testutils import *
import sys, os
sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
from sram_factory import factory
import debug
@unittest.skip("SKIPPING 50_riscv_func_test")
class riscv_func_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
OPTS.analytical_delay = False
OPTS.netlist_only = True
OPTS.trim_netlist = False
#OPTS.local_array_size = 16
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
globals.setup_bitcell()
# This is a hack to reload the characterizer __init__ with the spice version
from importlib import reload
import characterizer
reload(characterizer)
from characterizer import functional
from sram_config import sram_config
c = sram_config(word_size=32,
write_size=8,
num_words=128,
num_banks=1)
debug.info(1, "Functional test RISC-V memory"
"{} bit words, {} words, {} words per row, {} banks".format(c.word_size,
c.num_words,
c.words_per_row,
c.num_banks))
s = factory.create(module_type="sram", sram_config=c)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
f = functional(s.s, corner=corner, cycles=100)
(fail, error) = f.run()
self.assertTrue(fail, error)
globals.end_openram()
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())

View File

@ -0,0 +1,66 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2021 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import unittest
from testutils import *
import sys, os
sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
from sram_factory import factory
import debug
@unittest.skip("SKIPPING 50_riscv_func_test")
class riscv_func_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
OPTS.analytical_delay = False
OPTS.netlist_only = True
OPTS.trim_netlist = False
#OPTS.local_array_size = 16
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 0
OPTS.num_w_ports = 0
globals.setup_bitcell()
# This is a hack to reload the characterizer __init__ with the spice version
from importlib import reload
import characterizer
reload(characterizer)
from characterizer import functional
from sram_config import sram_config
c = sram_config(word_size=32,
write_size=8,
num_words=128,
num_banks=1,
num_spare_rows=1,
num_spare_cols=1)
debug.info(1, "Functional test RISC-V memory"
"{} bit words, {} words, {} words per row, {} banks".format(c.word_size,
c.num_words,
c.words_per_row,
c.num_banks))
s = factory.create(module_type="sram", sram_config=c)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
f = functional(s.s, corner=corner, cycles=25)
(fail, error) = f.run()
self.assertTrue(fail, error)
globals.end_openram()
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())

View File

@ -0,0 +1,64 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2021 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import unittest
from testutils import *
import sys, os
sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
from sram_factory import factory
import debug
@unittest.skip("SKIPPING 50_riscv_func_test")
class riscv_func_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
OPTS.analytical_delay = False
OPTS.netlist_only = True
OPTS.trim_netlist = False
OPTS.local_array_size = 16
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
globals.setup_bitcell()
# This is a hack to reload the characterizer __init__ with the spice version
from importlib import reload
import characterizer
reload(characterizer)
from characterizer import functional
from sram_config import sram_config
c = sram_config(word_size=32,
write_size=8,
num_words=2048,
num_banks=1)
debug.info(1, "Functional test RISC-V memory"
"{} bit words, {} words, {} words per row, {} banks".format(c.word_size,
c.num_words,
c.words_per_row,
c.num_banks))
s = factory.create(module_type="sram", sram_config=c)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
f = functional(s.s, corner=corner, cycles=100)
(fail, error) = f.run()
self.assertTrue(fail, error)
globals.end_openram()
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())

View File

@ -0,0 +1,66 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2021 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import unittest
from testutils import *
import sys, os
sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
from sram_factory import factory
import debug
@unittest.skip("SKIPPING 50_riscv_func_test")
class riscv_func_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
OPTS.analytical_delay = False
OPTS.netlist_only = True
OPTS.trim_netlist = False
OPTS.local_array_size = 16
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 0
OPTS.num_w_ports = 0
globals.setup_bitcell()
# This is a hack to reload the characterizer __init__ with the spice version
from importlib import reload
import characterizer
reload(characterizer)
from characterizer import functional
from sram_config import sram_config
c = sram_config(word_size=32,
write_size=8,
num_words=2048,
num_banks=1,
num_spare_rows=1,
num_spare_cols=1)
debug.info(1, "Functional test RISC-V memory"
"{} bit words, {} words, {} words per row, {} banks".format(c.word_size,
c.num_words,
c.words_per_row,
c.num_banks))
s = factory.create(module_type="sram", sram_config=c)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
f = functional(s.s, corner=corner, cycles=100)
(fail, error) = f.run()
self.assertTrue(fail, error)
globals.end_openram()
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())

View File

@ -3,17 +3,17 @@
import sys import sys
from gdsMill import gdsMill from gdsMill import gdsMill
if len(sys.argv) < 3: if len(sys.argv) < 4:
print("Script to prefix every instance and structure with the root cell name to provide unique namespace.") print("Script to prefix every instance and structure with the root cell name to provide unique namespace, but skip cells that begin with the library prefix.")
print("Usage: {0} in.gds out.gds".format(sys.argv[0])) print("Usage: {0} <library prefix> in.gds out.gds".format(sys.argv[0]))
sys.exit(1) sys.exit(1)
gds_file = sys.argv[1] gds_file = sys.argv[2]
gds = gdsMill.VlsiLayout() gds = gdsMill.VlsiLayout()
reader = gdsMill.Gds2reader(gds) reader = gdsMill.Gds2reader(gds)
reader.loadFromFile(gds_file) reader.loadFromFile(gds_file)
gds.uniquify() gds.uniquify(prefix_name=sys.argv[1])
writer = gdsMill.Gds2writer(gds) writer = gdsMill.Gds2writer(gds)
writer.writeToFile(sys.argv[2]) writer.writeToFile(sys.argv[3])