fix the conflicts for merge

This commit is contained in:
Bin wu 2016-11-17 17:19:48 -08:00
commit a22ba2087b
85 changed files with 988 additions and 692 deletions

Binary file not shown.

2
README
View File

@ -3,7 +3,7 @@ BASIC SETUP
-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)
3) a setup script for each technology
4) a technology directory for each technology with the base cells

View File

@ -29,4 +29,12 @@ hierarchical_predecode3x8 to hierarchical_predecode class
Fix stimuli.py to be more readable.
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

View File

@ -867,7 +867,7 @@ class bank(design.design):
for i in range(2):
ff_index = i + self.row_addr_size
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)
line_index = self.num_central_bus - 2 + i
@ -913,7 +913,7 @@ class bank(design.design):
mid2 = col_decoder_out_position + vector(connection_width,
-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],
offset=col_decoder_out_position)
@ -922,9 +922,9 @@ class bank(design.design):
elif(self.col_addr_size == 1):
ff_index = self.row_addr_size
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)
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)
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
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
- vector(0, 0.5 * drc["minwidth_metal3"]))
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):
# 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
- vector(0, 0.5 * drc["minwidth_metal3"]))
address_position = vector(self.left_vdd_x_offset,
@ -1083,7 +1083,7 @@ class bank(design.design):
""" CLK connection from central bus to MSF address
should we move this somewhere else hard to find when modify"""
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"],
2 * drc["minwidth_metal2"]))
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
end = vector(self.left_vdd_x_offset, start.y + 3 * drc["minwidth_metal3"])
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
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"]
- self.m1m2_via.width)
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
setattr(self,"{0}_position".format(self.control_signals[i]),

View File

@ -90,6 +90,7 @@ def run_drc(name, gds_name):
f.close()
# run drc
cwd = os.getcwd()
os.chdir(OPTS.openram_temp)
errfile = "%s%s.drc.err" % (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)
debug.info(1, cmd)
os.system(cmd)
os.chdir(cwd)
# check the result for these lines in the summary:
# TOTAL Original Layer Geometries: 106 (157)
@ -163,6 +165,7 @@ def run_lvs(name, gds_name, sp_name):
f.close()
# run LVS
cwd = os.getcwd()
os.chdir(OPTS.openram_temp)
errfile = "%s%s.lvs.err" % (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)
debug.info(2, cmd)
os.system(cmd)
os.chdir(cwd)
# check the result for these lines in the summary:
f = open(lvs_runset['lvsReportFile'], "r")
@ -265,6 +269,7 @@ def run_pex(name, gds_name, sp_name, output=None):
f.close()
# run pex
cwd = os.getcwd()
os.chdir(OPTS.openram_temp)
errfile = "{0}{1}.pex.err".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)
debug.info(2, cmd)
os.system(cmd)
os.chdir(cwd)
# also check the output file
f = open(outfile, "r")

View File

@ -27,7 +27,11 @@ def relative_compare(value1,value2):
def parse_output(filename, key):
"""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()
val = re.search(r"{0}\s*=\s*(-?\d+.?\d*\S*)\s+.*".format(key), contents)
if val != None:

View File

@ -6,6 +6,7 @@ import tech
import math
import stimuli
import charutils as ch
import utils
OPTS = globals.get_opts()
@ -262,20 +263,11 @@ class delay():
# run until the last cycle time
end_time = self.cycle_times[-1]
self.sf.write(".TRAN 5p {0}n\n".format(end_time))
if OPTS.spice_version == "hspice":
# create plots for all signals
self.sf.write(".OPTIONS POST=1 PROBE\n")
self.sf.write(".probe V(*)\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")
self.sf.write(".OPTIONS POST=1 PROBE\n")
# create plots for all signals
self.sf.write(".probe V(*)\n")
# end the stimulus file
self.sf.write(".end\n")
@ -353,20 +345,19 @@ class delay():
target_period = 0.5 * (ub_period + lb_period)
debug.info(1, "MinPeriod Search: {0}ns (ub: {1} lb: {2})".format(target_period,
ub_period,
lb_period))
ub_period,
lb_period))
(success, delay_out) = self.try_period(feasible_period, target_period, data_value)
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
else:
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)
return (target_period, delay_out)

View File

@ -165,20 +165,12 @@ class setup_hold():
def write_control(self, period):
# transient window
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")
if OPTS.spice_version == "hspice":
self.sf.write(".probe V(*)\n")
# end the stimulus file
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")
# create plots for all signals
self.sf.write(".probe V(*)\n")
# end the stimulus file
self.sf.write(".end\n")
def bidir_search(self, correct_value, noise_margin, measure_name, mode):
""" 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.
"""
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
# theis time.
# this time by half a period.
if mode == "HOLD":
target_time = 1.5 * period
lower_bound = 0.5*period
@ -212,6 +206,8 @@ class setup_hold():
setuphold_time = target_time - period
else:
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,
lower_bound,
upper_bound,
@ -220,6 +216,10 @@ class setup_hold():
debug.error("Initial period/target hold time fails for data value",2)
# 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":
target_time -= 0.5 * (upper_bound - lower_bound)
else:
@ -269,6 +269,8 @@ class setup_hold():
setuphold_time = target_time - period
else:
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

View File

@ -445,23 +445,31 @@ def write_supply(stim_file, vdd_name, gnd_name, vdd_voltage, gnd_voltage):
def run_sim():
"""Run hspice in batch mode and output rawfile to parse."""
temp_stim = "{0}stim.sp".format(OPTS.openram_temp)
if OPTS.spice_version == "hspice":
# 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,
OPTS.openram_temp)
valid_retcode=0
else:
cmd_args = "-b -i {1} -o {2}timing.lis 2>&1 /dev/null".format(OPTS.spice_exe,
temp_stim,
OPTS.openram_temp)
cmd = "{0} -b -o {2}timing.lis {1}".format(OPTS.spice_exe,
temp_stim,
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)
retcode = subprocess.call([OPTS.spice_exe, cmd_args], stdout=FNULL, stderr=FNULL)
FNULL.close()
spice_stdout = open("{0}spice_stdout.log".format(OPTS.openram_temp), 'w')
spice_stderr = open("{0}spice_stderr.log".format(OPTS.openram_temp), 'w')
if (retcode > 0):
debug.error("Spice simulation error: " + OPTS.spice_exe + " " + cmd_args)
sys.exit(-1)
debug.info(3, cmd)
retcode = subprocess.call(cmd, stdout=spice_stdout, stderr=spice_stderr, shell=True)
spice_stdout.close()
spice_stderr.close()
if (retcode > valid_retcode):
debug.error("Spice simulation error: " + cmd, -1)

View File

@ -18,7 +18,7 @@ class contact(design.design):
dimensions[1],
contact.unique_contact_id)
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
self.layer_stack = layer_stack
@ -40,8 +40,8 @@ class contact(design.design):
self.offset_attributes(coordinate)
self.translate(coordinate)
self.height = max(obj.offset[1] + obj.height for obj in self.objs)
self.width = max(obj.offset[0] + obj.width for obj in self.objs)
self.height = max(obj.offset.y + obj.height for obj in self.objs)
self.width = max(obj.offset.x + obj.width for obj in self.objs)
def setup_layers(self):
(first_layer, via_layer, second_layer) = self.layer_stack

View File

@ -146,7 +146,7 @@ class control_logic(design.design):
# Height and width
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):
""" Routing between modules """
@ -175,11 +175,11 @@ class control_logic(design.design):
# msf_control inputs
correct = vector(0, 0.5 * drc["minwidth_metal2"])
def translate_inputs(pt1,pt2):
return pt1 + pt2.rotate().scale(1,-1) - correct
return pt1 + pt2.rotate_scale(1,-1) - correct
# msf_control outputs
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)
pt1 = self.offset_msf_control
@ -197,21 +197,21 @@ class control_logic(design.design):
# clk , vdd
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
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
# gnd
self.msf_control_gnd_positions = []
for gnd_offset in self.msf_control.gnd_positions:
offset = self.offset_msf_control + vector(self.msf_control.height,
- gnd_offset[0])
- gnd_offset.x)
self.msf_control_gnd_positions.append(offset - correct)
def add_1st_row(self,y_off):
# 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.add_inst(name="clk_inverter",
mod=self.inv4,
@ -246,7 +246,7 @@ class control_logic(design.design):
self.set_nand2_nor2_pin("nand2",[1,1])
# 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
x_off = base_x + total_rail_gap + self.replica_bitline_gap
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):
# 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",
mod=self.NAND3,
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])
# 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",
mod=self.NAND3,
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])
# 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",
offset=self.nand3_1_Z_position,
width=drc["minwidth_metal1"],
@ -315,7 +315,7 @@ class control_logic(design.design):
height=-nand3_to_inv_connection_height)
# 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.add_inst(name="inv_rblk",
mod=self.inv,
@ -336,7 +336,7 @@ class control_logic(design.design):
self.set_inv2345_pins(inv_name="inv3", inv_scale=[1, 1])
# 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.add_inst(name="inv_w_en1",
mod=self.inv,
@ -344,7 +344,7 @@ class control_logic(design.design):
mirror="RO")
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.add_inst(name="inv_w_en2",
mod=self.inv,
@ -392,7 +392,7 @@ class control_logic(design.design):
def add_msf_control_routing(self):
# 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)
for i in range(self.num_rails_1):
correct = vector((i+1) * self.rail_offset_gap, 0)
@ -401,18 +401,18 @@ class control_logic(design.design):
offset=offset,
width=drc["minwidth_metal2"],
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)
for i in range(self.num_rails_2):
offset = [rail2_start_x + i * self.rail_offset_gap,
self.output_port_gap]
offset = vector(rail2_start_x + i * self.rail_offset_gap,
self.output_port_gap)
self.add_rect(layer="metal2",
offset=offset,
width=drc["minwidth_metal2"],
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):
# First rail routing left
@ -425,7 +425,7 @@ class control_logic(design.design):
line_x_offset = self.rail_1_x_offsets[line_indices[i]]
self.add_rect(layer="metal1",
offset=offset,
width=line_x_offset - offset[0] + drc["minwidth_metal2"],
width=line_x_offset - offset.x + drc["minwidth_metal2"],
height=drc["minwidth_metal1"])
correct1 = vector(self.gap_between_rails, - self.via_shift)
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])
self.add_rect(layer="metal1",
offset=base,
width=offset[0] - line_x_offset,
width=offset.x - line_x_offset,
height=drc["minwidth_metal1"])
self.add_via(layers=("metal1", "via1", "metal2"),
offset=base + correct1,
rotate=90)
# OE_bar [Bus # 1] to nor2 B input
layer_stack = ("metal2", "via1", "metal1")
layer_stack = ("metal1", "via1", "metal2")
start = self.nor2_1_B_position
mid1 = [self.nor2_1_B_position[0] + 2 * drc["minwidth_metal2"], start[1]]
mid2 = [mid1[0], self.nor2_1_gnd_position[1] - 2 * drc["minwidth_metal1"]]
mid3 = [self.rail_1_x_offsets[1] + 0.5 * drc["minwidth_metal2"], mid2[1]]
end = [mid3[0], self.output_port_gap]
mid1 = vector(self.nor2_1_B_position.x+ 2 * drc["minwidth_metal2"],
start.y)
mid2 = vector(mid1.x,
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])
layer_stack = ("metal1")
start = [self.inv1_Z_position[0], self.inv1_Z_position[1] + 0.5 * drc["minwidth_metal1"]]
mid1 = [start[0] + drc["minwidth_metal2"], start[1]]
mid2 = [mid1[0], self.nand2_1_B_position
[1] + 0.5 * drc["minwidth_metal1"]]
end = [self.nand2_1_B_position[0], mid2[1]]
start = self.inv1_Z_position+ vector(0, + 0.5 * drc["minwidth_metal1"])
mid1 = start + vector(drc["minwidth_metal2"], 0)
mid2 = vector(mid1.x,
self.nand2_1_B_position.y + 0.5 * drc["minwidth_metal1"])
end = [self.nand2_1_B_position.x, mid2.y]
self.add_path(layer_stack, [start, mid1, mid2, end])
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]]
self.add_rect(layer="metal1",
offset=offset,
width=line_x_offset - offset[0] + drc["minwidth_metal2"],
width=line_x_offset - offset.x+ drc["minwidth_metal2"],
height=drc["minwidth_metal1"])
self.add_via(layers=("metal1", "via1", "metal2"),
offset=[line_x_offset + self.gap_between_rails,
offset[1] - self.via_shift],
offset.y- self.via_shift],
rotate=90)
# Replica bitline (rblk to replica bitline input)
layer_stack = ("metal2", "via1", "metal1")
start = [self.rail_2_x_offsets[1] + 0.5 * drc["minwidth_metal2"],
self.output_port_gap]
mid1 = [start[0], 0.5 * drc["minwidth_metal1"]]
end = [self.replica_en_offset[0], mid1[1]]
layer_stack = ("metal1", "via1", "metal2")
start = vector(self.rail_2_x_offsets[1] + 0.5 * drc["minwidth_metal2"],
self.output_port_gap)
mid1 = vector(start.x, 0.5 * drc["minwidth_metal1"])
end = vector(self.replica_en_offset.x, mid1.y)
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",
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)
self.add_rect(layer="metal3",
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"])
self.add_via(layers=("metal2", "via2", "metal3"),
offset=start)
@ -536,7 +539,7 @@ class control_logic(design.design):
self.add_rect(layer="metal1",
offset=self.nand3_2_vdd_position,
width=(rail_2_x + drc["minwidth_metal2"]
- self.nand3_2_vdd_position[0]),
- self.nand3_2_vdd_position.x),
height=drc["minwidth_metal1"])
# Connection in horizontal metal2 vdd rail
@ -551,10 +554,10 @@ class control_logic(design.design):
# Connection of msf_vdd to inv1 vdd
self.add_rect(layer="metal1",
offset=[self.msf_control_vdd_position[0],
offset=[self.msf_control_vdd_position.x,
self.inv1_vdd_position[1]],
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"])
@ -569,25 +572,25 @@ class control_logic(design.design):
for gnd_offset in self.msf_control_gnd_positions:
self.add_rect(layer="metal2",
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"]),
height=drc["minwidth_metal2"])
# Connect msf_control gnd to nand3 gnd
self.add_rect(layer="metal1",
offset=self.nor2_1_gnd_position,
width=self.offset_replica_bitline[0],
width=self.offset_replica_bitline.x,
height=drc["minwidth_metal1"])
self.add_via(layers=("metal1", "via1", "metal2"),
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)
# nand3 gnd to replica bitline gnd
self.add_rect(layer="metal1",
offset=self.nand3_2_gnd_position,
width=(self.offset_replica_bitline[0]
- self.nand3_2_gnd_position[0]),
width=(self.offset_replica_bitline.x
- self.nand3_2_gnd_position.x),
height=drc["minwidth_metal1"])
def add_input_routing(self):
@ -598,13 +601,13 @@ class control_logic(design.design):
self.OEb_position = self.msf_control_OEb_position
# 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)
# 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"])
mid1 = vector(self.inv1_A_position[0] - 2 * drc["minwidth_metal2"],
mid1 = vector(self.inv1_A_position.x- 2 * drc["minwidth_metal2"],
start.y)
mid2 = vector(mid1.x, clk_y)
self.clk_position = vector(0, mid2[1])
@ -614,17 +617,17 @@ class control_logic(design.design):
# clk line to msf_control_clk
self.add_rect(layer="metal1",
offset=[self.msf_control_clk_position[0],
offset=[self.msf_control_clk_position.x,
self.clk_position[1]],
width=drc["minwidth_metal1"],
height=(self.msf_control_clk_position[1]
height=(self.msf_control_clk_position.y
- self.clk_position[1]))
# clk connection to nor2 A input
start = [self.inv1_A_position[0] - 2 * drc["minwidth_metal2"],
self.inv1_A_position[1] + 0.5 * drc["minwidth_metal1"]]
mid1 = [start[0] - 3 * drc["minwidth_metal2"], start[1]]
mid2 = [mid1[0], self.nor2_1_A_position[1]]
start = self.inv1_A_position + vector(- 2 * drc["minwidth_metal2"],
0.5 * drc["minwidth_metal1"])
mid1 = start - vector(3 * drc["minwidth_metal2"], 0)
mid2 = [mid1.x, self.nor2_1_A_position.y]
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)
self.add_via(layers=("metal2", "via2", "metal3"),
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
correct = vector(drc["minwidth_metal2"], 0)
@ -671,7 +674,7 @@ class control_logic(design.design):
self.add_rect(layer="metal2",
offset=self.tri_en_bar_position,
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"),
offset=self.tri_en_bar_position)
@ -691,6 +694,6 @@ class control_logic(design.design):
self.add_rect(layer="metal2",
offset=self.s_en_position,
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"),
offset=self.s_en_position)

View File

@ -14,19 +14,6 @@ import importlib
# Current version of OpenRAM.
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"
@ -81,6 +68,25 @@ def parse_args():
def get_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):
"""Initialize the technology, paths, simulators, etc."""
@ -134,7 +140,15 @@ def set_calibre():
debug.warning("Calibre not found. Not performing inline LVS/DRC.")
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():
""" Set up the non-tech related 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}/characterizer".format(OPENRAM_HOME))
if not OPTS.openram_temp.endswith('/'):
OPTS.openram_temp += "/"
debug.info(1, "Temporary files saved in " + OPTS.openram_temp)
# we should clean up this temp directory after execution...
if os.path.exists(OPTS.openram_temp):
shutil.rmtree(OPTS.openram_temp, ignore_errors=True)
cleanup_paths()
# make the directory if it doesn't exist
try:
@ -185,23 +196,48 @@ def set_spice():
debug.info(2,"Finding spice...")
global OPTS
# set the input dir for spice files if using ngspice (not needed for
# hspice)
OPTS.spice_exe = ""
# 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":
os.environ["NGSPICE_INPUT_DIR"] = "{0}".format(OPTS.openram_temp)
# search for calibre in the path
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:
if OPTS.spice_exe == "":
# 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
def import_tech():
global OPTS

View File

@ -329,7 +329,7 @@ class hierarchical_decoder(design.design):
# ADDING LABELS FOR OUTPUT SIDE OF THE 3:8 PRE-DECODER
for inv_3x8 in range(8):
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:
xoffset = 0
@ -403,7 +403,7 @@ class hierarchical_decoder(design.design):
mirror=mirror)
self.add_rect(layer="metal1",
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"],
height=y_dir * drc["minwidth_metal1"])
@ -454,9 +454,9 @@ class hierarchical_decoder(design.design):
# add output label for Row Decoder INVERTER array.
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:
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):
if ((row % 2) == 0):
@ -502,10 +502,10 @@ class hierarchical_decoder(design.design):
+ inv_2x4 * (self.inv.height))
if (inv_2x4 % 2 == 0):
pin_y = self.inv.Z_position[1]
pin_y = self.inv.Z_position.y
else:
pin_y = (self.inv.height - drc["minwidth_metal1"]
- self.inv.Z_position[1])
- self.inv.Z_position.y)
yoffset = current_inv_height + pin_y
self.add_extend_rails(yoffset = yoffset,
@ -519,10 +519,10 @@ class hierarchical_decoder(design.design):
+ self.no_of_pre2x4 * self.pre2_4.height
if (inv_3x8 % 2 == 0):
pin_y = self.inv.Z_position[1]
pin_y = self.inv.Z_position.y
else:
pin_y = (self.inv.height - drc["minwidth_metal1"]
- self.inv.Z_position[1])
- self.inv.Z_position.y)
yoffset = current_inv_height + pin_y
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)
if (row_index % 2 == 0):
yoffset_A = current_inv_height + self.nand2.A_position[1]
yoffset_B = current_inv_height + self.nand2.B_position[1]
yoffset_A = current_inv_height + self.nand2.A_position.y
yoffset_B = current_inv_height + self.nand2.B_position.y
else:
base = current_inv_height + self.inv.height - drc["minwidth_metal1"]
yoffset_A = base - self.nand2.A_position[1]
yoffset_B = base - self.nand2.B_position[1]
yoffset_A = base - self.nand2.A_position.y
yoffset_B = base - self.nand2.B_position.y
row_index = row_index + 1
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)
if (row_index % 2 == 0):
yoffset_A = current_inv_height + self.nand3.A_position[1]
yoffset_B = current_inv_height + self.nand3.B_position[1]
yoffset_C = current_inv_height + self.nand3.C_position[1]
yoffset_A = current_inv_height + self.nand3.A_position.y
yoffset_B = current_inv_height + self.nand3.B_position.y
yoffset_C = current_inv_height + self.nand3.C_position.y
contact_C_yoffset = yoffset_C - self.contact_shift
else:
base = current_inv_height + self.inv.height - drc["minwidth_metal1"]
yoffset_A = base - self.nand3.A_position[1]
yoffset_B = base - self.nand3.B_position[1]
yoffset_C = base - self.nand3.C_position[1]
yoffset_A = base - self.nand3.A_position.y
yoffset_B = base - self.nand3.B_position.y
yoffset_C = base - self.nand3.C_position.y
contact_C_yoffset = yoffset_C
row_index = row_index + 1

View File

@ -150,12 +150,12 @@ class hierarchical_predecode(design.design):
y_off = nand_input * (self.nand.height)
mirror = "R0"
offset = [self.x_off_nand + self.nand.width,
y_off + self.nand.Z_position[1]]
y_off + self.nand.Z_position.y]
else:
y_off = (nand_input + 1) * (self.nand.height)
mirror = "MX"
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,
mod=self.nand,
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):
self.add_rect(layer="metal1",
offset=[self.rails_x_offset[inv_rout],
inv_in_offset[1]],
width=inv_in_offset[0] - self.rails_x_offset[inv_rout] + drc["minwidth_metal2"],
inv_in_offset.y],
width=inv_in_offset.x - self.rails_x_offset[inv_rout] + drc["minwidth_metal2"],
height=drc["minwidth_metal1"])
self.add_via(layers=("metal1", "via1", "metal2"),
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)
def route_input_inverters_vdd(self,inv_vdd_offset):
self.add_rect(layer="metal1",
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"])
def route_input_inverters_gnd(self,inv_gnd_offset):
self.add_rect(layer="metal1",
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"])

View File

@ -65,22 +65,22 @@ class hierarchical_predecode2x4(hierarchical_predecode):
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_gnd_offset = base + self.inv.gnd_position.scale(1,y_dir)
out_y_mirrored = inv_vdd_offset[1] + output_shift + drc["minwidth_metal1"]
out_offset = [inv_out_offset[0],
inv_out_offset[1] * (1 + y_dir) / 2
out_y_mirrored = inv_vdd_offset.y+ output_shift + drc["minwidth_metal1"]
out_offset = [inv_out_offset.x,
inv_out_offset.y* (1 + y_dir) / 2
+ out_y_mirrored * (1 - y_dir) / 2]
# output connection
correct = y_dir * (output_shift + drc["minwidth_metal1"])
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",
offset=out_offset,
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",
offset=[inv_out_offset[0],
inv_vdd_offset[1] - correct],
width=self.rails_x_offset[inv_rout + 4] - inv_out_offset[0] + drc["minwidth_metal2"],
offset=[inv_out_offset.x,
inv_vdd_offset.y- correct],
width=self.rails_x_offset[inv_rout + 4] - inv_out_offset.x+ drc["minwidth_metal2"],
height=drc["minwidth_metal1"])
self.add_via(layers = ("metal1", "via1", "metal2"),
offset=off_via,

View File

@ -49,11 +49,11 @@ class hierarchical_predecode3x8(hierarchical_predecode):
# output connection
correct = y_dir * (output_shift + drc["minwidth_metal1"])
off_via = [self.rails_x_offset[inv_rout + 5] + self.gap_between_rails,
inv_vdd_offset[1] - self.via_shift - correct]
path1 = vector(inv_out_offset[0] + 0.5*drc["minwidth_metal1"],
inv_out_offset[1]- 1.5*drc["minwidth_metal1"] - correct)
inv_vdd_offset.y - self.via_shift - correct]
path1 = inv_out_offset + vector(0.5*drc["minwidth_metal1"],
- 1.5*drc["minwidth_metal1"] - correct)
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"],
path2.y)
self.add_path("metal1", [path1,path2,path3])

View File

@ -46,13 +46,13 @@ class layout:
#***1,000,000 number is used to avoid empty sequences errors***
# FIXME Is this hard coded value ok??
try:
lowestx1 = min(rect.offset[0] for rect in self.objs)
lowesty1 = min(rect.offset[1] for rect in self.objs)
lowestx1 = min(rect.offset.x for rect in self.objs)
lowesty1 = min(rect.offset.y for rect in self.objs)
except:
[lowestx1, lowesty1] = [1000000.0, 1000000.0]
try:
lowestx2 = min(inst.offset[0] for inst in self.insts)
lowesty2 = min(inst.offset[1] for inst in self.insts)
lowestx2 = min(inst.offset.x for inst in self.insts)
lowesty2 = min(inst.offset.y for inst in self.insts)
except:
[lowestx2, lowesty2] = [1000000.0, 1000000.0]
return vector(min(lowestx1, lowestx2), min(lowesty1, lowesty2))
@ -76,21 +76,18 @@ class layout:
for i in range(len(attr_val)):
# each unit in the list is a list coordinates
if isinstance(attr_val[i], (list,vector)):
attr_val[i] = vector([attr_val[i][0] - coordinate.x,
attr_val[i][1] - coordinate.y])
attr_val[i] = vector(attr_val[i] - coordinate)
# the list itself is a coordinate
else:
if len(attr_val)!=2: continue
for val in attr_val:
if not isinstance(val, (int, long, float)): continue
setattr(self,attr_key, vector([attr_val[0] - coordinate.x,
attr_val[1] - coordinate.y]))
setattr(self,attr_key, vector(attr_val - coordinate))
break
# if is a vector coordinate
if isinstance(attr_val, vector):
setattr(self, attr_key, vector(attr_val[0] - coordinate.x,
attr_val[1] - coordinate.y))
setattr(self, attr_key, vector(attr_val - coordinate))
@ -98,9 +95,9 @@ class layout:
"""Translates all 2d cartesian coordinates in a layout given
the (x,y) offset"""
for obj in self.objs:
obj.offset = obj.offset - coordinate
obj.offset = vector(obj.offset - coordinate)
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
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):
"""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
debug.info(3,"add wire " + str(layers) + " " + str(coordinates))
# 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."""
# open the gds file if it exists or else create a blank layout
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"])
reader = gdsMill.Gds2reader(self.gds)
reader.loadFromFile(self.gds_file)
# TODO: parse the width/height
# TODO: parse the pin locations
else:
debug.info(2, "creating structure %s" % self.name)
debug.info(3, "creating structure %s" % self.name)
self.gds = gdsMill.VlsiLayout(
name=self.name, units=GDS["unit"])

View File

@ -68,7 +68,7 @@ class spice:
"""Reads the sp file (and parse the pins) from the library
Otherwise, initialize it to null for dynamic generation"""
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)
self.spice = f.readlines()
for i in range(len(self.spice)):

View File

@ -160,16 +160,16 @@ class logic_effort_dc(design.design):
if end_inv < half_length:
end_i_offset = end_inv_offset + \
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:
end_i_offset = end_inv_offset + \
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:
mid = [half_length * self.inv.width \
- 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])
else:
self.add_path(("metal2"), [M2_start, M2_end])

View File

@ -90,7 +90,7 @@ class nand_2(design.design):
def setup_layout_constants(self):
""" 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 \
+ drc["active_to_body_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
# metal or poly_to_poly spacing)
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"])
- self.nmos1.poly_positions[0][1])
- self.nmos1.poly_positions[0].y)
# determine the position of the first transistor from the left
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.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)
self.add_inst(name="nmos2",
mod=self.nmos2,
@ -151,9 +151,9 @@ class nand_2(design.design):
# determines the spacing between the edge and pmos
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"] \
- self.pmos1.poly_positions[0][1])
- self.pmos1.poly_positions[0].y)
self.pmos_position1 = vector(0, self.height - 0.5 * drc["minwidth_metal1"]
- 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"],
0).scale(.5,0)
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",
offset=poffset, width=drc["minwidth_metal1"],
height=temp_height)
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",
offset=poffset,
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
- yoffset_nmos1 + drc["minwidth_poly"])
for position in self.pmos1.poly_positions:
offset = [position[0],
yoffset_nmos1 - 0.5 * drc["minwidth_poly"]]
offset = vector(position.x,
yoffset_nmos1 - 0.5 * drc["minwidth_poly"])
self.add_rect(layer="poly",
offset=offset, width=drc["minwidth_poly"],
height=poly_length)
self.add_rect(layer="poly",
offset=[offset[0] + self.pmos1.active_contact.width + 2 * drc["minwidth_poly"],
offset[1]],
offset=[offset.x + self.pmos1.active_contact.width + 2 * drc["minwidth_poly"],
offset.y],
width=drc["minwidth_poly"],
height=poly_length)
@ -262,18 +262,18 @@ class nand_2(design.design):
- yoffset - self.pmos1.height + 0.5 * drc["minwidth_metal2"])
for position in self.pmos1.active_contact_positions[1:][::2]:
start = self.drain_position = [position[0] + 0.5 * drc["minwidth_metal1"]
+ self.pmos_position2[0]
+ self.pmos2.active_contact.first_layer_position[0]
start = self.drain_position = vector(position.x + 0.5 * drc["minwidth_metal1"]
+ self.pmos_position2.x
+ self.pmos2.active_contact.first_layer_position.x
+ self.pmos2.active_contact.width / 2,
yoffset]
mid1 = [start[0],
yoffset)
mid1 = vector(start.x,
self.height - drc["minwidth_metal2"] - drc["metal2_to_metal2"] -
self.pmos_size - drc["metal1_to_metal1"] - 0.5 * drc["minwidth_metal1"]]
end = [position[0] + 0.5 * drc["minwidth_metal1"]
+ self.pmos2.active_contact.second_layer_position[0],
self.pmos_position1[1] + self.pmos1.active_contact_positions[0][1]]
mid2 = [end[0], mid1[1]]
self.pmos_size - drc["metal1_to_metal1"] - 0.5 * drc["minwidth_metal1"])
end = vector(position.x + 0.5 * drc["minwidth_metal1"]
+ self.pmos2.active_contact.second_layer_position.x,
self.pmos_position1.y + self.pmos1.active_contact_positions[0].y)
mid2 = vector(end.x, mid1.y)
self.add_path("metal1",[start, mid1, mid2, end])
@ -290,7 +290,7 @@ class nand_2(design.design):
def route_input_gate_A(self):
""" routing for input A """
xoffset = self.pmos1.poly_positions[0][0]
xoffset = self.pmos1.poly_positions[0].x
yoffset = (self.height
- (drc["minwidth_metal1"]
+ drc["metal1_to_metal1"]
@ -298,8 +298,8 @@ class nand_2(design.design):
+ drc["metal1_to_metal1"]
+ self.pmos2.active_contact.second_layer_width))
if (self.nmos_width == drc["minwidth_tx"]):
yoffset = (self.pmos_position1[1]
+ self.pmos1.poly_positions[0][1]
yoffset = (self.pmos_position1.y
+ self.pmos1.poly_positions[0].y
+ drc["poly_extend_active"]
- (self.pmos1.active_contact.height
- self.pmos1.active_height) / 2
@ -312,15 +312,15 @@ class nand_2(design.design):
size=(1,1),
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",
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)
input_length = (self.pmos1.poly_positions[0][0]
input_length = (self.pmos1.poly_positions[0].x
- 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)
self.add_rect(layer="metal1",
offset=offset,
@ -332,15 +332,15 @@ class nand_2(design.design):
def route_input_gate_B(self):
""" routing for input B """
xoffset = (self.pmos2.poly_positions[0][0]
+ self.pmos_position2[0] + drc["minwidth_poly"])
xoffset = (self.pmos2.poly_positions[0].x
+ self.pmos_position2.x + drc["minwidth_poly"])
yoffset = (drc["minwidth_metal1"]
+ drc["metal1_to_metal1"]
+ self.nmos2.active_height
+ drc["minwidth_metal1"])
if (self.nmos_width == drc["minwidth_tx"]):
yoffset = (self.nmos_position1[1]
+ self.nmos1.poly_positions[0][1]
yoffset = (self.nmos_position1.y
+ self.nmos1.poly_positions[0].y
+ self.nmos1.poly_height
+ drc["metal1_to_metal1"])
offset = [xoffset, yoffset]
@ -351,18 +351,18 @@ class nand_2(design.design):
input_length = self.pmos2.poly_positions[0].x - self.poly_contact.height
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",
layer="metal1",
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"])
def route_output(self):
""" routing for output Z """
yoffset = (self.nmos1.height - 2 * drc["minwidth_metal1"] / 3 +
(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)
output_length = self.width - xoffset
self.add_layout_pin(text="Z",
@ -420,9 +420,9 @@ class nand_2(design.design):
width=width,
height=self.pmos1.active_height)
offset = vector(self.nmos_position2[0] + self.nmos1.active_position[0],
self.nmos_position1[1] - self.nmos1.active_height
- self.nmos1.active_position[1] + self.nmos1.height)
offset = vector(self.nmos_position2.x + self.nmos1.active_position.x,
self.nmos_position1.y - self.nmos1.active_height
- self.nmos1.active_position.y + self.nmos1.height)
self.add_rect(layer="active",
offset=offset,
width=self.active_width,

View File

@ -99,7 +99,7 @@ class nand_3(design.design):
def setup_layout_constants(self):
""" 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"] \
+ drc["well_enclosure_active"] - self.nmos3.active_contact.width \
+ 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
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"]
- 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.pmos1.height - self.edge_to_pmos)
self.add_inst(name="pmos1",
@ -216,10 +216,10 @@ class nand_3(design.design):
def connect_well_contacts(self):
""" Connect well contacts to vdd and gnd rail """
well_tap_length = self.height - self.nwell_contact_position[1]
xoffset = (self.nwell_contact_position[0]
+ self.nwell_contact.second_layer_position[0]
- self.nwell_contact.first_layer_position[0])
well_tap_length = self.height - self.nwell_contact_position.y
xoffset = (self.nwell_contact_position.x
+ self.nwell_contact.second_layer_position.x
- self.nwell_contact.first_layer_position.x)
offset = [xoffset, self.nwell_contact_position.y]
self.add_rect(layer="metal1",
offset=offset,
@ -240,14 +240,14 @@ class nand_3(design.design):
correct = vector(self.pmos1.active_contact.width - drc["minwidth_metal1"],
0).scale(0.5,0)
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",
offset=poffset,
width=drc["minwidth_metal1"],
height=temp_height)
poffset = [self.pmos_position3.x + self.pmos3.active_contact_positions[0].x + correct.x,
poffset[1]]
poffset.y]
self.add_rect(layer="metal1",
offset=poffset,
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
- yoffset_nmos1 + drc["minwidth_poly"])
offset = [self.nmos_position1[0] + self.nmos1.poly_positions[0][0],
yoffset_nmos1 - drc["minwidth_poly"]]
offset = vector(self.nmos_position1.x + self.nmos1.poly_positions[0].x,
yoffset_nmos1 - drc["minwidth_poly"])
self.add_rect(layer="poly",
offset=offset,
width=drc["minwidth_poly"],
height=poly_length)
self.add_rect(layer="poly",
offset=[offset[0] + self.pmos1.active_contact.width + 2 * drc["minwidth_poly"],
offset[1]],
offset=[offset.x + self.pmos1.active_contact.width + 2 * drc["minwidth_poly"],
offset.y],
width=drc["minwidth_poly"],
height=poly_length)
self.add_rect(layer="poly",
offset=[offset[0] + 2 * self.pmos1.active_contact.width + 4 * drc["minwidth_poly"],
offset[1]],
offset=[offset.x + 2 * self.pmos1.active_contact.width + 4 * drc["minwidth_poly"],
offset.y],
width=drc["minwidth_poly"],
height=poly_length)
@ -294,7 +294,7 @@ class nand_3(design.design):
- drc["well_enclosure_active"]
+ drc["metal1_to_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")
for position in self.pmos1.active_contact_positions[1:][::2]:
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)
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.drain_position = vector(xoffset,
drc["minwidth_metal1"] + drc["metal1_to_metal1"])
@ -343,11 +343,11 @@ class nand_3(design.design):
rotate=90)
self.add_rect(layer="poly",
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)
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",
layer="metal1",
offset=offset,
@ -358,9 +358,9 @@ class nand_3(design.design):
def route_input_gate_B(self):
""" routing for input B """
xoffset = self.pmos2.poly_positions[0][0] \
+ self.pmos_position2[0] - drc["minwidth_poly"]
yoffset = self.nmos_position1[1] + self.nmos1.height \
xoffset = self.pmos2.poly_positions[0].x \
+ self.pmos_position2.x - drc["minwidth_poly"]
yoffset = self.nmos_position1.y + self.nmos1.height \
- drc["well_enclosure_active"] + (self.nmos1.active_contact.height \
- self.nmos1.active_height) / 2 \
+ drc["metal1_to_metal1"]
@ -369,7 +369,7 @@ class nand_3(design.design):
self.add_via(layers=("metal1", "via1", "metal2"),
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
length = -xoffset + self.m1m2_via.width
self.add_rect(layer="metal2",
@ -382,7 +382,7 @@ class nand_3(design.design):
layer="metal1",
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 \
- self.m1m2_via.second_layer_width) / 2
self.add_via(layers=("metal1", "via1", "metal2"),
@ -395,9 +395,9 @@ class nand_3(design.design):
def route_input_gate_C(self):
""" routing for input A """
xoffset = self.pmos3.poly_positions[0][0] \
+ self.pmos_position3[0] - drc["minwidth_poly"]
yoffset = self.nmos_position1[1] + self.nmos1.height \
xoffset = self.pmos3.poly_positions[0].x \
+ self.pmos_position3.x - drc["minwidth_poly"]
yoffset = self.nmos_position1.y + self.nmos1.height \
- drc["well_enclosure_active"] + (self.nmos1.active_contact.height \
- 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"),
offset=[xoffset,yoffset])
xoffset = self.pmos3.poly_positions[0][0] \
+ self.pmos_position3[0] - drc["minwidth_poly"] \
xoffset = self.pmos3.poly_positions[0].x \
+ self.pmos_position3.x - drc["minwidth_poly"] \
+ self.m1m2_via.width
length = -xoffset + self.m1m2_via.width
self.add_rect(layer="metal2",
@ -423,14 +423,14 @@ class nand_3(design.design):
width=self.m1m2_via.width,
height=-drc["minwidth_metal2"] - drc["metal2_to_metal2"])
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.first_layer_width))
self.add_label(text="C",
layer="metal1",
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 \
- self.m1m2_via.second_layer_width) / 2
self.add_via(layers=("metal1", "via1", "metal2"),
@ -445,7 +445,7 @@ class nand_3(design.design):
def route_output(self):
""" 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
yoffset = (self.nmos1.height + (self.height - drc["minwidth_metal1"]
- self.pmos1.height - self.nmos1.height) / 2
@ -463,11 +463,11 @@ class nand_3(design.design):
def extend_wells(self):
""" extension of well """
middle_point = self.nmos_position1[1] + self.nmos1.pwell_position[1] \
+ self.nmos1.well_height + (self.pmos_position1[1]
+ self.pmos1.nwell_position[1]
- 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.y
+ self.pmos1.nwell_position.y
- self.nmos_position1.y
- self.nmos1.pwell_position.y
- self.nmos1.well_height) / 2
offset = self.nwell_position = vector(0, middle_point)
self.nwell_height = self.height - middle_point
@ -508,9 +508,9 @@ class nand_3(design.design):
width=width,
height=self.pmos1.active_height)
offset = [self.nmos_position3[0] + self.nmos1.active_position[0],
self.nmos_position1[1] + self.nmos1.height
- self.nmos1.active_position[1] - self.nmos1.active_height]
offset = [self.nmos_position3.x + self.nmos1.active_position.x,
self.nmos_position1.y + self.nmos1.height
- self.nmos1.active_position.y - self.nmos1.active_height]
self.add_rect(layer="active",
offset=offset,
width=self.active_width,

View File

@ -81,10 +81,10 @@ class nor_2(design.design):
0.5 * gate_to_gate - test_pmos.poly_positions[0].y)
route_margin = .5 * (self.poly_contact.second_layer_width
+ drc["minwidth_metal1"]) + drc["metal1_to_metal1"]
pmos_position = [0, self.height - 0.5 * drc["minwidth_metal1"]
- edge_to_pmos - test_pmos.height]
nmos_position = [0, 0.5 * drc["minwidth_metal1"] + edge_to_nmos]
leftspace = (0.7 * (pmos_position[1] - nmos_position[1])
pmos_position = vector(0, self.height - 0.5 * drc["minwidth_metal1"]
- edge_to_pmos - test_pmos.height)
nmos_position = vector(0, 0.5 * drc["minwidth_metal1"] + edge_to_nmos)
leftspace = (0.7 * (pmos_position.y - nmos_position.y)
- 3 * route_margin - 2 * drc["metal1_to_metal1"])
if leftspace >= 0:
break
@ -209,10 +209,10 @@ class nor_2(design.design):
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))
xoffset = self.nmos_position2[0] + (self.nmos1.active_position[0]
xoffset = self.nmos_position2.x + (self.nmos1.active_position.x
+ self.nmos1.active_width
+ 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.height)
self.pwell_contact_position = vector(xoffset, yoffset)
@ -222,7 +222,7 @@ class nor_2(design.design):
def route(self):
self.route_pins()
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
+ drc["minwidth_metal1"]))
self.connect_tx(M1_track)
@ -230,11 +230,11 @@ class nor_2(design.design):
def connect_well_contacts(self):
""" 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
+ self.nwell_contact.second_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",
offset=offset,
width=drc["minwidth_metal1"],
@ -243,7 +243,7 @@ class nor_2(design.design):
offset = (self.pwell_contact_position.scale(1,0)
+ self.pwell_contact.second_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",
offset=offset,
width=drc["minwidth_metal1"],
@ -257,7 +257,7 @@ class nor_2(design.design):
if i % 2 == 0:
correct = self.pmos1.active_contact.second_layer_position.scale(1,0)
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",
offset=drain_posistion,
width=drc["minwidth_metal1"],
@ -268,7 +268,7 @@ class nor_2(design.design):
+ vector(self.pmos1.active_contact.second_layer_width,
0).scale(.5,0))
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])
# the second pmos
@ -279,13 +279,13 @@ class nor_2(design.design):
correct= (self.pmos2.active_contact.second_layer_position.scale(1,0)
+ vector(0.5 * self.pmos2.active_contact.second_layer_width,0))
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])
# two nmos source to gnd
source_posistion1 = (self.nmos_position1
+ self.nmos1.active_contact_positions[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",
offset=source_posistion1,
width=drc["minwidth_metal1"],
@ -294,7 +294,7 @@ class nor_2(design.design):
source_posistion2 = (self.nmos_position2
+ self.nmos2.active_contact_positions[1]
+ 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",
offset=source_posistion2,
width=drc["minwidth_metal1"],
@ -310,22 +310,22 @@ class nor_2(design.design):
pmos_gate = (self.pmos_position1
+ self.pmos1.poly_positions[i]
+ 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])
# connect pmos2 poly
nmos_gate = [self.nmos_position2[0] \
+ self.nmos2.poly_positions[0][0]
+ 0.5 * drc["minwidth_poly"], \
self.nmos_position1[1] \
+ self.nmos1.poly_positions[0][1]]
nmos_gate = vector(self.nmos_position2[0]
+ self.nmos2.poly_positions[0].x
+ 0.5 * drc["minwidth_poly"],
self.nmos_position1.y
+ self.nmos1.poly_positions[0].y)
for i in range(len(self.pmos2.poly_positions)):
pmos_gate = (self.pmos_position2
+ self.pmos2.poly_positions[i]
+ vector(0.5 * drc["minwidth_poly"], 0))
mid1 = [pmos_gate[0],
nmos_gate[1] + self.nmos2.height \
+ drc["poly_to_active"]]
mid1 = vector(pmos_gate.x,
nmos_gate.y + self.nmos2.height
+ drc["poly_to_active"])
self.add_path("poly", [nmos_gate, mid1, pmos_gate])
def route_pins(self):
@ -350,15 +350,15 @@ class nor_2(design.design):
rotate=90)
# 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)
self.add_rect(layer="poly",
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)
# extend the metal to the boundary of the cell
input_length = self.A_position[0]
offset = [0, self.A_position[1] - 0.5 * drc["minwidth_metal1"]]
input_length = self.A_position.x
offset = [0, self.A_position.y - 0.5 * drc["minwidth_metal1"]]
self.add_layout_pin(text="A",
layer="metal1",
offset=offset,
@ -367,9 +367,9 @@ class nor_2(design.design):
def route_input_B(self):
"""create input B layout """
xoffset = self.pmos2.poly_positions[0][0] \
+ self.pmos_position2[0]
yoffset = self.A_position[1] \
xoffset = self.pmos2.poly_positions[0].x \
+ self.pmos_position2.x
yoffset = self.A_position.y \
+ 0.5 * (self.poly_contact.second_layer_width \
+ drc["minwidth_metal1"]) + drc["metal1_to_metal1"]
self.B_position = vector(xoffset, yoffset)
@ -380,13 +380,13 @@ class nor_2(design.design):
self.add_rect(layer="poly",
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)
self.add_layout_pin(text="B",
layer="metal1",
offset=[0,
self.B_position[1] - 0.5 * drc["minwidth_metal1"]],
width=self.B_position[0],
self.B_position.y - 0.5 * drc["minwidth_metal1"]],
width=self.B_position.x,
height=drc["minwidth_metal1"])
def route_output(self):
@ -398,7 +398,7 @@ class nor_2(design.design):
+ self.nmos1.active_contact.second_layer_position
+ vector(self.nmos1.active_contact.second_layer_width,
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])
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)
self.add_via(layers=("metal1", "via1", "metal2"),
offset=offset)
mid = [pmos_contact[0], self.Z_position[1]]
self.add_wire(("metal2", "via1", "metal1"),
mid = [pmos_contact.x, self.Z_position.y]
self.add_wire(("metal1", "via1", "metal2"),
[self.Z_position, mid, pmos_contact])
def extend_wells(self):
""" extend well for well contact"""
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.pmos1.nwell_position[1]
- self.nmos_position1[1]
- self.nmos1.pwell_position[1]
+ (self.pmos_position1.y
+ self.pmos1.nwell_position.y
- self.nmos_position1.y
- self.nmos1.pwell_position.y
- self.nmos1.well_height) / 2 )
self.nwell_position = vector(0, middle_point)
self.nwell_height = self.height - middle_point

View File

@ -33,9 +33,8 @@ import debug
if len(args) < 1:
print globals.USAGE
sys.exit(2)
if OPTS.print_banner:
print globals.BANNER
globals.print_banner()
globals.init_openram(args[0])
@ -94,7 +93,7 @@ s.gds_write(gdsname)
# Run Characterizer on the design
sram_file = spname
if OPTS.run_pex:
if OPTS.use_pex:
sram_file = OPTS.out_path + "temp_pex.sp"
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)
lib.lib(libname,s,sram_file)
globals.end_openram()
print "End: ", datetime.datetime.now()

View File

@ -1,16 +1,18 @@
import optparse
import getpass
import os
class options(optparse.Values):
"""
Class for holding all of the OpenRAM options.
"""
# This is the technology directory.
openram_tech = ""
# This is the name of the technology.
tech_name = ""
# 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
# is minimal, etc.
debug_level = 0
@ -18,6 +20,8 @@ class options(optparse.Values):
check_lvsdrc = True
# Variable to select the variant of spice (hspice or ngspice right now)
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
print_banner = True
# 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.
spice_exe = ""
# Run with extracted parasitics
run_pex = False
use_pex = False
# Trim noncritical memory cells for simulation speed-up
trim_noncritical = False
# Define the output file paths

View File

@ -19,7 +19,7 @@ class path(design.design):
name = "path_{0}".format(path.unique_path_id)
path.unique_path_id += 1
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.layer_name = layer

View File

@ -109,7 +109,7 @@ class pinv(design.design):
"""Sets up constant variables"""
# the well width is determined the multi-finger PMOS device width plus
# 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 \
+ drc["active_to_body_active"] \
+ self.pmos.active_contact.width \
@ -140,10 +140,10 @@ class pinv(design.design):
# determines the spacing between the edge and nmos (rail to active
# metal or poly_to_poly spacing)
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["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)
offset = self.nmos_position + vector(0,self.nmos.height)
self.add_inst(name="pinv_nmos",
@ -154,10 +154,10 @@ class pinv(design.design):
# determines the spacing between the edge and pmos
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["minwidth_metal1"] \
- self.pmos.poly_positions[0][1])
- self.pmos.poly_positions[0].y)
self.pmos_position = vector(0,
self.height - 0.5 * drc["minwidth_metal1"]
- edge_to_pmos - self.pmos.height)
@ -168,9 +168,9 @@ class pinv(design.design):
def extend_wells(self):
"""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
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
middle_yposition = nmos_top_yposition + 0.5 * middle_length
@ -185,7 +185,7 @@ class pinv(design.design):
width=self.well_width,
height=self.nwell_height)
self.pwell_position = [0, 0]
self.pwell_position = vector(0, 0)
self.pwell_height = middle_yposition
self.add_rect(layer="pwell",
offset=self.pwell_position, width=self.well_width,
@ -239,14 +239,14 @@ class pinv(design.design):
def connect_poly(self):
"""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
nmos_top_poly_yposition = self.nmos_position[1] \
nmos_top_poly_yposition = self.nmos_position.y \
+ 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
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",
offset=offset,
width=drc["minwidth_poly"],
@ -257,14 +257,14 @@ class pinv(design.design):
# Determines the top y-coordinate of the nmos drain metal layer
yoffset = self.nmos.height \
- 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"] \
- (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]:
offset = [position[0] + self.pmos.active_contact.second_layer_position[0],
offset = [position.x + self.pmos.active_contact.second_layer_position.x,
yoffset]
self.drain_position = offset
self.drain_position = vector(offset)
self.add_rect(layer="metal1",
offset=offset,
width=self.nmos.active_contact.second_layer_width,
@ -273,7 +273,7 @@ class pinv(design.design):
def route_input_gate(self):
"""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
# (middle in between the pmos and nmos)
yoffset = self.nmos.height + (self.height
@ -285,13 +285,13 @@ class pinv(design.design):
rotate=90)
# 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",
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)
input_length = self.pmos.poly_positions[0][0] \
input_length = self.pmos.poly_positions[0].x \
- self.poly_contact.height
# Determine the y-coordinate for the placement of the metal1 via
self.input_position = vector(0, .5*(self.height - drc["minwidth_metal1"]
@ -305,9 +305,9 @@ class pinv(design.design):
def route_output_drain(self):
"""Routes the output (drain) to the right side of the cell for access"""
# 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.input_position[1])
self.input_position.y)
output_length = self.width - offset.x
if self.route_output == True:
self.output_position = offset + vector(output_length,0)
@ -325,22 +325,18 @@ class pinv(design.design):
"""Adds n/p well taps to the layout"""
layer_stack = ("active", "contact", "metal1")
# Same y-positions of the drain/source metals as the n/p mos
nwell_tap_xposition = self.pmos_position[0] \
+ self.pmos.active_position[0] \
+ self.active_width \
- self.nwell_contact.width
nwell_tap_yposition = self.pmos_position[1] \
+ self.pmos.active_contact_positions[0][1]
self.nwell_contact_position = [nwell_tap_xposition, nwell_tap_yposition]
well_contact_offset = vector(self.pmos.active_position.x
+ self.active_width
- self.nwell_contact.width,
self.pmos.active_contact_positions[0].y)
self.nwell_contact_position = self.pmos_position + well_contact_offset
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] \
+ self.nmos.active_position[0] \
+ self.active_width \
- self.pwell_contact.width
pwell_tap_yposition = self.nmos_position[1] \
+ self.nmos.active_contact_positions[0][1]
self.pwell_contact_position = [pwell_tap_xposition, pwell_tap_yposition]
well_contact_offset = vector(self.nmos.active_position.x
+ self.active_width
- self.pwell_contact.width,
self.nmos.active_contact_positions[0].y)
self.pwell_contact_position = self.nmos_position + well_contact_offset
self.pwell_contact=self.add_contact(layer_stack,self.pwell_contact_position,(1,self.nmos.num_of_tacts))
def connect_well_contacts(self):
@ -348,7 +344,7 @@ class pinv(design.design):
# calculates the length needed to connect the nwell_tap to vdd
nwell_tap_length = self.height \
- 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
offset = self.nwell_contact_position + \
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,
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"]
offset = [self.pwell_contact_position[0]
+ self.pwell_contact.second_layer_position[0],
offset = [self.pwell_contact_position.x
+ self.pwell_contact.second_layer_position.x,
0.5 * drc["minwidth_metal1"]]
self.add_rect(layer="metal1",
offset=offset,
@ -377,7 +373,7 @@ class pinv(design.design):
- drc["minwidth_metal1"]).scale(.5,.5)
# nmos position of the source metals
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"]]
self.add_rect(layer="metal1", offset=offset,
width=self.nmos.active_contact.second_layer_width,
@ -390,7 +386,7 @@ class pinv(design.design):
# pmos position of the source metals
offset = self.pmos_position + self.pmos.active_contact_positions[0]\
+ 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",
offset=offset,
width=self.pmos.active_contact.second_layer_width,

View File

@ -185,7 +185,7 @@ class precharge(design.design):
def add_vdd_rail(self):
"""Adds a vdd rail at the top 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.add_layout_pin(text="vdd",
layer="metal1",

View File

@ -16,7 +16,7 @@ class ptx(design.design):
name = "{0}{1}".format(name, ptx.unique_mos_id)
ptx.unique_mos_id += 1
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.mults = mults
@ -56,10 +56,10 @@ class ptx(design.design):
# 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?
self.height = max(max(obj.offset[1] + obj.height for obj in self.objs),
max(inst.offset[1] + inst.mod.height for inst in self.insts))
self.width = max(max(obj.offset[0] + obj.width for obj in self.objs),
max(inst.offset[0] + inst.mod.width for inst in self.insts))
self.height = max(max(obj.offset.y + obj.height for obj in self.objs),
max(inst.offset.y + inst.mod.height for inst in self.insts))
self.width = max(max(obj.offset.x + obj.width for obj in self.objs),
max(inst.offset.x + inst.mod.width for inst in self.insts))
def create_spice(self):
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"],
drc["poly_to_poly"])
outeractive_to_contact = max(drc["active_enclosure_contact"],
(drc["minwidth_active"] - drc["minwidth_contact"]) / 2)
self.active_width = 2 * (outeractive_to_contact \
+ drc["minwidth_contact"] \
+ drc["contact_to_poly"]) \
+ drc["minwidth_poly"] \
+ (self.mults - 1) * (
self.mults_poly_to_poly + drc["minwidth_poly"])
(drc["minwidth_active"] - drc["minwidth_contact"]) / 2)
self.active_width = (2 * (outeractive_to_contact + drc["minwidth_contact"]
+ drc["contact_to_poly"])
+ drc["minwidth_poly"]
+ (self.mults - 1) * (self.mults_poly_to_poly
+ drc["minwidth_poly"]))
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_height = max(drc["minarea_poly"] / self.poly_width,
self.gate_width \
+ 2 * drc["poly_extend_active"]) # vertical
self.well_width = self.active_width \
+ 2 * (drc["well_enclosure_active"])
self.gate_width
+ 2 * drc["poly_extend_active"]) # vertical
self.well_width = (self.active_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):
poly_connect_length = self.poly_positions[-1][0] + self.poly_width \
- self.poly_positions[0][0]
poly_connect_position = [self.poly_positions[0][0],
self.poly_positions[0][1] - self.poly_width]
poly_connect_length = self.poly_positions[-1].x + self.poly_width \
- self.poly_positions[0].x
poly_connect_position = self.poly_positions[0] - vector(0, self.poly_width)
if len(self.poly_positions) > 1:
self.add_rect(layer="poly",
offset=poly_connect_position,
@ -127,8 +125,8 @@ class ptx(design.design):
drc["minwidth_metal1"] + drc["minwidth_contact"]),
0.5 * (self.active_contact.height - drc["minwidth_contact"])
- drc["metal1_extend_contact"])
connected=vector(b[0] + drc["minwidth_metal1"],
a[1] + self.active_contact.height + drc["metal1_to_metal1"])
connected=vector(b.x + drc["minwidth_metal1"],
a.y + self.active_contact.height + drc["metal1_to_metal1"])
self.source_positions.append(a + correct)
self.source_positions.append(vector(a.x + correct.x, connected.y))
self.source_positions.append(vector(b.x + correct.x,
@ -144,10 +142,10 @@ class ptx(design.design):
+ drc["minwidth_contact"]),
0.5*(self.active_contact.height - drc["minwidth_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[0] + correct.x, connected.y))
self.drain_positions.append(vector(d[0] + correct.x,
self.drain_positions.append(vector(c.x + correct.x, connected.y))
self.drain_positions.append(vector(d.x + correct.x,
connected.y - 0.5 * drc["minwidth_metal1"]))
self.drain_positions.append(vector(d + correct))
@ -165,7 +163,7 @@ class ptx(design.design):
def add_poly(self):
# 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"]
poly_yoffset = -drc["poly_extend_active"]
self.poly_positions = []
@ -255,10 +253,10 @@ class ptx(design.design):
# middle contact columns
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) \
- (drc["minwidth_contact"] / 2) - \
self.active_contact.via_layer_position[0]
self.active_contact.via_layer_position.x
offset = vector(contact_xoffset, contact_yoffset)
self.add_contact(layers=("active", "contact", "metal1"),
offset=offset,
@ -267,9 +265,9 @@ class ptx(design.design):
self.active_contact_positions.append(offset)
# 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.active_contact.via_layer_position[0]
self.active_contact.via_layer_position.x
offset = vector(contact_xoffset, contact_yoffset)
self.add_contact(layers=("active", "contact", "metal1"),
offset=offset,

View File

@ -68,7 +68,8 @@ class replica_bitline(design.design):
self.inv.height * 0.5)
self.replica_bitline_offset = vector(self.delay_chain_offset.x
+ 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.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_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
vdd_offset = vector(self.delay_chain_offset.x + 9 * drc["minwidth_metal2"],
self.height)
self.create_input()
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_gnd()
# route loads after gnd and vdd created
self.route_loads()
self.route_RC()
self.route_loads(vdd_offset)
self.route_RC(vdd_offset)
def create_input(self):
# create routing module based on module offset
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
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_label(text="en",
layer="metal1",
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):
# BL_inv input to M3
mid1 = [BL_inv_in[0],
BL_inv_in[1] - drc["metal2_to_metal2"] - self.m1m2_via.width]
mid2 = [self.en_nor_offset[0] + 3*drc["metal1_to_metal1"],
mid1[1]]
mid3 = [mid2[0],
self.replica_bitline_offset[1] - self.replica_bitcell.height
- 0.5 * (self.m1m2_via.height + drc["metal1_to_metal1"])
- 2 * drc["metal1_to_metal1"]]
self.add_wire(("metal1", "via1", "metal2"),
[BL_inv_in, mid1, mid2, mid3])
mid1 = BL_inv_in - vector(0,
drc["metal2_to_metal2"] + self.m1m2_via.width)
mid2 = vector(self.en_nor_offset.x + 3 * drc["metal1_to_metal1"],
mid1.y)
mid3 = vector(mid2.x,
self.replica_bitline_offset.y - self.replica_bitcell.height
- 0.5 * (self.m1m2_via.height + drc["metal1_to_metal1"])
- 2 * drc["metal1_to_metal1"])
self.add_wire(layers=("metal2", "via1", "metal1"),
coordinates=[BL_inv_in, mid1, mid2, mid3])
# need to fix the mid point as this is done with two wire
# this seems to cover the metal1 error of the wire
@ -246,18 +232,18 @@ class replica_bitline(design.design):
width=drc["minwidth_metal1"],
height=drc["minwidth_metal1"])
mid4 = [BL_offset[0], mid3[1]]
self.add_wire(("metal2", "via1", "metal1"),
[BL_offset, mid4, mid3])
mid4 = [BL_offset.x, mid3.y]
self.add_wire(layers=("metal1", "via1", "metal2"),
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_drain()
self.route_tx_drain(vdd_offset)
self.route_tx_source(BL_inv_in)
def route_tx_gate(self, delay_chain_output):
# 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)
width = -6 * drc["minwidth_metal1"]
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):
m2rail_space = (drc["minwidth_metal2"] + drc["metal2_to_metal2"])
mid1 = [offset[0], self.delay_chain_offset[1] - 3 * m2rail_space]
mid2 = [delay_chain_output[0], mid1[1]]
mid1 = vector(offset.x, self.delay_chain_offset.y - 3 * m2rail_space)
mid2 = [delay_chain_output.x, mid1.y]
# Note the inverted wire stack
self.add_wire(("metal2", "via1", "metal1"),
[offset, mid1, mid2, delay_chain_output])
self.add_wire(layers=("metal1", "via1", "metal2"),
coordinates=[offset, mid1, mid2, delay_chain_output])
self.add_via(layers=("metal1", "via1", "metal2"),
offset=delay_chain_output,
mirror="MX")
offset=delay_chain_output,
mirror="MX")
def route_access_tx_t_WL(self, offset):
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"),
offset=m1m2_via_offset)
# route gate to RC WL
RC_WL = self.replica_bitline_offset - vector(0,1).scale(self.bitcell_chars["WL"])
mid1 = [offset[0], 0]
mid2 = [self.en_nor_offset[0] + 3 * drc["metal1_to_metal1"],
mid1[1]]
mid3 = [RC_WL[0] - drc["minwidth_metal1"] - self.m1m2_via.height,
mid1[1]]
mid4 = [mid3[0], RC_WL[1]]
mid1 = vector(offset.x, 0)
mid2 = vector(self.en_nor_offset.x + 3 * drc["metal1_to_metal1"],
mid1.y)
mid3 = vector(RC_WL.x - drc["minwidth_metal1"] - self.m1m2_via.height,
mid1.y)
mid4 = vector(mid3.x, RC_WL.y)
self.add_path("metal2", [offset, mid1, mid2, mid3, mid4])
offset = mid4 - vector([0.5 * drc["minwidth_metal1"]]*2)
width = RC_WL[0] - offset[0]
offset = mid4 - vector([0.5 * drc["minwidth_metal1"]] * 2)
width = RC_WL.x - offset.x
# enter the bit line array with metal1
via_offset = [mid4[0] - 0.5 * self.m1m2_via.width,
offset[1] - 0.5 * (self.m1m2_via.height
via_offset = [mid4.x - 0.5 * self.m1m2_via.width,
offset.y
- 0.5 * (self.m1m2_via.height
- drc["minwidth_metal1"])]
self.add_via(layers=("metal1", "via1", "metal2"),
offset=via_offset)
@ -313,26 +300,24 @@ class replica_bitline(design.design):
width=width,
height=drc["minwidth_metal1"])
def route_tx_drain(self):
def route_tx_drain(self,vdd_offset):
# route drain to Vdd
active_offset = self.access_tx.active_contact_positions[1].rotate().scale(-1,1)
correct = vector(drc["minwidth_metal1"],
self.access_tx.active_contact.width).scale(-0.5, 0.5)
active_offset = self.access_tx.active_contact_positions[1].rotate_scale(-1,1)
correct = vector(-0.5 * drc["minwidth_metal1"],
0.5 * self.access_tx.active_contact.width)
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)
self.add_path("metal1", [drain_offset, close_Vdd_offset])
mid = [vdd_rail[0], close_Vdd_offset[1]]
self.add_wire(("metal2", "via1", "metal1"),
[close_Vdd_offset, mid, vdd_rail])
mid = [vdd_offset.x, close_Vdd_offset.y]
self.add_wire(layers=("metal1", "via1", "metal2"),
coordinates=[close_Vdd_offset, mid, vdd_offset])
def route_tx_source(self, BL_inv_in):
# route source to BL inv input which is connected to BL
active_offset = self.access_tx.active_contact_positions[0].rotate().scale(-1,1)
correct = vector(drc["minwidth_metal1"],
self.access_tx.active_contact.width).scale(-0.5, 0.5)
active_offset = self.access_tx.active_contact_positions[0].rotate_scale(-1,1)
correct = vector(-0.5 * drc["minwidth_metal1"],
0.5 * self.access_tx.active_contact.width)
source_offset = self.access_tx_offset + active_offset + correct
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)
m1rail_space = (drc["minwidth_metal1"] + drc["metal1_to_metal1"])
mid1 = start - vector(0, m1rail_space)
mid2 = [self.delay_chain_offset[0] + 9 * drc["minwidth_metal2"],
mid1[1]]
end = [mid2[0], vdd_offset[1]]
self.add_path(("metal1"), [start, mid1, mid2])
self.add_wire(("metal2", "via1", "metal1"), [mid1, mid2, end])
mid2 = vector(self.delay_chain_offset.x + 9 * drc["minwidth_metal2"],
mid1.y)
end = [mid2.x, vdd_offset.y]
self.add_path(layer=("metal1"),
coordinates=[start, mid1, mid2])
self.add_wire(layers=("metal1", "via1", "metal2"),
coordinates=[mid1, mid2, end])
def route_gnd(self):
"""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)
share_gnd = vector(self.gnd_position.x, mid2.y)
# Note the inverted stacks
self.add_wire(("metal2", "via1", "metal1"),
[BL_gnd_offset, mid1, mid2, share_gnd, self.gnd_position])
lst = [BL_gnd_offset, mid1, mid2, share_gnd, self.gnd_position]
self.add_wire(layers=("metal1", "via1", "metal2"),
coordinates=lst)
self.add_label(text="gnd",
layer="metal1",
offset=self.gnd_position)
@ -377,51 +365,51 @@ class replica_bitline(design.design):
offset=offset,
width=drc["minwidth_metal1"],
height=-self.delay_chain.width)
offset = [offset[0] + self.delay_chain.height,
mid2[1]]
offset = [offset.x + self.delay_chain.height,
mid2.y]
self.add_rect(layer="metal1",
offset=offset,
width=drc["minwidth_metal1"],
height=-self.delay_chain.width)
def route_loads(self):
def route_loads(self,vdd_offset):
"""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"),
offset=vdd_offset,
mirror="MX")
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):
WL_offset = (self.replica_bitline_offset
+ self.bitline_load.WL_positions[i].scale(0,1))
mid = [self.delay_chain_offset[0] + 6 * drc["minwidth_metal2"],
gnd_offset[1]]
self.add_wire(("metal2", "via1", "metal1"), [gnd_offset, mid, WL_offset])
mid = [self.delay_chain_offset.x + 6 * drc["minwidth_metal2"],
gnd_offset.y]
self.add_wire(layers=("metal1", "via1", "metal2"),
coordinates=[gnd_offset, mid, WL_offset])
if i % 2 == 0:
load_vdd_offset = (self.replica_bitline_offset
+ self.bitline_load.vdd_positions[i])
mid = [vdd_offset[0], load_vdd_offset[1]]
self.add_wire(("metal2", "via1", "metal1"), [vdd_offset, mid, load_vdd_offset])
+ self.bitline_load.vdd_positions[i])
mid = [vdd_offset.x, load_vdd_offset.y]
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 """
# connect 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"],
self.height]
mid = [vdd_offset[0], RC_vdd[1]]
mid = [vdd_offset.x, RC_vdd.y]
# 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)
load_gnd = (self.replica_bitline_offset
+ vector(self.bitcell_chars["gnd"][0], self.bitline_load.height))
mid = [load_gnd[0], gnd_offset[1]]
self.add_wire(("metal2", "via1", "metal1"), [gnd_offset, mid, load_gnd])
load_gnd = self.replica_bitline_offset + vector(self.bitcell_chars["gnd"][0],
self.bitline_load.height)
mid = [load_gnd.x, gnd_offset.y]
self.add_wire(layers=("metal1", "via1", "metal2"),
coordinates=[gnd_offset, mid, load_gnd])
load_gnd = (self.replica_bitline_offset
+ vector(0, self.bitline_load.height))
mid = [load_gnd[0], gnd_offset[1]]
self.add_wire(("metal2", "via1", "metal1"), [gnd_offset, mid, load_gnd])
load_gnd = self.replica_bitline_offset + vector(0,
self.bitline_load.height)
mid = [load_gnd.x, gnd_offset.y]
self.add_wire(("metal1", "via1", "metal2"), [gnd_offset, mid, load_gnd])

View File

@ -79,7 +79,7 @@ class single_level_column_mux(design.design):
self.poly_offset = (self.nmos1_position
+ self.nmos1.poly_positions[0]
+ 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",
offset=self.poly_offset,
width=width,
@ -91,7 +91,7 @@ class single_level_column_mux(design.design):
def connect_to_bitlines(self):
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,
self.nmos1.active_position[1] + self.nmos1.active_height]
self.nmos1.active_position.y+ self.nmos1.active_height]
offset = self.nmos1_position + offset
connection = vector(0,
self.nmos2.active_height+ 2 * drc["poly_extend_active"] \
@ -101,7 +101,7 @@ class single_level_column_mux(design.design):
width=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)
+ connection)
self.add_via(layers=("metal1", "via1", "metal2"),
@ -116,10 +116,10 @@ class single_level_column_mux(design.design):
width=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",
offset=[offset[0],
self.BL_position[1] - 2*drc["minwidth_metal2"]],
self.BL_position.y- 2*drc["minwidth_metal2"]],
width=width,
height=drc["minwidth_metal2"])
@ -127,24 +127,24 @@ class single_level_column_mux(design.design):
self.add_via(layers=("metal1", "via1", "metal2"),
offset=offset)
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],
width=drc["minwidth_metal2"],
height=(drc["minwidth_metal2"] + offset[1]))
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]],
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"]),
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)
self.add_label(text="bl_out",
layer="metal2",
offset=self.BL_out_position)
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
self.add_via(layers=("metal1", "via1", "metal2"),
offset=offset,
@ -152,21 +152,21 @@ class single_level_column_mux(design.design):
mid = offset + vector(drc["minwidth_metal2"],0)
self.add_rect(layer="metal2",
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"])
self.add_rect(layer="metal2",
offset=[self.bitcell_chars["BR"][0] - 0.5*self.m1m2_via.width,
offset[1] - drc["metal1_to_metal1"]],
offset=[self.bitcell_chars["BR"][0]- 0.5*self.m1m2_via.width,
offset.y- drc["metal1_to_metal1"]],
width=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.add_label(text="br",
layer="metal2",
offset=self.BR_position)
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)
self.add_label(text="br_out",
layer="metal2",
@ -179,12 +179,12 @@ class single_level_column_mux(design.design):
height=drc["minwidth_metal2"])
self.add_rect(layer="metal2",
offset=[self.BR_out_position.x,
offset[1] + drc["minwidth_metal2"]],
offset.y+ drc["minwidth_metal2"]],
width=drc["minwidth_metal2"],
height=-(offset[1] + drc["minwidth_metal2"]))
height=-(offset.y+ drc["minwidth_metal2"]))
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)
self.add_layout_pin(text="gnd",
layer="metal2",
@ -193,7 +193,7 @@ class single_level_column_mux(design.design):
height=self.BL_position[1])
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.add_via(layers=("metal1", "via1", "metal2"),
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)
self.add_rect(layer="pwell",
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"])
self.add_rect(layer="vtg",
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"])
def setup_layout_constants(self):

View File

@ -380,14 +380,14 @@ class sram(design.design):
self.width = self.bank.width + self.control.height + 2*drc["minwidth_metal3"]
self.height = self.bank.height
self.control.CSb_position.rotate().scale(-1,1)
self.CSb_position = (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.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.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.clk_position = (self.control.clk_position.rotate().scale(-1,1)
self.clk_position = (self.control.clk_position.rotate_scale(-1,1)
+self.control_position)
for i in range(0, self.word_size):
self.add_label(text="DATA[{0}]".format(i),
@ -612,7 +612,7 @@ class sram(design.design):
bank_attr = self.sram_property[attr_index]
self.add_rect(layer="metal3",
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"])
self.add_via(layers=("metal2", "via2", "metal3"),
offset=[self.vertical_line_positions[attr_index].x,
@ -710,17 +710,17 @@ class sram(design.design):
# 0 = s_en
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)
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)
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)
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)
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)
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)
bank_side = []
@ -763,14 +763,14 @@ class sram(design.design):
msb_line = self.control_size + self.num_banks/2 - 1 - i
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)
contact_pos = [self.vertical_line_positions[msb_line].x,
msf_msb_din.y - 0.5*self.m2m3_via.width]
contact_pos = vector(self.vertical_line_positions[msb_line].x,
msf_msb_din.y - 0.5*self.m2m3_via.width)
self.add_rect(layer="metal3",
offset=contact_pos,
width=msf_msb_din[0] - contact_pos[0],
width=msf_msb_din.x - contact_pos.x,
height=drc["minwidth_metal3"])
self.add_via(layers=("metal2", "via2", "metal3"),
offset=contact_pos)
@ -785,9 +785,9 @@ class sram(design.design):
height=drc["minwidth_metal1"])
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)
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)
starts = [msb_msf_dout_bar_position,
msb_msf_dout_position]
@ -801,9 +801,9 @@ class sram(design.design):
+ self.msf_msb_address.height
+ 4 * (i + 1) * drc["minwidth_metal2"],
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"])
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
contact_pos = vector(x_off,
@ -818,7 +818,7 @@ class sram(design.design):
if(self.num_banks == 4):
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)
msb_decoder_in_position =(self.msb_decoder.A_positions[i].scale(-1, 1)
+ self.msb_decoder_position
@ -827,11 +827,11 @@ class sram(design.design):
start = msb_msf_out_position
mid1 = start + vector(4 * (i + 1) * drc["minwidth_metal1"], 0)
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"],
mid2.y)
layer_stack = ("metal1", "via1", "metal2")
layer_stack = ("metal2", "via1", "metal1")
self.add_wire(layer_stack, [start, mid1, mid2, end])
self.add_rect(layer="metal1",
@ -874,9 +874,9 @@ class sram(design.design):
# control logic
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.rotate().scale(-1, 1))
+ self.control.vdd2_position.rotate_scale(-1, 1))
self.add_rect(layer="metal1",
offset=self.control_vdd1_position,
@ -974,7 +974,7 @@ class sram(design.design):
# msf_msb_address
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,
self.msf_msb_address_position.y
- self.msf_msb_address.width
@ -1029,7 +1029,7 @@ class sram(design.design):
offset=self.gnd_offset)
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))
self.add_rect(layer="metal3",
@ -1070,12 +1070,12 @@ class sram(design.design):
self.add_rect(layer="metal2",
offset=self.sram_bank_left_gnd_positions[0],
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.add_via(layers=("metal1", "via1", "metal2"),
offset=[self.sram_bank_left_gnd_positions[0].x
+ drc["minwidth_metal2"],
control_gnd_supply[1]],
control_gnd_supply.y],
mirror="R90")
# Control gnd
self.add_via(layers=("metal1", "via1", "metal2"),

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python2.7
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals

View File

@ -2,7 +2,7 @@
"Run a regresion test the library cells for DRC"
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
@ -33,7 +33,7 @@ class library_drc_test(unittest.TestCase):
# fails if there are any DRC errors on any cells
self.assertEqual(drc_errors, 0)
globals.end_openram()
def setup_files():
gds_dir = OPTS.openram_tech + "/gds_lib"

View File

@ -2,7 +2,7 @@
"Run a regresion test the library cells for LVS"
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
@ -37,7 +37,7 @@ class library_lvs_test(unittest.TestCase):
# fail if the error count is not zero
self.assertEqual(lvs_errors, 0)
globals.end_openram()
def setup_files():
gds_dir = OPTS.openram_tech + "/gds_lib"

View File

@ -2,7 +2,7 @@
"Run a regresion test for DRC on basic contacts of different array sizes"
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
@ -54,7 +54,8 @@ class contact_test(unittest.TestCase):
self.local_check(c)
OPTS.check_lvsdrc = True
globals.end_openram()
def local_check(self, c):
tempgds = OPTS.openram_temp + "temp.gds"
c.gds_write(tempgds)

View File

@ -2,7 +2,7 @@
"Run a regresion test on a basic path"
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
@ -75,7 +75,8 @@ class path_test(unittest.TestCase):
# return it back to it's normal state
OPTS.check_lvsdrc = True
globals.end_openram()
def local_check(self, w):
tempgds = OPTS.openram_temp + "temp.gds"
w.gds_write(tempgds)

View File

@ -2,7 +2,7 @@
"Run a regresion test on a basic parameterized transistors"
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
@ -33,7 +33,7 @@ class ptx_test(unittest.TestCase):
OPTS.check_lvsdrc = True
self.local_check(fet)
globals.end_openram()
def add_mods(self, fet):

View File

@ -2,7 +2,7 @@
"Run a regresion test on a basic parameterized transistors"
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
@ -33,7 +33,7 @@ class ptx_test(unittest.TestCase):
OPTS.check_lvsdrc = True
self.local_check(fet)
globals.end_openram()
def add_mods(self, fet):

View File

@ -2,7 +2,7 @@
"Run a regresion test on a basic parameterized transistors"
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
@ -33,7 +33,7 @@ class ptx_test(unittest.TestCase):
OPTS.check_lvsdrc = True
self.local_check(fet)
globals.end_openram()
def add_mods(self, fet):
self.create_contacts()

View File

@ -2,7 +2,7 @@
"Run a regresion test on a basic parameterized transistors"
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
@ -33,7 +33,8 @@ class ptx_test(unittest.TestCase):
OPTS.check_lvsdrc = True
self.local_check(fet)
globals.end_openram()
def add_mods(self, fet):
self.create_contacts()
self.add_well_extension(fet)

View File

@ -2,7 +2,7 @@
"Run a regresion test on a basic wire"
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
@ -128,7 +128,8 @@ class wire_test(unittest.TestCase):
# return it back to it's normal state
OPTS.check_lvsdrc = True
globals.end_openram()
def local_check(self, w):
tempgds = OPTS.openram_temp + "temp.gds"
w.gds_write(tempgds)

View File

@ -6,7 +6,7 @@ size 2_input nand gate that is nmos_width=2*tech.drc[minwidth_tx].
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
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"])
OPTS.check_lvsdrc = True
self.local_check(tx)
globals.end_openram()
def local_check(self, tx):
tempspice = OPTS.openram_temp + "temp.sp"

View File

@ -6,7 +6,7 @@ It generate only the minimum size 3_input nand gate that is nmos_width=3*tech.dr
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
@ -31,7 +31,8 @@ class nand_3_test(unittest.TestCase):
OPTS.check_lvsdrc = True
self.local_check(tx)
globals.end_openram()
def local_check(self, tx):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"

View File

@ -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]
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
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"])
OPTS.check_lvsdrc = True
self.local_check(tx)
globals.end_openram()
def local_check(self, tx):
tempspice = OPTS.openram_temp + "temp.sp"

View File

@ -4,7 +4,7 @@ Run regresion tests on a parameterized inverter
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
@ -42,6 +42,7 @@ class pinv_test(unittest.TestCase):
OPTS.check_lvsdrc = True
self.local_check(tx)
globals.end_openram()
def local_check(self, tx):
tempspice = OPTS.openram_temp + "temp.sp"

View File

@ -4,7 +4,7 @@ Run a regresion test on a wordline_driver array
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
@ -33,7 +33,7 @@ class wordline_driver_test(unittest.TestCase):
OPTS.check_lvsdrc = True
self.local_check(tx)
globals.end_openram()
def local_check(self, tx):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"

View File

@ -4,7 +4,7 @@ Run a regresion test on a basic array
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
@ -31,7 +31,7 @@ class array_test(unittest.TestCase):
OPTS.check_lvsdrc = True
self.local_check(a)
globals.end_openram()
def local_check(self, a):
tempspice = OPTS.openram_temp + "temp.sp"

View File

@ -4,7 +4,7 @@ Run a regresion test on a thierarchy_decoder.
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
@ -57,7 +57,8 @@ class hierarchical_decoder_test(unittest.TestCase):
OPTS.check_lvsdrc = True
self.local_check(a)
globals.end_openram()
def local_check(self, a):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"

View File

@ -4,7 +4,7 @@ Run a regresion test on a hierarchical_predecode2x4.
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
@ -30,7 +30,8 @@ class hierarchical_predecode2x4_test(unittest.TestCase):
OPTS.check_lvsdrc = True
self.local_check(a)
globals.end_openram()
def local_check(self, a):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"

View File

@ -4,7 +4,7 @@ Run a regresion test on a hierarchical_predecode3x8.
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
@ -30,6 +30,7 @@ class hierarchical_predecode3x8_test(unittest.TestCase):
OPTS.check_lvsdrc = True
self.local_check(a)
globals.end_openram()
def local_check(self, a):
tempspice = OPTS.openram_temp + "temp.sp"

View File

@ -4,7 +4,7 @@ Run a regresion test on a single transistor column_mux.
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
@ -28,7 +28,8 @@ class single_level_column_mux_test(unittest.TestCase):
rows=32, columns=32, word_size=16)
OPTS.check_lvsdrc = True
self.local_check(a)
globals.end_openram()
def local_check(self, a):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"

View File

@ -4,7 +4,7 @@ Run a regresion test on a precharge array
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
@ -38,7 +38,8 @@ class precharge_test(unittest.TestCase):
OPTS.check_lvsdrc = True
self.local_check(pc)
globals.end_openram()
def local_check(self, pc):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"

View File

@ -4,7 +4,7 @@ Run a regresion test on a sense amp array
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
@ -41,7 +41,8 @@ class sense_amp_test(unittest.TestCase):
OPTS.check_lvsdrc = True
self.local_check(a)
globals.end_openram()
def local_check(self, a):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"

View File

@ -4,7 +4,7 @@ Run a regresion test on a write driver array
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
@ -35,6 +35,7 @@ class write_driver_test(unittest.TestCase):
OPTS.check_lvsdrc = True
self.local_check(a)
globals.end_openram()
def local_check(self, a):
tempspice = OPTS.openram_temp + "temp.sp"

View File

@ -4,7 +4,7 @@ Run a regresion test on a dff_array.
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
@ -31,6 +31,7 @@ class dff_array_test(unittest.TestCase):
OPTS.check_lvsdrc = True
self.local_check(a)
globals.end_openram()
def local_check(self, a):
tempspice = OPTS.openram_temp + "temp.sp"

View File

@ -4,7 +4,7 @@ Run a regresion test on a control_logic
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
@ -29,7 +29,8 @@ class control_logic_test(unittest.TestCase):
OPTS.check_lvsdrc = True
self.local_check(a)
globals.end_openram()
def local_check(self, a):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"

View File

@ -4,7 +4,7 @@ Run a test on a delay chain
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
@ -31,6 +31,8 @@ class logic_effort_dc_test(unittest.TestCase):
OPTS.check_lvsdrc = True
self.local_check(a)
globals.end_openram()
def local_check(self, a):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"

View File

@ -4,7 +4,7 @@ Run a regresion test on a tri_gate_array.
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
@ -28,6 +28,8 @@ class tri_gate_array_test(unittest.TestCase):
OPTS.check_lvsdrc = True
self.local_check(a)
globals.end_openram()
def local_check(self, a):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"

View File

@ -4,7 +4,7 @@ Run a test on a delay chain
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
@ -31,6 +31,8 @@ class replica_bitline_test(unittest.TestCase):
OPTS.check_lvsdrc = True
self.local_check(a)
globals.end_openram()
def local_check(self, a):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"

View File

@ -4,7 +4,7 @@ Run a regresion test on various srams
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
@ -35,6 +35,8 @@ class bank_test(unittest.TestCase):
OPTS.check_lvsdrc = True
self.local_check(a)
globals.end_openram()
def local_check(self, a):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"

View File

@ -4,7 +4,7 @@ Run a regresion test on a 1 bank SRAM
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
@ -30,7 +30,8 @@ class sram_1bank_test(unittest.TestCase):
OPTS.check_lvsdrc = True
self.local_check(a)
globals.end_openram()
def local_check(self, a):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"

View File

@ -4,7 +4,7 @@ Run a regresion test on a 2 bank SRAM
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
@ -30,6 +30,8 @@ class sram_2bank_test(unittest.TestCase):
OPTS.check_lvsdrc = True
self.local_check(a)
globals.end_openram()
def local_check(self, a):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"

View File

@ -4,7 +4,7 @@ Run a regresion test on a 4 bank SRAM
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
@ -30,6 +30,8 @@ class sram_4bank_test(unittest.TestCase):
OPTS.check_lvsdrc = True
self.local_check(a)
globals.end_openram()
def local_check(self, a):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"

View File

@ -4,7 +4,7 @@ Run a regresion test on various srams
"""
import unittest
from header import header
from testutils import header,isclose
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
@ -22,8 +22,10 @@ class timing_sram_test(unittest.TestCase):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
OPTS.check_lvsdrc = False
OPTS.use_pex = False
OPTS.spice_version="hspice"
OPTS.force_spice = True
globals.set_spice()
import sram
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)
def isclose(value1,value2):
""" This is used to compare relative values for convergence. """
return (abs(value1 - value2) / max(value1,value2) <= 1e-2)
globals.end_openram()
# instantiate a copdsay of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()

View File

@ -4,7 +4,7 @@ Run a regresion test on various srams
"""
import unittest
from header import header
from testutils import header,isclose
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
@ -22,7 +22,9 @@ class timing_setup_test(unittest.TestCase):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
OPTS.check_lvsdrc = False
OPTS.use_pex = False
OPTS.spice_version="hspice"
OPTS.force_spice = True
globals.set_spice()
import sram
import setup_hold
@ -41,10 +43,7 @@ class timing_setup_test(unittest.TestCase):
else:
self.assertTrue(False) # other techs fail
def isclose(value1,value2):
""" This is used to compare relative values for convergence. """
return (abs(value1 - value2) / max(value1,value2) <= 1e-2)
globals.end_openram()
# instantiate a copdsay of the class to actually run the test
if __name__ == "__main__":

View File

@ -4,7 +4,7 @@ Run a regresion test on various srams
"""
import unittest
from header import header
from testutils import header,isclose
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
@ -20,9 +20,12 @@ 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.use_pex = False
OPTS.spice_version="hspice"
OPTS.force_spice = True
globals.set_spice()
import sram
import setup_hold
@ -40,11 +43,8 @@ class timing_setup_test(unittest.TestCase):
else:
self.assertTrue(False) # other techs fail
def isclose(value1,value2):
""" This is used to compare relative values for convergence. """
return (abs(value1 - value2) / max(value1,value2) <= 1e-2)
globals.end_openram()
# instantiate a copdsay of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -4,7 +4,7 @@ Run a regression test on an extracted SRAM to ensure functionality.
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
@ -24,6 +24,8 @@ class sram_func_test(unittest.TestCase):
self.func_test(bank_num=2)
self.func_test(bank_num=4)
globals.end_openram()
def func_test(self, bank_num):
import sram

View File

@ -4,7 +4,7 @@ Run a regresion test on various srams
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
@ -22,7 +22,6 @@ class sram_func_test(unittest.TestCase):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
OPTS.check_lvsdrc = False
OPTS.use_pex = False
import sram
@ -51,6 +50,8 @@ class sram_func_test(unittest.TestCase):
os.remove(tempspice)
globals.end_openram()
# instantiate a copdsay of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()

View File

@ -4,7 +4,7 @@ Check the .lib file for an SRAM
"""
import unittest
from header import header
from testutils import header,isdiff
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
@ -20,11 +20,9 @@ class lib_test(unittest.TestCase):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
OPTS.check_lvsdrc = False
OPTS.use_pex = False
import sram
import lib
import filecmp
debug.info(1, "Testing timing for sample 2 bit, 16 words SRAM with 1 bank")
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))
OPTS.check_lvsdrc = True
tempspice = OPTS.openram_temp + "temp.sp"
s.sp_write(tempspice)
curpath=os.path.dirname(os.path.realpath(__file__)) + "/"
filename = s.name + ".lib"
libname = curpath + filename
libname = OPTS.openram_temp + filename
lib.lib(libname,s,tempspice)
# let's diff the result with a golden model
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))
globals.end_openram()
# instantiate a copdsay of the class to actually run the test
if __name__ == "__main__":

View File

@ -4,7 +4,7 @@ Check the LEF file for an SRMA
"""
import unittest
from header import header
from testutils import header,isdiff
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
@ -23,7 +23,6 @@ class lef_test(unittest.TestCase):
import sram
import lef
import filecmp
debug.info(1, "Testing LEF for sample 2 bit, 16 words SRAM with 1 bank")
s = sram.sram(word_size=2,
@ -33,22 +32,21 @@ class lef_test(unittest.TestCase):
OPTS.check_lvsdrc = True
curpath=os.path.dirname(os.path.realpath(__file__)) + "/"
gdsfile = s.name + ".gds"
leffile = s.name + ".lef"
gdsname = curpath + gdsfile
lefname = curpath + leffile
gdsname = OPTS.openram_temp + gdsfile
lefname = OPTS.openram_temp + leffile
s.gds_write(gdsname)
lef.lef(gdsname,lefname,s)
# let's diff the result with a golden model
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(lefname))
globals.end_openram()
# instantiate a copdsay of the class to actually run the test
if __name__ == "__main__":

View File

@ -4,7 +4,7 @@ Check the .v file for an SRAM
"""
import unittest
from header import header
from testutils import header,isdiff
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
@ -23,7 +23,6 @@ class verilog_test(unittest.TestCase):
import sram
import verilog
import filecmp
debug.info(1, "Testing Verilog for sample 2 bit, 16 words SRAM with 1 bank")
s = sram.sram(word_size=2,
@ -33,18 +32,19 @@ class verilog_test(unittest.TestCase):
OPTS.check_lvsdrc = True
curpath=os.path.dirname(os.path.realpath(__file__)) + "/"
vfile = s.name + ".v"
vname = curpath + vfile
vname = OPTS.openram_temp + vfile
verilog.verilog(vname,s)
# let's diff the result with a golden model
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))
globals.end_openram()
# instantiate a copdsay of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()

View File

@ -6,7 +6,7 @@ check that these files are right.
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
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.")
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
out_path += "/testsram"
out_path = OPTS.openram_temp + out_file
# make sure we start without the files existing
if os.path.exists(out_path):
@ -73,6 +71,7 @@ class openram_test(unittest.TestCase):
shutil.rmtree(out_path, ignore_errors=True)
self.assertEqual(os.path.exists(out_path),False)
globals.end_openram()
# instantiate a copdsay of the class to actually run the test
if __name__ == "__main__":

View File

@ -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 "|==============================================================================|"

View File

@ -9,8 +9,8 @@ import globals
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
import header
header.header(__file__, OPTS.tech_name)
from testutils import header
header(__file__, OPTS.tech_name)
# get a list of all files in the tests directory
files = os.listdir(sys.path[0])

View File

@ -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 "|==============================================================================|"

View File

@ -24,3 +24,7 @@ def auto_measure_libcell(pin_list, name, units, layer):
for pin in pin_list:
cell[str(pin)] = gdsPinToOffset(cell_vlsi.readPin(str(pin)))
return cell

View File

@ -83,6 +83,16 @@ class vector():
"""
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):
""" pass a copy of rotated vector, without altering the vector! """
return vector(self.y,self.x)
@ -94,12 +104,9 @@ class vector():
x_factor=x_factor[0]
return vector(self.x*x_factor,self.y*y_factor)
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_scale(self, x_factor, y_factor=None):
""" pass a copy of scaled vector, without altering the vector! """
if y_factor==None:
y_factor=x_factor[1]
x_factor=x_factor[0]
return vector(self.y*x_factor,self.x*y_factor)

View File

@ -20,7 +20,7 @@ class wire(path):
name = "wire_{0}".format(wire.unique_wire_id)
wire.unique_wire_id += 1
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.position_list = position_list
@ -37,7 +37,7 @@ class wire(path):
# wires and paths should not be offset to (0,0)
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):
self.via_layer_name = via_layer
else:

View File

@ -23,7 +23,8 @@ os.environ["MGC_TMPDIR"] = "/tmp"
#OpenRAM Paths
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"
##########################

View File

@ -21,8 +21,12 @@ os.environ["MGC_TMPDIR"] = "/tmp"
# OpenRAM Paths
OPENRAM_TECH=os.path.abspath(os.environ.get("OPENRAM_TECH"))
DRCLVS_HOME=OPENRAM_TECH+"/scn3me_subm/tech"
os.environ["DRCLVS_HOME"] = DRCLVS_HOME
os.environ["SPICE_MODEL_DIR"] = "/mada/software/techfiles/scn3me_subm"
os.environ["DRCLVS_HOME"] = DRCLVS_HOME
# 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