mirror of https://github.com/VLSIDA/OpenRAM.git
fix the conflicts for merge
This commit is contained in:
commit
a22ba2087b
Binary file not shown.
2
README
2
README
|
|
@ -3,7 +3,7 @@ BASIC SETUP
|
||||||
|
|
||||||
-The OpenRAM compiler has very few dependencies:
|
-The OpenRAM compiler has very few dependencies:
|
||||||
|
|
||||||
1) ngspice v20 or later or HSpice I-2013.12-1 or later
|
1) ngspice-25 or later or HSpice I-2013.12-1 or later
|
||||||
2) Python 2.7 and higher (currently excludes Python 3 and up)
|
2) Python 2.7 and higher (currently excludes Python 3 and up)
|
||||||
3) a setup script for each technology
|
3) a setup script for each technology
|
||||||
4) a technology directory for each technology with the base cells
|
4) a technology directory for each technology with the base cells
|
||||||
|
|
|
||||||
|
|
@ -29,4 +29,12 @@ hierarchical_predecode3x8 to hierarchical_predecode class
|
||||||
Fix stimuli.py to be more readable.
|
Fix stimuli.py to be more readable.
|
||||||
|
|
||||||
Change the delay measurement to be from the negative clock edge to
|
Change the delay measurement to be from the negative clock edge to
|
||||||
remove the dependency on the clock period.
|
remove the dependency on the clock period.
|
||||||
|
|
||||||
|
Remove duplicate clock inverter in MS flop.
|
||||||
|
|
||||||
|
Make lib file have delay relative to negedge for DATA. Must update
|
||||||
|
timing code too.
|
||||||
|
|
||||||
|
Convert characterizer into a Python package
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -867,7 +867,7 @@ class bank(design.design):
|
||||||
for i in range(2):
|
for i in range(2):
|
||||||
ff_index = i + self.row_addr_size
|
ff_index = i + self.row_addr_size
|
||||||
current_dout = self.msf_address.dout_positions[ff_index]
|
current_dout = self.msf_address.dout_positions[ff_index]
|
||||||
msf_row_addr_line_position = (current_dout.rotate().scale(1,-1)
|
msf_row_addr_line_position = (current_dout.rotate_scale(1,-1)
|
||||||
+ self.msf_address_offset)
|
+ self.msf_address_offset)
|
||||||
|
|
||||||
line_index = self.num_central_bus - 2 + i
|
line_index = self.num_central_bus - 2 + i
|
||||||
|
|
@ -913,7 +913,7 @@ class bank(design.design):
|
||||||
mid2 = col_decoder_out_position + vector(connection_width,
|
mid2 = col_decoder_out_position + vector(connection_width,
|
||||||
-self.central_line_y_offset)
|
-self.central_line_y_offset)
|
||||||
|
|
||||||
self.add_wire(layers=("metal2", "via1", "metal1"),
|
self.add_wire(layers=("metal1", "via1", "metal2"),
|
||||||
coordinates=[col_decoder_out_position,mid1,mid2],
|
coordinates=[col_decoder_out_position,mid1,mid2],
|
||||||
offset=col_decoder_out_position)
|
offset=col_decoder_out_position)
|
||||||
|
|
||||||
|
|
@ -922,9 +922,9 @@ class bank(design.design):
|
||||||
elif(self.col_addr_size == 1):
|
elif(self.col_addr_size == 1):
|
||||||
ff_index = self.row_addr_size
|
ff_index = self.row_addr_size
|
||||||
base = self.msf_address_offset - vector(0, 0.5 * drc["minwidth_metal3"])
|
base = self.msf_address_offset - vector(0, 0.5 * drc["minwidth_metal3"])
|
||||||
dout_position = (self.msf_address.dout_positions[ff_index].rotate().scale(1,-1)
|
dout_position = (self.msf_address.dout_positions[ff_index].rotate_scale(1,-1)
|
||||||
+ base)
|
+ base)
|
||||||
dout_bar_position = (self.msf_address.dout_bar_positions[ff_index].rotate().scale(1,-1)
|
dout_bar_position = (self.msf_address.dout_bar_positions[ff_index].rotate_scale(1,-1)
|
||||||
+ base)
|
+ base)
|
||||||
|
|
||||||
y_offset = self.msf_address_offset.y - self.msf_address.width
|
y_offset = self.msf_address_offset.y - self.msf_address.width
|
||||||
|
|
@ -988,7 +988,7 @@ class bank(design.design):
|
||||||
|
|
||||||
# addres translation should take care of the 270 degree CCW rotation
|
# addres translation should take care of the 270 degree CCW rotation
|
||||||
# addres translation should take care of the 270 degree CCW rotation
|
# addres translation should take care of the 270 degree CCW rotation
|
||||||
msf_row_addr_line_position = (self.msf_address.dout_positions[i].rotate().scale(1,-1)
|
msf_row_addr_line_position = (self.msf_address.dout_positions[i].rotate_scale(1,-1)
|
||||||
+ self.msf_address_offset
|
+ self.msf_address_offset
|
||||||
- vector(0, 0.5 * drc["minwidth_metal3"]))
|
- vector(0, 0.5 * drc["minwidth_metal3"]))
|
||||||
connection_width = (self.central_line_xoffset[line_index] + drc["minwidth_metal2"]
|
connection_width = (self.central_line_xoffset[line_index] + drc["minwidth_metal2"]
|
||||||
|
|
@ -1008,7 +1008,7 @@ class bank(design.design):
|
||||||
|
|
||||||
for i in range(self.addr_size):
|
for i in range(self.addr_size):
|
||||||
# Route msf address inputs
|
# Route msf address inputs
|
||||||
msf_din_position = (self.msf_address.din_positions[i].rotate().scale(1,-1)
|
msf_din_position = (self.msf_address.din_positions[i].rotate_scale(1,-1)
|
||||||
+ self.msf_address_offset
|
+ self.msf_address_offset
|
||||||
- vector(0, 0.5 * drc["minwidth_metal3"]))
|
- vector(0, 0.5 * drc["minwidth_metal3"]))
|
||||||
address_position = vector(self.left_vdd_x_offset,
|
address_position = vector(self.left_vdd_x_offset,
|
||||||
|
|
@ -1083,7 +1083,7 @@ class bank(design.design):
|
||||||
""" CLK connection from central bus to MSF address
|
""" CLK connection from central bus to MSF address
|
||||||
should we move this somewhere else hard to find when modify"""
|
should we move this somewhere else hard to find when modify"""
|
||||||
msf_address_clk_position = (self.msf_address_offset
|
msf_address_clk_position = (self.msf_address_offset
|
||||||
+ self.msf_address.clk_positions[0].rotate().scale(1,-1)
|
+ self.msf_address.clk_positions[0].rotate_scale(1,-1)
|
||||||
+ vector(- 0.5 * drc["minwidth_metal1"],
|
+ vector(- 0.5 * drc["minwidth_metal1"],
|
||||||
2 * drc["minwidth_metal2"]))
|
2 * drc["minwidth_metal2"]))
|
||||||
clk_connection_position = (self.msf_address_offset
|
clk_connection_position = (self.msf_address_offset
|
||||||
|
|
@ -1150,7 +1150,7 @@ class bank(design.design):
|
||||||
start = self.bank_select_inv_position + self.inv4x.A_position
|
start = self.bank_select_inv_position + self.inv4x.A_position
|
||||||
end = vector(self.left_vdd_x_offset, start.y + 3 * drc["minwidth_metal3"])
|
end = vector(self.left_vdd_x_offset, start.y + 3 * drc["minwidth_metal3"])
|
||||||
mid = vector(start.x, end.y)
|
mid = vector(start.x, end.y)
|
||||||
self.add_wire(("metal1", "via1", "metal2"), [start, mid, end])
|
self.add_wire(("metal2", "via1", "metal1"), [start, mid, end])
|
||||||
|
|
||||||
# save position
|
# save position
|
||||||
self.bank_select_position = end - vector(0, 0.5 * drc["minwidth_metal2"])
|
self.bank_select_position = end - vector(0, 0.5 * drc["minwidth_metal2"])
|
||||||
|
|
@ -1235,7 +1235,7 @@ class bank(design.design):
|
||||||
correct_y = (2 * self.NOR2.A_position.y + drc["minwidth_metal1"]
|
correct_y = (2 * self.NOR2.A_position.y + drc["minwidth_metal1"]
|
||||||
- self.m1m2_via.width)
|
- self.m1m2_via.width)
|
||||||
end = start + vector(0, correct_y)
|
end = start + vector(0, correct_y)
|
||||||
self.add_wire(("metal2", "via2", "metal3"), [start, mid, end])
|
self.add_wire(("metal3", "via2", "metal2"), [start, mid, end])
|
||||||
|
|
||||||
# Save position
|
# Save position
|
||||||
setattr(self,"{0}_position".format(self.control_signals[i]),
|
setattr(self,"{0}_position".format(self.control_signals[i]),
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,7 @@ def run_drc(name, gds_name):
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
# run drc
|
# run drc
|
||||||
|
cwd = os.getcwd()
|
||||||
os.chdir(OPTS.openram_temp)
|
os.chdir(OPTS.openram_temp)
|
||||||
errfile = "%s%s.drc.err" % (OPTS.openram_temp, name)
|
errfile = "%s%s.drc.err" % (OPTS.openram_temp, name)
|
||||||
outfile = "%s%s.drc.out" % (OPTS.openram_temp, name)
|
outfile = "%s%s.drc.out" % (OPTS.openram_temp, name)
|
||||||
|
|
@ -98,6 +99,7 @@ def run_drc(name, gds_name):
|
||||||
OPTS.calibre_exe, OPTS.openram_temp, errfile, outfile)
|
OPTS.calibre_exe, OPTS.openram_temp, errfile, outfile)
|
||||||
debug.info(1, cmd)
|
debug.info(1, cmd)
|
||||||
os.system(cmd)
|
os.system(cmd)
|
||||||
|
os.chdir(cwd)
|
||||||
|
|
||||||
# check the result for these lines in the summary:
|
# check the result for these lines in the summary:
|
||||||
# TOTAL Original Layer Geometries: 106 (157)
|
# TOTAL Original Layer Geometries: 106 (157)
|
||||||
|
|
@ -163,6 +165,7 @@ def run_lvs(name, gds_name, sp_name):
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
# run LVS
|
# run LVS
|
||||||
|
cwd = os.getcwd()
|
||||||
os.chdir(OPTS.openram_temp)
|
os.chdir(OPTS.openram_temp)
|
||||||
errfile = "%s%s.lvs.err" % (OPTS.openram_temp, name)
|
errfile = "%s%s.lvs.err" % (OPTS.openram_temp, name)
|
||||||
outfile = "%s%s.lvs.out" % (OPTS.openram_temp, name)
|
outfile = "%s%s.lvs.out" % (OPTS.openram_temp, name)
|
||||||
|
|
@ -171,6 +174,7 @@ def run_lvs(name, gds_name, sp_name):
|
||||||
OPTS.openram_temp, errfile, outfile)
|
OPTS.openram_temp, errfile, outfile)
|
||||||
debug.info(2, cmd)
|
debug.info(2, cmd)
|
||||||
os.system(cmd)
|
os.system(cmd)
|
||||||
|
os.chdir(cwd)
|
||||||
|
|
||||||
# check the result for these lines in the summary:
|
# check the result for these lines in the summary:
|
||||||
f = open(lvs_runset['lvsReportFile'], "r")
|
f = open(lvs_runset['lvsReportFile'], "r")
|
||||||
|
|
@ -265,6 +269,7 @@ def run_pex(name, gds_name, sp_name, output=None):
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
# run pex
|
# run pex
|
||||||
|
cwd = os.getcwd()
|
||||||
os.chdir(OPTS.openram_temp)
|
os.chdir(OPTS.openram_temp)
|
||||||
errfile = "{0}{1}.pex.err".format(OPTS.openram_temp, name)
|
errfile = "{0}{1}.pex.err".format(OPTS.openram_temp, name)
|
||||||
outfile = "{0}{1}.pex.out".format(OPTS.openram_temp, name)
|
outfile = "{0}{1}.pex.out".format(OPTS.openram_temp, name)
|
||||||
|
|
@ -275,6 +280,7 @@ def run_pex(name, gds_name, sp_name, output=None):
|
||||||
outfile)
|
outfile)
|
||||||
debug.info(2, cmd)
|
debug.info(2, cmd)
|
||||||
os.system(cmd)
|
os.system(cmd)
|
||||||
|
os.chdir(cwd)
|
||||||
|
|
||||||
# also check the output file
|
# also check the output file
|
||||||
f = open(outfile, "r")
|
f = open(outfile, "r")
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,11 @@ def relative_compare(value1,value2):
|
||||||
|
|
||||||
def parse_output(filename, key):
|
def parse_output(filename, key):
|
||||||
"""Parses a hspice output.lis file for a key value"""
|
"""Parses a hspice output.lis file for a key value"""
|
||||||
f = open("{0}/{1}.lis".format(OPTS.openram_temp, filename), "r")
|
full_filename="{0}{1}.lis".format(OPTS.openram_temp, filename)
|
||||||
|
try:
|
||||||
|
f = open(full_filename, "r")
|
||||||
|
except IOError:
|
||||||
|
debug.error("Unable to open spice output file: {0}".format(full_filename),1)
|
||||||
contents = f.read()
|
contents = f.read()
|
||||||
val = re.search(r"{0}\s*=\s*(-?\d+.?\d*\S*)\s+.*".format(key), contents)
|
val = re.search(r"{0}\s*=\s*(-?\d+.?\d*\S*)\s+.*".format(key), contents)
|
||||||
if val != None:
|
if val != None:
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import tech
|
||||||
import math
|
import math
|
||||||
import stimuli
|
import stimuli
|
||||||
import charutils as ch
|
import charutils as ch
|
||||||
|
import utils
|
||||||
|
|
||||||
OPTS = globals.get_opts()
|
OPTS = globals.get_opts()
|
||||||
|
|
||||||
|
|
@ -262,20 +263,11 @@ class delay():
|
||||||
# run until the last cycle time
|
# run until the last cycle time
|
||||||
end_time = self.cycle_times[-1]
|
end_time = self.cycle_times[-1]
|
||||||
self.sf.write(".TRAN 5p {0}n\n".format(end_time))
|
self.sf.write(".TRAN 5p {0}n\n".format(end_time))
|
||||||
|
self.sf.write(".OPTIONS POST=1 PROBE\n")
|
||||||
if OPTS.spice_version == "hspice":
|
# create plots for all signals
|
||||||
# create plots for all signals
|
self.sf.write(".probe V(*)\n")
|
||||||
self.sf.write(".OPTIONS POST=1 PROBE\n")
|
# end the stimulus file
|
||||||
self.sf.write(".probe V(*)\n")
|
self.sf.write(".end\n")
|
||||||
# end the stimulus file
|
|
||||||
self.sf.write(".end\n")
|
|
||||||
self.sf.close()
|
|
||||||
else:
|
|
||||||
self.sf.write(".control\n")
|
|
||||||
self.sf.write("run\n")
|
|
||||||
self.sf.write("quit\n")
|
|
||||||
self.sf.write(".endc\n")
|
|
||||||
self.sf.write(".end\n")
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -353,20 +345,19 @@ class delay():
|
||||||
|
|
||||||
target_period = 0.5 * (ub_period + lb_period)
|
target_period = 0.5 * (ub_period + lb_period)
|
||||||
debug.info(1, "MinPeriod Search: {0}ns (ub: {1} lb: {2})".format(target_period,
|
debug.info(1, "MinPeriod Search: {0}ns (ub: {1} lb: {2})".format(target_period,
|
||||||
ub_period,
|
ub_period,
|
||||||
lb_period))
|
lb_period))
|
||||||
|
|
||||||
(success, delay_out) = self.try_period(feasible_period, target_period, data_value)
|
(success, delay_out) = self.try_period(feasible_period, target_period, data_value)
|
||||||
if success:
|
if success:
|
||||||
if ch.relative_compare(ub_period, target_period):
|
|
||||||
# use the two values to compare, but only return the ub since it is guaranteed feasible
|
|
||||||
(success, delay_out) = self.try_period(feasible_period, ub_period, data_value)
|
|
||||||
return (ub_period, delay_out)
|
|
||||||
fail_flag = False
|
|
||||||
ub_period = target_period
|
ub_period = target_period
|
||||||
else:
|
else:
|
||||||
lb_period = target_period
|
lb_period = target_period
|
||||||
|
|
||||||
|
if ch.relative_compare(ub_period, lb_period):
|
||||||
|
# use the two values to compare, but only return the ub since it is guaranteed feasible
|
||||||
|
(success, delay_out) = self.try_period(feasible_period, ub_period, data_value)
|
||||||
|
return (ub_period, delay_out)
|
||||||
|
|
||||||
self.error("Should not reach here.",-1)
|
self.error("Should not reach here.",-1)
|
||||||
return (target_period, delay_out)
|
return (target_period, delay_out)
|
||||||
|
|
|
||||||
|
|
@ -165,20 +165,12 @@ class setup_hold():
|
||||||
def write_control(self, period):
|
def write_control(self, period):
|
||||||
# transient window
|
# transient window
|
||||||
end_time = 2 * period
|
end_time = 2 * period
|
||||||
self.sf.write(".TRAN 1n {0}n\n".format(end_time))
|
self.sf.write(".TRAN 5p {0}n\n".format(end_time))
|
||||||
self.sf.write(".OPTIONS POST=1 PROBE\n")
|
self.sf.write(".OPTIONS POST=1 PROBE\n")
|
||||||
|
# create plots for all signals
|
||||||
if OPTS.spice_version == "hspice":
|
self.sf.write(".probe V(*)\n")
|
||||||
self.sf.write(".probe V(*)\n")
|
# end the stimulus file
|
||||||
# end the stimulus file
|
self.sf.write(".end\n")
|
||||||
self.sf.write(".end\n")
|
|
||||||
else:
|
|
||||||
self.sf.write(".control\n")
|
|
||||||
self.sf.write("run\n")
|
|
||||||
self.sf.write("quit\n")
|
|
||||||
self.sf.write(".endc\n")
|
|
||||||
self.sf.write(".end\n")
|
|
||||||
|
|
||||||
|
|
||||||
def bidir_search(self, correct_value, noise_margin, measure_name, mode):
|
def bidir_search(self, correct_value, noise_margin, measure_name, mode):
|
||||||
""" This will perform a bidirectional search for either setup or hold times.
|
""" This will perform a bidirectional search for either setup or hold times.
|
||||||
|
|
@ -186,9 +178,11 @@ class setup_hold():
|
||||||
depending on whether we are doing setup or hold.
|
depending on whether we are doing setup or hold.
|
||||||
"""
|
"""
|
||||||
period = tech.spice["feasible_period"]
|
period = tech.spice["feasible_period"]
|
||||||
|
debug.info(2,"Feasible period from technology file: {0} ".format(period))
|
||||||
|
|
||||||
|
|
||||||
# The clock will start being offset by a period, so we want to look before and after
|
# The clock will start being offset by a period, so we want to look before and after
|
||||||
# theis time.
|
# this time by half a period.
|
||||||
if mode == "HOLD":
|
if mode == "HOLD":
|
||||||
target_time = 1.5 * period
|
target_time = 1.5 * period
|
||||||
lower_bound = 0.5*period
|
lower_bound = 0.5*period
|
||||||
|
|
@ -212,6 +206,8 @@ class setup_hold():
|
||||||
setuphold_time = target_time - period
|
setuphold_time = target_time - period
|
||||||
else:
|
else:
|
||||||
setuphold_time = period - target_time
|
setuphold_time = period - target_time
|
||||||
|
debug.info(2,"Checked initial {0} time {1}, data at {2}, clock at {3} ".format(mode,setuphold_time,
|
||||||
|
target_time,period))
|
||||||
debug.info(3,"Target time: {0} Low: {1} Up: {2} Measured: {3}".format(target_time,
|
debug.info(3,"Target time: {0} Low: {1} Up: {2} Measured: {3}".format(target_time,
|
||||||
lower_bound,
|
lower_bound,
|
||||||
upper_bound,
|
upper_bound,
|
||||||
|
|
@ -220,6 +216,10 @@ class setup_hold():
|
||||||
debug.error("Initial period/target hold time fails for data value",2)
|
debug.error("Initial period/target hold time fails for data value",2)
|
||||||
|
|
||||||
# We already found it feasible, so advance one step first thing.
|
# We already found it feasible, so advance one step first thing.
|
||||||
|
debug.info(2,"Performing bidir search on {3} time: {2} LB: {0} UB: {1} ".format(lower_bound,
|
||||||
|
upper_bound,
|
||||||
|
setuphold_time,
|
||||||
|
mode))
|
||||||
if mode == "HOLD":
|
if mode == "HOLD":
|
||||||
target_time -= 0.5 * (upper_bound - lower_bound)
|
target_time -= 0.5 * (upper_bound - lower_bound)
|
||||||
else:
|
else:
|
||||||
|
|
@ -269,6 +269,8 @@ class setup_hold():
|
||||||
setuphold_time = target_time - period
|
setuphold_time = target_time - period
|
||||||
else:
|
else:
|
||||||
setuphold_time = period - target_time
|
setuphold_time = period - target_time
|
||||||
|
|
||||||
|
debug.info(2,"Converged on {0} time {1}, data at {2}, clock at {3}.".format(mode,setuphold_time,target_time,period))
|
||||||
return setuphold_time
|
return setuphold_time
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -445,23 +445,31 @@ def write_supply(stim_file, vdd_name, gnd_name, vdd_voltage, gnd_voltage):
|
||||||
def run_sim():
|
def run_sim():
|
||||||
"""Run hspice in batch mode and output rawfile to parse."""
|
"""Run hspice in batch mode and output rawfile to parse."""
|
||||||
temp_stim = "{0}stim.sp".format(OPTS.openram_temp)
|
temp_stim = "{0}stim.sp".format(OPTS.openram_temp)
|
||||||
|
|
||||||
if OPTS.spice_version == "hspice":
|
if OPTS.spice_version == "hspice":
|
||||||
# TODO: Should make multithreading parameter a configuration option
|
# TODO: Should make multithreading parameter a configuration option
|
||||||
cmd_args = "-mt 8 -i {1} -o {2}timing 2>&1 /dev/null".format(OPTS.spice_exe,
|
cmd = "{0} -mt 8 -i {1} -o {2}timing".format(OPTS.spice_exe,
|
||||||
temp_stim,
|
temp_stim,
|
||||||
OPTS.openram_temp)
|
OPTS.openram_temp)
|
||||||
|
valid_retcode=0
|
||||||
else:
|
else:
|
||||||
cmd_args = "-b -i {1} -o {2}timing.lis 2>&1 /dev/null".format(OPTS.spice_exe,
|
cmd = "{0} -b -o {2}timing.lis {1}".format(OPTS.spice_exe,
|
||||||
temp_stim,
|
temp_stim,
|
||||||
OPTS.openram_temp)
|
OPTS.openram_temp)
|
||||||
|
# for some reason, ngspice-25 returns 1 when it only has acceptable warnings
|
||||||
|
valid_retcode=1
|
||||||
|
|
||||||
FNULL = open(os.devnull, 'w')
|
|
||||||
debug.info(2, OPTS.spice_exe + " " + cmd_args)
|
spice_stdout = open("{0}spice_stdout.log".format(OPTS.openram_temp), 'w')
|
||||||
retcode = subprocess.call([OPTS.spice_exe, cmd_args], stdout=FNULL, stderr=FNULL)
|
spice_stderr = open("{0}spice_stderr.log".format(OPTS.openram_temp), 'w')
|
||||||
FNULL.close()
|
|
||||||
|
|
||||||
if (retcode > 0):
|
debug.info(3, cmd)
|
||||||
debug.error("Spice simulation error: " + OPTS.spice_exe + " " + cmd_args)
|
retcode = subprocess.call(cmd, stdout=spice_stdout, stderr=spice_stderr, shell=True)
|
||||||
sys.exit(-1)
|
|
||||||
|
spice_stdout.close()
|
||||||
|
spice_stderr.close()
|
||||||
|
|
||||||
|
if (retcode > valid_retcode):
|
||||||
|
debug.error("Spice simulation error: " + cmd, -1)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ class contact(design.design):
|
||||||
dimensions[1],
|
dimensions[1],
|
||||||
contact.unique_contact_id)
|
contact.unique_contact_id)
|
||||||
design.design.__init__(self, name)
|
design.design.__init__(self, name)
|
||||||
debug.info(2, "create contact object {0}".format(name))
|
debug.info(3, "create contact object {0}".format(name))
|
||||||
contact.unique_contact_id += 1
|
contact.unique_contact_id += 1
|
||||||
|
|
||||||
self.layer_stack = layer_stack
|
self.layer_stack = layer_stack
|
||||||
|
|
@ -40,8 +40,8 @@ class contact(design.design):
|
||||||
self.offset_attributes(coordinate)
|
self.offset_attributes(coordinate)
|
||||||
self.translate(coordinate)
|
self.translate(coordinate)
|
||||||
|
|
||||||
self.height = max(obj.offset[1] + obj.height for obj in self.objs)
|
self.height = max(obj.offset.y + obj.height for obj in self.objs)
|
||||||
self.width = max(obj.offset[0] + obj.width for obj in self.objs)
|
self.width = max(obj.offset.x + obj.width for obj in self.objs)
|
||||||
|
|
||||||
def setup_layers(self):
|
def setup_layers(self):
|
||||||
(first_layer, via_layer, second_layer) = self.layer_stack
|
(first_layer, via_layer, second_layer) = self.layer_stack
|
||||||
|
|
|
||||||
|
|
@ -146,7 +146,7 @@ class control_logic(design.design):
|
||||||
|
|
||||||
# Height and width
|
# Height and width
|
||||||
self.height = self.logic_height + self.output_port_gap
|
self.height = self.logic_height + self.output_port_gap
|
||||||
self.width = self.offset_replica_bitline[0] + self.replica_bitline.height
|
self.width = self.offset_replica_bitline.x + self.replica_bitline.height
|
||||||
|
|
||||||
def add_routing(self):
|
def add_routing(self):
|
||||||
""" Routing between modules """
|
""" Routing between modules """
|
||||||
|
|
@ -175,11 +175,11 @@ class control_logic(design.design):
|
||||||
# msf_control inputs
|
# msf_control inputs
|
||||||
correct = vector(0, 0.5 * drc["minwidth_metal2"])
|
correct = vector(0, 0.5 * drc["minwidth_metal2"])
|
||||||
def translate_inputs(pt1,pt2):
|
def translate_inputs(pt1,pt2):
|
||||||
return pt1 + pt2.rotate().scale(1,-1) - correct
|
return pt1 + pt2.rotate_scale(1,-1) - correct
|
||||||
|
|
||||||
# msf_control outputs
|
# msf_control outputs
|
||||||
def translate_outputs(pt1,pt2):
|
def translate_outputs(pt1,pt2):
|
||||||
return pt1 - correct + vector(self.msf_control.height,- pt2[0])
|
return pt1 - correct + vector(self.msf_control.height,- pt2.x)
|
||||||
|
|
||||||
# set CSS WE OE signal groups(in, out, bar)
|
# set CSS WE OE signal groups(in, out, bar)
|
||||||
pt1 = self.offset_msf_control
|
pt1 = self.offset_msf_control
|
||||||
|
|
@ -197,21 +197,21 @@ class control_logic(design.design):
|
||||||
|
|
||||||
# clk , vdd
|
# clk , vdd
|
||||||
base = self.offset_msf_control - vector(0.5 * drc["minwidth_metal2"], 0)
|
base = self.offset_msf_control - vector(0.5 * drc["minwidth_metal2"], 0)
|
||||||
msf_clk = self.msf_control.clk_positions[0].rotate().scale(1,-1)
|
msf_clk = self.msf_control.clk_positions[0].rotate_scale(1,-1)
|
||||||
self.msf_control_clk_position = base + msf_clk
|
self.msf_control_clk_position = base + msf_clk
|
||||||
msf_vdd = self.msf_control.vdd_positions[0].rotate().scale(1,-1)
|
msf_vdd = self.msf_control.vdd_positions[0].rotate_scale(1,-1)
|
||||||
self.msf_control_vdd_position = base + msf_vdd
|
self.msf_control_vdd_position = base + msf_vdd
|
||||||
|
|
||||||
# gnd
|
# gnd
|
||||||
self.msf_control_gnd_positions = []
|
self.msf_control_gnd_positions = []
|
||||||
for gnd_offset in self.msf_control.gnd_positions:
|
for gnd_offset in self.msf_control.gnd_positions:
|
||||||
offset = self.offset_msf_control + vector(self.msf_control.height,
|
offset = self.offset_msf_control + vector(self.msf_control.height,
|
||||||
- gnd_offset[0])
|
- gnd_offset.x)
|
||||||
self.msf_control_gnd_positions.append(offset - correct)
|
self.msf_control_gnd_positions.append(offset - correct)
|
||||||
|
|
||||||
def add_1st_row(self,y_off):
|
def add_1st_row(self,y_off):
|
||||||
# inv1 with clk as gate input.
|
# inv1 with clk as gate input.
|
||||||
msf_control_rotate_x = self.offset_msf_control[0] + self.msf_control.height
|
msf_control_rotate_x = self.offset_msf_control.x + self.msf_control.height
|
||||||
self.offset_inv1 = vector(msf_control_rotate_x - self.inv4.width, y_off)
|
self.offset_inv1 = vector(msf_control_rotate_x - self.inv4.width, y_off)
|
||||||
self.add_inst(name="clk_inverter",
|
self.add_inst(name="clk_inverter",
|
||||||
mod=self.inv4,
|
mod=self.inv4,
|
||||||
|
|
@ -246,7 +246,7 @@ class control_logic(design.design):
|
||||||
self.set_nand2_nor2_pin("nand2",[1,1])
|
self.set_nand2_nor2_pin("nand2",[1,1])
|
||||||
|
|
||||||
# REPLICA BITLINE
|
# REPLICA BITLINE
|
||||||
base_x = self.nand_array_position[0] + self.NAND3.width + 3 * self.inv.width
|
base_x = self.nand_array_position.x + self.NAND3.width + 3 * self.inv.width
|
||||||
total_rail_gap = self.rail_offset_gap + self.overall_rail_2_gap
|
total_rail_gap = self.rail_offset_gap + self.overall_rail_2_gap
|
||||||
x_off = base_x + total_rail_gap + self.replica_bitline_gap
|
x_off = base_x + total_rail_gap + self.replica_bitline_gap
|
||||||
self.offset_replica_bitline = vector(x_off, y_off)
|
self.offset_replica_bitline = vector(x_off, y_off)
|
||||||
|
|
@ -284,7 +284,7 @@ class control_logic(design.design):
|
||||||
|
|
||||||
def add_2nd_row(self, y_off):
|
def add_2nd_row(self, y_off):
|
||||||
# Nand3_1 input: OE, clk_bar,CS output: rblk_bar
|
# Nand3_1 input: OE, clk_bar,CS output: rblk_bar
|
||||||
self.offset_nand3_1 = vector(self.nand_array_position[0], y_off)
|
self.offset_nand3_1 = vector(self.nand_array_position.x, y_off)
|
||||||
self.add_inst(name="NAND3_rblk_bar",
|
self.add_inst(name="NAND3_rblk_bar",
|
||||||
mod=self.NAND3,
|
mod=self.NAND3,
|
||||||
offset=self.offset_nand3_1,
|
offset=self.offset_nand3_1,
|
||||||
|
|
@ -294,7 +294,7 @@ class control_logic(design.design):
|
||||||
self.set_Nand3_pins(nand_name = "nand3_1",nand_scale = [0,-1])
|
self.set_Nand3_pins(nand_name = "nand3_1",nand_scale = [0,-1])
|
||||||
|
|
||||||
# Nand3_2 input: WE, clk_bar,CS output: w_en_bar
|
# Nand3_2 input: WE, clk_bar,CS output: w_en_bar
|
||||||
self.offset_nand3_2 = vector(self.nand_array_position[0], y_off)
|
self.offset_nand3_2 = vector(self.nand_array_position.x, y_off)
|
||||||
self.add_inst(name="NAND3_w_en_bar",
|
self.add_inst(name="NAND3_w_en_bar",
|
||||||
mod=self.NAND3,
|
mod=self.NAND3,
|
||||||
offset=self.offset_nand3_2,
|
offset=self.offset_nand3_2,
|
||||||
|
|
@ -304,7 +304,7 @@ class control_logic(design.design):
|
||||||
self.set_Nand3_pins(nand_name = "nand3_2",nand_scale = [0,1])
|
self.set_Nand3_pins(nand_name = "nand3_2",nand_scale = [0,1])
|
||||||
|
|
||||||
# connect nand2 and nand3 to inv
|
# connect nand2 and nand3 to inv
|
||||||
nand3_to_inv_connection_height = self.NAND3.Z_position[1] - self.inv.A_position[1] + drc["minwidth_metal1"]
|
nand3_to_inv_connection_height = self.NAND3.Z_position.y- self.inv.A_position.y+ drc["minwidth_metal1"]
|
||||||
self.add_rect(layer="metal1",
|
self.add_rect(layer="metal1",
|
||||||
offset=self.nand3_1_Z_position,
|
offset=self.nand3_1_Z_position,
|
||||||
width=drc["minwidth_metal1"],
|
width=drc["minwidth_metal1"],
|
||||||
|
|
@ -315,7 +315,7 @@ class control_logic(design.design):
|
||||||
height=-nand3_to_inv_connection_height)
|
height=-nand3_to_inv_connection_height)
|
||||||
|
|
||||||
# inv_2 input: rblk_bar, output: rblk
|
# inv_2 input: rblk_bar, output: rblk
|
||||||
x_off = self.nand_array_position[0] + self.NAND3.width
|
x_off = self.nand_array_position.x + self.NAND3.width
|
||||||
self.offset_inv2 = vector(x_off, y_off)
|
self.offset_inv2 = vector(x_off, y_off)
|
||||||
self.add_inst(name="inv_rblk",
|
self.add_inst(name="inv_rblk",
|
||||||
mod=self.inv,
|
mod=self.inv,
|
||||||
|
|
@ -336,7 +336,7 @@ class control_logic(design.design):
|
||||||
self.set_inv2345_pins(inv_name="inv3", inv_scale=[1, 1])
|
self.set_inv2345_pins(inv_name="inv3", inv_scale=[1, 1])
|
||||||
|
|
||||||
# BUFFER INVERTERS FOR W_EN
|
# BUFFER INVERTERS FOR W_EN
|
||||||
x_off = self.nand_array_position[0] + self.NAND3.width + self.inv.width
|
x_off = self.nand_array_position.x + self.NAND3.width + self.inv.width
|
||||||
self.offset_inv6 = vector(x_off, y_off)
|
self.offset_inv6 = vector(x_off, y_off)
|
||||||
self.add_inst(name="inv_w_en1",
|
self.add_inst(name="inv_w_en1",
|
||||||
mod=self.inv,
|
mod=self.inv,
|
||||||
|
|
@ -344,7 +344,7 @@ class control_logic(design.design):
|
||||||
mirror="RO")
|
mirror="RO")
|
||||||
self.connect_inst(["pre_w_en", "pre_w_en1", "vdd", "gnd"])
|
self.connect_inst(["pre_w_en", "pre_w_en1", "vdd", "gnd"])
|
||||||
|
|
||||||
x_off = self.nand_array_position[0] + self.NAND3.width + 2 * self.inv.width
|
x_off = self.nand_array_position.x + self.NAND3.width + 2 * self.inv.width
|
||||||
self.offset_inv7 = [x_off, y_off]
|
self.offset_inv7 = [x_off, y_off]
|
||||||
self.add_inst(name="inv_w_en2",
|
self.add_inst(name="inv_w_en2",
|
||||||
mod=self.inv,
|
mod=self.inv,
|
||||||
|
|
@ -392,7 +392,7 @@ class control_logic(design.design):
|
||||||
|
|
||||||
def add_msf_control_routing(self):
|
def add_msf_control_routing(self):
|
||||||
# FIRST RAIL : MSF_CONTROL OUTPUT RAIL
|
# FIRST RAIL : MSF_CONTROL OUTPUT RAIL
|
||||||
rail1_start = vector(self.msf_control_WE_position[0],
|
rail1_start = vector(self.msf_control_WE_position.x,
|
||||||
self.output_port_gap)
|
self.output_port_gap)
|
||||||
for i in range(self.num_rails_1):
|
for i in range(self.num_rails_1):
|
||||||
correct = vector((i+1) * self.rail_offset_gap, 0)
|
correct = vector((i+1) * self.rail_offset_gap, 0)
|
||||||
|
|
@ -401,18 +401,18 @@ class control_logic(design.design):
|
||||||
offset=offset,
|
offset=offset,
|
||||||
width=drc["minwidth_metal2"],
|
width=drc["minwidth_metal2"],
|
||||||
height=self.logic_height)
|
height=self.logic_height)
|
||||||
self.rail_1_x_offsets.append(offset[0])
|
self.rail_1_x_offsets.append(offset.x)
|
||||||
|
|
||||||
rail2_start_x = (self.nand_array_position[0] + self.NAND3.width
|
rail2_start_x = (self.nand_array_position.x + self.NAND3.width
|
||||||
+ 3 * self.inv.width + self.rail_offset_gap)
|
+ 3 * self.inv.width + self.rail_offset_gap)
|
||||||
for i in range(self.num_rails_2):
|
for i in range(self.num_rails_2):
|
||||||
offset = [rail2_start_x + i * self.rail_offset_gap,
|
offset = vector(rail2_start_x + i * self.rail_offset_gap,
|
||||||
self.output_port_gap]
|
self.output_port_gap)
|
||||||
self.add_rect(layer="metal2",
|
self.add_rect(layer="metal2",
|
||||||
offset=offset,
|
offset=offset,
|
||||||
width=drc["minwidth_metal2"],
|
width=drc["minwidth_metal2"],
|
||||||
height=self.logic_height)
|
height=self.logic_height)
|
||||||
self.rail_2_x_offsets.append(offset[0])
|
self.rail_2_x_offsets.append(offset.x)
|
||||||
|
|
||||||
def add_1st_row_routing(self):
|
def add_1st_row_routing(self):
|
||||||
# First rail routing left
|
# First rail routing left
|
||||||
|
|
@ -425,7 +425,7 @@ class control_logic(design.design):
|
||||||
line_x_offset = self.rail_1_x_offsets[line_indices[i]]
|
line_x_offset = self.rail_1_x_offsets[line_indices[i]]
|
||||||
self.add_rect(layer="metal1",
|
self.add_rect(layer="metal1",
|
||||||
offset=offset,
|
offset=offset,
|
||||||
width=line_x_offset - offset[0] + drc["minwidth_metal2"],
|
width=line_x_offset - offset.x + drc["minwidth_metal2"],
|
||||||
height=drc["minwidth_metal1"])
|
height=drc["minwidth_metal1"])
|
||||||
correct1 = vector(self.gap_between_rails, - self.via_shift)
|
correct1 = vector(self.gap_between_rails, - self.via_shift)
|
||||||
correct2 = vector(self.contact_shift + drc["minwidth_metal2"],0)
|
correct2 = vector(self.contact_shift + drc["minwidth_metal2"],0)
|
||||||
|
|
@ -450,27 +450,30 @@ class control_logic(design.design):
|
||||||
base = vector(line_x_offset, offset[1])
|
base = vector(line_x_offset, offset[1])
|
||||||
self.add_rect(layer="metal1",
|
self.add_rect(layer="metal1",
|
||||||
offset=base,
|
offset=base,
|
||||||
width=offset[0] - line_x_offset,
|
width=offset.x - line_x_offset,
|
||||||
height=drc["minwidth_metal1"])
|
height=drc["minwidth_metal1"])
|
||||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||||
offset=base + correct1,
|
offset=base + correct1,
|
||||||
rotate=90)
|
rotate=90)
|
||||||
|
|
||||||
# OE_bar [Bus # 1] to nor2 B input
|
# OE_bar [Bus # 1] to nor2 B input
|
||||||
layer_stack = ("metal2", "via1", "metal1")
|
layer_stack = ("metal1", "via1", "metal2")
|
||||||
start = self.nor2_1_B_position
|
start = self.nor2_1_B_position
|
||||||
mid1 = [self.nor2_1_B_position[0] + 2 * drc["minwidth_metal2"], start[1]]
|
mid1 = vector(self.nor2_1_B_position.x+ 2 * drc["minwidth_metal2"],
|
||||||
mid2 = [mid1[0], self.nor2_1_gnd_position[1] - 2 * drc["minwidth_metal1"]]
|
start.y)
|
||||||
mid3 = [self.rail_1_x_offsets[1] + 0.5 * drc["minwidth_metal2"], mid2[1]]
|
mid2 = vector(mid1.x,
|
||||||
end = [mid3[0], self.output_port_gap]
|
self.nor2_1_gnd_position.y- 2 * drc["minwidth_metal1"])
|
||||||
|
mid3 = vector(self.rail_1_x_offsets[1] + 0.5 * drc["minwidth_metal2"],
|
||||||
|
mid2.y)
|
||||||
|
end = [mid3.x, self.output_port_gap]
|
||||||
self.add_wire(layer_stack, [start, mid1, mid2, mid3, end])
|
self.add_wire(layer_stack, [start, mid1, mid2, mid3, end])
|
||||||
|
|
||||||
layer_stack = ("metal1")
|
layer_stack = ("metal1")
|
||||||
start = [self.inv1_Z_position[0], self.inv1_Z_position[1] + 0.5 * drc["minwidth_metal1"]]
|
start = self.inv1_Z_position+ vector(0, + 0.5 * drc["minwidth_metal1"])
|
||||||
mid1 = [start[0] + drc["minwidth_metal2"], start[1]]
|
mid1 = start + vector(drc["minwidth_metal2"], 0)
|
||||||
mid2 = [mid1[0], self.nand2_1_B_position
|
mid2 = vector(mid1.x,
|
||||||
[1] + 0.5 * drc["minwidth_metal1"]]
|
self.nand2_1_B_position.y + 0.5 * drc["minwidth_metal1"])
|
||||||
end = [self.nand2_1_B_position[0], mid2[1]]
|
end = [self.nand2_1_B_position.x, mid2.y]
|
||||||
self.add_path(layer_stack, [start, mid1, mid2, end])
|
self.add_path(layer_stack, [start, mid1, mid2, end])
|
||||||
|
|
||||||
def add_2nd_row_routing(self):
|
def add_2nd_row_routing(self):
|
||||||
|
|
@ -486,23 +489,23 @@ class control_logic(design.design):
|
||||||
line_x_offset = self.rail_2_x_offsets[line_indices[i]]
|
line_x_offset = self.rail_2_x_offsets[line_indices[i]]
|
||||||
self.add_rect(layer="metal1",
|
self.add_rect(layer="metal1",
|
||||||
offset=offset,
|
offset=offset,
|
||||||
width=line_x_offset - offset[0] + drc["minwidth_metal2"],
|
width=line_x_offset - offset.x+ drc["minwidth_metal2"],
|
||||||
height=drc["minwidth_metal1"])
|
height=drc["minwidth_metal1"])
|
||||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||||
offset=[line_x_offset + self.gap_between_rails,
|
offset=[line_x_offset + self.gap_between_rails,
|
||||||
offset[1] - self.via_shift],
|
offset.y- self.via_shift],
|
||||||
rotate=90)
|
rotate=90)
|
||||||
|
|
||||||
# Replica bitline (rblk to replica bitline input)
|
# Replica bitline (rblk to replica bitline input)
|
||||||
layer_stack = ("metal2", "via1", "metal1")
|
layer_stack = ("metal1", "via1", "metal2")
|
||||||
start = [self.rail_2_x_offsets[1] + 0.5 * drc["minwidth_metal2"],
|
start = vector(self.rail_2_x_offsets[1] + 0.5 * drc["minwidth_metal2"],
|
||||||
self.output_port_gap]
|
self.output_port_gap)
|
||||||
mid1 = [start[0], 0.5 * drc["minwidth_metal1"]]
|
mid1 = vector(start.x, 0.5 * drc["minwidth_metal1"])
|
||||||
end = [self.replica_en_offset[0], mid1[1]]
|
end = vector(self.replica_en_offset.x, mid1.y)
|
||||||
|
|
||||||
self.add_wire(layer_stack, [start, mid1, end])
|
self.add_wire(layer_stack, [start, mid1, end])
|
||||||
|
|
||||||
height = self.replica_en_offset[1] - end[1] + 0.5 * drc["minwidth_metal1"]
|
height = self.replica_en_offset.y- end.y+ 0.5 * drc["minwidth_metal1"]
|
||||||
|
|
||||||
self.add_rect(layer="metal1",
|
self.add_rect(layer="metal1",
|
||||||
offset=end - vector([0.5 * drc["minwidth_metal1"]] * 2),
|
offset=end - vector([0.5 * drc["minwidth_metal1"]] * 2),
|
||||||
|
|
@ -514,7 +517,7 @@ class control_logic(design.design):
|
||||||
end = self.replica_out_offset - vector(0.5 * drc["minwidth_metal1"],0)
|
end = self.replica_out_offset - vector(0.5 * drc["minwidth_metal1"],0)
|
||||||
self.add_rect(layer="metal3",
|
self.add_rect(layer="metal3",
|
||||||
offset=start,
|
offset=start,
|
||||||
width=self.replica_out_offset[0] - self.rail_2_x_offsets[2],
|
width=self.replica_out_offset.x- self.rail_2_x_offsets[2],
|
||||||
height=drc["minwidth_metal3"])
|
height=drc["minwidth_metal3"])
|
||||||
self.add_via(layers=("metal2", "via2", "metal3"),
|
self.add_via(layers=("metal2", "via2", "metal3"),
|
||||||
offset=start)
|
offset=start)
|
||||||
|
|
@ -536,7 +539,7 @@ class control_logic(design.design):
|
||||||
self.add_rect(layer="metal1",
|
self.add_rect(layer="metal1",
|
||||||
offset=self.nand3_2_vdd_position,
|
offset=self.nand3_2_vdd_position,
|
||||||
width=(rail_2_x + drc["minwidth_metal2"]
|
width=(rail_2_x + drc["minwidth_metal2"]
|
||||||
- self.nand3_2_vdd_position[0]),
|
- self.nand3_2_vdd_position.x),
|
||||||
height=drc["minwidth_metal1"])
|
height=drc["minwidth_metal1"])
|
||||||
|
|
||||||
# Connection in horizontal metal2 vdd rail
|
# Connection in horizontal metal2 vdd rail
|
||||||
|
|
@ -551,10 +554,10 @@ class control_logic(design.design):
|
||||||
|
|
||||||
# Connection of msf_vdd to inv1 vdd
|
# Connection of msf_vdd to inv1 vdd
|
||||||
self.add_rect(layer="metal1",
|
self.add_rect(layer="metal1",
|
||||||
offset=[self.msf_control_vdd_position[0],
|
offset=[self.msf_control_vdd_position.x,
|
||||||
self.inv1_vdd_position[1]],
|
self.inv1_vdd_position[1]],
|
||||||
width=drc["minwidth_metal1"],
|
width=drc["minwidth_metal1"],
|
||||||
height=self.msf_control_vdd_position[1] - self.inv1_vdd_position[1])
|
height=self.msf_control_vdd_position.y- self.inv1_vdd_position[1])
|
||||||
|
|
||||||
vdd_offset = vector(self.replica_bitline.height,3 * drc["minwidth_metal1"])
|
vdd_offset = vector(self.replica_bitline.height,3 * drc["minwidth_metal1"])
|
||||||
|
|
||||||
|
|
@ -569,25 +572,25 @@ class control_logic(design.design):
|
||||||
for gnd_offset in self.msf_control_gnd_positions:
|
for gnd_offset in self.msf_control_gnd_positions:
|
||||||
self.add_rect(layer="metal2",
|
self.add_rect(layer="metal2",
|
||||||
offset=gnd_offset,
|
offset=gnd_offset,
|
||||||
width=(self.rail_1_x_offsets[0] - gnd_offset[0]
|
width=(self.rail_1_x_offsets[0] - gnd_offset.x
|
||||||
+ drc["minwidth_metal2"]),
|
+ drc["minwidth_metal2"]),
|
||||||
height=drc["minwidth_metal2"])
|
height=drc["minwidth_metal2"])
|
||||||
|
|
||||||
# Connect msf_control gnd to nand3 gnd
|
# Connect msf_control gnd to nand3 gnd
|
||||||
self.add_rect(layer="metal1",
|
self.add_rect(layer="metal1",
|
||||||
offset=self.nor2_1_gnd_position,
|
offset=self.nor2_1_gnd_position,
|
||||||
width=self.offset_replica_bitline[0],
|
width=self.offset_replica_bitline.x,
|
||||||
height=drc["minwidth_metal1"])
|
height=drc["minwidth_metal1"])
|
||||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||||
offset=[self.rail_1_x_offsets[0] + self.gap_between_rails,
|
offset=[self.rail_1_x_offsets[0] + self.gap_between_rails,
|
||||||
self.nor2_1_gnd_position[1] - self.via_shift],
|
self.nor2_1_gnd_position.y- self.via_shift],
|
||||||
rotate=90)
|
rotate=90)
|
||||||
|
|
||||||
# nand3 gnd to replica bitline gnd
|
# nand3 gnd to replica bitline gnd
|
||||||
self.add_rect(layer="metal1",
|
self.add_rect(layer="metal1",
|
||||||
offset=self.nand3_2_gnd_position,
|
offset=self.nand3_2_gnd_position,
|
||||||
width=(self.offset_replica_bitline[0]
|
width=(self.offset_replica_bitline.x
|
||||||
- self.nand3_2_gnd_position[0]),
|
- self.nand3_2_gnd_position.x),
|
||||||
height=drc["minwidth_metal1"])
|
height=drc["minwidth_metal1"])
|
||||||
|
|
||||||
def add_input_routing(self):
|
def add_input_routing(self):
|
||||||
|
|
@ -598,13 +601,13 @@ class control_logic(design.design):
|
||||||
self.OEb_position = self.msf_control_OEb_position
|
self.OEb_position = self.msf_control_OEb_position
|
||||||
|
|
||||||
# Clk
|
# Clk
|
||||||
clk_y = self.inv1_vdd_position[1] + 6 * drc["minwidth_metal1"]
|
clk_y = self.inv1_vdd_position.y+ 6 * drc["minwidth_metal1"]
|
||||||
self.clk_position = vector(0, clk_y)
|
self.clk_position = vector(0, clk_y)
|
||||||
|
|
||||||
# clk port to inv1 A
|
# clk port to inv1 A
|
||||||
layer_stack = ("metal2", "via1", "metal1")
|
layer_stack = ("metal1", "via1", "metal2")
|
||||||
start = self.inv1_A_position + vector(0, 0.5 * drc["minwidth_metal1"])
|
start = self.inv1_A_position + vector(0, 0.5 * drc["minwidth_metal1"])
|
||||||
mid1 = vector(self.inv1_A_position[0] - 2 * drc["minwidth_metal2"],
|
mid1 = vector(self.inv1_A_position.x- 2 * drc["minwidth_metal2"],
|
||||||
start.y)
|
start.y)
|
||||||
mid2 = vector(mid1.x, clk_y)
|
mid2 = vector(mid1.x, clk_y)
|
||||||
self.clk_position = vector(0, mid2[1])
|
self.clk_position = vector(0, mid2[1])
|
||||||
|
|
@ -614,17 +617,17 @@ class control_logic(design.design):
|
||||||
|
|
||||||
# clk line to msf_control_clk
|
# clk line to msf_control_clk
|
||||||
self.add_rect(layer="metal1",
|
self.add_rect(layer="metal1",
|
||||||
offset=[self.msf_control_clk_position[0],
|
offset=[self.msf_control_clk_position.x,
|
||||||
self.clk_position[1]],
|
self.clk_position[1]],
|
||||||
width=drc["minwidth_metal1"],
|
width=drc["minwidth_metal1"],
|
||||||
height=(self.msf_control_clk_position[1]
|
height=(self.msf_control_clk_position.y
|
||||||
- self.clk_position[1]))
|
- self.clk_position[1]))
|
||||||
|
|
||||||
# clk connection to nor2 A input
|
# clk connection to nor2 A input
|
||||||
start = [self.inv1_A_position[0] - 2 * drc["minwidth_metal2"],
|
start = self.inv1_A_position + vector(- 2 * drc["minwidth_metal2"],
|
||||||
self.inv1_A_position[1] + 0.5 * drc["minwidth_metal1"]]
|
0.5 * drc["minwidth_metal1"])
|
||||||
mid1 = [start[0] - 3 * drc["minwidth_metal2"], start[1]]
|
mid1 = start - vector(3 * drc["minwidth_metal2"], 0)
|
||||||
mid2 = [mid1[0], self.nor2_1_A_position[1]]
|
mid2 = [mid1.x, self.nor2_1_A_position.y]
|
||||||
|
|
||||||
self.add_path("metal1", [start, mid1, mid2, self.nor2_1_A_position])
|
self.add_path("metal1", [start, mid1, mid2, self.nor2_1_A_position])
|
||||||
|
|
||||||
|
|
@ -661,7 +664,7 @@ class control_logic(design.design):
|
||||||
height=self.nor2_1_Z_position.y + correct.y)
|
height=self.nor2_1_Z_position.y + correct.y)
|
||||||
self.add_via(layers=("metal2", "via2", "metal3"),
|
self.add_via(layers=("metal2", "via2", "metal3"),
|
||||||
offset=self.nor2_1_Z_position.scale(1, 0))
|
offset=self.nor2_1_Z_position.scale(1, 0))
|
||||||
self.tri_en_position = vector(self.nor2_1_Z_position[0], 0)
|
self.tri_en_position = vector(self.nor2_1_Z_position.x, 0)
|
||||||
|
|
||||||
# tri_en_bar
|
# tri_en_bar
|
||||||
correct = vector(drc["minwidth_metal2"], 0)
|
correct = vector(drc["minwidth_metal2"], 0)
|
||||||
|
|
@ -671,7 +674,7 @@ class control_logic(design.design):
|
||||||
self.add_rect(layer="metal2",
|
self.add_rect(layer="metal2",
|
||||||
offset=self.tri_en_bar_position,
|
offset=self.tri_en_bar_position,
|
||||||
width=drc["minwidth_metal2"],
|
width=drc["minwidth_metal2"],
|
||||||
height=self.nand2_1_Z_position[1] + drc["minwidth_metal1"])
|
height=self.nand2_1_Z_position.y+ drc["minwidth_metal1"])
|
||||||
self.add_via(layers=("metal2", "via2", "metal3"),
|
self.add_via(layers=("metal2", "via2", "metal3"),
|
||||||
offset=self.tri_en_bar_position)
|
offset=self.tri_en_bar_position)
|
||||||
|
|
||||||
|
|
@ -691,6 +694,6 @@ class control_logic(design.design):
|
||||||
self.add_rect(layer="metal2",
|
self.add_rect(layer="metal2",
|
||||||
offset=self.s_en_position,
|
offset=self.s_en_position,
|
||||||
width=drc["minwidth_metal2"],
|
width=drc["minwidth_metal2"],
|
||||||
height=self.inv4_Z_position[1] + drc["minwidth_metal1"])
|
height=self.inv4_Z_position.y+ drc["minwidth_metal1"])
|
||||||
self.add_via(layers=("metal2", "via2", "metal3"),
|
self.add_via(layers=("metal2", "via2", "metal3"),
|
||||||
offset=self.s_en_position)
|
offset=self.s_en_position)
|
||||||
|
|
|
||||||
|
|
@ -14,19 +14,6 @@ import importlib
|
||||||
# Current version of OpenRAM.
|
# Current version of OpenRAM.
|
||||||
VERSION = "1.0"
|
VERSION = "1.0"
|
||||||
|
|
||||||
# Output banner for file output and program execution.
|
|
||||||
BANNER = """\
|
|
||||||
##############################################################
|
|
||||||
# #
|
|
||||||
# OpenRAM Compiler v""" + VERSION + """ #
|
|
||||||
# #
|
|
||||||
# VLSI Design Automation Lab #
|
|
||||||
# UCSC CE Department #
|
|
||||||
# #
|
|
||||||
# VLSI Computer Architecture Research Group #
|
|
||||||
# Oklahoma State University ECE Department #
|
|
||||||
# #
|
|
||||||
##############################################################\n"""
|
|
||||||
|
|
||||||
USAGE = "usage: openram.py [options] <config file>\n"
|
USAGE = "usage: openram.py [options] <config file>\n"
|
||||||
|
|
||||||
|
|
@ -81,6 +68,25 @@ def parse_args():
|
||||||
def get_opts():
|
def get_opts():
|
||||||
return(OPTS)
|
return(OPTS)
|
||||||
|
|
||||||
|
def print_banner():
|
||||||
|
""" Conditionally print the banner to stdout """
|
||||||
|
global OPTS
|
||||||
|
if not OPTS.print_banner:
|
||||||
|
return
|
||||||
|
|
||||||
|
print "|==============================================================================|"
|
||||||
|
name = "OpenRAM Compiler v"+VERSION
|
||||||
|
print "|=========" + name.center(60) + "=========|"
|
||||||
|
print "|=========" + " ".center(60) + "=========|"
|
||||||
|
print "|=========" + "VLSI Design and Automation Lab".center(60) + "=========|"
|
||||||
|
print "|=========" + "University of California Santa Cruz CE Department".center(60) + "=========|"
|
||||||
|
print "|=========" + " ".center(60) + "=========|"
|
||||||
|
print "|=========" + "VLSI Computer Architecture Research Group".center(60) + "=========|"
|
||||||
|
print "|=========" + "Oklahoma State University ECE Department".center(60) + "=========|"
|
||||||
|
print "|=========" + " ".center(60) + "=========|"
|
||||||
|
print "|=========" + OPTS.openram_temp.center(60) + "=========|"
|
||||||
|
print "|==============================================================================|"
|
||||||
|
|
||||||
|
|
||||||
def init_openram(config_file):
|
def init_openram(config_file):
|
||||||
"""Initialize the technology, paths, simulators, etc."""
|
"""Initialize the technology, paths, simulators, etc."""
|
||||||
|
|
@ -134,7 +140,15 @@ def set_calibre():
|
||||||
debug.warning("Calibre not found. Not performing inline LVS/DRC.")
|
debug.warning("Calibre not found. Not performing inline LVS/DRC.")
|
||||||
OPTS.check_lvsdrc = False
|
OPTS.check_lvsdrc = False
|
||||||
|
|
||||||
|
def end_openram():
|
||||||
|
""" Clean up openram for a proper exit """
|
||||||
|
cleanup_paths()
|
||||||
|
|
||||||
|
def cleanup_paths():
|
||||||
|
# we should clean up this temp directory after execution...
|
||||||
|
if os.path.exists(OPTS.openram_temp):
|
||||||
|
shutil.rmtree(OPTS.openram_temp, ignore_errors=True)
|
||||||
|
|
||||||
def setup_paths():
|
def setup_paths():
|
||||||
""" Set up the non-tech related paths. """
|
""" Set up the non-tech related paths. """
|
||||||
debug.info(2,"Setting up paths...")
|
debug.info(2,"Setting up paths...")
|
||||||
|
|
@ -150,14 +164,11 @@ def setup_paths():
|
||||||
sys.path.append("{0}/tests".format(OPENRAM_HOME))
|
sys.path.append("{0}/tests".format(OPENRAM_HOME))
|
||||||
sys.path.append("{0}/characterizer".format(OPENRAM_HOME))
|
sys.path.append("{0}/characterizer".format(OPENRAM_HOME))
|
||||||
|
|
||||||
|
|
||||||
if not OPTS.openram_temp.endswith('/'):
|
if not OPTS.openram_temp.endswith('/'):
|
||||||
OPTS.openram_temp += "/"
|
OPTS.openram_temp += "/"
|
||||||
debug.info(1, "Temporary files saved in " + OPTS.openram_temp)
|
debug.info(1, "Temporary files saved in " + OPTS.openram_temp)
|
||||||
|
|
||||||
# we should clean up this temp directory after execution...
|
cleanup_paths()
|
||||||
if os.path.exists(OPTS.openram_temp):
|
|
||||||
shutil.rmtree(OPTS.openram_temp, ignore_errors=True)
|
|
||||||
|
|
||||||
# make the directory if it doesn't exist
|
# make the directory if it doesn't exist
|
||||||
try:
|
try:
|
||||||
|
|
@ -185,23 +196,48 @@ def set_spice():
|
||||||
debug.info(2,"Finding spice...")
|
debug.info(2,"Finding spice...")
|
||||||
global OPTS
|
global OPTS
|
||||||
|
|
||||||
# set the input dir for spice files if using ngspice (not needed for
|
OPTS.spice_exe = ""
|
||||||
# hspice)
|
|
||||||
|
# Check if the preferred spice option exists in the path
|
||||||
|
for path in os.environ["PATH"].split(os.pathsep):
|
||||||
|
spice_exe = os.path.join(path, OPTS.spice_version)
|
||||||
|
# if it is found, then break and use first version
|
||||||
|
if is_exe(spice_exe):
|
||||||
|
debug.info(1, "Using spice: " + spice_exe)
|
||||||
|
OPTS.spice_exe = spice_exe
|
||||||
|
break
|
||||||
|
|
||||||
|
if not OPTS.force_spice and OPTS.spice_exe == "":
|
||||||
|
# if we didn't find the preferred version, try the other version and warn
|
||||||
|
prev_version=OPTS.spice_version
|
||||||
|
if OPTS.spice_version == "hspice":
|
||||||
|
OPTS.spice_version = "ngspice"
|
||||||
|
else:
|
||||||
|
OPTS.spice_version = "hspice"
|
||||||
|
debug.warning("Unable to find {0} so trying {1}".format(prev_version,OPTS.spice_version))
|
||||||
|
|
||||||
|
for path in os.environ["PATH"].split(os.pathsep):
|
||||||
|
spice_exe = os.path.join(path, OPTS.spice_version)
|
||||||
|
# if it is found, then break and use first version
|
||||||
|
if is_exe(spice_exe):
|
||||||
|
found_spice = True
|
||||||
|
debug.info(1, "Using spice: " + spice_exe)
|
||||||
|
OPTS.spice_exe = spice_exe
|
||||||
|
break
|
||||||
|
|
||||||
|
# set the input dir for spice files if using ngspice
|
||||||
if OPTS.spice_version == "ngspice":
|
if OPTS.spice_version == "ngspice":
|
||||||
os.environ["NGSPICE_INPUT_DIR"] = "{0}".format(OPTS.openram_temp)
|
os.environ["NGSPICE_INPUT_DIR"] = "{0}".format(OPTS.openram_temp)
|
||||||
|
|
||||||
# search for calibre in the path
|
if OPTS.spice_exe == "":
|
||||||
for path in os.environ["PATH"].split(os.pathsep):
|
|
||||||
OPTS.spice_exe = os.path.join(path, OPTS.spice_version)
|
|
||||||
# if it is found, then break and use first version
|
|
||||||
if is_exe(OPTS.spice_exe):
|
|
||||||
debug.info(1, "Using spice: " + OPTS.spice_exe)
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
# otherwise, give warning and procede
|
# otherwise, give warning and procede
|
||||||
debug.warning("Spice not found. Unable to perform characterization.")
|
if OPTS.force_spice:
|
||||||
|
debug.error("{0} not found. Unable to perform characterization.".format(OPTS.spice_version),1)
|
||||||
|
else:
|
||||||
|
debug.error("Neither hspice/ngspice not found. Unable to perform characterization.",1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# imports correct technology directories for testing
|
# imports correct technology directories for testing
|
||||||
def import_tech():
|
def import_tech():
|
||||||
global OPTS
|
global OPTS
|
||||||
|
|
|
||||||
|
|
@ -329,7 +329,7 @@ class hierarchical_decoder(design.design):
|
||||||
# ADDING LABELS FOR OUTPUT SIDE OF THE 3:8 PRE-DECODER
|
# ADDING LABELS FOR OUTPUT SIDE OF THE 3:8 PRE-DECODER
|
||||||
for inv_3x8 in range(8):
|
for inv_3x8 in range(8):
|
||||||
if (self.num_inputs == 3):
|
if (self.num_inputs == 3):
|
||||||
xoffset = self.pre3_8.x_off_inv_2 + self.inv.Z_position[0]
|
xoffset = self.pre3_8.x_off_inv_2 + self.inv.Z_position.x
|
||||||
else:
|
else:
|
||||||
xoffset = 0
|
xoffset = 0
|
||||||
|
|
||||||
|
|
@ -403,7 +403,7 @@ class hierarchical_decoder(design.design):
|
||||||
mirror=mirror)
|
mirror=mirror)
|
||||||
self.add_rect(layer="metal1",
|
self.add_rect(layer="metal1",
|
||||||
offset=[nand.width - correct,
|
offset=[nand.width - correct,
|
||||||
y_off + y_dir * (nand.Z_position[1]-correct)],
|
y_off + y_dir * (nand.Z_position.y-correct)],
|
||||||
width=drc["minwidth_metal1"],
|
width=drc["minwidth_metal1"],
|
||||||
height=y_dir * drc["minwidth_metal1"])
|
height=y_dir * drc["minwidth_metal1"])
|
||||||
|
|
||||||
|
|
@ -454,9 +454,9 @@ class hierarchical_decoder(design.design):
|
||||||
|
|
||||||
# add output label for Row Decoder INVERTER array.
|
# add output label for Row Decoder INVERTER array.
|
||||||
if (self.num_inputs == 4 or self.num_inputs == 5):
|
if (self.num_inputs == 4 or self.num_inputs == 5):
|
||||||
x_off = self.nand2.width + self.inv.Z_position[0]
|
x_off = self.nand2.width + self.inv.Z_position.x
|
||||||
else:
|
else:
|
||||||
x_off = self.nand3.width + self.inv.Z_position[0]
|
x_off = self.nand3.width + self.inv.Z_position.x
|
||||||
|
|
||||||
for row in range(self.rows):
|
for row in range(self.rows):
|
||||||
if ((row % 2) == 0):
|
if ((row % 2) == 0):
|
||||||
|
|
@ -502,10 +502,10 @@ class hierarchical_decoder(design.design):
|
||||||
+ inv_2x4 * (self.inv.height))
|
+ inv_2x4 * (self.inv.height))
|
||||||
|
|
||||||
if (inv_2x4 % 2 == 0):
|
if (inv_2x4 % 2 == 0):
|
||||||
pin_y = self.inv.Z_position[1]
|
pin_y = self.inv.Z_position.y
|
||||||
else:
|
else:
|
||||||
pin_y = (self.inv.height - drc["minwidth_metal1"]
|
pin_y = (self.inv.height - drc["minwidth_metal1"]
|
||||||
- self.inv.Z_position[1])
|
- self.inv.Z_position.y)
|
||||||
yoffset = current_inv_height + pin_y
|
yoffset = current_inv_height + pin_y
|
||||||
|
|
||||||
self.add_extend_rails(yoffset = yoffset,
|
self.add_extend_rails(yoffset = yoffset,
|
||||||
|
|
@ -519,10 +519,10 @@ class hierarchical_decoder(design.design):
|
||||||
+ self.no_of_pre2x4 * self.pre2_4.height
|
+ self.no_of_pre2x4 * self.pre2_4.height
|
||||||
|
|
||||||
if (inv_3x8 % 2 == 0):
|
if (inv_3x8 % 2 == 0):
|
||||||
pin_y = self.inv.Z_position[1]
|
pin_y = self.inv.Z_position.y
|
||||||
else:
|
else:
|
||||||
pin_y = (self.inv.height - drc["minwidth_metal1"]
|
pin_y = (self.inv.height - drc["minwidth_metal1"]
|
||||||
- self.inv.Z_position[1])
|
- self.inv.Z_position.y)
|
||||||
yoffset = current_inv_height + pin_y
|
yoffset = current_inv_height + pin_y
|
||||||
|
|
||||||
self.add_extend_rails(yoffset = yoffset,
|
self.add_extend_rails(yoffset = yoffset,
|
||||||
|
|
@ -545,13 +545,13 @@ class hierarchical_decoder(design.design):
|
||||||
|
|
||||||
current_inv_height = self.predecoder_height + row_index * (self.inv.height)
|
current_inv_height = self.predecoder_height + row_index * (self.inv.height)
|
||||||
if (row_index % 2 == 0):
|
if (row_index % 2 == 0):
|
||||||
yoffset_A = current_inv_height + self.nand2.A_position[1]
|
yoffset_A = current_inv_height + self.nand2.A_position.y
|
||||||
yoffset_B = current_inv_height + self.nand2.B_position[1]
|
yoffset_B = current_inv_height + self.nand2.B_position.y
|
||||||
|
|
||||||
else:
|
else:
|
||||||
base = current_inv_height + self.inv.height - drc["minwidth_metal1"]
|
base = current_inv_height + self.inv.height - drc["minwidth_metal1"]
|
||||||
yoffset_A = base - self.nand2.A_position[1]
|
yoffset_A = base - self.nand2.A_position.y
|
||||||
yoffset_B = base - self.nand2.B_position[1]
|
yoffset_B = base - self.nand2.B_position.y
|
||||||
|
|
||||||
row_index = row_index + 1
|
row_index = row_index + 1
|
||||||
self.add_extend_rails(yoffset =yoffset_A,
|
self.add_extend_rails(yoffset =yoffset_A,
|
||||||
|
|
@ -567,15 +567,15 @@ class hierarchical_decoder(design.design):
|
||||||
current_inv_height = self.predecoder_height + row_index * (self.inv.height)
|
current_inv_height = self.predecoder_height + row_index * (self.inv.height)
|
||||||
|
|
||||||
if (row_index % 2 == 0):
|
if (row_index % 2 == 0):
|
||||||
yoffset_A = current_inv_height + self.nand3.A_position[1]
|
yoffset_A = current_inv_height + self.nand3.A_position.y
|
||||||
yoffset_B = current_inv_height + self.nand3.B_position[1]
|
yoffset_B = current_inv_height + self.nand3.B_position.y
|
||||||
yoffset_C = current_inv_height + self.nand3.C_position[1]
|
yoffset_C = current_inv_height + self.nand3.C_position.y
|
||||||
contact_C_yoffset = yoffset_C - self.contact_shift
|
contact_C_yoffset = yoffset_C - self.contact_shift
|
||||||
else:
|
else:
|
||||||
base = current_inv_height + self.inv.height - drc["minwidth_metal1"]
|
base = current_inv_height + self.inv.height - drc["minwidth_metal1"]
|
||||||
yoffset_A = base - self.nand3.A_position[1]
|
yoffset_A = base - self.nand3.A_position.y
|
||||||
yoffset_B = base - self.nand3.B_position[1]
|
yoffset_B = base - self.nand3.B_position.y
|
||||||
yoffset_C = base - self.nand3.C_position[1]
|
yoffset_C = base - self.nand3.C_position.y
|
||||||
contact_C_yoffset = yoffset_C
|
contact_C_yoffset = yoffset_C
|
||||||
|
|
||||||
row_index = row_index + 1
|
row_index = row_index + 1
|
||||||
|
|
|
||||||
|
|
@ -150,12 +150,12 @@ class hierarchical_predecode(design.design):
|
||||||
y_off = nand_input * (self.nand.height)
|
y_off = nand_input * (self.nand.height)
|
||||||
mirror = "R0"
|
mirror = "R0"
|
||||||
offset = [self.x_off_nand + self.nand.width,
|
offset = [self.x_off_nand + self.nand.width,
|
||||||
y_off + self.nand.Z_position[1]]
|
y_off + self.nand.Z_position.y]
|
||||||
else:
|
else:
|
||||||
y_off = (nand_input + 1) * (self.nand.height)
|
y_off = (nand_input + 1) * (self.nand.height)
|
||||||
mirror = "MX"
|
mirror = "MX"
|
||||||
offset =[self.x_off_nand + self.nand.width,
|
offset =[self.x_off_nand + self.nand.width,
|
||||||
y_off - self.nand.Z_position[1] - drc["minwidth_metal1"]]
|
y_off - self.nand.Z_position.y - drc["minwidth_metal1"]]
|
||||||
self.add_inst(name=name,
|
self.add_inst(name=name,
|
||||||
mod=self.nand,
|
mod=self.nand,
|
||||||
offset=[self.x_off_nand, y_off],
|
offset=[self.x_off_nand, y_off],
|
||||||
|
|
@ -175,22 +175,22 @@ class hierarchical_predecode(design.design):
|
||||||
def route_input_inverters_input(self,inv_rout,inv_in_offset):
|
def route_input_inverters_input(self,inv_rout,inv_in_offset):
|
||||||
self.add_rect(layer="metal1",
|
self.add_rect(layer="metal1",
|
||||||
offset=[self.rails_x_offset[inv_rout],
|
offset=[self.rails_x_offset[inv_rout],
|
||||||
inv_in_offset[1]],
|
inv_in_offset.y],
|
||||||
width=inv_in_offset[0] - self.rails_x_offset[inv_rout] + drc["minwidth_metal2"],
|
width=inv_in_offset.x - self.rails_x_offset[inv_rout] + drc["minwidth_metal2"],
|
||||||
height=drc["minwidth_metal1"])
|
height=drc["minwidth_metal1"])
|
||||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||||
offset=[self.rails_x_offset[inv_rout] + self.gap_between_rails,
|
offset=[self.rails_x_offset[inv_rout] + self.gap_between_rails,
|
||||||
inv_in_offset[1] - self.via_shift],
|
inv_in_offset.y - self.via_shift],
|
||||||
rotate=90)
|
rotate=90)
|
||||||
|
|
||||||
def route_input_inverters_vdd(self,inv_vdd_offset):
|
def route_input_inverters_vdd(self,inv_vdd_offset):
|
||||||
self.add_rect(layer="metal1",
|
self.add_rect(layer="metal1",
|
||||||
offset=inv_vdd_offset,
|
offset=inv_vdd_offset,
|
||||||
width=self.rails_x_offset[self.number_of_inputs] - inv_vdd_offset[0] + drc["minwidth_metal2"],
|
width=self.rails_x_offset[self.number_of_inputs] - inv_vdd_offset.x + drc["minwidth_metal2"],
|
||||||
height=drc["minwidth_metal1"])
|
height=drc["minwidth_metal1"])
|
||||||
|
|
||||||
def route_input_inverters_gnd(self,inv_gnd_offset):
|
def route_input_inverters_gnd(self,inv_gnd_offset):
|
||||||
self.add_rect(layer="metal1",
|
self.add_rect(layer="metal1",
|
||||||
offset=inv_gnd_offset,
|
offset=inv_gnd_offset,
|
||||||
width=self.rails_x_offset[self.number_of_inputs+1] - inv_gnd_offset[0] + drc["minwidth_metal2"],
|
width=self.rails_x_offset[self.number_of_inputs+1] - inv_gnd_offset.x + drc["minwidth_metal2"],
|
||||||
height=drc["minwidth_metal1"])
|
height=drc["minwidth_metal1"])
|
||||||
|
|
|
||||||
|
|
@ -65,22 +65,22 @@ class hierarchical_predecode2x4(hierarchical_predecode):
|
||||||
inv_in_offset = base + self.inv.A_position.scale(1,y_dir)
|
inv_in_offset = base + self.inv.A_position.scale(1,y_dir)
|
||||||
inv_vdd_offset = base + self.inv.vdd_position.scale(1,y_dir)
|
inv_vdd_offset = base + self.inv.vdd_position.scale(1,y_dir)
|
||||||
inv_gnd_offset = base + self.inv.gnd_position.scale(1,y_dir)
|
inv_gnd_offset = base + self.inv.gnd_position.scale(1,y_dir)
|
||||||
out_y_mirrored = inv_vdd_offset[1] + output_shift + drc["minwidth_metal1"]
|
out_y_mirrored = inv_vdd_offset.y+ output_shift + drc["minwidth_metal1"]
|
||||||
out_offset = [inv_out_offset[0],
|
out_offset = [inv_out_offset.x,
|
||||||
inv_out_offset[1] * (1 + y_dir) / 2
|
inv_out_offset.y* (1 + y_dir) / 2
|
||||||
+ out_y_mirrored * (1 - y_dir) / 2]
|
+ out_y_mirrored * (1 - y_dir) / 2]
|
||||||
# output connection
|
# output connection
|
||||||
correct = y_dir * (output_shift + drc["minwidth_metal1"])
|
correct = y_dir * (output_shift + drc["minwidth_metal1"])
|
||||||
off_via = [self.rails_x_offset[inv_rout + 4] + self.gap_between_rails,
|
off_via = [self.rails_x_offset[inv_rout + 4] + self.gap_between_rails,
|
||||||
inv_vdd_offset[1] - self.via_shift - correct]
|
inv_vdd_offset.y- self.via_shift - correct]
|
||||||
self.add_rect(layer="metal1",
|
self.add_rect(layer="metal1",
|
||||||
offset=out_offset,
|
offset=out_offset,
|
||||||
width=drc["minwidth_metal1"],
|
width=drc["minwidth_metal1"],
|
||||||
height=(inv_vdd_offset[1] - inv_out_offset[1]) * y_dir - output_shift)
|
height=(inv_vdd_offset.y- inv_out_offset.y) * y_dir - output_shift)
|
||||||
self.add_rect(layer="metal1",
|
self.add_rect(layer="metal1",
|
||||||
offset=[inv_out_offset[0],
|
offset=[inv_out_offset.x,
|
||||||
inv_vdd_offset[1] - correct],
|
inv_vdd_offset.y- correct],
|
||||||
width=self.rails_x_offset[inv_rout + 4] - inv_out_offset[0] + drc["minwidth_metal2"],
|
width=self.rails_x_offset[inv_rout + 4] - inv_out_offset.x+ drc["minwidth_metal2"],
|
||||||
height=drc["minwidth_metal1"])
|
height=drc["minwidth_metal1"])
|
||||||
self.add_via(layers = ("metal1", "via1", "metal2"),
|
self.add_via(layers = ("metal1", "via1", "metal2"),
|
||||||
offset=off_via,
|
offset=off_via,
|
||||||
|
|
|
||||||
|
|
@ -49,11 +49,11 @@ class hierarchical_predecode3x8(hierarchical_predecode):
|
||||||
# output connection
|
# output connection
|
||||||
correct = y_dir * (output_shift + drc["minwidth_metal1"])
|
correct = y_dir * (output_shift + drc["minwidth_metal1"])
|
||||||
off_via = [self.rails_x_offset[inv_rout + 5] + self.gap_between_rails,
|
off_via = [self.rails_x_offset[inv_rout + 5] + self.gap_between_rails,
|
||||||
inv_vdd_offset[1] - self.via_shift - correct]
|
inv_vdd_offset.y - self.via_shift - correct]
|
||||||
path1 = vector(inv_out_offset[0] + 0.5*drc["minwidth_metal1"],
|
path1 = inv_out_offset + vector(0.5*drc["minwidth_metal1"],
|
||||||
inv_out_offset[1]- 1.5*drc["minwidth_metal1"] - correct)
|
- 1.5*drc["minwidth_metal1"] - correct)
|
||||||
path2 = vector(path1.x,
|
path2 = vector(path1.x,
|
||||||
inv_vdd_offset[1] + 0.5 * drc["minwidth_metal1"] - correct)
|
inv_vdd_offset.y + 0.5 * drc["minwidth_metal1"] - correct)
|
||||||
path3 = vector(self.rails_x_offset[inv_rout + 5] + drc["minwidth_metal2"],
|
path3 = vector(self.rails_x_offset[inv_rout + 5] + drc["minwidth_metal2"],
|
||||||
path2.y)
|
path2.y)
|
||||||
self.add_path("metal1", [path1,path2,path3])
|
self.add_path("metal1", [path1,path2,path3])
|
||||||
|
|
|
||||||
|
|
@ -46,13 +46,13 @@ class layout:
|
||||||
#***1,000,000 number is used to avoid empty sequences errors***
|
#***1,000,000 number is used to avoid empty sequences errors***
|
||||||
# FIXME Is this hard coded value ok??
|
# FIXME Is this hard coded value ok??
|
||||||
try:
|
try:
|
||||||
lowestx1 = min(rect.offset[0] for rect in self.objs)
|
lowestx1 = min(rect.offset.x for rect in self.objs)
|
||||||
lowesty1 = min(rect.offset[1] for rect in self.objs)
|
lowesty1 = min(rect.offset.y for rect in self.objs)
|
||||||
except:
|
except:
|
||||||
[lowestx1, lowesty1] = [1000000.0, 1000000.0]
|
[lowestx1, lowesty1] = [1000000.0, 1000000.0]
|
||||||
try:
|
try:
|
||||||
lowestx2 = min(inst.offset[0] for inst in self.insts)
|
lowestx2 = min(inst.offset.x for inst in self.insts)
|
||||||
lowesty2 = min(inst.offset[1] for inst in self.insts)
|
lowesty2 = min(inst.offset.y for inst in self.insts)
|
||||||
except:
|
except:
|
||||||
[lowestx2, lowesty2] = [1000000.0, 1000000.0]
|
[lowestx2, lowesty2] = [1000000.0, 1000000.0]
|
||||||
return vector(min(lowestx1, lowestx2), min(lowesty1, lowesty2))
|
return vector(min(lowestx1, lowestx2), min(lowesty1, lowesty2))
|
||||||
|
|
@ -76,21 +76,18 @@ class layout:
|
||||||
for i in range(len(attr_val)):
|
for i in range(len(attr_val)):
|
||||||
# each unit in the list is a list coordinates
|
# each unit in the list is a list coordinates
|
||||||
if isinstance(attr_val[i], (list,vector)):
|
if isinstance(attr_val[i], (list,vector)):
|
||||||
attr_val[i] = vector([attr_val[i][0] - coordinate.x,
|
attr_val[i] = vector(attr_val[i] - coordinate)
|
||||||
attr_val[i][1] - coordinate.y])
|
|
||||||
# the list itself is a coordinate
|
# the list itself is a coordinate
|
||||||
else:
|
else:
|
||||||
if len(attr_val)!=2: continue
|
if len(attr_val)!=2: continue
|
||||||
for val in attr_val:
|
for val in attr_val:
|
||||||
if not isinstance(val, (int, long, float)): continue
|
if not isinstance(val, (int, long, float)): continue
|
||||||
setattr(self,attr_key, vector([attr_val[0] - coordinate.x,
|
setattr(self,attr_key, vector(attr_val - coordinate))
|
||||||
attr_val[1] - coordinate.y]))
|
|
||||||
break
|
break
|
||||||
|
|
||||||
# if is a vector coordinate
|
# if is a vector coordinate
|
||||||
if isinstance(attr_val, vector):
|
if isinstance(attr_val, vector):
|
||||||
setattr(self, attr_key, vector(attr_val[0] - coordinate.x,
|
setattr(self, attr_key, vector(attr_val - coordinate))
|
||||||
attr_val[1] - coordinate.y))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -98,9 +95,9 @@ class layout:
|
||||||
"""Translates all 2d cartesian coordinates in a layout given
|
"""Translates all 2d cartesian coordinates in a layout given
|
||||||
the (x,y) offset"""
|
the (x,y) offset"""
|
||||||
for obj in self.objs:
|
for obj in self.objs:
|
||||||
obj.offset = obj.offset - coordinate
|
obj.offset = vector(obj.offset - coordinate)
|
||||||
for inst in self.insts:
|
for inst in self.insts:
|
||||||
inst.offset = inst.offset - coordinate
|
inst.offset = vector(inst.offset - coordinate)
|
||||||
|
|
||||||
# FIXME: Make name optional and pick a random one if not specified
|
# FIXME: Make name optional and pick a random one if not specified
|
||||||
def add_inst(self, name, mod, offset=[0,0], mirror="R0",rotate=0):
|
def add_inst(self, name, mod, offset=[0,0], mirror="R0",rotate=0):
|
||||||
|
|
@ -177,7 +174,7 @@ class layout:
|
||||||
|
|
||||||
def add_wire(self, layers, coordinates, offset=None):
|
def add_wire(self, layers, coordinates, offset=None):
|
||||||
"""Connects a routing path on given layer,coordinates,width.
|
"""Connects a routing path on given layer,coordinates,width.
|
||||||
The layers are the (vertical, via, horizontal). """
|
The layers are the (horizontal, via, vertical). """
|
||||||
import wire
|
import wire
|
||||||
debug.info(3,"add wire " + str(layers) + " " + str(coordinates))
|
debug.info(3,"add wire " + str(layers) + " " + str(coordinates))
|
||||||
# Wires/paths are created so that the first point is (0,0)
|
# Wires/paths are created so that the first point is (0,0)
|
||||||
|
|
@ -242,14 +239,14 @@ class layout:
|
||||||
Otherwise, start a new layout for dynamic generation."""
|
Otherwise, start a new layout for dynamic generation."""
|
||||||
# open the gds file if it exists or else create a blank layout
|
# open the gds file if it exists or else create a blank layout
|
||||||
if os.path.isfile(self.gds_file):
|
if os.path.isfile(self.gds_file):
|
||||||
debug.info(2, "opening %s" % self.gds_file)
|
debug.info(3, "opening %s" % self.gds_file)
|
||||||
self.gds = gdsMill.VlsiLayout(units=GDS["unit"])
|
self.gds = gdsMill.VlsiLayout(units=GDS["unit"])
|
||||||
reader = gdsMill.Gds2reader(self.gds)
|
reader = gdsMill.Gds2reader(self.gds)
|
||||||
reader.loadFromFile(self.gds_file)
|
reader.loadFromFile(self.gds_file)
|
||||||
# TODO: parse the width/height
|
# TODO: parse the width/height
|
||||||
# TODO: parse the pin locations
|
# TODO: parse the pin locations
|
||||||
else:
|
else:
|
||||||
debug.info(2, "creating structure %s" % self.name)
|
debug.info(3, "creating structure %s" % self.name)
|
||||||
self.gds = gdsMill.VlsiLayout(
|
self.gds = gdsMill.VlsiLayout(
|
||||||
name=self.name, units=GDS["unit"])
|
name=self.name, units=GDS["unit"])
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ class spice:
|
||||||
"""Reads the sp file (and parse the pins) from the library
|
"""Reads the sp file (and parse the pins) from the library
|
||||||
Otherwise, initialize it to null for dynamic generation"""
|
Otherwise, initialize it to null for dynamic generation"""
|
||||||
if os.path.isfile(self.sp_file):
|
if os.path.isfile(self.sp_file):
|
||||||
debug.info(2, "opening {0}".format(self.sp_file))
|
debug.info(3, "opening {0}".format(self.sp_file))
|
||||||
f = open(self.sp_file)
|
f = open(self.sp_file)
|
||||||
self.spice = f.readlines()
|
self.spice = f.readlines()
|
||||||
for i in range(len(self.spice)):
|
for i in range(len(self.spice)):
|
||||||
|
|
|
||||||
|
|
@ -160,16 +160,16 @@ class logic_effort_dc(design.design):
|
||||||
if end_inv < half_length:
|
if end_inv < half_length:
|
||||||
end_i_offset = end_inv_offset + \
|
end_i_offset = end_inv_offset + \
|
||||||
self.inv.input_position.scale(1,-1)
|
self.inv.input_position.scale(1,-1)
|
||||||
M2_end = [end_i_offset[0], end_i_offset[1] - 0.5 * drc["minwidth_metal2"]]
|
M2_end = end_i_offset - vector(0, 0.5 * drc["minwidth_metal2"])
|
||||||
else:
|
else:
|
||||||
end_i_offset = end_inv_offset + \
|
end_i_offset = end_inv_offset + \
|
||||||
self.inv.input_position.scale(-1,1)
|
self.inv.input_position.scale(-1,1)
|
||||||
M2_end = [end_i_offset[0], end_i_offset[1] + 0.5 * drc["minwidth_metal2"]]
|
M2_end = end_i_offset + vector(0, 0.5 * drc["minwidth_metal2"])
|
||||||
|
|
||||||
if start_inv < half_length and end_inv >= half_length:
|
if start_inv < half_length and end_inv >= half_length:
|
||||||
mid = [half_length * self.inv.width \
|
mid = [half_length * self.inv.width \
|
||||||
- 0.5 * drc["minwidth_metal2"], M2_start[1]]
|
- 0.5 * drc["minwidth_metal2"], M2_start[1]]
|
||||||
self.add_wire(("metal3", "via2", "metal2"),
|
self.add_wire(("metal2", "via2", "metal3"),
|
||||||
[M2_start, mid, M2_end])
|
[M2_start, mid, M2_end])
|
||||||
else:
|
else:
|
||||||
self.add_path(("metal2"), [M2_start, M2_end])
|
self.add_path(("metal2"), [M2_start, M2_end])
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@ class nand_2(design.design):
|
||||||
|
|
||||||
def setup_layout_constants(self):
|
def setup_layout_constants(self):
|
||||||
""" Calculate the layout constraints """
|
""" Calculate the layout constraints """
|
||||||
self.well_width = self.pmos1.active_position[0] \
|
self.well_width = self.pmos1.active_position.x \
|
||||||
+ 2 * self.pmos1.active_width \
|
+ 2 * self.pmos1.active_width \
|
||||||
+ drc["active_to_body_active"] + \
|
+ drc["active_to_body_active"] + \
|
||||||
drc["well_enclosure_active"]
|
drc["well_enclosure_active"]
|
||||||
|
|
@ -127,9 +127,9 @@ class nand_2(design.design):
|
||||||
# determines the spacing between the edge and nmos (rail to active
|
# determines the spacing between the edge and nmos (rail to active
|
||||||
# metal or poly_to_poly spacing)
|
# metal or poly_to_poly spacing)
|
||||||
edge_to_nmos = max(drc["metal1_to_metal1"]
|
edge_to_nmos = max(drc["metal1_to_metal1"]
|
||||||
- self.nmos1.active_contact_positions[0][1],
|
- self.nmos1.active_contact_positions[0].y,
|
||||||
0.5 * (drc["poly_to_poly"] - drc["minwidth_metal1"])
|
0.5 * (drc["poly_to_poly"] - drc["minwidth_metal1"])
|
||||||
- self.nmos1.poly_positions[0][1])
|
- self.nmos1.poly_positions[0].y)
|
||||||
|
|
||||||
# determine the position of the first transistor from the left
|
# determine the position of the first transistor from the left
|
||||||
self.nmos_position1 = vector(0, 0.5 * drc["minwidth_metal1"] + edge_to_nmos)
|
self.nmos_position1 = vector(0, 0.5 * drc["minwidth_metal1"] + edge_to_nmos)
|
||||||
|
|
@ -141,7 +141,7 @@ class nand_2(design.design):
|
||||||
self.connect_inst(["Z", "A", "net1", "gnd"])
|
self.connect_inst(["Z", "A", "net1", "gnd"])
|
||||||
|
|
||||||
self.nmos_position2 = vector(self.nmos2.active_width - self.nmos2.active_contact.width,
|
self.nmos_position2 = vector(self.nmos2.active_width - self.nmos2.active_contact.width,
|
||||||
self.nmos_position1[1])
|
self.nmos_position1.y)
|
||||||
offset = self.nmos_position2 + vector(0,self.nmos2.height)
|
offset = self.nmos_position2 + vector(0,self.nmos2.height)
|
||||||
self.add_inst(name="nmos2",
|
self.add_inst(name="nmos2",
|
||||||
mod=self.nmos2,
|
mod=self.nmos2,
|
||||||
|
|
@ -151,9 +151,9 @@ class nand_2(design.design):
|
||||||
|
|
||||||
# determines the spacing between the edge and pmos
|
# determines the spacing between the edge and pmos
|
||||||
edge_to_pmos = max(drc["metal1_to_metal1"] \
|
edge_to_pmos = max(drc["metal1_to_metal1"] \
|
||||||
- self.pmos1.active_contact_positions[0][1],
|
- self.pmos1.active_contact_positions[0].y,
|
||||||
0.5 * drc["poly_to_poly"] - 0.5 * drc["minwidth_metal1"] \
|
0.5 * drc["poly_to_poly"] - 0.5 * drc["minwidth_metal1"] \
|
||||||
- self.pmos1.poly_positions[0][1])
|
- self.pmos1.poly_positions[0].y)
|
||||||
|
|
||||||
self.pmos_position1 = vector(0, self.height - 0.5 * drc["minwidth_metal1"]
|
self.pmos_position1 = vector(0, self.height - 0.5 * drc["minwidth_metal1"]
|
||||||
- edge_to_pmos - self.pmos1.height)
|
- edge_to_pmos - self.pmos1.height)
|
||||||
|
|
@ -213,13 +213,13 @@ class nand_2(design.design):
|
||||||
correct = vector(self.pmos1.active_contact.width - drc["minwidth_metal1"],
|
correct = vector(self.pmos1.active_contact.width - drc["minwidth_metal1"],
|
||||||
0).scale(.5,0)
|
0).scale(.5,0)
|
||||||
poffset = self.pmos_position1 + self.pmos1.active_contact_positions[0] + correct
|
poffset = self.pmos_position1 + self.pmos1.active_contact_positions[0] + correct
|
||||||
temp_height = self.height - poffset[1]
|
temp_height = self.height - poffset.y
|
||||||
self.add_rect(layer="metal1",
|
self.add_rect(layer="metal1",
|
||||||
offset=poffset, width=drc["minwidth_metal1"],
|
offset=poffset, width=drc["minwidth_metal1"],
|
||||||
height=temp_height)
|
height=temp_height)
|
||||||
|
|
||||||
poffset = vector(2 * self.pmos_position2.x + correct.x
|
poffset = vector(2 * self.pmos_position2.x + correct.x
|
||||||
+ self.pmos2.active_contact_positions[0].x , poffset[1])
|
+ self.pmos2.active_contact_positions[0].x , poffset.y)
|
||||||
self.add_rect(layer="metal1",
|
self.add_rect(layer="metal1",
|
||||||
offset=poffset,
|
offset=poffset,
|
||||||
width=drc["minwidth_metal1"],
|
width=drc["minwidth_metal1"],
|
||||||
|
|
@ -244,14 +244,14 @@ class nand_2(design.design):
|
||||||
poly_length = (self.pmos_position1.y + self.pmos1.poly_positions[0].y
|
poly_length = (self.pmos_position1.y + self.pmos1.poly_positions[0].y
|
||||||
- yoffset_nmos1 + drc["minwidth_poly"])
|
- yoffset_nmos1 + drc["minwidth_poly"])
|
||||||
for position in self.pmos1.poly_positions:
|
for position in self.pmos1.poly_positions:
|
||||||
offset = [position[0],
|
offset = vector(position.x,
|
||||||
yoffset_nmos1 - 0.5 * drc["minwidth_poly"]]
|
yoffset_nmos1 - 0.5 * drc["minwidth_poly"])
|
||||||
self.add_rect(layer="poly",
|
self.add_rect(layer="poly",
|
||||||
offset=offset, width=drc["minwidth_poly"],
|
offset=offset, width=drc["minwidth_poly"],
|
||||||
height=poly_length)
|
height=poly_length)
|
||||||
self.add_rect(layer="poly",
|
self.add_rect(layer="poly",
|
||||||
offset=[offset[0] + self.pmos1.active_contact.width + 2 * drc["minwidth_poly"],
|
offset=[offset.x + self.pmos1.active_contact.width + 2 * drc["minwidth_poly"],
|
||||||
offset[1]],
|
offset.y],
|
||||||
width=drc["minwidth_poly"],
|
width=drc["minwidth_poly"],
|
||||||
height=poly_length)
|
height=poly_length)
|
||||||
|
|
||||||
|
|
@ -262,18 +262,18 @@ class nand_2(design.design):
|
||||||
- yoffset - self.pmos1.height + 0.5 * drc["minwidth_metal2"])
|
- yoffset - self.pmos1.height + 0.5 * drc["minwidth_metal2"])
|
||||||
|
|
||||||
for position in self.pmos1.active_contact_positions[1:][::2]:
|
for position in self.pmos1.active_contact_positions[1:][::2]:
|
||||||
start = self.drain_position = [position[0] + 0.5 * drc["minwidth_metal1"]
|
start = self.drain_position = vector(position.x + 0.5 * drc["minwidth_metal1"]
|
||||||
+ self.pmos_position2[0]
|
+ self.pmos_position2.x
|
||||||
+ self.pmos2.active_contact.first_layer_position[0]
|
+ self.pmos2.active_contact.first_layer_position.x
|
||||||
+ self.pmos2.active_contact.width / 2,
|
+ self.pmos2.active_contact.width / 2,
|
||||||
yoffset]
|
yoffset)
|
||||||
mid1 = [start[0],
|
mid1 = vector(start.x,
|
||||||
self.height - drc["minwidth_metal2"] - drc["metal2_to_metal2"] -
|
self.height - drc["minwidth_metal2"] - drc["metal2_to_metal2"] -
|
||||||
self.pmos_size - drc["metal1_to_metal1"] - 0.5 * drc["minwidth_metal1"]]
|
self.pmos_size - drc["metal1_to_metal1"] - 0.5 * drc["minwidth_metal1"])
|
||||||
end = [position[0] + 0.5 * drc["minwidth_metal1"]
|
end = vector(position.x + 0.5 * drc["minwidth_metal1"]
|
||||||
+ self.pmos2.active_contact.second_layer_position[0],
|
+ self.pmos2.active_contact.second_layer_position.x,
|
||||||
self.pmos_position1[1] + self.pmos1.active_contact_positions[0][1]]
|
self.pmos_position1.y + self.pmos1.active_contact_positions[0].y)
|
||||||
mid2 = [end[0], mid1[1]]
|
mid2 = vector(end.x, mid1.y)
|
||||||
|
|
||||||
self.add_path("metal1",[start, mid1, mid2, end])
|
self.add_path("metal1",[start, mid1, mid2, end])
|
||||||
|
|
||||||
|
|
@ -290,7 +290,7 @@ class nand_2(design.design):
|
||||||
def route_input_gate_A(self):
|
def route_input_gate_A(self):
|
||||||
""" routing for input A """
|
""" routing for input A """
|
||||||
|
|
||||||
xoffset = self.pmos1.poly_positions[0][0]
|
xoffset = self.pmos1.poly_positions[0].x
|
||||||
yoffset = (self.height
|
yoffset = (self.height
|
||||||
- (drc["minwidth_metal1"]
|
- (drc["minwidth_metal1"]
|
||||||
+ drc["metal1_to_metal1"]
|
+ drc["metal1_to_metal1"]
|
||||||
|
|
@ -298,8 +298,8 @@ class nand_2(design.design):
|
||||||
+ drc["metal1_to_metal1"]
|
+ drc["metal1_to_metal1"]
|
||||||
+ self.pmos2.active_contact.second_layer_width))
|
+ self.pmos2.active_contact.second_layer_width))
|
||||||
if (self.nmos_width == drc["minwidth_tx"]):
|
if (self.nmos_width == drc["minwidth_tx"]):
|
||||||
yoffset = (self.pmos_position1[1]
|
yoffset = (self.pmos_position1.y
|
||||||
+ self.pmos1.poly_positions[0][1]
|
+ self.pmos1.poly_positions[0].y
|
||||||
+ drc["poly_extend_active"]
|
+ drc["poly_extend_active"]
|
||||||
- (self.pmos1.active_contact.height
|
- (self.pmos1.active_contact.height
|
||||||
- self.pmos1.active_height) / 2
|
- self.pmos1.active_height) / 2
|
||||||
|
|
@ -312,15 +312,15 @@ class nand_2(design.design):
|
||||||
size=(1,1),
|
size=(1,1),
|
||||||
rotate=90)
|
rotate=90)
|
||||||
|
|
||||||
offset = offset - self.poly_contact.first_layer_position.rotate().scale(1,0)
|
offset = offset - self.poly_contact.first_layer_position.rotate_scale(1,0)
|
||||||
self.add_rect(layer="poly",
|
self.add_rect(layer="poly",
|
||||||
offset=offset,
|
offset=offset,
|
||||||
width=self.poly_contact.first_layer_position[1] + drc["minwidth_poly"],
|
width=self.poly_contact.first_layer_position.y + drc["minwidth_poly"],
|
||||||
height=self.poly_contact.first_layer_width)
|
height=self.poly_contact.first_layer_width)
|
||||||
|
|
||||||
input_length = (self.pmos1.poly_positions[0][0]
|
input_length = (self.pmos1.poly_positions[0].x
|
||||||
- self.poly_contact.height)
|
- self.poly_contact.height)
|
||||||
yoffset += self.poly_contact.via_layer_position[0]
|
yoffset += self.poly_contact.via_layer_position.x
|
||||||
offset = self.input_position1 = vector(0, yoffset)
|
offset = self.input_position1 = vector(0, yoffset)
|
||||||
self.add_rect(layer="metal1",
|
self.add_rect(layer="metal1",
|
||||||
offset=offset,
|
offset=offset,
|
||||||
|
|
@ -332,15 +332,15 @@ class nand_2(design.design):
|
||||||
|
|
||||||
def route_input_gate_B(self):
|
def route_input_gate_B(self):
|
||||||
""" routing for input B """
|
""" routing for input B """
|
||||||
xoffset = (self.pmos2.poly_positions[0][0]
|
xoffset = (self.pmos2.poly_positions[0].x
|
||||||
+ self.pmos_position2[0] + drc["minwidth_poly"])
|
+ self.pmos_position2.x + drc["minwidth_poly"])
|
||||||
yoffset = (drc["minwidth_metal1"]
|
yoffset = (drc["minwidth_metal1"]
|
||||||
+ drc["metal1_to_metal1"]
|
+ drc["metal1_to_metal1"]
|
||||||
+ self.nmos2.active_height
|
+ self.nmos2.active_height
|
||||||
+ drc["minwidth_metal1"])
|
+ drc["minwidth_metal1"])
|
||||||
if (self.nmos_width == drc["minwidth_tx"]):
|
if (self.nmos_width == drc["minwidth_tx"]):
|
||||||
yoffset = (self.nmos_position1[1]
|
yoffset = (self.nmos_position1.y
|
||||||
+ self.nmos1.poly_positions[0][1]
|
+ self.nmos1.poly_positions[0].y
|
||||||
+ self.nmos1.poly_height
|
+ self.nmos1.poly_height
|
||||||
+ drc["metal1_to_metal1"])
|
+ drc["metal1_to_metal1"])
|
||||||
offset = [xoffset, yoffset]
|
offset = [xoffset, yoffset]
|
||||||
|
|
@ -351,18 +351,18 @@ class nand_2(design.design):
|
||||||
|
|
||||||
input_length = self.pmos2.poly_positions[0].x - self.poly_contact.height
|
input_length = self.pmos2.poly_positions[0].x - self.poly_contact.height
|
||||||
self.input_position2 = vector(xoffset - self.poly_contact.width,
|
self.input_position2 = vector(xoffset - self.poly_contact.width,
|
||||||
yoffset + self.poly_contact.via_layer_position[0])
|
yoffset + self.poly_contact.via_layer_position.x)
|
||||||
self.add_layout_pin(text="B",
|
self.add_layout_pin(text="B",
|
||||||
layer="metal1",
|
layer="metal1",
|
||||||
offset=self.input_position2.scale(0,1),
|
offset=self.input_position2.scale(0,1),
|
||||||
width=(input_length + self.pmos_position2[0] + drc["minwidth_poly"]),
|
width=(input_length + self.pmos_position2.x + drc["minwidth_poly"]),
|
||||||
height=drc["minwidth_metal1"])
|
height=drc["minwidth_metal1"])
|
||||||
|
|
||||||
def route_output(self):
|
def route_output(self):
|
||||||
""" routing for output Z """
|
""" routing for output Z """
|
||||||
yoffset = (self.nmos1.height - 2 * drc["minwidth_metal1"] / 3 +
|
yoffset = (self.nmos1.height - 2 * drc["minwidth_metal1"] / 3 +
|
||||||
(self.height - self.pmos1.height - self.nmos1.height - drc["minwidth_metal1"]) / 2 )
|
(self.height - self.pmos1.height - self.nmos1.height - drc["minwidth_metal1"]) / 2 )
|
||||||
xoffset = self.drain_position[0]
|
xoffset = self.drain_position.x
|
||||||
offset = self.output_position = vector(xoffset, yoffset)
|
offset = self.output_position = vector(xoffset, yoffset)
|
||||||
output_length = self.width - xoffset
|
output_length = self.width - xoffset
|
||||||
self.add_layout_pin(text="Z",
|
self.add_layout_pin(text="Z",
|
||||||
|
|
@ -420,9 +420,9 @@ class nand_2(design.design):
|
||||||
width=width,
|
width=width,
|
||||||
height=self.pmos1.active_height)
|
height=self.pmos1.active_height)
|
||||||
|
|
||||||
offset = vector(self.nmos_position2[0] + self.nmos1.active_position[0],
|
offset = vector(self.nmos_position2.x + self.nmos1.active_position.x,
|
||||||
self.nmos_position1[1] - self.nmos1.active_height
|
self.nmos_position1.y - self.nmos1.active_height
|
||||||
- self.nmos1.active_position[1] + self.nmos1.height)
|
- self.nmos1.active_position.y + self.nmos1.height)
|
||||||
self.add_rect(layer="active",
|
self.add_rect(layer="active",
|
||||||
offset=offset,
|
offset=offset,
|
||||||
width=self.active_width,
|
width=self.active_width,
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,7 @@ class nand_3(design.design):
|
||||||
|
|
||||||
def setup_layout_constants(self):
|
def setup_layout_constants(self):
|
||||||
""" setup layout constraints """
|
""" setup layout constraints """
|
||||||
self.well_width = self.nmos1.active_position[0] \
|
self.well_width = self.nmos1.active_position.x \
|
||||||
+ 3 * self.pmos1.active_width + drc["active_to_body_active"] \
|
+ 3 * self.pmos1.active_width + drc["active_to_body_active"] \
|
||||||
+ drc["well_enclosure_active"] - self.nmos3.active_contact.width \
|
+ drc["well_enclosure_active"] - self.nmos3.active_contact.width \
|
||||||
+ self.pmos1.active_contact.height + drc["minwidth_metal1"] \
|
+ self.pmos1.active_contact.height + drc["minwidth_metal1"] \
|
||||||
|
|
@ -171,11 +171,11 @@ class nand_3(design.design):
|
||||||
|
|
||||||
# determines the spacing between the edge and pmos
|
# determines the spacing between the edge and pmos
|
||||||
self.edge_to_pmos = max(drc["metal1_to_metal1"]
|
self.edge_to_pmos = max(drc["metal1_to_metal1"]
|
||||||
- self.pmos1.active_contact_positions[0][1],
|
- self.pmos1.active_contact_positions[0].y,
|
||||||
0.5 * drc["poly_to_poly"] - 0.5 * drc["minwidth_metal1"]
|
0.5 * drc["poly_to_poly"] - 0.5 * drc["minwidth_metal1"]
|
||||||
- self.pmos1.poly_positions[0][1])
|
- self.pmos1.poly_positions[0].y)
|
||||||
|
|
||||||
self.pmos_position1 = vector(self.nmos_position1[0],
|
self.pmos_position1 = vector(self.nmos_position1.x,
|
||||||
self.height - 0.5 * drc["minwidth_metal1"]
|
self.height - 0.5 * drc["minwidth_metal1"]
|
||||||
- self.pmos1.height - self.edge_to_pmos)
|
- self.pmos1.height - self.edge_to_pmos)
|
||||||
self.add_inst(name="pmos1",
|
self.add_inst(name="pmos1",
|
||||||
|
|
@ -216,10 +216,10 @@ class nand_3(design.design):
|
||||||
|
|
||||||
def connect_well_contacts(self):
|
def connect_well_contacts(self):
|
||||||
""" Connect well contacts to vdd and gnd rail """
|
""" Connect well contacts to vdd and gnd rail """
|
||||||
well_tap_length = self.height - self.nwell_contact_position[1]
|
well_tap_length = self.height - self.nwell_contact_position.y
|
||||||
xoffset = (self.nwell_contact_position[0]
|
xoffset = (self.nwell_contact_position.x
|
||||||
+ self.nwell_contact.second_layer_position[0]
|
+ self.nwell_contact.second_layer_position.x
|
||||||
- self.nwell_contact.first_layer_position[0])
|
- self.nwell_contact.first_layer_position.x)
|
||||||
offset = [xoffset, self.nwell_contact_position.y]
|
offset = [xoffset, self.nwell_contact_position.y]
|
||||||
self.add_rect(layer="metal1",
|
self.add_rect(layer="metal1",
|
||||||
offset=offset,
|
offset=offset,
|
||||||
|
|
@ -240,14 +240,14 @@ class nand_3(design.design):
|
||||||
correct = vector(self.pmos1.active_contact.width - drc["minwidth_metal1"],
|
correct = vector(self.pmos1.active_contact.width - drc["minwidth_metal1"],
|
||||||
0).scale(0.5,0)
|
0).scale(0.5,0)
|
||||||
poffset = self.pmos_position1 + self.pmos1.active_contact_positions[0] + correct
|
poffset = self.pmos_position1 + self.pmos1.active_contact_positions[0] + correct
|
||||||
temp_height = self.height - poffset[1]
|
temp_height = self.height - poffset.y
|
||||||
self.add_rect(layer="metal1",
|
self.add_rect(layer="metal1",
|
||||||
offset=poffset,
|
offset=poffset,
|
||||||
width=drc["minwidth_metal1"],
|
width=drc["minwidth_metal1"],
|
||||||
height=temp_height)
|
height=temp_height)
|
||||||
|
|
||||||
poffset = [self.pmos_position3.x + self.pmos3.active_contact_positions[0].x + correct.x,
|
poffset = [self.pmos_position3.x + self.pmos3.active_contact_positions[0].x + correct.x,
|
||||||
poffset[1]]
|
poffset.y]
|
||||||
self.add_rect(layer="metal1",
|
self.add_rect(layer="metal1",
|
||||||
offset=poffset,
|
offset=poffset,
|
||||||
width=drc["minwidth_metal1"],
|
width=drc["minwidth_metal1"],
|
||||||
|
|
@ -271,20 +271,20 @@ class nand_3(design.design):
|
||||||
poly_length = (self.pmos_position1.y + self.pmos1.poly_positions[0].y
|
poly_length = (self.pmos_position1.y + self.pmos1.poly_positions[0].y
|
||||||
- yoffset_nmos1 + drc["minwidth_poly"])
|
- yoffset_nmos1 + drc["minwidth_poly"])
|
||||||
|
|
||||||
offset = [self.nmos_position1[0] + self.nmos1.poly_positions[0][0],
|
offset = vector(self.nmos_position1.x + self.nmos1.poly_positions[0].x,
|
||||||
yoffset_nmos1 - drc["minwidth_poly"]]
|
yoffset_nmos1 - drc["minwidth_poly"])
|
||||||
self.add_rect(layer="poly",
|
self.add_rect(layer="poly",
|
||||||
offset=offset,
|
offset=offset,
|
||||||
width=drc["minwidth_poly"],
|
width=drc["minwidth_poly"],
|
||||||
height=poly_length)
|
height=poly_length)
|
||||||
self.add_rect(layer="poly",
|
self.add_rect(layer="poly",
|
||||||
offset=[offset[0] + self.pmos1.active_contact.width + 2 * drc["minwidth_poly"],
|
offset=[offset.x + self.pmos1.active_contact.width + 2 * drc["minwidth_poly"],
|
||||||
offset[1]],
|
offset.y],
|
||||||
width=drc["minwidth_poly"],
|
width=drc["minwidth_poly"],
|
||||||
height=poly_length)
|
height=poly_length)
|
||||||
self.add_rect(layer="poly",
|
self.add_rect(layer="poly",
|
||||||
offset=[offset[0] + 2 * self.pmos1.active_contact.width + 4 * drc["minwidth_poly"],
|
offset=[offset.x + 2 * self.pmos1.active_contact.width + 4 * drc["minwidth_poly"],
|
||||||
offset[1]],
|
offset.y],
|
||||||
width=drc["minwidth_poly"],
|
width=drc["minwidth_poly"],
|
||||||
height=poly_length)
|
height=poly_length)
|
||||||
|
|
||||||
|
|
@ -294,7 +294,7 @@ class nand_3(design.design):
|
||||||
- drc["well_enclosure_active"]
|
- drc["well_enclosure_active"]
|
||||||
+ drc["metal1_to_metal1"])
|
+ drc["metal1_to_metal1"])
|
||||||
drain_length = (self.height - yoffset + 0.5 * drc["minwidth_metal1"]
|
drain_length = (self.height - yoffset + 0.5 * drc["minwidth_metal1"]
|
||||||
- (self.pmos1.height - self.pmos1.active_contact_positions[0][1]))
|
- (self.pmos1.height - self.pmos1.active_contact_positions[0].y))
|
||||||
layer_stack = ("metal1", "via1", "metal2")
|
layer_stack = ("metal1", "via1", "metal2")
|
||||||
for position in self.pmos1.active_contact_positions[1:][::2]:
|
for position in self.pmos1.active_contact_positions[1:][::2]:
|
||||||
diff_active_via = self.pmos2.active_contact.width - self.m1m2_via.second_layer_width
|
diff_active_via = self.pmos2.active_contact.width - self.m1m2_via.second_layer_width
|
||||||
|
|
@ -315,7 +315,7 @@ class nand_3(design.design):
|
||||||
+ diff_active_via / 2)
|
+ diff_active_via / 2)
|
||||||
self.add_via(layer_stack,[xoffset,offset.y])
|
self.add_via(layer_stack,[xoffset,offset.y])
|
||||||
|
|
||||||
xoffset = (self.nmos_position3[0] + self.nmos3.active_position[0]
|
xoffset = (self.nmos_position3.x + self.nmos3.active_position.x
|
||||||
+ self.nmos3.active_width - self.nmos3.active_contact.width / 2)
|
+ self.nmos3.active_width - self.nmos3.active_contact.width / 2)
|
||||||
self.drain_position = vector(xoffset,
|
self.drain_position = vector(xoffset,
|
||||||
drc["minwidth_metal1"] + drc["metal1_to_metal1"])
|
drc["minwidth_metal1"] + drc["metal1_to_metal1"])
|
||||||
|
|
@ -343,11 +343,11 @@ class nand_3(design.design):
|
||||||
rotate=90)
|
rotate=90)
|
||||||
self.add_rect(layer="poly",
|
self.add_rect(layer="poly",
|
||||||
offset=offset + vector(drc["minwidth_poly"] / 2,0),
|
offset=offset + vector(drc["minwidth_poly"] / 2,0),
|
||||||
width=-(self.poly_contact.first_layer_position[1] + drc["minwidth_poly"]),
|
width=-(self.poly_contact.first_layer_position.y + drc["minwidth_poly"]),
|
||||||
height=self.poly_contact.first_layer_width)
|
height=self.poly_contact.first_layer_width)
|
||||||
|
|
||||||
offset = vector(offset.x,
|
offset = vector(offset.x,
|
||||||
self.pmos_position1[1] + self.pmos1.poly_positions[0][1])
|
self.pmos_position1.y + self.pmos1.poly_positions[0].y)
|
||||||
self.add_layout_pin(text="A",
|
self.add_layout_pin(text="A",
|
||||||
layer="metal1",
|
layer="metal1",
|
||||||
offset=offset,
|
offset=offset,
|
||||||
|
|
@ -358,9 +358,9 @@ class nand_3(design.design):
|
||||||
|
|
||||||
def route_input_gate_B(self):
|
def route_input_gate_B(self):
|
||||||
""" routing for input B """
|
""" routing for input B """
|
||||||
xoffset = self.pmos2.poly_positions[0][0] \
|
xoffset = self.pmos2.poly_positions[0].x \
|
||||||
+ self.pmos_position2[0] - drc["minwidth_poly"]
|
+ self.pmos_position2.x - drc["minwidth_poly"]
|
||||||
yoffset = self.nmos_position1[1] + self.nmos1.height \
|
yoffset = self.nmos_position1.y + self.nmos1.height \
|
||||||
- drc["well_enclosure_active"] + (self.nmos1.active_contact.height \
|
- drc["well_enclosure_active"] + (self.nmos1.active_contact.height \
|
||||||
- self.nmos1.active_height) / 2 \
|
- self.nmos1.active_height) / 2 \
|
||||||
+ drc["metal1_to_metal1"]
|
+ drc["metal1_to_metal1"]
|
||||||
|
|
@ -369,7 +369,7 @@ class nand_3(design.design):
|
||||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||||
offset=[xoffset,yoffset])
|
offset=[xoffset,yoffset])
|
||||||
|
|
||||||
xoffset = self.pmos2.poly_positions[0][0] + self.pmos_position2[0] \
|
xoffset = self.pmos2.poly_positions[0].x + self.pmos_position2.x \
|
||||||
- drc["minwidth_poly"] + self.m1m2_via.width
|
- drc["minwidth_poly"] + self.m1m2_via.width
|
||||||
length = -xoffset + self.m1m2_via.width
|
length = -xoffset + self.m1m2_via.width
|
||||||
self.add_rect(layer="metal2",
|
self.add_rect(layer="metal2",
|
||||||
|
|
@ -382,7 +382,7 @@ class nand_3(design.design):
|
||||||
layer="metal1",
|
layer="metal1",
|
||||||
offset=self.B_position)
|
offset=self.B_position)
|
||||||
|
|
||||||
xoffset = self.pmos_position1[0] + self.pmos1.active_position[0] \
|
xoffset = self.pmos_position1.x + self.pmos1.active_position.x \
|
||||||
- drc["metal1_to_metal1"] + (self.pmos1.active_contact.width \
|
- drc["metal1_to_metal1"] + (self.pmos1.active_contact.width \
|
||||||
- self.m1m2_via.second_layer_width) / 2
|
- self.m1m2_via.second_layer_width) / 2
|
||||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||||
|
|
@ -395,9 +395,9 @@ class nand_3(design.design):
|
||||||
|
|
||||||
def route_input_gate_C(self):
|
def route_input_gate_C(self):
|
||||||
""" routing for input A """
|
""" routing for input A """
|
||||||
xoffset = self.pmos3.poly_positions[0][0] \
|
xoffset = self.pmos3.poly_positions[0].x \
|
||||||
+ self.pmos_position3[0] - drc["minwidth_poly"]
|
+ self.pmos_position3.x - drc["minwidth_poly"]
|
||||||
yoffset = self.nmos_position1[1] + self.nmos1.height \
|
yoffset = self.nmos_position1.y + self.nmos1.height \
|
||||||
- drc["well_enclosure_active"] + (self.nmos1.active_contact.height \
|
- drc["well_enclosure_active"] + (self.nmos1.active_contact.height \
|
||||||
- self.nmos1.active_height) / 2 + drc["metal1_to_metal1"]
|
- self.nmos1.active_height) / 2 + drc["metal1_to_metal1"]
|
||||||
|
|
||||||
|
|
@ -406,8 +406,8 @@ class nand_3(design.design):
|
||||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||||
offset=[xoffset,yoffset])
|
offset=[xoffset,yoffset])
|
||||||
|
|
||||||
xoffset = self.pmos3.poly_positions[0][0] \
|
xoffset = self.pmos3.poly_positions[0].x \
|
||||||
+ self.pmos_position3[0] - drc["minwidth_poly"] \
|
+ self.pmos_position3.x - drc["minwidth_poly"] \
|
||||||
+ self.m1m2_via.width
|
+ self.m1m2_via.width
|
||||||
length = -xoffset + self.m1m2_via.width
|
length = -xoffset + self.m1m2_via.width
|
||||||
self.add_rect(layer="metal2",
|
self.add_rect(layer="metal2",
|
||||||
|
|
@ -423,14 +423,14 @@ class nand_3(design.design):
|
||||||
width=self.m1m2_via.width,
|
width=self.m1m2_via.width,
|
||||||
height=-drc["minwidth_metal2"] - drc["metal2_to_metal2"])
|
height=-drc["minwidth_metal2"] - drc["metal2_to_metal2"])
|
||||||
self.C_position = vector(0,
|
self.C_position = vector(0,
|
||||||
self.B_position[1] - drc["metal2_to_metal2"] - drc["minwidth_metal1"] \
|
self.B_position.y - drc["metal2_to_metal2"] - drc["minwidth_metal1"] \
|
||||||
- (self.m1m2_via.second_layer_width
|
- (self.m1m2_via.second_layer_width
|
||||||
- self.m1m2_via.first_layer_width))
|
- self.m1m2_via.first_layer_width))
|
||||||
self.add_label(text="C",
|
self.add_label(text="C",
|
||||||
layer="metal1",
|
layer="metal1",
|
||||||
offset=self.C_position)
|
offset=self.C_position)
|
||||||
|
|
||||||
xoffset = self.pmos_position1[0] + self.pmos1.active_position[0] \
|
xoffset = self.pmos_position1.x + self.pmos1.active_position.x \
|
||||||
- drc["metal1_to_metal1"] + (self.pmos1.active_contact.width \
|
- drc["metal1_to_metal1"] + (self.pmos1.active_contact.width \
|
||||||
- self.m1m2_via.second_layer_width) / 2
|
- self.m1m2_via.second_layer_width) / 2
|
||||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||||
|
|
@ -445,7 +445,7 @@ class nand_3(design.design):
|
||||||
|
|
||||||
def route_output(self):
|
def route_output(self):
|
||||||
""" routing for output Z """
|
""" routing for output Z """
|
||||||
xoffset = self.nmos_position3[0] + self.nmos3.active_position[0] \
|
xoffset = self.nmos_position3.x + self.nmos3.active_position.x \
|
||||||
+ self.nmos3.active_width - self.nmos3.active_contact.width / 2
|
+ self.nmos3.active_width - self.nmos3.active_contact.width / 2
|
||||||
yoffset = (self.nmos1.height + (self.height - drc["minwidth_metal1"]
|
yoffset = (self.nmos1.height + (self.height - drc["minwidth_metal1"]
|
||||||
- self.pmos1.height - self.nmos1.height) / 2
|
- self.pmos1.height - self.nmos1.height) / 2
|
||||||
|
|
@ -463,11 +463,11 @@ class nand_3(design.design):
|
||||||
|
|
||||||
def extend_wells(self):
|
def extend_wells(self):
|
||||||
""" extension of well """
|
""" extension of well """
|
||||||
middle_point = self.nmos_position1[1] + self.nmos1.pwell_position[1] \
|
middle_point = self.nmos_position1.y + self.nmos1.pwell_position.y \
|
||||||
+ self.nmos1.well_height + (self.pmos_position1[1]
|
+ self.nmos1.well_height + (self.pmos_position1.y
|
||||||
+ self.pmos1.nwell_position[1]
|
+ self.pmos1.nwell_position.y
|
||||||
- self.nmos_position1[1]
|
- self.nmos_position1.y
|
||||||
- self.nmos1.pwell_position[1]
|
- self.nmos1.pwell_position.y
|
||||||
- self.nmos1.well_height) / 2
|
- self.nmos1.well_height) / 2
|
||||||
offset = self.nwell_position = vector(0, middle_point)
|
offset = self.nwell_position = vector(0, middle_point)
|
||||||
self.nwell_height = self.height - middle_point
|
self.nwell_height = self.height - middle_point
|
||||||
|
|
@ -508,9 +508,9 @@ class nand_3(design.design):
|
||||||
width=width,
|
width=width,
|
||||||
height=self.pmos1.active_height)
|
height=self.pmos1.active_height)
|
||||||
|
|
||||||
offset = [self.nmos_position3[0] + self.nmos1.active_position[0],
|
offset = [self.nmos_position3.x + self.nmos1.active_position.x,
|
||||||
self.nmos_position1[1] + self.nmos1.height
|
self.nmos_position1.y + self.nmos1.height
|
||||||
- self.nmos1.active_position[1] - self.nmos1.active_height]
|
- self.nmos1.active_position.y - self.nmos1.active_height]
|
||||||
self.add_rect(layer="active",
|
self.add_rect(layer="active",
|
||||||
offset=offset,
|
offset=offset,
|
||||||
width=self.active_width,
|
width=self.active_width,
|
||||||
|
|
|
||||||
|
|
@ -81,10 +81,10 @@ class nor_2(design.design):
|
||||||
0.5 * gate_to_gate - test_pmos.poly_positions[0].y)
|
0.5 * gate_to_gate - test_pmos.poly_positions[0].y)
|
||||||
route_margin = .5 * (self.poly_contact.second_layer_width
|
route_margin = .5 * (self.poly_contact.second_layer_width
|
||||||
+ drc["minwidth_metal1"]) + drc["metal1_to_metal1"]
|
+ drc["minwidth_metal1"]) + drc["metal1_to_metal1"]
|
||||||
pmos_position = [0, self.height - 0.5 * drc["minwidth_metal1"]
|
pmos_position = vector(0, self.height - 0.5 * drc["minwidth_metal1"]
|
||||||
- edge_to_pmos - test_pmos.height]
|
- edge_to_pmos - test_pmos.height)
|
||||||
nmos_position = [0, 0.5 * drc["minwidth_metal1"] + edge_to_nmos]
|
nmos_position = vector(0, 0.5 * drc["minwidth_metal1"] + edge_to_nmos)
|
||||||
leftspace = (0.7 * (pmos_position[1] - nmos_position[1])
|
leftspace = (0.7 * (pmos_position.y - nmos_position.y)
|
||||||
- 3 * route_margin - 2 * drc["metal1_to_metal1"])
|
- 3 * route_margin - 2 * drc["metal1_to_metal1"])
|
||||||
if leftspace >= 0:
|
if leftspace >= 0:
|
||||||
break
|
break
|
||||||
|
|
@ -209,10 +209,10 @@ class nor_2(design.design):
|
||||||
self.nwell_contact_position = vector(xoffset, yoffset)
|
self.nwell_contact_position = vector(xoffset, yoffset)
|
||||||
self.nwell_contact=self.add_contact(layer_stack,self.nwell_contact_position,(1,self.pmos1.num_of_tacts))
|
self.nwell_contact=self.add_contact(layer_stack,self.nwell_contact_position,(1,self.pmos1.num_of_tacts))
|
||||||
|
|
||||||
xoffset = self.nmos_position2[0] + (self.nmos1.active_position[0]
|
xoffset = self.nmos_position2.x + (self.nmos1.active_position.x
|
||||||
+ self.nmos1.active_width
|
+ self.nmos1.active_width
|
||||||
+ drc["active_to_body_active"])
|
+ drc["active_to_body_active"])
|
||||||
yoffset = (self.nmos_position1[1] + self.nmos1.height
|
yoffset = (self.nmos_position1.y + self.nmos1.height
|
||||||
- self.nmos1.active_contact_positions[0].y
|
- self.nmos1.active_contact_positions[0].y
|
||||||
- self.nmos1.active_contact.height)
|
- self.nmos1.active_contact.height)
|
||||||
self.pwell_contact_position = vector(xoffset, yoffset)
|
self.pwell_contact_position = vector(xoffset, yoffset)
|
||||||
|
|
@ -222,7 +222,7 @@ class nor_2(design.design):
|
||||||
def route(self):
|
def route(self):
|
||||||
self.route_pins()
|
self.route_pins()
|
||||||
self.connect_well_contacts()
|
self.connect_well_contacts()
|
||||||
M1_track = (self.B_position[1] + drc["metal1_to_metal1"]
|
M1_track = (self.B_position.y + drc["metal1_to_metal1"]
|
||||||
+ .5 * (self.poly_contact.second_layer_width
|
+ .5 * (self.poly_contact.second_layer_width
|
||||||
+ drc["minwidth_metal1"]))
|
+ drc["minwidth_metal1"]))
|
||||||
self.connect_tx(M1_track)
|
self.connect_tx(M1_track)
|
||||||
|
|
@ -230,11 +230,11 @@ class nor_2(design.design):
|
||||||
|
|
||||||
def connect_well_contacts(self):
|
def connect_well_contacts(self):
|
||||||
""" Connect well contacts to vdd and gnd rail """
|
""" Connect well contacts to vdd and gnd rail """
|
||||||
well_tap_length = self.height - self.nwell_contact_position[1]
|
well_tap_length = self.height - self.nwell_contact_position.y
|
||||||
xoffset = (self.nwell_contact_position.x
|
xoffset = (self.nwell_contact_position.x
|
||||||
+ self.nwell_contact.second_layer_position.x
|
+ self.nwell_contact.second_layer_position.x
|
||||||
- self.nwell_contact.first_layer_position.x)
|
- self.nwell_contact.first_layer_position.x)
|
||||||
offset = [xoffset, self.nwell_contact_position[1]]
|
offset = [xoffset, self.nwell_contact_position.y]
|
||||||
self.add_rect(layer="metal1",
|
self.add_rect(layer="metal1",
|
||||||
offset=offset,
|
offset=offset,
|
||||||
width=drc["minwidth_metal1"],
|
width=drc["minwidth_metal1"],
|
||||||
|
|
@ -243,7 +243,7 @@ class nor_2(design.design):
|
||||||
offset = (self.pwell_contact_position.scale(1,0)
|
offset = (self.pwell_contact_position.scale(1,0)
|
||||||
+ self.pwell_contact.second_layer_position.scale(1,0)
|
+ self.pwell_contact.second_layer_position.scale(1,0)
|
||||||
- self.pwell_contact.first_layer_position.scale(1,0))
|
- self.pwell_contact.first_layer_position.scale(1,0))
|
||||||
well_tap_length = self.pwell_contact_position[1]
|
well_tap_length = self.pwell_contact_position.y
|
||||||
self.add_rect(layer="metal1",
|
self.add_rect(layer="metal1",
|
||||||
offset=offset,
|
offset=offset,
|
||||||
width=drc["minwidth_metal1"],
|
width=drc["minwidth_metal1"],
|
||||||
|
|
@ -257,7 +257,7 @@ class nor_2(design.design):
|
||||||
if i % 2 == 0:
|
if i % 2 == 0:
|
||||||
correct = self.pmos1.active_contact.second_layer_position.scale(1,0)
|
correct = self.pmos1.active_contact.second_layer_position.scale(1,0)
|
||||||
drain_posistion = contact_pos + correct
|
drain_posistion = contact_pos + correct
|
||||||
height = self.vdd_position[1] - drain_posistion[1]
|
height = self.vdd_position.y - drain_posistion.y
|
||||||
self.add_rect(layer="metal1",
|
self.add_rect(layer="metal1",
|
||||||
offset=drain_posistion,
|
offset=drain_posistion,
|
||||||
width=drc["minwidth_metal1"],
|
width=drc["minwidth_metal1"],
|
||||||
|
|
@ -268,7 +268,7 @@ class nor_2(design.design):
|
||||||
+ vector(self.pmos1.active_contact.second_layer_width,
|
+ vector(self.pmos1.active_contact.second_layer_width,
|
||||||
0).scale(.5,0))
|
0).scale(.5,0))
|
||||||
source_position = contact_pos + correct
|
source_position = contact_pos + correct
|
||||||
mid = [self.pmos_position2[0], M1_track]
|
mid = [self.pmos_position2.x, M1_track]
|
||||||
self.add_path("metal1", [source_position, mid])
|
self.add_path("metal1", [source_position, mid])
|
||||||
|
|
||||||
# the second pmos
|
# the second pmos
|
||||||
|
|
@ -279,13 +279,13 @@ class nor_2(design.design):
|
||||||
correct= (self.pmos2.active_contact.second_layer_position.scale(1,0)
|
correct= (self.pmos2.active_contact.second_layer_position.scale(1,0)
|
||||||
+ vector(0.5 * self.pmos2.active_contact.second_layer_width,0))
|
+ vector(0.5 * self.pmos2.active_contact.second_layer_width,0))
|
||||||
source_position = pmos_active + correct
|
source_position = pmos_active + correct
|
||||||
mid = [self.pmos_position2[0], M1_track]
|
mid = [self.pmos_position2.x, M1_track]
|
||||||
self.add_path("metal1", [source_position, mid])
|
self.add_path("metal1", [source_position, mid])
|
||||||
# two nmos source to gnd
|
# two nmos source to gnd
|
||||||
source_posistion1 = (self.nmos_position1
|
source_posistion1 = (self.nmos_position1
|
||||||
+ self.nmos1.active_contact_positions[0]
|
+ self.nmos1.active_contact_positions[0]
|
||||||
+ self.nmos1.active_contact.second_layer_position.scale(1,0))
|
+ self.nmos1.active_contact.second_layer_position.scale(1,0))
|
||||||
height = self.gnd_position[1] - source_posistion1[1]
|
height = self.gnd_position.y - source_posistion1.y
|
||||||
self.add_rect(layer="metal1",
|
self.add_rect(layer="metal1",
|
||||||
offset=source_posistion1,
|
offset=source_posistion1,
|
||||||
width=drc["minwidth_metal1"],
|
width=drc["minwidth_metal1"],
|
||||||
|
|
@ -294,7 +294,7 @@ class nor_2(design.design):
|
||||||
source_posistion2 = (self.nmos_position2
|
source_posistion2 = (self.nmos_position2
|
||||||
+ self.nmos2.active_contact_positions[1]
|
+ self.nmos2.active_contact_positions[1]
|
||||||
+ self.nmos2.active_contact.second_layer_position.scale(1,0))
|
+ self.nmos2.active_contact.second_layer_position.scale(1,0))
|
||||||
height = self.gnd_position[1] - source_posistion2[1]
|
height = self.gnd_position.y - source_posistion2.y
|
||||||
self.add_rect(layer="metal1",
|
self.add_rect(layer="metal1",
|
||||||
offset=source_posistion2,
|
offset=source_posistion2,
|
||||||
width=drc["minwidth_metal1"],
|
width=drc["minwidth_metal1"],
|
||||||
|
|
@ -310,22 +310,22 @@ class nor_2(design.design):
|
||||||
pmos_gate = (self.pmos_position1
|
pmos_gate = (self.pmos_position1
|
||||||
+ self.pmos1.poly_positions[i]
|
+ self.pmos1.poly_positions[i]
|
||||||
+ vector(0.5 * drc["minwidth_poly"], 0))
|
+ vector(0.5 * drc["minwidth_poly"], 0))
|
||||||
mid1 = [pmos_gate[0], pmos_gate[1] - drc["poly_to_active"]]
|
mid1 = [pmos_gate.x, pmos_gate.y - drc["poly_to_active"]]
|
||||||
self.add_path("poly", [nmos_gate, mid1, pmos_gate])
|
self.add_path("poly", [nmos_gate, mid1, pmos_gate])
|
||||||
|
|
||||||
# connect pmos2 poly
|
# connect pmos2 poly
|
||||||
nmos_gate = [self.nmos_position2[0] \
|
nmos_gate = vector(self.nmos_position2[0]
|
||||||
+ self.nmos2.poly_positions[0][0]
|
+ self.nmos2.poly_positions[0].x
|
||||||
+ 0.5 * drc["minwidth_poly"], \
|
+ 0.5 * drc["minwidth_poly"],
|
||||||
self.nmos_position1[1] \
|
self.nmos_position1.y
|
||||||
+ self.nmos1.poly_positions[0][1]]
|
+ self.nmos1.poly_positions[0].y)
|
||||||
for i in range(len(self.pmos2.poly_positions)):
|
for i in range(len(self.pmos2.poly_positions)):
|
||||||
pmos_gate = (self.pmos_position2
|
pmos_gate = (self.pmos_position2
|
||||||
+ self.pmos2.poly_positions[i]
|
+ self.pmos2.poly_positions[i]
|
||||||
+ vector(0.5 * drc["minwidth_poly"], 0))
|
+ vector(0.5 * drc["minwidth_poly"], 0))
|
||||||
mid1 = [pmos_gate[0],
|
mid1 = vector(pmos_gate.x,
|
||||||
nmos_gate[1] + self.nmos2.height \
|
nmos_gate.y + self.nmos2.height
|
||||||
+ drc["poly_to_active"]]
|
+ drc["poly_to_active"])
|
||||||
self.add_path("poly", [nmos_gate, mid1, pmos_gate])
|
self.add_path("poly", [nmos_gate, mid1, pmos_gate])
|
||||||
|
|
||||||
def route_pins(self):
|
def route_pins(self):
|
||||||
|
|
@ -350,15 +350,15 @@ class nor_2(design.design):
|
||||||
rotate=90)
|
rotate=90)
|
||||||
|
|
||||||
# connect gate input to tx gate
|
# connect gate input to tx gate
|
||||||
offset = self.A_position - vector(self.poly_contact.first_layer_position[1],
|
offset = self.A_position - vector(self.poly_contact.first_layer_position.y,
|
||||||
0.5 * self.poly_contact.width)
|
0.5 * self.poly_contact.width)
|
||||||
self.add_rect(layer="poly",
|
self.add_rect(layer="poly",
|
||||||
offset=offset,
|
offset=offset,
|
||||||
width=self.poly_contact.first_layer_position[1] + drc["minwidth_poly"],
|
width=self.poly_contact.first_layer_position.y + drc["minwidth_poly"],
|
||||||
height=self.poly_contact.first_layer_width)
|
height=self.poly_contact.first_layer_width)
|
||||||
# extend the metal to the boundary of the cell
|
# extend the metal to the boundary of the cell
|
||||||
input_length = self.A_position[0]
|
input_length = self.A_position.x
|
||||||
offset = [0, self.A_position[1] - 0.5 * drc["minwidth_metal1"]]
|
offset = [0, self.A_position.y - 0.5 * drc["minwidth_metal1"]]
|
||||||
self.add_layout_pin(text="A",
|
self.add_layout_pin(text="A",
|
||||||
layer="metal1",
|
layer="metal1",
|
||||||
offset=offset,
|
offset=offset,
|
||||||
|
|
@ -367,9 +367,9 @@ class nor_2(design.design):
|
||||||
|
|
||||||
def route_input_B(self):
|
def route_input_B(self):
|
||||||
"""create input B layout """
|
"""create input B layout """
|
||||||
xoffset = self.pmos2.poly_positions[0][0] \
|
xoffset = self.pmos2.poly_positions[0].x \
|
||||||
+ self.pmos_position2[0]
|
+ self.pmos_position2.x
|
||||||
yoffset = self.A_position[1] \
|
yoffset = self.A_position.y \
|
||||||
+ 0.5 * (self.poly_contact.second_layer_width \
|
+ 0.5 * (self.poly_contact.second_layer_width \
|
||||||
+ drc["minwidth_metal1"]) + drc["metal1_to_metal1"]
|
+ drc["minwidth_metal1"]) + drc["metal1_to_metal1"]
|
||||||
self.B_position = vector(xoffset, yoffset)
|
self.B_position = vector(xoffset, yoffset)
|
||||||
|
|
@ -380,13 +380,13 @@ class nor_2(design.design):
|
||||||
|
|
||||||
self.add_rect(layer="poly",
|
self.add_rect(layer="poly",
|
||||||
offset=offset,
|
offset=offset,
|
||||||
width=-(self.poly_contact.first_layer_position[1] + drc["minwidth_poly"]),
|
width=-(self.poly_contact.first_layer_position.y + drc["minwidth_poly"]),
|
||||||
height=self.poly_contact.first_layer_width)
|
height=self.poly_contact.first_layer_width)
|
||||||
self.add_layout_pin(text="B",
|
self.add_layout_pin(text="B",
|
||||||
layer="metal1",
|
layer="metal1",
|
||||||
offset=[0,
|
offset=[0,
|
||||||
self.B_position[1] - 0.5 * drc["minwidth_metal1"]],
|
self.B_position.y - 0.5 * drc["minwidth_metal1"]],
|
||||||
width=self.B_position[0],
|
width=self.B_position.x,
|
||||||
height=drc["minwidth_metal1"])
|
height=drc["minwidth_metal1"])
|
||||||
|
|
||||||
def route_output(self):
|
def route_output(self):
|
||||||
|
|
@ -398,7 +398,7 @@ class nor_2(design.design):
|
||||||
+ self.nmos1.active_contact.second_layer_position
|
+ self.nmos1.active_contact.second_layer_position
|
||||||
+ vector(self.nmos1.active_contact.second_layer_width,
|
+ vector(self.nmos1.active_contact.second_layer_width,
|
||||||
0).scale(0.5, 0))
|
0).scale(0.5, 0))
|
||||||
mid = [nmos_contact[0], self.A_position[1]]
|
mid = [nmos_contact.x, self.A_position.y]
|
||||||
self.add_path("metal1", [self.Z_position, mid, nmos_contact])
|
self.add_path("metal1", [self.Z_position, mid, nmos_contact])
|
||||||
|
|
||||||
for i in range(len(self.pmos2.poly_positions) + 1):
|
for i in range(len(self.pmos2.poly_positions) + 1):
|
||||||
|
|
@ -412,19 +412,19 @@ class nor_2(design.design):
|
||||||
offset = pmos_contact - vector(0.5 * self.m1m2_via.width, 0)
|
offset = pmos_contact - vector(0.5 * self.m1m2_via.width, 0)
|
||||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||||
offset=offset)
|
offset=offset)
|
||||||
mid = [pmos_contact[0], self.Z_position[1]]
|
mid = [pmos_contact.x, self.Z_position.y]
|
||||||
self.add_wire(("metal2", "via1", "metal1"),
|
self.add_wire(("metal1", "via1", "metal2"),
|
||||||
[self.Z_position, mid, pmos_contact])
|
[self.Z_position, mid, pmos_contact])
|
||||||
|
|
||||||
def extend_wells(self):
|
def extend_wells(self):
|
||||||
""" extend well for well contact"""
|
""" extend well for well contact"""
|
||||||
middle_point = (self.nmos_position1[1]
|
middle_point = (self.nmos_position1.y
|
||||||
+ self.nmos1.pwell_position[1]
|
+ self.nmos1.pwell_position.y
|
||||||
+ self.nmos1.well_height
|
+ self.nmos1.well_height
|
||||||
+ (self.pmos_position1[1]
|
+ (self.pmos_position1.y
|
||||||
+ self.pmos1.nwell_position[1]
|
+ self.pmos1.nwell_position.y
|
||||||
- self.nmos_position1[1]
|
- self.nmos_position1.y
|
||||||
- self.nmos1.pwell_position[1]
|
- self.nmos1.pwell_position.y
|
||||||
- self.nmos1.well_height) / 2 )
|
- self.nmos1.well_height) / 2 )
|
||||||
self.nwell_position = vector(0, middle_point)
|
self.nwell_position = vector(0, middle_point)
|
||||||
self.nwell_height = self.height - middle_point
|
self.nwell_height = self.height - middle_point
|
||||||
|
|
|
||||||
|
|
@ -33,9 +33,8 @@ import debug
|
||||||
if len(args) < 1:
|
if len(args) < 1:
|
||||||
print globals.USAGE
|
print globals.USAGE
|
||||||
sys.exit(2)
|
sys.exit(2)
|
||||||
|
|
||||||
if OPTS.print_banner:
|
globals.print_banner()
|
||||||
print globals.BANNER
|
|
||||||
|
|
||||||
globals.init_openram(args[0])
|
globals.init_openram(args[0])
|
||||||
|
|
||||||
|
|
@ -94,7 +93,7 @@ s.gds_write(gdsname)
|
||||||
|
|
||||||
# Run Characterizer on the design
|
# Run Characterizer on the design
|
||||||
sram_file = spname
|
sram_file = spname
|
||||||
if OPTS.run_pex:
|
if OPTS.use_pex:
|
||||||
sram_file = OPTS.out_path + "temp_pex.sp"
|
sram_file = OPTS.out_path + "temp_pex.sp"
|
||||||
calibre.run_pex(s.name, gdsname, spname, output=sram_file)
|
calibre.run_pex(s.name, gdsname, spname, output=sram_file)
|
||||||
|
|
||||||
|
|
@ -117,5 +116,6 @@ libname = OPTS.out_path + s.name + ".lib"
|
||||||
print "LIB: Writing to {0}".format(libname)
|
print "LIB: Writing to {0}".format(libname)
|
||||||
lib.lib(libname,s,sram_file)
|
lib.lib(libname,s,sram_file)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
print "End: ", datetime.datetime.now()
|
print "End: ", datetime.datetime.now()
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,18 @@
|
||||||
import optparse
|
import optparse
|
||||||
import getpass
|
import getpass
|
||||||
|
import os
|
||||||
|
|
||||||
class options(optparse.Values):
|
class options(optparse.Values):
|
||||||
"""
|
"""
|
||||||
Class for holding all of the OpenRAM options.
|
Class for holding all of the OpenRAM options.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# This is the technology directory.
|
# This is the technology directory.
|
||||||
openram_tech = ""
|
openram_tech = ""
|
||||||
# This is the name of the technology.
|
# This is the name of the technology.
|
||||||
tech_name = ""
|
tech_name = ""
|
||||||
# This is the temp directory where all intermediate results are stored.
|
# This is the temp directory where all intermediate results are stored.
|
||||||
openram_temp = "/tmp/openram_{0}_temp/".format(getpass.getuser())
|
openram_temp = "/tmp/openram_{0}_{1}_temp/".format(getpass.getuser(),os.getpid())
|
||||||
# This is the verbosity level to control debug information. 0 is none, 1
|
# This is the verbosity level to control debug information. 0 is none, 1
|
||||||
# is minimal, etc.
|
# is minimal, etc.
|
||||||
debug_level = 0
|
debug_level = 0
|
||||||
|
|
@ -18,6 +20,8 @@ class options(optparse.Values):
|
||||||
check_lvsdrc = True
|
check_lvsdrc = True
|
||||||
# Variable to select the variant of spice (hspice or ngspice right now)
|
# Variable to select the variant of spice (hspice or ngspice right now)
|
||||||
spice_version = "hspice"
|
spice_version = "hspice"
|
||||||
|
# Should we fall back if we can't find our preferred spice?
|
||||||
|
force_spice = False
|
||||||
# Should we print out the banner at startup
|
# Should we print out the banner at startup
|
||||||
print_banner = True
|
print_banner = True
|
||||||
# The Calibre executable being used which is derived from the user PATH.
|
# The Calibre executable being used which is derived from the user PATH.
|
||||||
|
|
@ -25,7 +29,7 @@ class options(optparse.Values):
|
||||||
# The spice executable being used which is derived from the user PATH.
|
# The spice executable being used which is derived from the user PATH.
|
||||||
spice_exe = ""
|
spice_exe = ""
|
||||||
# Run with extracted parasitics
|
# Run with extracted parasitics
|
||||||
run_pex = False
|
use_pex = False
|
||||||
# Trim noncritical memory cells for simulation speed-up
|
# Trim noncritical memory cells for simulation speed-up
|
||||||
trim_noncritical = False
|
trim_noncritical = False
|
||||||
# Define the output file paths
|
# Define the output file paths
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ class path(design.design):
|
||||||
name = "path_{0}".format(path.unique_path_id)
|
name = "path_{0}".format(path.unique_path_id)
|
||||||
path.unique_path_id += 1
|
path.unique_path_id += 1
|
||||||
design.design.__init__(self, name)
|
design.design.__init__(self, name)
|
||||||
debug.info(2, "create path obj {0}".format(name))
|
debug.info(3, "create path obj {0}".format(name))
|
||||||
|
|
||||||
self.name = name
|
self.name = name
|
||||||
self.layer_name = layer
|
self.layer_name = layer
|
||||||
|
|
|
||||||
|
|
@ -109,7 +109,7 @@ class pinv(design.design):
|
||||||
"""Sets up constant variables"""
|
"""Sets up constant variables"""
|
||||||
# the well width is determined the multi-finger PMOS device width plus
|
# the well width is determined the multi-finger PMOS device width plus
|
||||||
# the well contact width and enclosure
|
# the well contact width and enclosure
|
||||||
self.well_width = self.pmos.active_position[0] \
|
self.well_width = self.pmos.active_position.x \
|
||||||
+ self.pmos.active_width \
|
+ self.pmos.active_width \
|
||||||
+ drc["active_to_body_active"] \
|
+ drc["active_to_body_active"] \
|
||||||
+ self.pmos.active_contact.width \
|
+ self.pmos.active_contact.width \
|
||||||
|
|
@ -140,10 +140,10 @@ class pinv(design.design):
|
||||||
# determines the spacing between the edge and nmos (rail to active
|
# determines the spacing between the edge and nmos (rail to active
|
||||||
# metal or poly_to_poly spacing)
|
# metal or poly_to_poly spacing)
|
||||||
edge_to_nmos = max(drc["metal1_to_metal1"] \
|
edge_to_nmos = max(drc["metal1_to_metal1"] \
|
||||||
- self.nmos.active_contact_positions[0][1],
|
- self.nmos.active_contact_positions[0].y,
|
||||||
0.5 * drc["poly_to_poly"] \
|
0.5 * drc["poly_to_poly"] \
|
||||||
- 0.5 * drc["minwidth_metal1"] \
|
- 0.5 * drc["minwidth_metal1"] \
|
||||||
- self.nmos.poly_positions[0][1])
|
- self.nmos.poly_positions[0].y)
|
||||||
self.nmos_position = vector(0, 0.5 * drc["minwidth_metal1"] + edge_to_nmos)
|
self.nmos_position = vector(0, 0.5 * drc["minwidth_metal1"] + edge_to_nmos)
|
||||||
offset = self.nmos_position + vector(0,self.nmos.height)
|
offset = self.nmos_position + vector(0,self.nmos.height)
|
||||||
self.add_inst(name="pinv_nmos",
|
self.add_inst(name="pinv_nmos",
|
||||||
|
|
@ -154,10 +154,10 @@ class pinv(design.design):
|
||||||
|
|
||||||
# determines the spacing between the edge and pmos
|
# determines the spacing between the edge and pmos
|
||||||
edge_to_pmos = max(drc["metal1_to_metal1"] \
|
edge_to_pmos = max(drc["metal1_to_metal1"] \
|
||||||
- self.pmos.active_contact_positions[0][1],
|
- self.pmos.active_contact_positions[0].y,
|
||||||
0.5 * drc["poly_to_poly"] \
|
0.5 * drc["poly_to_poly"] \
|
||||||
- 0.5 * drc["minwidth_metal1"] \
|
- 0.5 * drc["minwidth_metal1"] \
|
||||||
- self.pmos.poly_positions[0][1])
|
- self.pmos.poly_positions[0].y)
|
||||||
self.pmos_position = vector(0,
|
self.pmos_position = vector(0,
|
||||||
self.height - 0.5 * drc["minwidth_metal1"]
|
self.height - 0.5 * drc["minwidth_metal1"]
|
||||||
- edge_to_pmos - self.pmos.height)
|
- edge_to_pmos - self.pmos.height)
|
||||||
|
|
@ -168,9 +168,9 @@ class pinv(design.design):
|
||||||
|
|
||||||
def extend_wells(self):
|
def extend_wells(self):
|
||||||
"""Extends the n/p wells to cover whole layout"""
|
"""Extends the n/p wells to cover whole layout"""
|
||||||
nmos_top_yposition = self.nmos_position[1] + self.nmos.height
|
nmos_top_yposition = self.nmos_position.y + self.nmos.height
|
||||||
# calculates the length between the pmos and nmos
|
# calculates the length between the pmos and nmos
|
||||||
middle_length = self.pmos_position[1] - nmos_top_yposition
|
middle_length = self.pmos_position.y - nmos_top_yposition
|
||||||
# calculate the middle point between the pmos and nmos
|
# calculate the middle point between the pmos and nmos
|
||||||
middle_yposition = nmos_top_yposition + 0.5 * middle_length
|
middle_yposition = nmos_top_yposition + 0.5 * middle_length
|
||||||
|
|
||||||
|
|
@ -185,7 +185,7 @@ class pinv(design.design):
|
||||||
width=self.well_width,
|
width=self.well_width,
|
||||||
height=self.nwell_height)
|
height=self.nwell_height)
|
||||||
|
|
||||||
self.pwell_position = [0, 0]
|
self.pwell_position = vector(0, 0)
|
||||||
self.pwell_height = middle_yposition
|
self.pwell_height = middle_yposition
|
||||||
self.add_rect(layer="pwell",
|
self.add_rect(layer="pwell",
|
||||||
offset=self.pwell_position, width=self.well_width,
|
offset=self.pwell_position, width=self.well_width,
|
||||||
|
|
@ -239,14 +239,14 @@ class pinv(design.design):
|
||||||
def connect_poly(self):
|
def connect_poly(self):
|
||||||
"""Connects the poly from nmos to pmos (as well if it is multi-fingered)"""
|
"""Connects the poly from nmos to pmos (as well if it is multi-fingered)"""
|
||||||
# Calculates the y-coordinate of the top of the poly of the nmos
|
# Calculates the y-coordinate of the top of the poly of the nmos
|
||||||
nmos_top_poly_yposition = self.nmos_position[1] \
|
nmos_top_poly_yposition = self.nmos_position.y \
|
||||||
+ self.nmos.height \
|
+ self.nmos.height \
|
||||||
- self.nmos.poly_positions[0][1]
|
- self.nmos.poly_positions[0].y
|
||||||
|
|
||||||
poly_length = self.pmos_position[1] + self.pmos.poly_positions[0][1] \
|
poly_length = self.pmos_position.y + self.pmos.poly_positions[0].y \
|
||||||
- nmos_top_poly_yposition
|
- nmos_top_poly_yposition
|
||||||
for position in self.pmos.poly_positions:
|
for position in self.pmos.poly_positions:
|
||||||
offset = [position[0], nmos_top_poly_yposition]
|
offset = [position.x, nmos_top_poly_yposition]
|
||||||
self.add_rect(layer="poly",
|
self.add_rect(layer="poly",
|
||||||
offset=offset,
|
offset=offset,
|
||||||
width=drc["minwidth_poly"],
|
width=drc["minwidth_poly"],
|
||||||
|
|
@ -257,14 +257,14 @@ class pinv(design.design):
|
||||||
# Determines the top y-coordinate of the nmos drain metal layer
|
# Determines the top y-coordinate of the nmos drain metal layer
|
||||||
yoffset = self.nmos.height \
|
yoffset = self.nmos.height \
|
||||||
- 0.5 * drc["minwidth_metal1"] \
|
- 0.5 * drc["minwidth_metal1"] \
|
||||||
- self.nmos.active_contact_positions[0][1]
|
- self.nmos.active_contact_positions[0].y
|
||||||
drain_length = self.height - yoffset + drc["minwidth_metal1"] \
|
drain_length = self.height - yoffset + drc["minwidth_metal1"] \
|
||||||
- (self.pmos.height
|
- (self.pmos.height
|
||||||
- self.pmos.active_contact_positions[0][1])
|
- self.pmos.active_contact_positions[0].y)
|
||||||
for position in self.pmos.active_contact_positions[1:][::2]:
|
for position in self.pmos.active_contact_positions[1:][::2]:
|
||||||
offset = [position[0] + self.pmos.active_contact.second_layer_position[0],
|
offset = [position.x + self.pmos.active_contact.second_layer_position.x,
|
||||||
yoffset]
|
yoffset]
|
||||||
self.drain_position = offset
|
self.drain_position = vector(offset)
|
||||||
self.add_rect(layer="metal1",
|
self.add_rect(layer="metal1",
|
||||||
offset=offset,
|
offset=offset,
|
||||||
width=self.nmos.active_contact.second_layer_width,
|
width=self.nmos.active_contact.second_layer_width,
|
||||||
|
|
@ -273,7 +273,7 @@ class pinv(design.design):
|
||||||
def route_input_gate(self):
|
def route_input_gate(self):
|
||||||
"""Routes the input gate to the left side of the cell for access"""
|
"""Routes the input gate to the left side of the cell for access"""
|
||||||
|
|
||||||
xoffset = self.pmos.poly_positions[0][0]
|
xoffset = self.pmos.poly_positions[0].x
|
||||||
# Determines the y-coordinate of where to place the gate input poly pin
|
# Determines the y-coordinate of where to place the gate input poly pin
|
||||||
# (middle in between the pmos and nmos)
|
# (middle in between the pmos and nmos)
|
||||||
yoffset = self.nmos.height + (self.height
|
yoffset = self.nmos.height + (self.height
|
||||||
|
|
@ -285,13 +285,13 @@ class pinv(design.design):
|
||||||
rotate=90)
|
rotate=90)
|
||||||
|
|
||||||
# Determines the poly coordinate to connect to the poly contact
|
# Determines the poly coordinate to connect to the poly contact
|
||||||
offset = offset - self.poly_contact.first_layer_position.rotate().scale(1,0)
|
offset = offset - self.poly_contact.first_layer_position.rotate_scale(1,0)
|
||||||
self.add_rect(layer="poly",
|
self.add_rect(layer="poly",
|
||||||
offset=offset,
|
offset=offset,
|
||||||
width=self.poly_contact.first_layer_position[1] + drc["minwidth_poly"],
|
width=self.poly_contact.first_layer_position.y + drc["minwidth_poly"],
|
||||||
height=self.poly_contact.first_layer_width)
|
height=self.poly_contact.first_layer_width)
|
||||||
|
|
||||||
input_length = self.pmos.poly_positions[0][0] \
|
input_length = self.pmos.poly_positions[0].x \
|
||||||
- self.poly_contact.height
|
- self.poly_contact.height
|
||||||
# Determine the y-coordinate for the placement of the metal1 via
|
# Determine the y-coordinate for the placement of the metal1 via
|
||||||
self.input_position = vector(0, .5*(self.height - drc["minwidth_metal1"]
|
self.input_position = vector(0, .5*(self.height - drc["minwidth_metal1"]
|
||||||
|
|
@ -305,9 +305,9 @@ class pinv(design.design):
|
||||||
def route_output_drain(self):
|
def route_output_drain(self):
|
||||||
"""Routes the output (drain) to the right side of the cell for access"""
|
"""Routes the output (drain) to the right side of the cell for access"""
|
||||||
# Determines the y-coordinate of the output metal1 via pin
|
# Determines the y-coordinate of the output metal1 via pin
|
||||||
offset = vector(self.drain_position[0]
|
offset = vector(self.drain_position.x
|
||||||
+ self.nmos.active_contact.second_layer_width,
|
+ self.nmos.active_contact.second_layer_width,
|
||||||
self.input_position[1])
|
self.input_position.y)
|
||||||
output_length = self.width - offset.x
|
output_length = self.width - offset.x
|
||||||
if self.route_output == True:
|
if self.route_output == True:
|
||||||
self.output_position = offset + vector(output_length,0)
|
self.output_position = offset + vector(output_length,0)
|
||||||
|
|
@ -325,22 +325,18 @@ class pinv(design.design):
|
||||||
"""Adds n/p well taps to the layout"""
|
"""Adds n/p well taps to the layout"""
|
||||||
layer_stack = ("active", "contact", "metal1")
|
layer_stack = ("active", "contact", "metal1")
|
||||||
# Same y-positions of the drain/source metals as the n/p mos
|
# Same y-positions of the drain/source metals as the n/p mos
|
||||||
nwell_tap_xposition = self.pmos_position[0] \
|
well_contact_offset = vector(self.pmos.active_position.x
|
||||||
+ self.pmos.active_position[0] \
|
+ self.active_width
|
||||||
+ self.active_width \
|
- self.nwell_contact.width,
|
||||||
- self.nwell_contact.width
|
self.pmos.active_contact_positions[0].y)
|
||||||
nwell_tap_yposition = self.pmos_position[1] \
|
self.nwell_contact_position = self.pmos_position + well_contact_offset
|
||||||
+ self.pmos.active_contact_positions[0][1]
|
|
||||||
self.nwell_contact_position = [nwell_tap_xposition, nwell_tap_yposition]
|
|
||||||
self.nwell_contact=self.add_contact(layer_stack,self.nwell_contact_position,(1,self.pmos.num_of_tacts))
|
self.nwell_contact=self.add_contact(layer_stack,self.nwell_contact_position,(1,self.pmos.num_of_tacts))
|
||||||
|
|
||||||
pwell_tap_xposition = self.nmos_position[0] \
|
well_contact_offset = vector(self.nmos.active_position.x
|
||||||
+ self.nmos.active_position[0] \
|
+ self.active_width
|
||||||
+ self.active_width \
|
- self.pwell_contact.width,
|
||||||
- self.pwell_contact.width
|
self.nmos.active_contact_positions[0].y)
|
||||||
pwell_tap_yposition = self.nmos_position[1] \
|
self.pwell_contact_position = self.nmos_position + well_contact_offset
|
||||||
+ self.nmos.active_contact_positions[0][1]
|
|
||||||
self.pwell_contact_position = [pwell_tap_xposition, pwell_tap_yposition]
|
|
||||||
self.pwell_contact=self.add_contact(layer_stack,self.pwell_contact_position,(1,self.nmos.num_of_tacts))
|
self.pwell_contact=self.add_contact(layer_stack,self.pwell_contact_position,(1,self.nmos.num_of_tacts))
|
||||||
|
|
||||||
def connect_well_contacts(self):
|
def connect_well_contacts(self):
|
||||||
|
|
@ -348,7 +344,7 @@ class pinv(design.design):
|
||||||
# calculates the length needed to connect the nwell_tap to vdd
|
# calculates the length needed to connect the nwell_tap to vdd
|
||||||
nwell_tap_length = self.height \
|
nwell_tap_length = self.height \
|
||||||
- 0.5 * drc["minwidth_metal1"] \
|
- 0.5 * drc["minwidth_metal1"] \
|
||||||
- self.nwell_contact_position[1]
|
- self.nwell_contact_position.y
|
||||||
# obtains the position for the metal 1 layer in the nwell_tap
|
# obtains the position for the metal 1 layer in the nwell_tap
|
||||||
offset = self.nwell_contact_position + \
|
offset = self.nwell_contact_position + \
|
||||||
self.nwell_contact.second_layer_position.scale(1,0)
|
self.nwell_contact.second_layer_position.scale(1,0)
|
||||||
|
|
@ -356,10 +352,10 @@ class pinv(design.design):
|
||||||
offset=offset, width=self.nwell_contact.second_layer_width,
|
offset=offset, width=self.nwell_contact.second_layer_width,
|
||||||
height=nwell_tap_length)
|
height=nwell_tap_length)
|
||||||
|
|
||||||
pwell_tap_length = self.pwell_contact_position[1] \
|
pwell_tap_length = self.pwell_contact_position.y \
|
||||||
+ 0.5 * drc["minwidth_metal1"]
|
+ 0.5 * drc["minwidth_metal1"]
|
||||||
offset = [self.pwell_contact_position[0]
|
offset = [self.pwell_contact_position.x
|
||||||
+ self.pwell_contact.second_layer_position[0],
|
+ self.pwell_contact.second_layer_position.x,
|
||||||
0.5 * drc["minwidth_metal1"]]
|
0.5 * drc["minwidth_metal1"]]
|
||||||
self.add_rect(layer="metal1",
|
self.add_rect(layer="metal1",
|
||||||
offset=offset,
|
offset=offset,
|
||||||
|
|
@ -377,7 +373,7 @@ class pinv(design.design):
|
||||||
- drc["minwidth_metal1"]).scale(.5,.5)
|
- drc["minwidth_metal1"]).scale(.5,.5)
|
||||||
# nmos position of the source metals
|
# nmos position of the source metals
|
||||||
noffset = self.nmos_position + self.nmos.active_contact_positions[0] + correct
|
noffset = self.nmos_position + self.nmos.active_contact_positions[0] + correct
|
||||||
offset = [self.nmos.active_contact.second_layer_position[0] + noffset[0],
|
offset = [self.nmos.active_contact.second_layer_position.x + noffset.x,
|
||||||
0.5 * drc["minwidth_metal1"]]
|
0.5 * drc["minwidth_metal1"]]
|
||||||
self.add_rect(layer="metal1", offset=offset,
|
self.add_rect(layer="metal1", offset=offset,
|
||||||
width=self.nmos.active_contact.second_layer_width,
|
width=self.nmos.active_contact.second_layer_width,
|
||||||
|
|
@ -390,7 +386,7 @@ class pinv(design.design):
|
||||||
# pmos position of the source metals
|
# pmos position of the source metals
|
||||||
offset = self.pmos_position + self.pmos.active_contact_positions[0]\
|
offset = self.pmos_position + self.pmos.active_contact_positions[0]\
|
||||||
+ correct + self.pmos.active_contact.second_layer_position
|
+ correct + self.pmos.active_contact.second_layer_position
|
||||||
temp_height = self.height - offset[1] - 0.5 * drc["minwidth_metal1"]
|
temp_height = self.height - offset.y - 0.5 * drc["minwidth_metal1"]
|
||||||
self.add_rect(layer="metal1",
|
self.add_rect(layer="metal1",
|
||||||
offset=offset,
|
offset=offset,
|
||||||
width=self.pmos.active_contact.second_layer_width,
|
width=self.pmos.active_contact.second_layer_width,
|
||||||
|
|
|
||||||
|
|
@ -185,7 +185,7 @@ class precharge(design.design):
|
||||||
def add_vdd_rail(self):
|
def add_vdd_rail(self):
|
||||||
"""Adds a vdd rail at the top of the cell"""
|
"""Adds a vdd rail at the top of the cell"""
|
||||||
# adds the rail across the width of the cell
|
# adds the rail across the width of the cell
|
||||||
self.vdd_position = vector(self.pclk_position[0],
|
self.vdd_position = vector(self.pclk_position.x,
|
||||||
self.height - drc["minwidth_metal1"])
|
self.height - drc["minwidth_metal1"])
|
||||||
self.add_layout_pin(text="vdd",
|
self.add_layout_pin(text="vdd",
|
||||||
layer="metal1",
|
layer="metal1",
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ class ptx(design.design):
|
||||||
name = "{0}{1}".format(name, ptx.unique_mos_id)
|
name = "{0}{1}".format(name, ptx.unique_mos_id)
|
||||||
ptx.unique_mos_id += 1
|
ptx.unique_mos_id += 1
|
||||||
design.design.__init__(self, name)
|
design.design.__init__(self, name)
|
||||||
debug.info(2, "create ptx structure {0}".format(name))
|
debug.info(3, "create ptx structure {0}".format(name))
|
||||||
|
|
||||||
self.tx_type = tx_type
|
self.tx_type = tx_type
|
||||||
self.mults = mults
|
self.mults = mults
|
||||||
|
|
@ -56,10 +56,10 @@ class ptx(design.design):
|
||||||
|
|
||||||
# We can do this in ptx because we have offset all modules it uses.
|
# We can do this in ptx because we have offset all modules it uses.
|
||||||
# Is this really true considering the paths that connect the src/drain?
|
# Is this really true considering the paths that connect the src/drain?
|
||||||
self.height = max(max(obj.offset[1] + obj.height for obj in self.objs),
|
self.height = max(max(obj.offset.y + obj.height for obj in self.objs),
|
||||||
max(inst.offset[1] + inst.mod.height for inst in self.insts))
|
max(inst.offset.y + inst.mod.height for inst in self.insts))
|
||||||
self.width = max(max(obj.offset[0] + obj.width for obj in self.objs),
|
self.width = max(max(obj.offset.x + obj.width for obj in self.objs),
|
||||||
max(inst.offset[0] + inst.mod.width for inst in self.insts))
|
max(inst.offset.x + inst.mod.width for inst in self.insts))
|
||||||
|
|
||||||
def create_spice(self):
|
def create_spice(self):
|
||||||
self.spice.append("\n.SUBCKT {0} {1}".format(self.name,
|
self.spice.append("\n.SUBCKT {0} {1}".format(self.name,
|
||||||
|
|
@ -78,29 +78,27 @@ class ptx(design.design):
|
||||||
self.mults_poly_to_poly = max(2 * drc["contact_to_poly"] + drc["minwidth_contact"],
|
self.mults_poly_to_poly = max(2 * drc["contact_to_poly"] + drc["minwidth_contact"],
|
||||||
drc["poly_to_poly"])
|
drc["poly_to_poly"])
|
||||||
outeractive_to_contact = max(drc["active_enclosure_contact"],
|
outeractive_to_contact = max(drc["active_enclosure_contact"],
|
||||||
(drc["minwidth_active"] - drc["minwidth_contact"]) / 2)
|
(drc["minwidth_active"] - drc["minwidth_contact"]) / 2)
|
||||||
self.active_width = 2 * (outeractive_to_contact \
|
self.active_width = (2 * (outeractive_to_contact + drc["minwidth_contact"]
|
||||||
+ drc["minwidth_contact"] \
|
+ drc["contact_to_poly"])
|
||||||
+ drc["contact_to_poly"]) \
|
+ drc["minwidth_poly"]
|
||||||
+ drc["minwidth_poly"] \
|
+ (self.mults - 1) * (self.mults_poly_to_poly
|
||||||
+ (self.mults - 1) * (
|
+ drc["minwidth_poly"]))
|
||||||
self.mults_poly_to_poly + drc["minwidth_poly"])
|
|
||||||
self.active_height = max(drc["minarea_active"] / self.active_width,
|
self.active_height = max(drc["minarea_active"] / self.active_width,
|
||||||
self.gate_width)
|
self.gate_width)
|
||||||
self.poly_width = drc["minwidth_poly"] # horizontal
|
self.poly_width = drc["minwidth_poly"] # horizontal
|
||||||
self.poly_height = max(drc["minarea_poly"] / self.poly_width,
|
self.poly_height = max(drc["minarea_poly"] / self.poly_width,
|
||||||
self.gate_width \
|
self.gate_width
|
||||||
+ 2 * drc["poly_extend_active"]) # vertical
|
+ 2 * drc["poly_extend_active"]) # vertical
|
||||||
self.well_width = self.active_width \
|
self.well_width = (self.active_width
|
||||||
+ 2 * (drc["well_enclosure_active"])
|
+ 2 * (drc["well_enclosure_active"]))
|
||||||
self.well_height = max(self.gate_width + 2 * (drc["well_enclosure_active"]),
|
self.well_height = max(self.gate_width + 2 * (drc["well_enclosure_active"]),
|
||||||
drc["minwidth_well"])
|
drc["minwidth_well"])
|
||||||
|
|
||||||
def connect_fingered_poly(self):
|
def connect_fingered_poly(self):
|
||||||
poly_connect_length = self.poly_positions[-1][0] + self.poly_width \
|
poly_connect_length = self.poly_positions[-1].x + self.poly_width \
|
||||||
- self.poly_positions[0][0]
|
- self.poly_positions[0].x
|
||||||
poly_connect_position = [self.poly_positions[0][0],
|
poly_connect_position = self.poly_positions[0] - vector(0, self.poly_width)
|
||||||
self.poly_positions[0][1] - self.poly_width]
|
|
||||||
if len(self.poly_positions) > 1:
|
if len(self.poly_positions) > 1:
|
||||||
self.add_rect(layer="poly",
|
self.add_rect(layer="poly",
|
||||||
offset=poly_connect_position,
|
offset=poly_connect_position,
|
||||||
|
|
@ -127,8 +125,8 @@ class ptx(design.design):
|
||||||
drc["minwidth_metal1"] + drc["minwidth_contact"]),
|
drc["minwidth_metal1"] + drc["minwidth_contact"]),
|
||||||
0.5 * (self.active_contact.height - drc["minwidth_contact"])
|
0.5 * (self.active_contact.height - drc["minwidth_contact"])
|
||||||
- drc["metal1_extend_contact"])
|
- drc["metal1_extend_contact"])
|
||||||
connected=vector(b[0] + drc["minwidth_metal1"],
|
connected=vector(b.x + drc["minwidth_metal1"],
|
||||||
a[1] + self.active_contact.height + drc["metal1_to_metal1"])
|
a.y + self.active_contact.height + drc["metal1_to_metal1"])
|
||||||
self.source_positions.append(a + correct)
|
self.source_positions.append(a + correct)
|
||||||
self.source_positions.append(vector(a.x + correct.x, connected.y))
|
self.source_positions.append(vector(a.x + correct.x, connected.y))
|
||||||
self.source_positions.append(vector(b.x + correct.x,
|
self.source_positions.append(vector(b.x + correct.x,
|
||||||
|
|
@ -144,10 +142,10 @@ class ptx(design.design):
|
||||||
+ drc["minwidth_contact"]),
|
+ drc["minwidth_contact"]),
|
||||||
0.5*(self.active_contact.height - drc["minwidth_contact"])
|
0.5*(self.active_contact.height - drc["minwidth_contact"])
|
||||||
- drc["metal1_extend_contact"])
|
- drc["metal1_extend_contact"])
|
||||||
connected = vector(d[0] + drc["minwidth_metal1"], c[1] - drc["metal1_to_metal1"])
|
connected = vector(d.x + drc["minwidth_metal1"], c.y - drc["metal1_to_metal1"])
|
||||||
self.drain_positions.append(vector(c + correct))
|
self.drain_positions.append(vector(c + correct))
|
||||||
self.drain_positions.append(vector(c[0] + correct.x, connected.y))
|
self.drain_positions.append(vector(c.x + correct.x, connected.y))
|
||||||
self.drain_positions.append(vector(d[0] + correct.x,
|
self.drain_positions.append(vector(d.x + correct.x,
|
||||||
connected.y - 0.5 * drc["minwidth_metal1"]))
|
connected.y - 0.5 * drc["minwidth_metal1"]))
|
||||||
self.drain_positions.append(vector(d + correct))
|
self.drain_positions.append(vector(d + correct))
|
||||||
|
|
||||||
|
|
@ -165,7 +163,7 @@ class ptx(design.design):
|
||||||
|
|
||||||
def add_poly(self):
|
def add_poly(self):
|
||||||
# left_most poly
|
# left_most poly
|
||||||
poly_xoffset = self.active_contact.via_layer_position[0] \
|
poly_xoffset = self.active_contact.via_layer_position.x \
|
||||||
+ drc["minwidth_contact"] + drc["contact_to_poly"]
|
+ drc["minwidth_contact"] + drc["contact_to_poly"]
|
||||||
poly_yoffset = -drc["poly_extend_active"]
|
poly_yoffset = -drc["poly_extend_active"]
|
||||||
self.poly_positions = []
|
self.poly_positions = []
|
||||||
|
|
@ -255,10 +253,10 @@ class ptx(design.design):
|
||||||
|
|
||||||
# middle contact columns
|
# middle contact columns
|
||||||
for i in range(self.mults - 1):
|
for i in range(self.mults - 1):
|
||||||
contact_xoffset = self.poly_positions[i][0] + self.poly_width \
|
contact_xoffset = self.poly_positions[i].x + self.poly_width \
|
||||||
+ (self.mults_poly_to_poly / 2) \
|
+ (self.mults_poly_to_poly / 2) \
|
||||||
- (drc["minwidth_contact"] / 2) - \
|
- (drc["minwidth_contact"] / 2) - \
|
||||||
self.active_contact.via_layer_position[0]
|
self.active_contact.via_layer_position.x
|
||||||
offset = vector(contact_xoffset, contact_yoffset)
|
offset = vector(contact_xoffset, contact_yoffset)
|
||||||
self.add_contact(layers=("active", "contact", "metal1"),
|
self.add_contact(layers=("active", "contact", "metal1"),
|
||||||
offset=offset,
|
offset=offset,
|
||||||
|
|
@ -267,9 +265,9 @@ class ptx(design.design):
|
||||||
self.active_contact_positions.append(offset)
|
self.active_contact_positions.append(offset)
|
||||||
|
|
||||||
# right_most contact column
|
# right_most contact column
|
||||||
contact_xoffset = self.poly_positions[-1][0] \
|
contact_xoffset = self.poly_positions[-1].x \
|
||||||
+ self.poly_width + drc["contact_to_poly"] - \
|
+ self.poly_width + drc["contact_to_poly"] - \
|
||||||
self.active_contact.via_layer_position[0]
|
self.active_contact.via_layer_position.x
|
||||||
offset = vector(contact_xoffset, contact_yoffset)
|
offset = vector(contact_xoffset, contact_yoffset)
|
||||||
self.add_contact(layers=("active", "contact", "metal1"),
|
self.add_contact(layers=("active", "contact", "metal1"),
|
||||||
offset=offset,
|
offset=offset,
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,8 @@ class replica_bitline(design.design):
|
||||||
self.inv.height * 0.5)
|
self.inv.height * 0.5)
|
||||||
self.replica_bitline_offset = vector(self.delay_chain_offset.x
|
self.replica_bitline_offset = vector(self.delay_chain_offset.x
|
||||||
+ bitcell_array_spacing,
|
+ bitcell_array_spacing,
|
||||||
self.bitcell_chars["height"] + gnd_route_margin)
|
self.bitcell_chars["height"]
|
||||||
|
+ gnd_route_margin)
|
||||||
self.delay_inv_offset = vector(self.delay_chain_offset.x - self.inv.width,
|
self.delay_inv_offset = vector(self.delay_chain_offset.x - self.inv.width,
|
||||||
self.inv.height * 2)
|
self.inv.height * 2)
|
||||||
|
|
||||||
|
|
@ -184,59 +185,44 @@ class replica_bitline(design.design):
|
||||||
|
|
||||||
BL_inv_in = self.BL_inv_offset + self.inv.A_position + correct
|
BL_inv_in = self.BL_inv_offset + self.inv.A_position + correct
|
||||||
BL_offset = self.replica_bitline_offset + vector(1,0).scale(self.bitcell_chars["BL"])
|
BL_offset = self.replica_bitline_offset + vector(1,0).scale(self.bitcell_chars["BL"])
|
||||||
pin_offset = self.delay_chain.clk_out_offset.rotate().scale(-1,1)
|
pin_offset = self.delay_chain.clk_out_offset.rotate_scale(-1,1)
|
||||||
delay_chain_output = self.delay_chain_offset + pin_offset
|
delay_chain_output = self.delay_chain_offset + pin_offset
|
||||||
|
vdd_offset = vector(self.delay_chain_offset.x + 9 * drc["minwidth_metal2"],
|
||||||
|
self.height)
|
||||||
self.create_input()
|
self.create_input()
|
||||||
|
|
||||||
self.route_BL_t_BL_inv(BL_offset, BL_inv_in)
|
self.route_BL_t_BL_inv(BL_offset, BL_inv_in)
|
||||||
self.route_access_tx(delay_chain_output, BL_inv_in)
|
self.route_access_tx(delay_chain_output, BL_inv_in, vdd_offset)
|
||||||
self.route_vdd()
|
self.route_vdd()
|
||||||
self.route_gnd()
|
self.route_gnd()
|
||||||
# route loads after gnd and vdd created
|
# route loads after gnd and vdd created
|
||||||
self.route_loads()
|
self.route_loads(vdd_offset)
|
||||||
self.route_RC()
|
self.route_RC(vdd_offset)
|
||||||
|
|
||||||
def create_input(self):
|
def create_input(self):
|
||||||
# create routing module based on module offset
|
# create routing module based on module offset
|
||||||
correct = vector(0.5 * drc["minwidth_metal1"], 0)
|
correct = vector(0.5 * drc["minwidth_metal1"], 0)
|
||||||
pin_offset = self.delay_chain.clk_in_offset.rotate().scale(-1,1)
|
pin_offset = self.delay_chain.clk_in_offset.rotate_scale(-1,1)
|
||||||
input_offset = self.delay_chain_offset + pin_offset + correct
|
input_offset = self.delay_chain_offset + pin_offset + correct
|
||||||
mid1 = [input_offset[0], self.en_input_offset[1]]
|
mid1 = [input_offset.x, self.en_input_offset.y]
|
||||||
self.add_path("metal1", [self.en_input_offset, mid1, input_offset])
|
self.add_path("metal1", [self.en_input_offset, mid1, input_offset])
|
||||||
|
|
||||||
self.add_label(text="en",
|
self.add_label(text="en",
|
||||||
layer="metal1",
|
layer="metal1",
|
||||||
offset=self.en_input_offset)
|
offset=self.en_input_offset)
|
||||||
|
|
||||||
def route_nor2A_t_dc(self, nor_A, delayed_en_offset):
|
|
||||||
# delay chain output to m2
|
|
||||||
dc_offset = [delayed_en_offset[0], delayed_en_offset[1]]
|
|
||||||
mid1 = [dc_offset[0], self.en_nor_offset
|
|
||||||
[1] + 3 * drc["minwidth_metal2"]]
|
|
||||||
mid2 = [self.delay_chain_offset[0] + 3*drc["minwidth_metal2"],
|
|
||||||
dc_offset[1]]
|
|
||||||
mid3 = [mid2[0], nor_A[1]]
|
|
||||||
self.add_wire(("metal2", "via1", "metal1"),
|
|
||||||
[dc_offset, mid2, mid3, nor_A])
|
|
||||||
|
|
||||||
def route_nor2B_t_BL_inv(self, nor_B, BL_inv_out):
|
|
||||||
mid1 = [nor_B[0] + 0.5 * drc["metal2_to_metal2"], nor_B[1]]
|
|
||||||
self.add_wire(("metal2", "via1", "metal1"),
|
|
||||||
[nor_B, mid1, BL_inv_out])
|
|
||||||
|
|
||||||
def route_BL_t_BL_inv(self, BL_offset, BL_inv_in):
|
def route_BL_t_BL_inv(self, BL_offset, BL_inv_in):
|
||||||
# BL_inv input to M3
|
# BL_inv input to M3
|
||||||
mid1 = [BL_inv_in[0],
|
mid1 = BL_inv_in - vector(0,
|
||||||
BL_inv_in[1] - drc["metal2_to_metal2"] - self.m1m2_via.width]
|
drc["metal2_to_metal2"] + self.m1m2_via.width)
|
||||||
mid2 = [self.en_nor_offset[0] + 3*drc["metal1_to_metal1"],
|
mid2 = vector(self.en_nor_offset.x + 3 * drc["metal1_to_metal1"],
|
||||||
mid1[1]]
|
mid1.y)
|
||||||
mid3 = [mid2[0],
|
mid3 = vector(mid2.x,
|
||||||
self.replica_bitline_offset[1] - self.replica_bitcell.height
|
self.replica_bitline_offset.y - self.replica_bitcell.height
|
||||||
- 0.5 * (self.m1m2_via.height + drc["metal1_to_metal1"])
|
- 0.5 * (self.m1m2_via.height + drc["metal1_to_metal1"])
|
||||||
- 2 * drc["metal1_to_metal1"]]
|
- 2 * drc["metal1_to_metal1"])
|
||||||
self.add_wire(("metal1", "via1", "metal2"),
|
self.add_wire(layers=("metal2", "via1", "metal1"),
|
||||||
[BL_inv_in, mid1, mid2, mid3])
|
coordinates=[BL_inv_in, mid1, mid2, mid3])
|
||||||
|
|
||||||
# need to fix the mid point as this is done with two wire
|
# need to fix the mid point as this is done with two wire
|
||||||
# this seems to cover the metal1 error of the wire
|
# this seems to cover the metal1 error of the wire
|
||||||
|
|
@ -246,18 +232,18 @@ class replica_bitline(design.design):
|
||||||
width=drc["minwidth_metal1"],
|
width=drc["minwidth_metal1"],
|
||||||
height=drc["minwidth_metal1"])
|
height=drc["minwidth_metal1"])
|
||||||
|
|
||||||
mid4 = [BL_offset[0], mid3[1]]
|
mid4 = [BL_offset.x, mid3.y]
|
||||||
self.add_wire(("metal2", "via1", "metal1"),
|
self.add_wire(layers=("metal1", "via1", "metal2"),
|
||||||
[BL_offset, mid4, mid3])
|
coordinates=[BL_offset, mid4, mid3])
|
||||||
|
|
||||||
def route_access_tx(self, delay_chain_output, BL_inv_in):
|
def route_access_tx(self, delay_chain_output, BL_inv_in, vdd_offset):
|
||||||
self.route_tx_gate(delay_chain_output)
|
self.route_tx_gate(delay_chain_output)
|
||||||
self.route_tx_drain()
|
self.route_tx_drain(vdd_offset)
|
||||||
self.route_tx_source(BL_inv_in)
|
self.route_tx_source(BL_inv_in)
|
||||||
|
|
||||||
def route_tx_gate(self, delay_chain_output):
|
def route_tx_gate(self, delay_chain_output):
|
||||||
# gate input for access tx
|
# gate input for access tx
|
||||||
offset = (self.access_tx.poly_positions[0].rotate().scale(0,1)
|
offset = (self.access_tx.poly_positions[0].rotate_scale(0,1)
|
||||||
+ self.access_tx_offset)
|
+ self.access_tx_offset)
|
||||||
width = -6 * drc["minwidth_metal1"]
|
width = -6 * drc["minwidth_metal1"]
|
||||||
self.add_rect(layer="poly",
|
self.add_rect(layer="poly",
|
||||||
|
|
@ -276,35 +262,36 @@ class replica_bitline(design.design):
|
||||||
|
|
||||||
def route_access_tx_t_delay_chain(self, offset, delay_chain_output):
|
def route_access_tx_t_delay_chain(self, offset, delay_chain_output):
|
||||||
m2rail_space = (drc["minwidth_metal2"] + drc["metal2_to_metal2"])
|
m2rail_space = (drc["minwidth_metal2"] + drc["metal2_to_metal2"])
|
||||||
mid1 = [offset[0], self.delay_chain_offset[1] - 3 * m2rail_space]
|
mid1 = vector(offset.x, self.delay_chain_offset.y - 3 * m2rail_space)
|
||||||
mid2 = [delay_chain_output[0], mid1[1]]
|
mid2 = [delay_chain_output.x, mid1.y]
|
||||||
# Note the inverted wire stack
|
# Note the inverted wire stack
|
||||||
self.add_wire(("metal2", "via1", "metal1"),
|
self.add_wire(layers=("metal1", "via1", "metal2"),
|
||||||
[offset, mid1, mid2, delay_chain_output])
|
coordinates=[offset, mid1, mid2, delay_chain_output])
|
||||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||||
offset=delay_chain_output,
|
offset=delay_chain_output,
|
||||||
mirror="MX")
|
mirror="MX")
|
||||||
|
|
||||||
def route_access_tx_t_WL(self, offset):
|
def route_access_tx_t_WL(self, offset):
|
||||||
m1m2_via_offset = offset - vector(0.5 * self.m1m2_via.width,
|
m1m2_via_offset = offset - vector(0.5 * self.m1m2_via.width,
|
||||||
0.5 * self.m1m2_via.height)
|
0.5 * self.m1m2_via.height)
|
||||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||||
offset=m1m2_via_offset)
|
offset=m1m2_via_offset)
|
||||||
# route gate to RC WL
|
# route gate to RC WL
|
||||||
RC_WL = self.replica_bitline_offset - vector(0,1).scale(self.bitcell_chars["WL"])
|
RC_WL = self.replica_bitline_offset - vector(0,1).scale(self.bitcell_chars["WL"])
|
||||||
mid1 = [offset[0], 0]
|
mid1 = vector(offset.x, 0)
|
||||||
mid2 = [self.en_nor_offset[0] + 3 * drc["metal1_to_metal1"],
|
mid2 = vector(self.en_nor_offset.x + 3 * drc["metal1_to_metal1"],
|
||||||
mid1[1]]
|
mid1.y)
|
||||||
mid3 = [RC_WL[0] - drc["minwidth_metal1"] - self.m1m2_via.height,
|
mid3 = vector(RC_WL.x - drc["minwidth_metal1"] - self.m1m2_via.height,
|
||||||
mid1[1]]
|
mid1.y)
|
||||||
mid4 = [mid3[0], RC_WL[1]]
|
mid4 = vector(mid3.x, RC_WL.y)
|
||||||
self.add_path("metal2", [offset, mid1, mid2, mid3, mid4])
|
self.add_path("metal2", [offset, mid1, mid2, mid3, mid4])
|
||||||
|
|
||||||
offset = mid4 - vector([0.5 * drc["minwidth_metal1"]]*2)
|
offset = mid4 - vector([0.5 * drc["minwidth_metal1"]] * 2)
|
||||||
width = RC_WL[0] - offset[0]
|
width = RC_WL.x - offset.x
|
||||||
# enter the bit line array with metal1
|
# enter the bit line array with metal1
|
||||||
via_offset = [mid4[0] - 0.5 * self.m1m2_via.width,
|
via_offset = [mid4.x - 0.5 * self.m1m2_via.width,
|
||||||
offset[1] - 0.5 * (self.m1m2_via.height
|
offset.y
|
||||||
|
- 0.5 * (self.m1m2_via.height
|
||||||
- drc["minwidth_metal1"])]
|
- drc["minwidth_metal1"])]
|
||||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||||
offset=via_offset)
|
offset=via_offset)
|
||||||
|
|
@ -313,26 +300,24 @@ class replica_bitline(design.design):
|
||||||
width=width,
|
width=width,
|
||||||
height=drc["minwidth_metal1"])
|
height=drc["minwidth_metal1"])
|
||||||
|
|
||||||
def route_tx_drain(self):
|
def route_tx_drain(self,vdd_offset):
|
||||||
# route drain to Vdd
|
# route drain to Vdd
|
||||||
active_offset = self.access_tx.active_contact_positions[1].rotate().scale(-1,1)
|
active_offset = self.access_tx.active_contact_positions[1].rotate_scale(-1,1)
|
||||||
correct = vector(drc["minwidth_metal1"],
|
correct = vector(-0.5 * drc["minwidth_metal1"],
|
||||||
self.access_tx.active_contact.width).scale(-0.5, 0.5)
|
0.5 * self.access_tx.active_contact.width)
|
||||||
drain_offset = self.access_tx_offset + active_offset + correct
|
drain_offset = self.access_tx_offset + active_offset + correct
|
||||||
vdd_rail = [self.delay_chain_offset[0] + 9 * drc["minwidth_metal2"],
|
|
||||||
self.height]
|
|
||||||
close_Vdd_offset = self.BL_inv_offset + vector(0, self.inv.height)
|
close_Vdd_offset = self.BL_inv_offset + vector(0, self.inv.height)
|
||||||
self.add_path("metal1", [drain_offset, close_Vdd_offset])
|
self.add_path("metal1", [drain_offset, close_Vdd_offset])
|
||||||
|
|
||||||
mid = [vdd_rail[0], close_Vdd_offset[1]]
|
mid = [vdd_offset.x, close_Vdd_offset.y]
|
||||||
self.add_wire(("metal2", "via1", "metal1"),
|
self.add_wire(layers=("metal1", "via1", "metal2"),
|
||||||
[close_Vdd_offset, mid, vdd_rail])
|
coordinates=[close_Vdd_offset, mid, vdd_offset])
|
||||||
|
|
||||||
def route_tx_source(self, BL_inv_in):
|
def route_tx_source(self, BL_inv_in):
|
||||||
# route source to BL inv input which is connected to BL
|
# route source to BL inv input which is connected to BL
|
||||||
active_offset = self.access_tx.active_contact_positions[0].rotate().scale(-1,1)
|
active_offset = self.access_tx.active_contact_positions[0].rotate_scale(-1,1)
|
||||||
correct = vector(drc["minwidth_metal1"],
|
correct = vector(-0.5 * drc["minwidth_metal1"],
|
||||||
self.access_tx.active_contact.width).scale(-0.5, 0.5)
|
0.5 * self.access_tx.active_contact.width)
|
||||||
source_offset = self.access_tx_offset + active_offset + correct
|
source_offset = self.access_tx_offset + active_offset + correct
|
||||||
self.add_path("metal1", [source_offset, BL_inv_in])
|
self.add_path("metal1", [source_offset, BL_inv_in])
|
||||||
|
|
||||||
|
|
@ -347,11 +332,13 @@ class replica_bitline(design.design):
|
||||||
start = self.delay_chain_offset - vector(0.5 * self.delay_chain.height, 0)
|
start = self.delay_chain_offset - vector(0.5 * self.delay_chain.height, 0)
|
||||||
m1rail_space = (drc["minwidth_metal1"] + drc["metal1_to_metal1"])
|
m1rail_space = (drc["minwidth_metal1"] + drc["metal1_to_metal1"])
|
||||||
mid1 = start - vector(0, m1rail_space)
|
mid1 = start - vector(0, m1rail_space)
|
||||||
mid2 = [self.delay_chain_offset[0] + 9 * drc["minwidth_metal2"],
|
mid2 = vector(self.delay_chain_offset.x + 9 * drc["minwidth_metal2"],
|
||||||
mid1[1]]
|
mid1.y)
|
||||||
end = [mid2[0], vdd_offset[1]]
|
end = [mid2.x, vdd_offset.y]
|
||||||
self.add_path(("metal1"), [start, mid1, mid2])
|
self.add_path(layer=("metal1"),
|
||||||
self.add_wire(("metal2", "via1", "metal1"), [mid1, mid2, end])
|
coordinates=[start, mid1, mid2])
|
||||||
|
self.add_wire(layers=("metal1", "via1", "metal2"),
|
||||||
|
coordinates=[mid1, mid2, end])
|
||||||
|
|
||||||
def route_gnd(self):
|
def route_gnd(self):
|
||||||
"""route gnd of delay chain, en_nor, en_inv and BL_inv"""
|
"""route gnd of delay chain, en_nor, en_inv and BL_inv"""
|
||||||
|
|
@ -366,8 +353,9 @@ class replica_bitline(design.design):
|
||||||
mid2 = vector(mid1.x, y_off)
|
mid2 = vector(mid1.x, y_off)
|
||||||
share_gnd = vector(self.gnd_position.x, mid2.y)
|
share_gnd = vector(self.gnd_position.x, mid2.y)
|
||||||
# Note the inverted stacks
|
# Note the inverted stacks
|
||||||
self.add_wire(("metal2", "via1", "metal1"),
|
lst = [BL_gnd_offset, mid1, mid2, share_gnd, self.gnd_position]
|
||||||
[BL_gnd_offset, mid1, mid2, share_gnd, self.gnd_position])
|
self.add_wire(layers=("metal1", "via1", "metal2"),
|
||||||
|
coordinates=lst)
|
||||||
self.add_label(text="gnd",
|
self.add_label(text="gnd",
|
||||||
layer="metal1",
|
layer="metal1",
|
||||||
offset=self.gnd_position)
|
offset=self.gnd_position)
|
||||||
|
|
@ -377,51 +365,51 @@ class replica_bitline(design.design):
|
||||||
offset=offset,
|
offset=offset,
|
||||||
width=drc["minwidth_metal1"],
|
width=drc["minwidth_metal1"],
|
||||||
height=-self.delay_chain.width)
|
height=-self.delay_chain.width)
|
||||||
offset = [offset[0] + self.delay_chain.height,
|
offset = [offset.x + self.delay_chain.height,
|
||||||
mid2[1]]
|
mid2.y]
|
||||||
self.add_rect(layer="metal1",
|
self.add_rect(layer="metal1",
|
||||||
offset=offset,
|
offset=offset,
|
||||||
width=drc["minwidth_metal1"],
|
width=drc["minwidth_metal1"],
|
||||||
height=-self.delay_chain.width)
|
height=-self.delay_chain.width)
|
||||||
|
|
||||||
def route_loads(self):
|
def route_loads(self,vdd_offset):
|
||||||
"""connect all the loads word line to gnd"""
|
"""connect all the loads word line to gnd"""
|
||||||
vdd_offset = [self.delay_chain_offset[0] + 9*drc["minwidth_metal2"],
|
|
||||||
self.height]
|
|
||||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||||
offset=vdd_offset,
|
offset=vdd_offset,
|
||||||
mirror="MX")
|
mirror="MX")
|
||||||
gnd_offset = (self.delay_chain_offset
|
gnd_offset = (self.delay_chain_offset
|
||||||
+ vector([drc["minwidth_metal1"]]*2).scale(-.5,.5))
|
+ vector([drc["minwidth_metal1"]] * 2).scale(-.5,.5))
|
||||||
for i in range(self.rows):
|
for i in range(self.rows):
|
||||||
WL_offset = (self.replica_bitline_offset
|
WL_offset = (self.replica_bitline_offset
|
||||||
+ self.bitline_load.WL_positions[i].scale(0,1))
|
+ self.bitline_load.WL_positions[i].scale(0,1))
|
||||||
mid = [self.delay_chain_offset[0] + 6 * drc["minwidth_metal2"],
|
mid = [self.delay_chain_offset.x + 6 * drc["minwidth_metal2"],
|
||||||
gnd_offset[1]]
|
gnd_offset.y]
|
||||||
self.add_wire(("metal2", "via1", "metal1"), [gnd_offset, mid, WL_offset])
|
self.add_wire(layers=("metal1", "via1", "metal2"),
|
||||||
|
coordinates=[gnd_offset, mid, WL_offset])
|
||||||
if i % 2 == 0:
|
if i % 2 == 0:
|
||||||
load_vdd_offset = (self.replica_bitline_offset
|
load_vdd_offset = (self.replica_bitline_offset
|
||||||
+ self.bitline_load.vdd_positions[i])
|
+ self.bitline_load.vdd_positions[i])
|
||||||
mid = [vdd_offset[0], load_vdd_offset[1]]
|
mid = [vdd_offset.x, load_vdd_offset.y]
|
||||||
self.add_wire(("metal2", "via1", "metal1"), [vdd_offset, mid, load_vdd_offset])
|
self.add_wire(layers=("metal1", "via1", "metal2"),
|
||||||
|
coordinates=[vdd_offset, mid, load_vdd_offset])
|
||||||
|
|
||||||
def route_RC(self):
|
def route_RC(self,vdd_offset):
|
||||||
"""route vdd gnd to the replica cell """
|
"""route vdd gnd to the replica cell """
|
||||||
# connect vdd
|
# connect vdd
|
||||||
RC_vdd = self.replica_bitline_offset + vector(1,-1).scale(self.bitcell_chars["vdd"])
|
RC_vdd = self.replica_bitline_offset + vector(1,-1).scale(self.bitcell_chars["vdd"])
|
||||||
vdd_offset = [self.delay_chain_offset[0] + 9 * drc["minwidth_metal2"],
|
mid = [vdd_offset.x, RC_vdd.y]
|
||||||
self.height]
|
|
||||||
mid = [vdd_offset[0], RC_vdd[1]]
|
|
||||||
# Note the inverted stacks
|
# Note the inverted stacks
|
||||||
self.add_wire(("metal2", "via1", "metal1"), [vdd_offset, mid, RC_vdd])
|
self.add_wire(layers=("metal1", "via1", "metal2"),
|
||||||
|
coordinates=[vdd_offset, mid, RC_vdd])
|
||||||
|
|
||||||
gnd_offset = self.BL_inv_offset - vector(self.inv.width, 0)
|
gnd_offset = self.BL_inv_offset - vector(self.inv.width, 0)
|
||||||
load_gnd = (self.replica_bitline_offset
|
load_gnd = self.replica_bitline_offset + vector(self.bitcell_chars["gnd"][0],
|
||||||
+ vector(self.bitcell_chars["gnd"][0], self.bitline_load.height))
|
self.bitline_load.height)
|
||||||
mid = [load_gnd[0], gnd_offset[1]]
|
mid = [load_gnd.x, gnd_offset.y]
|
||||||
self.add_wire(("metal2", "via1", "metal1"), [gnd_offset, mid, load_gnd])
|
self.add_wire(layers=("metal1", "via1", "metal2"),
|
||||||
|
coordinates=[gnd_offset, mid, load_gnd])
|
||||||
|
|
||||||
load_gnd = (self.replica_bitline_offset
|
load_gnd = self.replica_bitline_offset + vector(0,
|
||||||
+ vector(0, self.bitline_load.height))
|
self.bitline_load.height)
|
||||||
mid = [load_gnd[0], gnd_offset[1]]
|
mid = [load_gnd.x, gnd_offset.y]
|
||||||
self.add_wire(("metal2", "via1", "metal1"), [gnd_offset, mid, load_gnd])
|
self.add_wire(("metal1", "via1", "metal2"), [gnd_offset, mid, load_gnd])
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ class single_level_column_mux(design.design):
|
||||||
self.poly_offset = (self.nmos1_position
|
self.poly_offset = (self.nmos1_position
|
||||||
+ self.nmos1.poly_positions[0]
|
+ self.nmos1.poly_positions[0]
|
||||||
+ vector(0,self.nmos1.poly_height))
|
+ vector(0,self.nmos1.poly_height))
|
||||||
width=self.nmos2_position[0] - self.nmos1_position[0] + drc["minwidth_poly"]
|
width=self.nmos2_position.x- self.nmos1_position.x+ drc["minwidth_poly"]
|
||||||
self.poly = self.add_rect(layer="poly",
|
self.poly = self.add_rect(layer="poly",
|
||||||
offset=self.poly_offset,
|
offset=self.poly_offset,
|
||||||
width=width,
|
width=width,
|
||||||
|
|
@ -91,7 +91,7 @@ class single_level_column_mux(design.design):
|
||||||
def connect_to_bitlines(self):
|
def connect_to_bitlines(self):
|
||||||
offset = [self.nmos1.active_contact_positions[0].x + self.m1m2_via.contact_width / 2
|
offset = [self.nmos1.active_contact_positions[0].x + self.m1m2_via.contact_width / 2
|
||||||
+ 3 * (self.m1m2_via.second_layer_width - self.m1m2_via.first_layer_width) / 2,
|
+ 3 * (self.m1m2_via.second_layer_width - self.m1m2_via.first_layer_width) / 2,
|
||||||
self.nmos1.active_position[1] + self.nmos1.active_height]
|
self.nmos1.active_position.y+ self.nmos1.active_height]
|
||||||
offset = self.nmos1_position + offset
|
offset = self.nmos1_position + offset
|
||||||
connection = vector(0,
|
connection = vector(0,
|
||||||
self.nmos2.active_height+ 2 * drc["poly_extend_active"] \
|
self.nmos2.active_height+ 2 * drc["poly_extend_active"] \
|
||||||
|
|
@ -101,7 +101,7 @@ class single_level_column_mux(design.design):
|
||||||
width=drc["minwidth_metal2"],
|
width=drc["minwidth_metal2"],
|
||||||
height=connection.y - drc["minwidth_metal2"])
|
height=connection.y - drc["minwidth_metal2"])
|
||||||
|
|
||||||
self.BL_position = (vector(self.bitcell_chars["BL"][0] - 0.5 * self.m1m2_via.width,
|
self.BL_position = (vector(self.bitcell_chars["BL"][0]- 0.5 * self.m1m2_via.width,
|
||||||
offset.y)
|
offset.y)
|
||||||
+ connection)
|
+ connection)
|
||||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||||
|
|
@ -116,10 +116,10 @@ class single_level_column_mux(design.design):
|
||||||
width=drc["minwidth_metal2"],
|
width=drc["minwidth_metal2"],
|
||||||
height=2 * drc["minwidth_metal2"])
|
height=2 * drc["minwidth_metal2"])
|
||||||
|
|
||||||
width = self.bitcell_chars["BL"][0] - 0.5 * self.m1m2_via.width - offset[0] + drc["minwidth_metal2"]
|
width = self.bitcell_chars["BL"][0]- 0.5 * self.m1m2_via.width - offset.x+ drc["minwidth_metal2"]
|
||||||
self.add_rect(layer="metal2",
|
self.add_rect(layer="metal2",
|
||||||
offset=[offset[0],
|
offset=[offset[0],
|
||||||
self.BL_position[1] - 2*drc["minwidth_metal2"]],
|
self.BL_position.y- 2*drc["minwidth_metal2"]],
|
||||||
width=width,
|
width=width,
|
||||||
height=drc["minwidth_metal2"])
|
height=drc["minwidth_metal2"])
|
||||||
|
|
||||||
|
|
@ -127,24 +127,24 @@ class single_level_column_mux(design.design):
|
||||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||||
offset=offset)
|
offset=offset)
|
||||||
self.add_rect(layer="metal2",
|
self.add_rect(layer="metal2",
|
||||||
offset=[self.bitcell_chars["BL"][0] - 0.5 * self.m1m2_via.width,
|
offset=[self.bitcell_chars["BL"][0]- 0.5 * self.m1m2_via.width,
|
||||||
0],
|
0],
|
||||||
width=drc["minwidth_metal2"],
|
width=drc["minwidth_metal2"],
|
||||||
height=(drc["minwidth_metal2"] + offset[1]))
|
height=(drc["minwidth_metal2"] + offset[1]))
|
||||||
self.add_rect(layer="metal2",
|
self.add_rect(layer="metal2",
|
||||||
offset=[self.bitcell_chars["BL"][0] - 0.5 * self.m1m2_via.width,
|
offset=[self.bitcell_chars["BL"][0]- 0.5 * self.m1m2_via.width,
|
||||||
offset[1]],
|
offset[1]],
|
||||||
width=(offset[0] - self.bitcell_chars["BL"][0] - 0.5 * self.m1m2_via.width
|
width=(offset.x- self.bitcell_chars["BL"][0]- 0.5 * self.m1m2_via.width
|
||||||
+ 2 * drc["minwidth_metal2"]),
|
+ 2 * drc["minwidth_metal2"]),
|
||||||
height=drc["minwidth_metal2"])
|
height=drc["minwidth_metal2"])
|
||||||
self.BL_out_position = vector(self.bitcell_chars["BL"][0] - 0.5* self.m1m2_via.width,
|
self.BL_out_position = vector(self.bitcell_chars["BL"][0]- 0.5* self.m1m2_via.width,
|
||||||
0)
|
0)
|
||||||
self.add_label(text="bl_out",
|
self.add_label(text="bl_out",
|
||||||
layer="metal2",
|
layer="metal2",
|
||||||
offset=self.BL_out_position)
|
offset=self.BL_out_position)
|
||||||
|
|
||||||
offset = [self.nmos2.active_contact_positions[1].x - self.m1m2_via.contact_width / 2,
|
offset = [self.nmos2.active_contact_positions[1].x - self.m1m2_via.contact_width / 2,
|
||||||
self.nmos2.active_position[1] + self.nmos2.active_height]
|
self.nmos2.active_position.y+ self.nmos2.active_height]
|
||||||
offset = self.nmos2_position + offset
|
offset = self.nmos2_position + offset
|
||||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||||
offset=offset,
|
offset=offset,
|
||||||
|
|
@ -152,21 +152,21 @@ class single_level_column_mux(design.design):
|
||||||
mid = offset + vector(drc["minwidth_metal2"],0)
|
mid = offset + vector(drc["minwidth_metal2"],0)
|
||||||
self.add_rect(layer="metal2",
|
self.add_rect(layer="metal2",
|
||||||
offset= mid,
|
offset= mid,
|
||||||
width= (self.bitcell_chars["BR"][0] - mid[0] + 0.5*self.m1m2_via.width),
|
width= (self.bitcell_chars["BR"][0]- mid.x+ 0.5*self.m1m2_via.width),
|
||||||
height=-drc["minwidth_metal2"])
|
height=-drc["minwidth_metal2"])
|
||||||
self.add_rect(layer="metal2",
|
self.add_rect(layer="metal2",
|
||||||
offset=[self.bitcell_chars["BR"][0] - 0.5*self.m1m2_via.width,
|
offset=[self.bitcell_chars["BR"][0]- 0.5*self.m1m2_via.width,
|
||||||
offset[1] - drc["metal1_to_metal1"]],
|
offset.y- drc["metal1_to_metal1"]],
|
||||||
width=drc["minwidth_metal2"],
|
width=drc["minwidth_metal2"],
|
||||||
height=2*drc["minwidth_metal2"])
|
height=2*drc["minwidth_metal2"])
|
||||||
self.BR_position = vector(self.bitcell_chars["BR"][0] - 0.5 * self.m1m2_via.width,
|
self.BR_position = vector(self.bitcell_chars["BR"][0]- 0.5 * self.m1m2_via.width,
|
||||||
self.BL_position.y)
|
self.BL_position.y)
|
||||||
self.add_label(text="br",
|
self.add_label(text="br",
|
||||||
layer="metal2",
|
layer="metal2",
|
||||||
offset=self.BR_position)
|
offset=self.BR_position)
|
||||||
|
|
||||||
offset = self.nmos2_position + self.nmos2.active_contact_positions[0]
|
offset = self.nmos2_position + self.nmos2.active_contact_positions[0]
|
||||||
self.BR_out_position = vector(self.bitcell_chars["BR"][0] - 0.5 * self.m1m2_via.width,
|
self.BR_out_position = vector(self.bitcell_chars["BR"][0]- 0.5 * self.m1m2_via.width,
|
||||||
0)
|
0)
|
||||||
self.add_label(text="br_out",
|
self.add_label(text="br_out",
|
||||||
layer="metal2",
|
layer="metal2",
|
||||||
|
|
@ -179,12 +179,12 @@ class single_level_column_mux(design.design):
|
||||||
height=drc["minwidth_metal2"])
|
height=drc["minwidth_metal2"])
|
||||||
self.add_rect(layer="metal2",
|
self.add_rect(layer="metal2",
|
||||||
offset=[self.BR_out_position.x,
|
offset=[self.BR_out_position.x,
|
||||||
offset[1] + drc["minwidth_metal2"]],
|
offset.y+ drc["minwidth_metal2"]],
|
||||||
width=drc["minwidth_metal2"],
|
width=drc["minwidth_metal2"],
|
||||||
height=-(offset[1] + drc["minwidth_metal2"]))
|
height=-(offset.y+ drc["minwidth_metal2"]))
|
||||||
|
|
||||||
def add_gnd_rail(self):
|
def add_gnd_rail(self):
|
||||||
self.gnd_position = vector(self.bitcell_chars["gnd"][0] - 0.5 * self.m1m2_via.width,
|
self.gnd_position = vector(self.bitcell_chars["gnd"][0]- 0.5 * self.m1m2_via.width,
|
||||||
0)
|
0)
|
||||||
self.add_layout_pin(text="gnd",
|
self.add_layout_pin(text="gnd",
|
||||||
layer="metal2",
|
layer="metal2",
|
||||||
|
|
@ -193,7 +193,7 @@ class single_level_column_mux(design.design):
|
||||||
height=self.BL_position[1])
|
height=self.BL_position[1])
|
||||||
|
|
||||||
def add_well_contacts(self):
|
def add_well_contacts(self):
|
||||||
offset = vector(self.gnd_position[0] + drc["minwidth_metal2"],
|
offset = vector(self.gnd_position.x+ drc["minwidth_metal2"],
|
||||||
self.nmos1.poly_height / 2)
|
self.nmos1.poly_height / 2)
|
||||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||||
offset=offset - vector(self.m1m2_via.width / 2, 0),
|
offset=offset - vector(self.m1m2_via.width / 2, 0),
|
||||||
|
|
@ -212,11 +212,11 @@ class single_level_column_mux(design.design):
|
||||||
offset_well = self.nmos1_position + vector(self.nmos1.width, 0)
|
offset_well = self.nmos1_position + vector(self.nmos1.width, 0)
|
||||||
self.add_rect(layer="pwell",
|
self.add_rect(layer="pwell",
|
||||||
offset=offset_well,
|
offset=offset_well,
|
||||||
width=self.gnd_position[0] + drc["minwidth_metal2"] - offset_well[0],
|
width=self.gnd_position.x+ drc["minwidth_metal2"] - offset_well[0],
|
||||||
height=self.nmos1.height + drc["minwidth_poly"])
|
height=self.nmos1.height + drc["minwidth_poly"])
|
||||||
self.add_rect(layer="vtg",
|
self.add_rect(layer="vtg",
|
||||||
offset=offset_well,
|
offset=offset_well,
|
||||||
width=self.gnd_position[0] + drc["minwidth_metal2"] - offset_well[0],
|
width=self.gnd_position.x+ drc["minwidth_metal2"] - offset_well[0],
|
||||||
height=self.nmos1.height + drc["minwidth_poly"])
|
height=self.nmos1.height + drc["minwidth_poly"])
|
||||||
|
|
||||||
def setup_layout_constants(self):
|
def setup_layout_constants(self):
|
||||||
|
|
|
||||||
|
|
@ -380,14 +380,14 @@ class sram(design.design):
|
||||||
|
|
||||||
self.width = self.bank.width + self.control.height + 2*drc["minwidth_metal3"]
|
self.width = self.bank.width + self.control.height + 2*drc["minwidth_metal3"]
|
||||||
self.height = self.bank.height
|
self.height = self.bank.height
|
||||||
self.control.CSb_position.rotate().scale(-1,1)
|
self.control.CSb_position.rotate_scale(-1,1)
|
||||||
self.CSb_position = (self.control.CSb_position.rotate().scale(-1,1)
|
self.CSb_position = (self.control.CSb_position.rotate_scale(-1,1)
|
||||||
+self.control_position)
|
+self.control_position)
|
||||||
self.OEb_position = (self.control.OEb_position.rotate().scale(-1,1)
|
self.OEb_position = (self.control.OEb_position.rotate_scale(-1,1)
|
||||||
+self.control_position)
|
+self.control_position)
|
||||||
self.WEb_position = (self.control.WEb_position.rotate().scale(-1,1)
|
self.WEb_position = (self.control.WEb_position.rotate_scale(-1,1)
|
||||||
+self.control_position)
|
+self.control_position)
|
||||||
self.clk_position = (self.control.clk_position.rotate().scale(-1,1)
|
self.clk_position = (self.control.clk_position.rotate_scale(-1,1)
|
||||||
+self.control_position)
|
+self.control_position)
|
||||||
for i in range(0, self.word_size):
|
for i in range(0, self.word_size):
|
||||||
self.add_label(text="DATA[{0}]".format(i),
|
self.add_label(text="DATA[{0}]".format(i),
|
||||||
|
|
@ -612,7 +612,7 @@ class sram(design.design):
|
||||||
bank_attr = self.sram_property[attr_index]
|
bank_attr = self.sram_property[attr_index]
|
||||||
self.add_rect(layer="metal3",
|
self.add_rect(layer="metal3",
|
||||||
offset=getattr(self,bank_attr)[left_bank_index],
|
offset=getattr(self,bank_attr)[left_bank_index],
|
||||||
width=getattr(self,bank_attr)[right_bank_index].x - getattr(self,bank_attr)[left_bank_index][0],
|
width=getattr(self,bank_attr)[right_bank_index].x - getattr(self,bank_attr)[left_bank_index].x,
|
||||||
height=drc["minwidth_metal3"])
|
height=drc["minwidth_metal3"])
|
||||||
self.add_via(layers=("metal2", "via2", "metal3"),
|
self.add_via(layers=("metal2", "via2", "metal3"),
|
||||||
offset=[self.vertical_line_positions[attr_index].x,
|
offset=[self.vertical_line_positions[attr_index].x,
|
||||||
|
|
@ -710,17 +710,17 @@ class sram(design.design):
|
||||||
# 0 = s_en
|
# 0 = s_en
|
||||||
|
|
||||||
control_side = []
|
control_side = []
|
||||||
control_side.append(self.control.clk_position.rotate().scale(-1, 1)
|
control_side.append(self.control.clk_position.rotate_scale(-1, 1)
|
||||||
+ self.control_position)
|
+ self.control_position)
|
||||||
control_side.append(self.control.clk_bar_position.rotate().scale(-1, 1)
|
control_side.append(self.control.clk_bar_position.rotate_scale(-1, 1)
|
||||||
+ self.control_position)
|
+ self.control_position)
|
||||||
control_side.append(self.control.tri_en_position.rotate().scale(-1, 1)
|
control_side.append(self.control.tri_en_position.rotate_scale(-1, 1)
|
||||||
+ self.control_position)
|
+ self.control_position)
|
||||||
control_side.append(self.control.tri_en_bar_position.rotate().scale(-1, 1)
|
control_side.append(self.control.tri_en_bar_position.rotate_scale(-1, 1)
|
||||||
+ self.control_position)
|
+ self.control_position)
|
||||||
control_side.append(self.control.w_en_position.rotate().scale(-1, 1)
|
control_side.append(self.control.w_en_position.rotate_scale(-1, 1)
|
||||||
+ self.control_position)
|
+ self.control_position)
|
||||||
control_side.append(self.control.s_en_position.rotate().scale(-1, 1)
|
control_side.append(self.control.s_en_position.rotate_scale(-1, 1)
|
||||||
+ self.control_position)
|
+ self.control_position)
|
||||||
|
|
||||||
bank_side = []
|
bank_side = []
|
||||||
|
|
@ -763,14 +763,14 @@ class sram(design.design):
|
||||||
msb_line = self.control_size + self.num_banks/2 - 1 - i
|
msb_line = self.control_size + self.num_banks/2 - 1 - i
|
||||||
bank_select_start_line = msb_line + 2 + self.bank_addr_size
|
bank_select_start_line = msb_line + 2 + self.bank_addr_size
|
||||||
|
|
||||||
msf_msb_din = (self.msf_msb_address.din_positions[i].rotate().scale(1, -1)
|
msf_msb_din = (self.msf_msb_address.din_positions[i].rotate_scale(1, -1)
|
||||||
+ self.msf_msb_address_position)
|
+ self.msf_msb_address_position)
|
||||||
|
|
||||||
contact_pos = [self.vertical_line_positions[msb_line].x,
|
contact_pos = vector(self.vertical_line_positions[msb_line].x,
|
||||||
msf_msb_din.y - 0.5*self.m2m3_via.width]
|
msf_msb_din.y - 0.5*self.m2m3_via.width)
|
||||||
self.add_rect(layer="metal3",
|
self.add_rect(layer="metal3",
|
||||||
offset=contact_pos,
|
offset=contact_pos,
|
||||||
width=msf_msb_din[0] - contact_pos[0],
|
width=msf_msb_din.x - contact_pos.x,
|
||||||
height=drc["minwidth_metal3"])
|
height=drc["minwidth_metal3"])
|
||||||
self.add_via(layers=("metal2", "via2", "metal3"),
|
self.add_via(layers=("metal2", "via2", "metal3"),
|
||||||
offset=contact_pos)
|
offset=contact_pos)
|
||||||
|
|
@ -785,9 +785,9 @@ class sram(design.design):
|
||||||
height=drc["minwidth_metal1"])
|
height=drc["minwidth_metal1"])
|
||||||
|
|
||||||
if(self.num_banks == 2):
|
if(self.num_banks == 2):
|
||||||
msb_msf_dout_position = (self.msf_msb_address.dout_positions[i].rotate().scale(1, -1)
|
msb_msf_dout_position = (self.msf_msb_address.dout_positions[i].rotate_scale(1, -1)
|
||||||
+ self.msf_msb_address_position)
|
+ self.msf_msb_address_position)
|
||||||
msb_msf_dout_bar_position = (self.msf_msb_address.dout_bar_positions[i].rotate().scale(1, -1)
|
msb_msf_dout_bar_position = (self.msf_msb_address.dout_bar_positions[i].rotate_scale(1, -1)
|
||||||
+ self.msf_msb_address_position)
|
+ self.msf_msb_address_position)
|
||||||
starts = [msb_msf_dout_bar_position,
|
starts = [msb_msf_dout_bar_position,
|
||||||
msb_msf_dout_position]
|
msb_msf_dout_position]
|
||||||
|
|
@ -801,9 +801,9 @@ class sram(design.design):
|
||||||
+ self.msf_msb_address.height
|
+ self.msf_msb_address.height
|
||||||
+ 4 * (i + 1) * drc["minwidth_metal2"],
|
+ 4 * (i + 1) * drc["minwidth_metal2"],
|
||||||
start.y)
|
start.y)
|
||||||
end = vector(mid1.x, self.msf_msb_address_position[1]
|
end = vector(mid1.x, self.msf_msb_address_position.y
|
||||||
+ 4 * (i + 1) * drc["minwidth_metal2"])
|
+ 4 * (i + 1) * drc["minwidth_metal2"])
|
||||||
self.add_wire(("metal1", "via1", "metal2"), [start, mid1, end])
|
self.add_wire(("metal2", "via1", "metal1"), [start, mid1, end])
|
||||||
|
|
||||||
x_off = self.vertical_line_positions[bank_select_line].x
|
x_off = self.vertical_line_positions[bank_select_line].x
|
||||||
contact_pos = vector(x_off,
|
contact_pos = vector(x_off,
|
||||||
|
|
@ -818,7 +818,7 @@ class sram(design.design):
|
||||||
|
|
||||||
if(self.num_banks == 4):
|
if(self.num_banks == 4):
|
||||||
for i in range(2):
|
for i in range(2):
|
||||||
msb_msf_out_position = (self.msf_msb_address.dout_positions[i].rotate().scale(1, -1)
|
msb_msf_out_position = (self.msf_msb_address.dout_positions[i].rotate_scale(1, -1)
|
||||||
+ self.msf_msb_address_position)
|
+ self.msf_msb_address_position)
|
||||||
msb_decoder_in_position =(self.msb_decoder.A_positions[i].scale(-1, 1)
|
msb_decoder_in_position =(self.msb_decoder.A_positions[i].scale(-1, 1)
|
||||||
+ self.msb_decoder_position
|
+ self.msb_decoder_position
|
||||||
|
|
@ -827,11 +827,11 @@ class sram(design.design):
|
||||||
start = msb_msf_out_position
|
start = msb_msf_out_position
|
||||||
mid1 = start + vector(4 * (i + 1) * drc["minwidth_metal1"], 0)
|
mid1 = start + vector(4 * (i + 1) * drc["minwidth_metal1"], 0)
|
||||||
mid2 = vector(mid1.x, msb_decoder_in_position.y)
|
mid2 = vector(mid1.x, msb_decoder_in_position.y)
|
||||||
end = vector(self.msb_decoder_position[0]
|
end = vector(self.msb_decoder_position.x
|
||||||
+ 3*drc["minwidth_metal3"],
|
+ 3*drc["minwidth_metal3"],
|
||||||
mid2.y)
|
mid2.y)
|
||||||
|
|
||||||
layer_stack = ("metal1", "via1", "metal2")
|
layer_stack = ("metal2", "via1", "metal1")
|
||||||
self.add_wire(layer_stack, [start, mid1, mid2, end])
|
self.add_wire(layer_stack, [start, mid1, mid2, end])
|
||||||
|
|
||||||
self.add_rect(layer="metal1",
|
self.add_rect(layer="metal1",
|
||||||
|
|
@ -874,9 +874,9 @@ class sram(design.design):
|
||||||
|
|
||||||
# control logic
|
# control logic
|
||||||
self.control_vdd1_position = (self.control_position
|
self.control_vdd1_position = (self.control_position
|
||||||
+ self.control.vdd1_position.rotate().scale(-1, 1))
|
+ self.control.vdd1_position.rotate_scale(-1, 1))
|
||||||
self.control_vdd2_position = (self.control_position
|
self.control_vdd2_position = (self.control_position
|
||||||
+ self.control.vdd2_position.rotate().scale(-1, 1))
|
+ self.control.vdd2_position.rotate_scale(-1, 1))
|
||||||
|
|
||||||
self.add_rect(layer="metal1",
|
self.add_rect(layer="metal1",
|
||||||
offset=self.control_vdd1_position,
|
offset=self.control_vdd1_position,
|
||||||
|
|
@ -974,7 +974,7 @@ class sram(design.design):
|
||||||
|
|
||||||
# msf_msb_address
|
# msf_msb_address
|
||||||
start = msf_address_vdd_position = (self.msf_msb_address_position
|
start = msf_address_vdd_position = (self.msf_msb_address_position
|
||||||
+ self.msf_msb_address.vdd_positions[0].rotate().scale(1,-1))
|
+ self.msf_msb_address.vdd_positions[0].rotate_scale(1,-1))
|
||||||
mid1 = vector(start.x,
|
mid1 = vector(start.x,
|
||||||
self.msf_msb_address_position.y
|
self.msf_msb_address_position.y
|
||||||
- self.msf_msb_address.width
|
- self.msf_msb_address.width
|
||||||
|
|
@ -1029,7 +1029,7 @@ class sram(design.design):
|
||||||
offset=self.gnd_offset)
|
offset=self.gnd_offset)
|
||||||
|
|
||||||
self.control_gnd_position = (self.control_position
|
self.control_gnd_position = (self.control_position
|
||||||
+ self.control.gnd_position.rotate().scale(-1,1)
|
+ self.control.gnd_position.rotate_scale(-1,1)
|
||||||
+ vector(drc["minwidth_metal2"],0))
|
+ vector(drc["minwidth_metal2"],0))
|
||||||
|
|
||||||
self.add_rect(layer="metal3",
|
self.add_rect(layer="metal3",
|
||||||
|
|
@ -1070,12 +1070,12 @@ class sram(design.design):
|
||||||
self.add_rect(layer="metal2",
|
self.add_rect(layer="metal2",
|
||||||
offset=self.sram_bank_left_gnd_positions[0],
|
offset=self.sram_bank_left_gnd_positions[0],
|
||||||
width=drc["minwidth_metal2"],
|
width=drc["minwidth_metal2"],
|
||||||
height=control_gnd_supply[1] + drc["minwidth_metal1"]
|
height=control_gnd_supply.y + drc["minwidth_metal1"]
|
||||||
- self.sram_bank_left_gnd_positions[0].y)
|
- self.sram_bank_left_gnd_positions[0].y)
|
||||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||||
offset=[self.sram_bank_left_gnd_positions[0].x
|
offset=[self.sram_bank_left_gnd_positions[0].x
|
||||||
+ drc["minwidth_metal2"],
|
+ drc["minwidth_metal2"],
|
||||||
control_gnd_supply[1]],
|
control_gnd_supply.y],
|
||||||
mirror="R90")
|
mirror="R90")
|
||||||
# Control gnd
|
# Control gnd
|
||||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env python2.7
|
#!/usr/bin/env python2.7
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from header import header
|
from testutils import header
|
||||||
import sys,os
|
import sys,os
|
||||||
sys.path.append(os.path.join(sys.path[0],".."))
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
import globals
|
import globals
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
"Run a regresion test the library cells for DRC"
|
"Run a regresion test the library cells for DRC"
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from header import header
|
from testutils import header
|
||||||
import sys,os
|
import sys,os
|
||||||
sys.path.append(os.path.join(sys.path[0],".."))
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
import globals
|
import globals
|
||||||
|
|
@ -33,7 +33,7 @@ class library_drc_test(unittest.TestCase):
|
||||||
|
|
||||||
# fails if there are any DRC errors on any cells
|
# fails if there are any DRC errors on any cells
|
||||||
self.assertEqual(drc_errors, 0)
|
self.assertEqual(drc_errors, 0)
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
def setup_files():
|
def setup_files():
|
||||||
gds_dir = OPTS.openram_tech + "/gds_lib"
|
gds_dir = OPTS.openram_tech + "/gds_lib"
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
"Run a regresion test the library cells for LVS"
|
"Run a regresion test the library cells for LVS"
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from header import header
|
from testutils import header
|
||||||
import sys,os
|
import sys,os
|
||||||
sys.path.append(os.path.join(sys.path[0],".."))
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
import globals
|
import globals
|
||||||
|
|
@ -37,7 +37,7 @@ class library_lvs_test(unittest.TestCase):
|
||||||
|
|
||||||
# fail if the error count is not zero
|
# fail if the error count is not zero
|
||||||
self.assertEqual(lvs_errors, 0)
|
self.assertEqual(lvs_errors, 0)
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
def setup_files():
|
def setup_files():
|
||||||
gds_dir = OPTS.openram_tech + "/gds_lib"
|
gds_dir = OPTS.openram_tech + "/gds_lib"
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
"Run a regresion test for DRC on basic contacts of different array sizes"
|
"Run a regresion test for DRC on basic contacts of different array sizes"
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from header import header
|
from testutils import header
|
||||||
import sys,os
|
import sys,os
|
||||||
sys.path.append(os.path.join(sys.path[0],".."))
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
import globals
|
import globals
|
||||||
|
|
@ -54,7 +54,8 @@ class contact_test(unittest.TestCase):
|
||||||
self.local_check(c)
|
self.local_check(c)
|
||||||
|
|
||||||
OPTS.check_lvsdrc = True
|
OPTS.check_lvsdrc = True
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
def local_check(self, c):
|
def local_check(self, c):
|
||||||
tempgds = OPTS.openram_temp + "temp.gds"
|
tempgds = OPTS.openram_temp + "temp.gds"
|
||||||
c.gds_write(tempgds)
|
c.gds_write(tempgds)
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
"Run a regresion test on a basic path"
|
"Run a regresion test on a basic path"
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from header import header
|
from testutils import header
|
||||||
import sys,os
|
import sys,os
|
||||||
sys.path.append(os.path.join(sys.path[0],".."))
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
import globals
|
import globals
|
||||||
|
|
@ -75,7 +75,8 @@ class path_test(unittest.TestCase):
|
||||||
|
|
||||||
# return it back to it's normal state
|
# return it back to it's normal state
|
||||||
OPTS.check_lvsdrc = True
|
OPTS.check_lvsdrc = True
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
def local_check(self, w):
|
def local_check(self, w):
|
||||||
tempgds = OPTS.openram_temp + "temp.gds"
|
tempgds = OPTS.openram_temp + "temp.gds"
|
||||||
w.gds_write(tempgds)
|
w.gds_write(tempgds)
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
"Run a regresion test on a basic parameterized transistors"
|
"Run a regresion test on a basic parameterized transistors"
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from header import header
|
from testutils import header
|
||||||
import sys,os
|
import sys,os
|
||||||
sys.path.append(os.path.join(sys.path[0],".."))
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
import globals
|
import globals
|
||||||
|
|
@ -33,7 +33,7 @@ class ptx_test(unittest.TestCase):
|
||||||
OPTS.check_lvsdrc = True
|
OPTS.check_lvsdrc = True
|
||||||
|
|
||||||
self.local_check(fet)
|
self.local_check(fet)
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
|
|
||||||
def add_mods(self, fet):
|
def add_mods(self, fet):
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
"Run a regresion test on a basic parameterized transistors"
|
"Run a regresion test on a basic parameterized transistors"
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from header import header
|
from testutils import header
|
||||||
import sys,os
|
import sys,os
|
||||||
sys.path.append(os.path.join(sys.path[0],".."))
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
import globals
|
import globals
|
||||||
|
|
@ -33,7 +33,7 @@ class ptx_test(unittest.TestCase):
|
||||||
OPTS.check_lvsdrc = True
|
OPTS.check_lvsdrc = True
|
||||||
|
|
||||||
self.local_check(fet)
|
self.local_check(fet)
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
|
|
||||||
def add_mods(self, fet):
|
def add_mods(self, fet):
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
"Run a regresion test on a basic parameterized transistors"
|
"Run a regresion test on a basic parameterized transistors"
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from header import header
|
from testutils import header
|
||||||
import sys,os
|
import sys,os
|
||||||
sys.path.append(os.path.join(sys.path[0],".."))
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
import globals
|
import globals
|
||||||
|
|
@ -33,7 +33,7 @@ class ptx_test(unittest.TestCase):
|
||||||
OPTS.check_lvsdrc = True
|
OPTS.check_lvsdrc = True
|
||||||
|
|
||||||
self.local_check(fet)
|
self.local_check(fet)
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
def add_mods(self, fet):
|
def add_mods(self, fet):
|
||||||
self.create_contacts()
|
self.create_contacts()
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
"Run a regresion test on a basic parameterized transistors"
|
"Run a regresion test on a basic parameterized transistors"
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from header import header
|
from testutils import header
|
||||||
import sys,os
|
import sys,os
|
||||||
sys.path.append(os.path.join(sys.path[0],".."))
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
import globals
|
import globals
|
||||||
|
|
@ -33,7 +33,8 @@ class ptx_test(unittest.TestCase):
|
||||||
OPTS.check_lvsdrc = True
|
OPTS.check_lvsdrc = True
|
||||||
|
|
||||||
self.local_check(fet)
|
self.local_check(fet)
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
def add_mods(self, fet):
|
def add_mods(self, fet):
|
||||||
self.create_contacts()
|
self.create_contacts()
|
||||||
self.add_well_extension(fet)
|
self.add_well_extension(fet)
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
"Run a regresion test on a basic wire"
|
"Run a regresion test on a basic wire"
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from header import header
|
from testutils import header
|
||||||
import sys,os
|
import sys,os
|
||||||
sys.path.append(os.path.join(sys.path[0],".."))
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
import globals
|
import globals
|
||||||
|
|
@ -128,7 +128,8 @@ class wire_test(unittest.TestCase):
|
||||||
|
|
||||||
# return it back to it's normal state
|
# return it back to it's normal state
|
||||||
OPTS.check_lvsdrc = True
|
OPTS.check_lvsdrc = True
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
def local_check(self, w):
|
def local_check(self, w):
|
||||||
tempgds = OPTS.openram_temp + "temp.gds"
|
tempgds = OPTS.openram_temp + "temp.gds"
|
||||||
w.gds_write(tempgds)
|
w.gds_write(tempgds)
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ size 2_input nand gate that is nmos_width=2*tech.drc[minwidth_tx].
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from header import header
|
from testutils import header
|
||||||
import sys,os
|
import sys,os
|
||||||
sys.path.append(os.path.join(sys.path[0],".."))
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
import globals
|
import globals
|
||||||
|
|
@ -33,7 +33,8 @@ class nand_2_test(unittest.TestCase):
|
||||||
tx = nand_2.nand_2(name="a_nand_1", nmos_width=2 * tech.drc["minwidth_tx"])
|
tx = nand_2.nand_2(name="a_nand_1", nmos_width=2 * tech.drc["minwidth_tx"])
|
||||||
OPTS.check_lvsdrc = True
|
OPTS.check_lvsdrc = True
|
||||||
self.local_check(tx)
|
self.local_check(tx)
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
|
|
||||||
def local_check(self, tx):
|
def local_check(self, tx):
|
||||||
tempspice = OPTS.openram_temp + "temp.sp"
|
tempspice = OPTS.openram_temp + "temp.sp"
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ It generate only the minimum size 3_input nand gate that is nmos_width=3*tech.dr
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from header import header
|
from testutils import header
|
||||||
import sys,os
|
import sys,os
|
||||||
sys.path.append(os.path.join(sys.path[0],".."))
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
import globals
|
import globals
|
||||||
|
|
@ -31,7 +31,8 @@ class nand_3_test(unittest.TestCase):
|
||||||
|
|
||||||
OPTS.check_lvsdrc = True
|
OPTS.check_lvsdrc = True
|
||||||
self.local_check(tx)
|
self.local_check(tx)
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
def local_check(self, tx):
|
def local_check(self, tx):
|
||||||
tempspice = OPTS.openram_temp + "temp.sp"
|
tempspice = OPTS.openram_temp + "temp.sp"
|
||||||
tempgds = OPTS.openram_temp + "temp.gds"
|
tempgds = OPTS.openram_temp + "temp.gds"
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ This module doesn't generate multi_finger 2_input nor gate
|
||||||
It generate only the minimum size 2_input nor gate that is nmos_width=2*tech.drc[minwidth_tx]
|
It generate only the minimum size 2_input nor gate that is nmos_width=2*tech.drc[minwidth_tx]
|
||||||
"""
|
"""
|
||||||
import unittest
|
import unittest
|
||||||
from header import header
|
from testutils import header
|
||||||
import sys,os
|
import sys,os
|
||||||
sys.path.append(os.path.join(sys.path[0],".."))
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
import globals
|
import globals
|
||||||
|
|
@ -32,7 +32,7 @@ class nor_2_test(unittest.TestCase):
|
||||||
tx = nor_2.nor_2(name="a_nor_1", nmos_width=2 * tech.drc["minwidth_tx"])
|
tx = nor_2.nor_2(name="a_nor_1", nmos_width=2 * tech.drc["minwidth_tx"])
|
||||||
OPTS.check_lvsdrc = True
|
OPTS.check_lvsdrc = True
|
||||||
self.local_check(tx)
|
self.local_check(tx)
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
def local_check(self, tx):
|
def local_check(self, tx):
|
||||||
tempspice = OPTS.openram_temp + "temp.sp"
|
tempspice = OPTS.openram_temp + "temp.sp"
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ Run regresion tests on a parameterized inverter
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from header import header
|
from testutils import header
|
||||||
import sys,os
|
import sys,os
|
||||||
sys.path.append(os.path.join(sys.path[0],".."))
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
import globals
|
import globals
|
||||||
|
|
@ -42,6 +42,7 @@ class pinv_test(unittest.TestCase):
|
||||||
OPTS.check_lvsdrc = True
|
OPTS.check_lvsdrc = True
|
||||||
self.local_check(tx)
|
self.local_check(tx)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
def local_check(self, tx):
|
def local_check(self, tx):
|
||||||
tempspice = OPTS.openram_temp + "temp.sp"
|
tempspice = OPTS.openram_temp + "temp.sp"
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ Run a regresion test on a wordline_driver array
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from header import header
|
from testutils import header
|
||||||
import sys,os
|
import sys,os
|
||||||
sys.path.append(os.path.join(sys.path[0],".."))
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
import globals
|
import globals
|
||||||
|
|
@ -33,7 +33,7 @@ class wordline_driver_test(unittest.TestCase):
|
||||||
OPTS.check_lvsdrc = True
|
OPTS.check_lvsdrc = True
|
||||||
|
|
||||||
self.local_check(tx)
|
self.local_check(tx)
|
||||||
|
globals.end_openram()
|
||||||
def local_check(self, tx):
|
def local_check(self, tx):
|
||||||
tempspice = OPTS.openram_temp + "temp.sp"
|
tempspice = OPTS.openram_temp + "temp.sp"
|
||||||
tempgds = OPTS.openram_temp + "temp.gds"
|
tempgds = OPTS.openram_temp + "temp.gds"
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ Run a regresion test on a basic array
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from header import header
|
from testutils import header
|
||||||
import sys,os
|
import sys,os
|
||||||
sys.path.append(os.path.join(sys.path[0],".."))
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
import globals
|
import globals
|
||||||
|
|
@ -31,7 +31,7 @@ class array_test(unittest.TestCase):
|
||||||
OPTS.check_lvsdrc = True
|
OPTS.check_lvsdrc = True
|
||||||
|
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
def local_check(self, a):
|
def local_check(self, a):
|
||||||
tempspice = OPTS.openram_temp + "temp.sp"
|
tempspice = OPTS.openram_temp + "temp.sp"
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ Run a regresion test on a thierarchy_decoder.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from header import header
|
from testutils import header
|
||||||
import sys,os
|
import sys,os
|
||||||
sys.path.append(os.path.join(sys.path[0],".."))
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
import globals
|
import globals
|
||||||
|
|
@ -57,7 +57,8 @@ class hierarchical_decoder_test(unittest.TestCase):
|
||||||
OPTS.check_lvsdrc = True
|
OPTS.check_lvsdrc = True
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
def local_check(self, a):
|
def local_check(self, a):
|
||||||
tempspice = OPTS.openram_temp + "temp.sp"
|
tempspice = OPTS.openram_temp + "temp.sp"
|
||||||
tempgds = OPTS.openram_temp + "temp.gds"
|
tempgds = OPTS.openram_temp + "temp.gds"
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ Run a regresion test on a hierarchical_predecode2x4.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from header import header
|
from testutils import header
|
||||||
import sys,os
|
import sys,os
|
||||||
sys.path.append(os.path.join(sys.path[0],".."))
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
import globals
|
import globals
|
||||||
|
|
@ -30,7 +30,8 @@ class hierarchical_predecode2x4_test(unittest.TestCase):
|
||||||
OPTS.check_lvsdrc = True
|
OPTS.check_lvsdrc = True
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
def local_check(self, a):
|
def local_check(self, a):
|
||||||
tempspice = OPTS.openram_temp + "temp.sp"
|
tempspice = OPTS.openram_temp + "temp.sp"
|
||||||
tempgds = OPTS.openram_temp + "temp.gds"
|
tempgds = OPTS.openram_temp + "temp.gds"
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ Run a regresion test on a hierarchical_predecode3x8.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from header import header
|
from testutils import header
|
||||||
import sys,os
|
import sys,os
|
||||||
sys.path.append(os.path.join(sys.path[0],".."))
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
import globals
|
import globals
|
||||||
|
|
@ -30,6 +30,7 @@ class hierarchical_predecode3x8_test(unittest.TestCase):
|
||||||
OPTS.check_lvsdrc = True
|
OPTS.check_lvsdrc = True
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
def local_check(self, a):
|
def local_check(self, a):
|
||||||
tempspice = OPTS.openram_temp + "temp.sp"
|
tempspice = OPTS.openram_temp + "temp.sp"
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ Run a regresion test on a single transistor column_mux.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from header import header
|
from testutils import header
|
||||||
import sys,os
|
import sys,os
|
||||||
sys.path.append(os.path.join(sys.path[0],".."))
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
import globals
|
import globals
|
||||||
|
|
@ -28,7 +28,8 @@ class single_level_column_mux_test(unittest.TestCase):
|
||||||
rows=32, columns=32, word_size=16)
|
rows=32, columns=32, word_size=16)
|
||||||
OPTS.check_lvsdrc = True
|
OPTS.check_lvsdrc = True
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
def local_check(self, a):
|
def local_check(self, a):
|
||||||
tempspice = OPTS.openram_temp + "temp.sp"
|
tempspice = OPTS.openram_temp + "temp.sp"
|
||||||
tempgds = OPTS.openram_temp + "temp.gds"
|
tempgds = OPTS.openram_temp + "temp.gds"
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ Run a regresion test on a precharge array
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from header import header
|
from testutils import header
|
||||||
import sys,os
|
import sys,os
|
||||||
sys.path.append(os.path.join(sys.path[0],".."))
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
import globals
|
import globals
|
||||||
|
|
@ -38,7 +38,8 @@ class precharge_test(unittest.TestCase):
|
||||||
OPTS.check_lvsdrc = True
|
OPTS.check_lvsdrc = True
|
||||||
self.local_check(pc)
|
self.local_check(pc)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
def local_check(self, pc):
|
def local_check(self, pc):
|
||||||
tempspice = OPTS.openram_temp + "temp.sp"
|
tempspice = OPTS.openram_temp + "temp.sp"
|
||||||
tempgds = OPTS.openram_temp + "temp.gds"
|
tempgds = OPTS.openram_temp + "temp.gds"
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ Run a regresion test on a sense amp array
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from header import header
|
from testutils import header
|
||||||
import sys,os
|
import sys,os
|
||||||
sys.path.append(os.path.join(sys.path[0],".."))
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
import globals
|
import globals
|
||||||
|
|
@ -41,7 +41,8 @@ class sense_amp_test(unittest.TestCase):
|
||||||
OPTS.check_lvsdrc = True
|
OPTS.check_lvsdrc = True
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
def local_check(self, a):
|
def local_check(self, a):
|
||||||
tempspice = OPTS.openram_temp + "temp.sp"
|
tempspice = OPTS.openram_temp + "temp.sp"
|
||||||
tempgds = OPTS.openram_temp + "temp.gds"
|
tempgds = OPTS.openram_temp + "temp.gds"
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ Run a regresion test on a write driver array
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from header import header
|
from testutils import header
|
||||||
import sys,os
|
import sys,os
|
||||||
sys.path.append(os.path.join(sys.path[0],".."))
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
import globals
|
import globals
|
||||||
|
|
@ -35,6 +35,7 @@ class write_driver_test(unittest.TestCase):
|
||||||
OPTS.check_lvsdrc = True
|
OPTS.check_lvsdrc = True
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
def local_check(self, a):
|
def local_check(self, a):
|
||||||
tempspice = OPTS.openram_temp + "temp.sp"
|
tempspice = OPTS.openram_temp + "temp.sp"
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ Run a regresion test on a dff_array.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from header import header
|
from testutils import header
|
||||||
import sys,os
|
import sys,os
|
||||||
sys.path.append(os.path.join(sys.path[0],".."))
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
import globals
|
import globals
|
||||||
|
|
@ -31,6 +31,7 @@ class dff_array_test(unittest.TestCase):
|
||||||
OPTS.check_lvsdrc = True
|
OPTS.check_lvsdrc = True
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
def local_check(self, a):
|
def local_check(self, a):
|
||||||
tempspice = OPTS.openram_temp + "temp.sp"
|
tempspice = OPTS.openram_temp + "temp.sp"
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ Run a regresion test on a control_logic
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from header import header
|
from testutils import header
|
||||||
import sys,os
|
import sys,os
|
||||||
sys.path.append(os.path.join(sys.path[0],".."))
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
import globals
|
import globals
|
||||||
|
|
@ -29,7 +29,8 @@ class control_logic_test(unittest.TestCase):
|
||||||
OPTS.check_lvsdrc = True
|
OPTS.check_lvsdrc = True
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
def local_check(self, a):
|
def local_check(self, a):
|
||||||
tempspice = OPTS.openram_temp + "temp.sp"
|
tempspice = OPTS.openram_temp + "temp.sp"
|
||||||
tempgds = OPTS.openram_temp + "temp.gds"
|
tempgds = OPTS.openram_temp + "temp.gds"
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ Run a test on a delay chain
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from header import header
|
from testutils import header
|
||||||
import sys,os
|
import sys,os
|
||||||
sys.path.append(os.path.join(sys.path[0],".."))
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
import globals
|
import globals
|
||||||
|
|
@ -31,6 +31,8 @@ class logic_effort_dc_test(unittest.TestCase):
|
||||||
OPTS.check_lvsdrc = True
|
OPTS.check_lvsdrc = True
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
def local_check(self, a):
|
def local_check(self, a):
|
||||||
tempspice = OPTS.openram_temp + "temp.sp"
|
tempspice = OPTS.openram_temp + "temp.sp"
|
||||||
tempgds = OPTS.openram_temp + "temp.gds"
|
tempgds = OPTS.openram_temp + "temp.gds"
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ Run a regresion test on a tri_gate_array.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from header import header
|
from testutils import header
|
||||||
import sys,os
|
import sys,os
|
||||||
sys.path.append(os.path.join(sys.path[0],".."))
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
import globals
|
import globals
|
||||||
|
|
@ -28,6 +28,8 @@ class tri_gate_array_test(unittest.TestCase):
|
||||||
OPTS.check_lvsdrc = True
|
OPTS.check_lvsdrc = True
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
def local_check(self, a):
|
def local_check(self, a):
|
||||||
tempspice = OPTS.openram_temp + "temp.sp"
|
tempspice = OPTS.openram_temp + "temp.sp"
|
||||||
tempgds = OPTS.openram_temp + "temp.gds"
|
tempgds = OPTS.openram_temp + "temp.gds"
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ Run a test on a delay chain
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from header import header
|
from testutils import header
|
||||||
import sys,os
|
import sys,os
|
||||||
sys.path.append(os.path.join(sys.path[0],".."))
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
import globals
|
import globals
|
||||||
|
|
@ -31,6 +31,8 @@ class replica_bitline_test(unittest.TestCase):
|
||||||
OPTS.check_lvsdrc = True
|
OPTS.check_lvsdrc = True
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
def local_check(self, a):
|
def local_check(self, a):
|
||||||
tempspice = OPTS.openram_temp + "temp.sp"
|
tempspice = OPTS.openram_temp + "temp.sp"
|
||||||
tempgds = OPTS.openram_temp + "temp.gds"
|
tempgds = OPTS.openram_temp + "temp.gds"
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ Run a regresion test on various srams
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from header import header
|
from testutils import header
|
||||||
import sys,os
|
import sys,os
|
||||||
sys.path.append(os.path.join(sys.path[0],".."))
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
import globals
|
import globals
|
||||||
|
|
@ -35,6 +35,8 @@ class bank_test(unittest.TestCase):
|
||||||
OPTS.check_lvsdrc = True
|
OPTS.check_lvsdrc = True
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
def local_check(self, a):
|
def local_check(self, a):
|
||||||
tempspice = OPTS.openram_temp + "temp.sp"
|
tempspice = OPTS.openram_temp + "temp.sp"
|
||||||
tempgds = OPTS.openram_temp + "temp.gds"
|
tempgds = OPTS.openram_temp + "temp.gds"
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ Run a regresion test on a 1 bank SRAM
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from header import header
|
from testutils import header
|
||||||
import sys,os
|
import sys,os
|
||||||
sys.path.append(os.path.join(sys.path[0],".."))
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
import globals
|
import globals
|
||||||
|
|
@ -30,7 +30,8 @@ class sram_1bank_test(unittest.TestCase):
|
||||||
OPTS.check_lvsdrc = True
|
OPTS.check_lvsdrc = True
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
def local_check(self, a):
|
def local_check(self, a):
|
||||||
tempspice = OPTS.openram_temp + "temp.sp"
|
tempspice = OPTS.openram_temp + "temp.sp"
|
||||||
tempgds = OPTS.openram_temp + "temp.gds"
|
tempgds = OPTS.openram_temp + "temp.gds"
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ Run a regresion test on a 2 bank SRAM
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from header import header
|
from testutils import header
|
||||||
import sys,os
|
import sys,os
|
||||||
sys.path.append(os.path.join(sys.path[0],".."))
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
import globals
|
import globals
|
||||||
|
|
@ -30,6 +30,8 @@ class sram_2bank_test(unittest.TestCase):
|
||||||
OPTS.check_lvsdrc = True
|
OPTS.check_lvsdrc = True
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
def local_check(self, a):
|
def local_check(self, a):
|
||||||
tempspice = OPTS.openram_temp + "temp.sp"
|
tempspice = OPTS.openram_temp + "temp.sp"
|
||||||
tempgds = OPTS.openram_temp + "temp.gds"
|
tempgds = OPTS.openram_temp + "temp.gds"
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ Run a regresion test on a 4 bank SRAM
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from header import header
|
from testutils import header
|
||||||
import sys,os
|
import sys,os
|
||||||
sys.path.append(os.path.join(sys.path[0],".."))
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
import globals
|
import globals
|
||||||
|
|
@ -30,6 +30,8 @@ class sram_4bank_test(unittest.TestCase):
|
||||||
OPTS.check_lvsdrc = True
|
OPTS.check_lvsdrc = True
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
def local_check(self, a):
|
def local_check(self, a):
|
||||||
tempspice = OPTS.openram_temp + "temp.sp"
|
tempspice = OPTS.openram_temp + "temp.sp"
|
||||||
tempgds = OPTS.openram_temp + "temp.gds"
|
tempgds = OPTS.openram_temp + "temp.gds"
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ Run a regresion test on various srams
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from header import header
|
from testutils import header,isclose
|
||||||
import sys,os
|
import sys,os
|
||||||
sys.path.append(os.path.join(sys.path[0],".."))
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
import globals
|
import globals
|
||||||
|
|
@ -22,8 +22,10 @@ class timing_sram_test(unittest.TestCase):
|
||||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||||
# we will manually run lvs/drc
|
# we will manually run lvs/drc
|
||||||
OPTS.check_lvsdrc = False
|
OPTS.check_lvsdrc = False
|
||||||
OPTS.use_pex = False
|
OPTS.spice_version="hspice"
|
||||||
|
OPTS.force_spice = True
|
||||||
|
globals.set_spice()
|
||||||
|
|
||||||
import sram
|
import sram
|
||||||
|
|
||||||
debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank")
|
debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank")
|
||||||
|
|
@ -61,11 +63,8 @@ class timing_sram_test(unittest.TestCase):
|
||||||
|
|
||||||
os.remove(tempspice)
|
os.remove(tempspice)
|
||||||
|
|
||||||
def isclose(value1,value2):
|
globals.end_openram()
|
||||||
""" This is used to compare relative values for convergence. """
|
|
||||||
return (abs(value1 - value2) / max(value1,value2) <= 1e-2)
|
|
||||||
|
|
||||||
|
|
||||||
# instantiate a copdsay of the class to actually run the test
|
# instantiate a copdsay of the class to actually run the test
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
(OPTS, args) = globals.parse_args()
|
(OPTS, args) = globals.parse_args()
|
||||||
|
|
@ -4,7 +4,7 @@ Run a regresion test on various srams
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from header import header
|
from testutils import header,isclose
|
||||||
import sys,os
|
import sys,os
|
||||||
sys.path.append(os.path.join(sys.path[0],".."))
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
import globals
|
import globals
|
||||||
|
|
@ -22,7 +22,9 @@ class timing_setup_test(unittest.TestCase):
|
||||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||||
# we will manually run lvs/drc
|
# we will manually run lvs/drc
|
||||||
OPTS.check_lvsdrc = False
|
OPTS.check_lvsdrc = False
|
||||||
OPTS.use_pex = False
|
OPTS.spice_version="hspice"
|
||||||
|
OPTS.force_spice = True
|
||||||
|
globals.set_spice()
|
||||||
|
|
||||||
import sram
|
import sram
|
||||||
import setup_hold
|
import setup_hold
|
||||||
|
|
@ -41,10 +43,7 @@ class timing_setup_test(unittest.TestCase):
|
||||||
else:
|
else:
|
||||||
self.assertTrue(False) # other techs fail
|
self.assertTrue(False) # other techs fail
|
||||||
|
|
||||||
def isclose(value1,value2):
|
globals.end_openram()
|
||||||
""" This is used to compare relative values for convergence. """
|
|
||||||
return (abs(value1 - value2) / max(value1,value2) <= 1e-2)
|
|
||||||
|
|
||||||
|
|
||||||
# instantiate a copdsay of the class to actually run the test
|
# instantiate a copdsay of the class to actually run the test
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
@ -4,7 +4,7 @@ Run a regresion test on various srams
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from header import header
|
from testutils import header,isclose
|
||||||
import sys,os
|
import sys,os
|
||||||
sys.path.append(os.path.join(sys.path[0],".."))
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
import globals
|
import globals
|
||||||
|
|
@ -20,9 +20,12 @@ class timing_setup_test(unittest.TestCase):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||||
|
|
||||||
# we will manually run lvs/drc
|
# we will manually run lvs/drc
|
||||||
OPTS.check_lvsdrc = False
|
OPTS.check_lvsdrc = False
|
||||||
OPTS.use_pex = False
|
OPTS.spice_version="hspice"
|
||||||
|
OPTS.force_spice = True
|
||||||
|
globals.set_spice()
|
||||||
|
|
||||||
import sram
|
import sram
|
||||||
import setup_hold
|
import setup_hold
|
||||||
|
|
@ -40,11 +43,8 @@ class timing_setup_test(unittest.TestCase):
|
||||||
else:
|
else:
|
||||||
self.assertTrue(False) # other techs fail
|
self.assertTrue(False) # other techs fail
|
||||||
|
|
||||||
def isclose(value1,value2):
|
globals.end_openram()
|
||||||
""" This is used to compare relative values for convergence. """
|
|
||||||
return (abs(value1 - value2) / max(value1,value2) <= 1e-2)
|
|
||||||
|
|
||||||
|
|
||||||
# instantiate a copdsay of the class to actually run the test
|
# instantiate a copdsay of the class to actually run the test
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
(OPTS, args) = globals.parse_args()
|
(OPTS, args) = globals.parse_args()
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
#!/usr/bin/env python2.7
|
||||||
|
"""
|
||||||
|
Run a regresion test on various srams
|
||||||
|
"""
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
from testutils import header,isclose
|
||||||
|
import sys,os
|
||||||
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
|
import globals
|
||||||
|
import debug
|
||||||
|
import calibre
|
||||||
|
|
||||||
|
OPTS = globals.get_opts()
|
||||||
|
|
||||||
|
#@unittest.skip("SKIPPING 21_ngspice_delay_test")
|
||||||
|
class timing_sram_test(unittest.TestCase):
|
||||||
|
|
||||||
|
def runTest(self):
|
||||||
|
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||||
|
# we will manually run lvs/drc
|
||||||
|
OPTS.check_lvsdrc = False
|
||||||
|
OPTS.spice_version="ngspice"
|
||||||
|
OPTS.force_spice = True
|
||||||
|
globals.set_spice()
|
||||||
|
|
||||||
|
import sram
|
||||||
|
|
||||||
|
debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank")
|
||||||
|
s = sram.sram(word_size=OPTS.config.word_size,
|
||||||
|
num_words=OPTS.config.num_words,
|
||||||
|
num_banks=OPTS.config.num_banks,
|
||||||
|
name="test_sram1")
|
||||||
|
|
||||||
|
# reset these options
|
||||||
|
OPTS.check_lvsdrc = True
|
||||||
|
OPTS.spice_version="hspice"
|
||||||
|
OPTS.force_spice = False
|
||||||
|
globals.set_spice()
|
||||||
|
|
||||||
|
import delay
|
||||||
|
|
||||||
|
tempspice = OPTS.openram_temp + "temp.sp"
|
||||||
|
s.sp_write(tempspice)
|
||||||
|
|
||||||
|
probe_address = "1" * s.addr_size
|
||||||
|
probe_data = s.word_size - 1
|
||||||
|
debug.info(1, "Probe address {0} probe data {1}".format(probe_address, probe_data))
|
||||||
|
|
||||||
|
d = delay.delay(s,tempspice)
|
||||||
|
data = d.analyze(probe_address, probe_data)
|
||||||
|
|
||||||
|
if OPTS.tech_name == "freepdk45":
|
||||||
|
self.assertTrue(isclose(data['delay1'],0.013649)) # diff than hspice
|
||||||
|
self.assertTrue(isclose(data['delay0'],0.22893)) # diff than hspice
|
||||||
|
self.assertTrue(isclose(data['min_period1'],0.078582763671875)) # diff than hspice
|
||||||
|
self.assertTrue(isclose(data['min_period0'],0.25543212890625)) # diff than hspice
|
||||||
|
elif OPTS.tech_name == "scn3me_subm":
|
||||||
|
self.assertTrue(isclose(data['delay1'],1.5342000000000002)) # diff than hspice
|
||||||
|
self.assertTrue(isclose(data['delay0'],2.2698)) # diff than hspice
|
||||||
|
self.assertTrue(isclose(data['min_period1'],1.534423828125)) # diff than hspice
|
||||||
|
self.assertTrue(isclose(data['min_period0'],2.99560546875)) # diff than hspice
|
||||||
|
else:
|
||||||
|
self.assertTrue(False) # other techs fail
|
||||||
|
|
||||||
|
os.remove(tempspice)
|
||||||
|
|
||||||
|
# instantiate a copdsay 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()
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
#!/usr/bin/env python2.7
|
||||||
|
"""
|
||||||
|
Run a regresion test on various srams
|
||||||
|
"""
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
from testutils import header,isclose
|
||||||
|
import sys,os
|
||||||
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
|
import globals
|
||||||
|
import debug
|
||||||
|
import calibre
|
||||||
|
|
||||||
|
OPTS = globals.get_opts()
|
||||||
|
|
||||||
|
#@unittest.skip("SKIPPING 21_timing_sram_test")
|
||||||
|
|
||||||
|
|
||||||
|
class timing_setup_test(unittest.TestCase):
|
||||||
|
|
||||||
|
def runTest(self):
|
||||||
|
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||||
|
# we will manually run lvs/drc
|
||||||
|
OPTS.check_lvsdrc = False
|
||||||
|
OPTS.spice_version="ngspice"
|
||||||
|
OPTS.force_spice = True
|
||||||
|
globals.set_spice()
|
||||||
|
|
||||||
|
import sram
|
||||||
|
import setup_hold
|
||||||
|
|
||||||
|
sh = setup_hold.setup_hold()
|
||||||
|
[one_setup_time, zero_setup_time] = sh.hold_time()
|
||||||
|
|
||||||
|
# reset these options
|
||||||
|
OPTS.check_lvsdrc = True
|
||||||
|
OPTS.spice_version="hspice"
|
||||||
|
OPTS.force_spice = False
|
||||||
|
globals.set_spice()
|
||||||
|
|
||||||
|
if OPTS.tech_name == "freepdk45":
|
||||||
|
self.assertTrue(isclose(one_setup_time,-0.0048828125))
|
||||||
|
self.assertTrue(isclose(zero_setup_time,-0.010986328125))
|
||||||
|
elif OPTS.tech_name == "scn3me_subm":
|
||||||
|
self.assertTrue(isclose(one_setup_time,0.45654296875)) # diff than hspice
|
||||||
|
self.assertTrue(isclose(zero_setup_time,-0.0830078125))
|
||||||
|
else:
|
||||||
|
self.assertTrue(False) # other techs fail
|
||||||
|
|
||||||
|
# instantiate a copdsay 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()
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
#!/usr/bin/env python2.7
|
||||||
|
"""
|
||||||
|
Run a regresion test on various srams
|
||||||
|
"""
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
from testutils import header,isclose
|
||||||
|
import sys,os
|
||||||
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
|
import globals
|
||||||
|
import debug
|
||||||
|
import calibre
|
||||||
|
|
||||||
|
OPTS = globals.get_opts()
|
||||||
|
|
||||||
|
#@unittest.skip("SKIPPING 21_timing_sram_test")
|
||||||
|
|
||||||
|
|
||||||
|
class timing_setup_test(unittest.TestCase):
|
||||||
|
|
||||||
|
def runTest(self):
|
||||||
|
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||||
|
# we will manually run lvs/drc
|
||||||
|
OPTS.check_lvsdrc = False
|
||||||
|
OPTS.spice_version="ngspice"
|
||||||
|
OPTS.force_spice = True
|
||||||
|
globals.set_spice()
|
||||||
|
|
||||||
|
import sram
|
||||||
|
import setup_hold
|
||||||
|
|
||||||
|
sh = setup_hold.setup_hold()
|
||||||
|
[one_setup_time, zero_setup_time] = sh.setup_time()
|
||||||
|
|
||||||
|
# reset these options
|
||||||
|
OPTS.check_lvsdrc = True
|
||||||
|
OPTS.spice_version="hspice"
|
||||||
|
OPTS.force_spice = False
|
||||||
|
globals.set_spice()
|
||||||
|
|
||||||
|
if OPTS.tech_name == "freepdk45":
|
||||||
|
self.assertTrue(isclose(one_setup_time,0.0146484375))
|
||||||
|
self.assertTrue(isclose(zero_setup_time,0.008544921875))
|
||||||
|
elif OPTS.tech_name == "scn3me_subm":
|
||||||
|
self.assertTrue(isclose(one_setup_time,0.09521484375)) #diff than hspice
|
||||||
|
self.assertTrue(isclose(zero_setup_time,-0.0244140625))
|
||||||
|
else:
|
||||||
|
self.assertTrue(False) # other techs fail
|
||||||
|
|
||||||
|
# instantiate a copdsay 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()
|
||||||
|
|
@ -4,7 +4,7 @@ Run a regression test on an extracted SRAM to ensure functionality.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from header import header
|
from testutils import header
|
||||||
import sys,os
|
import sys,os
|
||||||
sys.path.append(os.path.join(sys.path[0],".."))
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
import globals
|
import globals
|
||||||
|
|
@ -24,6 +24,8 @@ class sram_func_test(unittest.TestCase):
|
||||||
self.func_test(bank_num=2)
|
self.func_test(bank_num=2)
|
||||||
self.func_test(bank_num=4)
|
self.func_test(bank_num=4)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
def func_test(self, bank_num):
|
def func_test(self, bank_num):
|
||||||
|
|
||||||
import sram
|
import sram
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ Run a regresion test on various srams
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from header import header
|
from testutils import header
|
||||||
import sys,os
|
import sys,os
|
||||||
sys.path.append(os.path.join(sys.path[0],".."))
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
import globals
|
import globals
|
||||||
|
|
@ -22,7 +22,6 @@ class sram_func_test(unittest.TestCase):
|
||||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||||
# we will manually run lvs/drc
|
# we will manually run lvs/drc
|
||||||
OPTS.check_lvsdrc = False
|
OPTS.check_lvsdrc = False
|
||||||
OPTS.use_pex = False
|
|
||||||
|
|
||||||
import sram
|
import sram
|
||||||
|
|
||||||
|
|
@ -51,6 +50,8 @@ class sram_func_test(unittest.TestCase):
|
||||||
|
|
||||||
os.remove(tempspice)
|
os.remove(tempspice)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
# instantiate a copdsay of the class to actually run the test
|
# instantiate a copdsay of the class to actually run the test
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
(OPTS, args) = globals.parse_args()
|
(OPTS, args) = globals.parse_args()
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ Check the .lib file for an SRAM
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from header import header
|
from testutils import header,isdiff
|
||||||
import sys,os
|
import sys,os
|
||||||
sys.path.append(os.path.join(sys.path[0],".."))
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
import globals
|
import globals
|
||||||
|
|
@ -20,11 +20,9 @@ class lib_test(unittest.TestCase):
|
||||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||||
# we will manually run lvs/drc
|
# we will manually run lvs/drc
|
||||||
OPTS.check_lvsdrc = False
|
OPTS.check_lvsdrc = False
|
||||||
OPTS.use_pex = False
|
|
||||||
|
|
||||||
import sram
|
import sram
|
||||||
import lib
|
import lib
|
||||||
import filecmp
|
|
||||||
|
|
||||||
debug.info(1, "Testing timing for sample 2 bit, 16 words SRAM with 1 bank")
|
debug.info(1, "Testing timing for sample 2 bit, 16 words SRAM with 1 bank")
|
||||||
s = sram.sram(word_size=2,
|
s = sram.sram(word_size=2,
|
||||||
|
|
@ -33,22 +31,20 @@ class lib_test(unittest.TestCase):
|
||||||
name="sram_2_16_1_{0}".format(OPTS.tech_name))
|
name="sram_2_16_1_{0}".format(OPTS.tech_name))
|
||||||
OPTS.check_lvsdrc = True
|
OPTS.check_lvsdrc = True
|
||||||
|
|
||||||
|
|
||||||
tempspice = OPTS.openram_temp + "temp.sp"
|
tempspice = OPTS.openram_temp + "temp.sp"
|
||||||
s.sp_write(tempspice)
|
s.sp_write(tempspice)
|
||||||
|
|
||||||
curpath=os.path.dirname(os.path.realpath(__file__)) + "/"
|
|
||||||
filename = s.name + ".lib"
|
filename = s.name + ".lib"
|
||||||
libname = curpath + filename
|
libname = OPTS.openram_temp + filename
|
||||||
lib.lib(libname,s,tempspice)
|
lib.lib(libname,s,tempspice)
|
||||||
|
|
||||||
# let's diff the result with a golden model
|
# let's diff the result with a golden model
|
||||||
golden = "{0}/golden/{1}".format(os.path.dirname(os.path.realpath(__file__)),filename)
|
golden = "{0}/golden/{1}".format(os.path.dirname(os.path.realpath(__file__)),filename)
|
||||||
self.assertEqual(filecmp.cmp(libname,golden),True)
|
self.assertEqual(isdiff(libname,golden),True)
|
||||||
|
|
||||||
os.system("rm {0}".format(libname))
|
os.system("rm {0}".format(libname))
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
# instantiate a copdsay of the class to actually run the test
|
# instantiate a copdsay of the class to actually run the test
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ Check the LEF file for an SRMA
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from header import header
|
from testutils import header,isdiff
|
||||||
import sys,os
|
import sys,os
|
||||||
sys.path.append(os.path.join(sys.path[0],".."))
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
import globals
|
import globals
|
||||||
|
|
@ -23,7 +23,6 @@ class lef_test(unittest.TestCase):
|
||||||
|
|
||||||
import sram
|
import sram
|
||||||
import lef
|
import lef
|
||||||
import filecmp
|
|
||||||
|
|
||||||
debug.info(1, "Testing LEF for sample 2 bit, 16 words SRAM with 1 bank")
|
debug.info(1, "Testing LEF for sample 2 bit, 16 words SRAM with 1 bank")
|
||||||
s = sram.sram(word_size=2,
|
s = sram.sram(word_size=2,
|
||||||
|
|
@ -33,22 +32,21 @@ class lef_test(unittest.TestCase):
|
||||||
|
|
||||||
OPTS.check_lvsdrc = True
|
OPTS.check_lvsdrc = True
|
||||||
|
|
||||||
curpath=os.path.dirname(os.path.realpath(__file__)) + "/"
|
|
||||||
gdsfile = s.name + ".gds"
|
gdsfile = s.name + ".gds"
|
||||||
leffile = s.name + ".lef"
|
leffile = s.name + ".lef"
|
||||||
gdsname = curpath + gdsfile
|
gdsname = OPTS.openram_temp + gdsfile
|
||||||
lefname = curpath + leffile
|
lefname = OPTS.openram_temp + leffile
|
||||||
s.gds_write(gdsname)
|
s.gds_write(gdsname)
|
||||||
lef.lef(gdsname,lefname,s)
|
lef.lef(gdsname,lefname,s)
|
||||||
|
|
||||||
# let's diff the result with a golden model
|
# let's diff the result with a golden model
|
||||||
golden = "{0}/golden/{1}".format(os.path.dirname(os.path.realpath(__file__)),leffile)
|
golden = "{0}/golden/{1}".format(os.path.dirname(os.path.realpath(__file__)),leffile)
|
||||||
self.assertEqual(filecmp.cmp(lefname,golden),True)
|
self.assertEqual(isdiff(lefname,golden),True)
|
||||||
|
|
||||||
os.system("rm {0}".format(gdsname))
|
os.system("rm {0}".format(gdsname))
|
||||||
os.system("rm {0}".format(lefname))
|
os.system("rm {0}".format(lefname))
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
# instantiate a copdsay of the class to actually run the test
|
# instantiate a copdsay of the class to actually run the test
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ Check the .v file for an SRAM
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from header import header
|
from testutils import header,isdiff
|
||||||
import sys,os
|
import sys,os
|
||||||
sys.path.append(os.path.join(sys.path[0],".."))
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
import globals
|
import globals
|
||||||
|
|
@ -23,7 +23,6 @@ class verilog_test(unittest.TestCase):
|
||||||
|
|
||||||
import sram
|
import sram
|
||||||
import verilog
|
import verilog
|
||||||
import filecmp
|
|
||||||
|
|
||||||
debug.info(1, "Testing Verilog for sample 2 bit, 16 words SRAM with 1 bank")
|
debug.info(1, "Testing Verilog for sample 2 bit, 16 words SRAM with 1 bank")
|
||||||
s = sram.sram(word_size=2,
|
s = sram.sram(word_size=2,
|
||||||
|
|
@ -33,18 +32,19 @@ class verilog_test(unittest.TestCase):
|
||||||
|
|
||||||
OPTS.check_lvsdrc = True
|
OPTS.check_lvsdrc = True
|
||||||
|
|
||||||
curpath=os.path.dirname(os.path.realpath(__file__)) + "/"
|
|
||||||
vfile = s.name + ".v"
|
vfile = s.name + ".v"
|
||||||
vname = curpath + vfile
|
vname = OPTS.openram_temp + vfile
|
||||||
verilog.verilog(vname,s)
|
verilog.verilog(vname,s)
|
||||||
|
|
||||||
|
|
||||||
# let's diff the result with a golden model
|
# let's diff the result with a golden model
|
||||||
golden = "{0}/golden/{1}".format(os.path.dirname(os.path.realpath(__file__)),vfile)
|
golden = "{0}/golden/{1}".format(os.path.dirname(os.path.realpath(__file__)),vfile)
|
||||||
self.assertEqual(filecmp.cmp(vname,golden),True)
|
self.assertEqual(isdiff(vname,golden),True)
|
||||||
|
|
||||||
os.system("rm {0}".format(vname))
|
os.system("rm {0}".format(vname))
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
# instantiate a copdsay of the class to actually run the test
|
# instantiate a copdsay of the class to actually run the test
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
(OPTS, args) = globals.parse_args()
|
(OPTS, args) = globals.parse_args()
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ check that these files are right.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from header import header
|
from testutils import header
|
||||||
import sys,os
|
import sys,os
|
||||||
sys.path.append(os.path.join(sys.path[0],".."))
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
import globals
|
import globals
|
||||||
|
|
@ -24,10 +24,8 @@ class openram_test(unittest.TestCase):
|
||||||
|
|
||||||
debug.info(1, "Testing top-level openram.py with 2-bit, 16 word SRAM.")
|
debug.info(1, "Testing top-level openram.py with 2-bit, 16 word SRAM.")
|
||||||
out_file = "testsram"
|
out_file = "testsram"
|
||||||
# get the directory under the test modules
|
|
||||||
out_path=os.path.dirname(os.path.realpath(__file__))
|
|
||||||
# make a temp directory for output
|
# make a temp directory for output
|
||||||
out_path += "/testsram"
|
out_path = OPTS.openram_temp + out_file
|
||||||
|
|
||||||
# make sure we start without the files existing
|
# make sure we start without the files existing
|
||||||
if os.path.exists(out_path):
|
if os.path.exists(out_path):
|
||||||
|
|
@ -73,6 +71,7 @@ class openram_test(unittest.TestCase):
|
||||||
shutil.rmtree(out_path, ignore_errors=True)
|
shutil.rmtree(out_path, ignore_errors=True)
|
||||||
self.assertEqual(os.path.exists(out_path),False)
|
self.assertEqual(os.path.exists(out_path),False)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
# instantiate a copdsay of the class to actually run the test
|
# instantiate a copdsay of the class to actually run the test
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
|
|
||||||
def header(str, tec):
|
|
||||||
tst = "Running Test for:"
|
|
||||||
print "\n"
|
|
||||||
print " ______________________________________________________________________________ "
|
|
||||||
print "|==============================================================================|"
|
|
||||||
print "|=========" + tst.center(60) + "=========|"
|
|
||||||
print "|=========" + tec.center(60) + "=========|"
|
|
||||||
print "|=========" + str.center(60) + "=========|"
|
|
||||||
print "|==============================================================================|"
|
|
||||||
|
|
@ -9,8 +9,8 @@ import globals
|
||||||
(OPTS, args) = globals.parse_args()
|
(OPTS, args) = globals.parse_args()
|
||||||
del sys.argv[1:]
|
del sys.argv[1:]
|
||||||
|
|
||||||
import header
|
from testutils import header
|
||||||
header.header(__file__, OPTS.tech_name)
|
header(__file__, OPTS.tech_name)
|
||||||
|
|
||||||
# get a list of all files in the tests directory
|
# get a list of all files in the tests directory
|
||||||
files = os.listdir(sys.path[0])
|
files = os.listdir(sys.path[0])
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -0,0 +1,43 @@
|
||||||
|
|
||||||
|
|
||||||
|
def isclose(value1,value2,error_tolerance=1e-2):
|
||||||
|
""" This is used to compare relative values. """
|
||||||
|
import debug
|
||||||
|
relative_diff = abs(value1 - value2) / max(value1,value2)
|
||||||
|
check = relative_diff <= error_tolerance
|
||||||
|
if not check:
|
||||||
|
debug.info(1,"NOT CLOSE {0} {1} relative diff={2}".format(value1,value2,relative_diff))
|
||||||
|
else:
|
||||||
|
debug.info(2,"CLOSE {0} {1} relative diff={2}".format(value1,value2,relative_diff))
|
||||||
|
return (check)
|
||||||
|
|
||||||
|
def isdiff(file1,file2):
|
||||||
|
""" This is used to compare two files and display the diff if they are different.. """
|
||||||
|
import debug
|
||||||
|
import filecmp
|
||||||
|
import difflib
|
||||||
|
check = filecmp.cmp(file1,file2)
|
||||||
|
if not check:
|
||||||
|
debug.info(2,"MISMATCH {0} {1}".format(file1,file2))
|
||||||
|
f1 = open(file1,"r")
|
||||||
|
s1 = f1.readlines()
|
||||||
|
f2 = open(file2,"r")
|
||||||
|
s2 = f2.readlines()
|
||||||
|
for line in difflib.unified_diff(s1, s2):
|
||||||
|
debug.error(line)
|
||||||
|
else:
|
||||||
|
debug.info(2,"MATCH {0} {1}".format(file1,file2))
|
||||||
|
return (check)
|
||||||
|
|
||||||
|
def header(filename, technology):
|
||||||
|
tst = "Running Test for:"
|
||||||
|
print "\n"
|
||||||
|
print " ______________________________________________________________________________ "
|
||||||
|
print "|==============================================================================|"
|
||||||
|
print "|=========" + tst.center(60) + "=========|"
|
||||||
|
print "|=========" + technology.center(60) + "=========|"
|
||||||
|
print "|=========" + filename.center(60) + "=========|"
|
||||||
|
import globals
|
||||||
|
OPTS = globals.get_opts()
|
||||||
|
print "|=========" + OPTS.openram_temp.center(60) + "=========|"
|
||||||
|
print "|==============================================================================|"
|
||||||
|
|
@ -24,3 +24,7 @@ def auto_measure_libcell(pin_list, name, units, layer):
|
||||||
for pin in pin_list:
|
for pin in pin_list:
|
||||||
cell[str(pin)] = gdsPinToOffset(cell_vlsi.readPin(str(pin)))
|
cell[str(pin)] = gdsPinToOffset(cell_vlsi.readPin(str(pin)))
|
||||||
return cell
|
return cell
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,16 @@ class vector():
|
||||||
"""
|
"""
|
||||||
return vector(other[0]- self.x, other[1] - self.y)
|
return vector(other[0]- self.x, other[1] - self.y)
|
||||||
|
|
||||||
|
def snap_to_grid(self, offset):
|
||||||
|
"""
|
||||||
|
Changes the coodrinate to match the grid settings
|
||||||
|
"""
|
||||||
|
grid = tech.drc["grid"]
|
||||||
|
# this gets the nearest integer value
|
||||||
|
off_in_grid = int(round(round((offset / grid), 2), 0))
|
||||||
|
offset = off_in_grid * grid
|
||||||
|
return offset
|
||||||
|
|
||||||
def rotate(self):
|
def rotate(self):
|
||||||
""" pass a copy of rotated vector, without altering the vector! """
|
""" pass a copy of rotated vector, without altering the vector! """
|
||||||
return vector(self.y,self.x)
|
return vector(self.y,self.x)
|
||||||
|
|
@ -94,12 +104,9 @@ class vector():
|
||||||
x_factor=x_factor[0]
|
x_factor=x_factor[0]
|
||||||
return vector(self.x*x_factor,self.y*y_factor)
|
return vector(self.x*x_factor,self.y*y_factor)
|
||||||
|
|
||||||
def snap_to_grid(self, offset):
|
def rotate_scale(self, x_factor, y_factor=None):
|
||||||
"""
|
""" pass a copy of scaled vector, without altering the vector! """
|
||||||
Changes the coodrinate to match the grid settings
|
if y_factor==None:
|
||||||
"""
|
y_factor=x_factor[1]
|
||||||
grid = tech.drc["grid"]
|
x_factor=x_factor[0]
|
||||||
# this gets the nearest integer value
|
return vector(self.y*x_factor,self.x*y_factor)
|
||||||
off_in_grid = int(round(round((offset / grid), 2), 0))
|
|
||||||
offset = off_in_grid * grid
|
|
||||||
return offset
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ class wire(path):
|
||||||
name = "wire_{0}".format(wire.unique_wire_id)
|
name = "wire_{0}".format(wire.unique_wire_id)
|
||||||
wire.unique_wire_id += 1
|
wire.unique_wire_id += 1
|
||||||
design.design.__init__(self, name)
|
design.design.__init__(self, name)
|
||||||
debug.info(2, "create wire obj {0}".format(name))
|
debug.info(3, "create wire obj {0}".format(name))
|
||||||
|
|
||||||
self.layer_stack = layer_stack
|
self.layer_stack = layer_stack
|
||||||
self.position_list = position_list
|
self.position_list = position_list
|
||||||
|
|
@ -37,7 +37,7 @@ class wire(path):
|
||||||
# wires and paths should not be offset to (0,0)
|
# wires and paths should not be offset to (0,0)
|
||||||
|
|
||||||
def setup_layers(self):
|
def setup_layers(self):
|
||||||
(vert_layer, via_layer, horiz_layer) = self.layer_stack
|
(horiz_layer, via_layer, vert_layer) = self.layer_stack
|
||||||
if (via_layer != None):
|
if (via_layer != None):
|
||||||
self.via_layer_name = via_layer
|
self.via_layer_name = via_layer
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,8 @@ os.environ["MGC_TMPDIR"] = "/tmp"
|
||||||
#OpenRAM Paths
|
#OpenRAM Paths
|
||||||
|
|
||||||
DRCLVS_HOME= PDK_DIR+"/ncsu_basekit/techfile/calibre"
|
DRCLVS_HOME= PDK_DIR+"/ncsu_basekit/techfile/calibre"
|
||||||
os.environ["DRCLVS_HOME"] = DRCLVS_HOME
|
os.environ["DRCLVS_HOME"] = DRCLVS_HOME
|
||||||
|
|
||||||
os.environ["SPICE_MODEL_DIR"] = PDK_DIR+"/ncsu_basekit/models/hspice/tran_models/models_nom"
|
os.environ["SPICE_MODEL_DIR"] = PDK_DIR+"/ncsu_basekit/models/hspice/tran_models/models_nom"
|
||||||
|
|
||||||
##########################
|
##########################
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,12 @@ os.environ["MGC_TMPDIR"] = "/tmp"
|
||||||
# OpenRAM Paths
|
# OpenRAM Paths
|
||||||
OPENRAM_TECH=os.path.abspath(os.environ.get("OPENRAM_TECH"))
|
OPENRAM_TECH=os.path.abspath(os.environ.get("OPENRAM_TECH"))
|
||||||
DRCLVS_HOME=OPENRAM_TECH+"/scn3me_subm/tech"
|
DRCLVS_HOME=OPENRAM_TECH+"/scn3me_subm/tech"
|
||||||
os.environ["DRCLVS_HOME"] = DRCLVS_HOME
|
os.environ["DRCLVS_HOME"] = DRCLVS_HOME
|
||||||
os.environ["SPICE_MODEL_DIR"] = "/mada/software/techfiles/scn3me_subm"
|
# You can override the spice model diretory in the environment
|
||||||
|
try:
|
||||||
|
SPICE_MODEL_DIR = os.path.abspath(os.environ.get("SPICE_MODEL_DIR"))
|
||||||
|
except:
|
||||||
|
os.environ["SPICE_MODEL_DIR"] = "/mada/software/techfiles/scn3me_subm"
|
||||||
|
|
||||||
##########################
|
##########################
|
||||||
# Paths required for OPENRAM to function
|
# Paths required for OPENRAM to function
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue