diff --git a/ICCAD16_openram_paper/OpenRAM_ICCAD_2016_paper.pdf b/ICCAD16_openram_paper/OpenRAM_ICCAD_2016_paper.pdf new file mode 100644 index 00000000..fd3a4a65 Binary files /dev/null and b/ICCAD16_openram_paper/OpenRAM_ICCAD_2016_paper.pdf differ diff --git a/README b/README index 2c315a6f..a0a14ee7 100644 --- a/README +++ b/README @@ -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 diff --git a/compiler/TODO b/compiler/TODO index e8750fbc..5526f91a 100644 --- a/compiler/TODO +++ b/compiler/TODO @@ -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. \ No newline at end of file +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 + diff --git a/compiler/bank.py b/compiler/bank.py index 7cb2ba12..8c60c9d9 100644 --- a/compiler/bank.py +++ b/compiler/bank.py @@ -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]), diff --git a/compiler/calibre.py b/compiler/calibre.py index 17dd45a5..5b9e17b5 100644 --- a/compiler/calibre.py +++ b/compiler/calibre.py @@ -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") diff --git a/compiler/characterizer/charutils.py b/compiler/characterizer/charutils.py index 8f5952e7..009e1d82 100644 --- a/compiler/characterizer/charutils.py +++ b/compiler/characterizer/charutils.py @@ -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: diff --git a/compiler/characterizer/delay.py b/compiler/characterizer/delay.py index e140ab24..d737d2c9 100644 --- a/compiler/characterizer/delay.py +++ b/compiler/characterizer/delay.py @@ -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) diff --git a/compiler/characterizer/setup_hold.py b/compiler/characterizer/setup_hold.py index 2ce38411..999a3a95 100644 --- a/compiler/characterizer/setup_hold.py +++ b/compiler/characterizer/setup_hold.py @@ -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 diff --git a/compiler/characterizer/stimuli.py b/compiler/characterizer/stimuli.py index 52fd3350..6116021c 100644 --- a/compiler/characterizer/stimuli.py +++ b/compiler/characterizer/stimuli.py @@ -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) diff --git a/compiler/contact.py b/compiler/contact.py index 4553ff91..4a329610 100644 --- a/compiler/contact.py +++ b/compiler/contact.py @@ -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 diff --git a/compiler/control_logic.py b/compiler/control_logic.py index e08663ad..93430f34 100644 --- a/compiler/control_logic.py +++ b/compiler/control_logic.py @@ -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) diff --git a/compiler/globals.py b/compiler/globals.py index a4b60f94..2d8a9667 100644 --- a/compiler/globals.py +++ b/compiler/globals.py @@ -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] \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 diff --git a/compiler/hierarchical_decoder.py b/compiler/hierarchical_decoder.py index e964cc2a..ace1792f 100644 --- a/compiler/hierarchical_decoder.py +++ b/compiler/hierarchical_decoder.py @@ -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 diff --git a/compiler/hierarchical_predecode.py b/compiler/hierarchical_predecode.py index 0b2566f8..ef5095af 100644 --- a/compiler/hierarchical_predecode.py +++ b/compiler/hierarchical_predecode.py @@ -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"]) diff --git a/compiler/hierarchical_predecode2x4.py b/compiler/hierarchical_predecode2x4.py index 33065db8..c5cfd5b4 100644 --- a/compiler/hierarchical_predecode2x4.py +++ b/compiler/hierarchical_predecode2x4.py @@ -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, diff --git a/compiler/hierarchical_predecode3x8.py b/compiler/hierarchical_predecode3x8.py index 4d6f4c0d..50fc6031 100644 --- a/compiler/hierarchical_predecode3x8.py +++ b/compiler/hierarchical_predecode3x8.py @@ -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]) diff --git a/compiler/hierarchy_layout.py b/compiler/hierarchy_layout.py index bd6d4685..f08cb016 100644 --- a/compiler/hierarchy_layout.py +++ b/compiler/hierarchy_layout.py @@ -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"]) diff --git a/compiler/hierarchy_spice.py b/compiler/hierarchy_spice.py index 857b5ec7..78fc56e0 100644 --- a/compiler/hierarchy_spice.py +++ b/compiler/hierarchy_spice.py @@ -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)): diff --git a/compiler/logic_effort_dc.py b/compiler/logic_effort_dc.py index df7f178f..8d0431e4 100644 --- a/compiler/logic_effort_dc.py +++ b/compiler/logic_effort_dc.py @@ -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]) diff --git a/compiler/nand_2.py b/compiler/nand_2.py index 4b97aa61..775be9da 100644 --- a/compiler/nand_2.py +++ b/compiler/nand_2.py @@ -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, diff --git a/compiler/nand_3.py b/compiler/nand_3.py index 7e4904e1..b8e67f44 100644 --- a/compiler/nand_3.py +++ b/compiler/nand_3.py @@ -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, diff --git a/compiler/nor_2.py b/compiler/nor_2.py index 8e22f30c..b2de66fd 100644 --- a/compiler/nor_2.py +++ b/compiler/nor_2.py @@ -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 diff --git a/compiler/openram.py b/compiler/openram.py index dace6489..f9f6e2f4 100755 --- a/compiler/openram.py +++ b/compiler/openram.py @@ -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() diff --git a/compiler/options.py b/compiler/options.py index 616630a0..ffe7f01d 100644 --- a/compiler/options.py +++ b/compiler/options.py @@ -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 diff --git a/compiler/path.py b/compiler/path.py index 5e88eb40..75d6df96 100644 --- a/compiler/path.py +++ b/compiler/path.py @@ -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 diff --git a/compiler/pinv.py b/compiler/pinv.py index 3bad3d81..e03f4c06 100644 --- a/compiler/pinv.py +++ b/compiler/pinv.py @@ -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, diff --git a/compiler/precharge.py b/compiler/precharge.py index 138df604..c5eb6a31 100644 --- a/compiler/precharge.py +++ b/compiler/precharge.py @@ -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", diff --git a/compiler/ptx.py b/compiler/ptx.py index f6d29027..0821f762 100644 --- a/compiler/ptx.py +++ b/compiler/ptx.py @@ -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, diff --git a/compiler/replica_bitline.py b/compiler/replica_bitline.py index cd91b4bf..6d562937 100644 --- a/compiler/replica_bitline.py +++ b/compiler/replica_bitline.py @@ -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]) diff --git a/compiler/single_level_column_mux.py b/compiler/single_level_column_mux.py index 30c32176..ab38ceb4 100644 --- a/compiler/single_level_column_mux.py +++ b/compiler/single_level_column_mux.py @@ -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): diff --git a/compiler/sram.py b/compiler/sram.py index 67a12817..420ac873 100644 --- a/compiler/sram.py +++ b/compiler/sram.py @@ -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"), diff --git a/compiler/tests/00_code_format_check_test.py b/compiler/tests/00_code_format_check_test.py index b732edde..04ea2e99 100644 --- a/compiler/tests/00_code_format_check_test.py +++ b/compiler/tests/00_code_format_check_test.py @@ -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 diff --git a/compiler/tests/01_library_drc_test.py b/compiler/tests/01_library_drc_test.py index 63f7f90e..e394d84b 100644 --- a/compiler/tests/01_library_drc_test.py +++ b/compiler/tests/01_library_drc_test.py @@ -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" diff --git a/compiler/tests/02_library_lvs_test.py b/compiler/tests/02_library_lvs_test.py index 356ad075..734784e0 100644 --- a/compiler/tests/02_library_lvs_test.py +++ b/compiler/tests/02_library_lvs_test.py @@ -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" diff --git a/compiler/tests/03_contact_test.py b/compiler/tests/03_contact_test.py index 502a0e2f..85acc10a 100644 --- a/compiler/tests/03_contact_test.py +++ b/compiler/tests/03_contact_test.py @@ -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) diff --git a/compiler/tests/03_path_test.py b/compiler/tests/03_path_test.py index dd622a13..64767f3f 100644 --- a/compiler/tests/03_path_test.py +++ b/compiler/tests/03_path_test.py @@ -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) diff --git a/compiler/tests/03_ptx_1finger_nmos_test.py b/compiler/tests/03_ptx_1finger_nmos_test.py index 07d233e6..3f023020 100644 --- a/compiler/tests/03_ptx_1finger_nmos_test.py +++ b/compiler/tests/03_ptx_1finger_nmos_test.py @@ -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): diff --git a/compiler/tests/03_ptx_1finger_pmos_test.py b/compiler/tests/03_ptx_1finger_pmos_test.py index 7c9a012a..4bb3e312 100644 --- a/compiler/tests/03_ptx_1finger_pmos_test.py +++ b/compiler/tests/03_ptx_1finger_pmos_test.py @@ -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): diff --git a/compiler/tests/03_ptx_3finger_nmos_test.py b/compiler/tests/03_ptx_3finger_nmos_test.py index d146cea7..17ec9092 100644 --- a/compiler/tests/03_ptx_3finger_nmos_test.py +++ b/compiler/tests/03_ptx_3finger_nmos_test.py @@ -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() diff --git a/compiler/tests/03_ptx_3finger_pmos_test.py b/compiler/tests/03_ptx_3finger_pmos_test.py index 603e0b64..f889527d 100644 --- a/compiler/tests/03_ptx_3finger_pmos_test.py +++ b/compiler/tests/03_ptx_3finger_pmos_test.py @@ -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) diff --git a/compiler/tests/03_wire_test.py b/compiler/tests/03_wire_test.py index b458d458..d9856b43 100644 --- a/compiler/tests/03_wire_test.py +++ b/compiler/tests/03_wire_test.py @@ -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) diff --git a/compiler/tests/04_nand_2_test.py b/compiler/tests/04_nand_2_test.py index 1472cb0d..aa8d6c08 100644 --- a/compiler/tests/04_nand_2_test.py +++ b/compiler/tests/04_nand_2_test.py @@ -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" diff --git a/compiler/tests/04_nand_3_test.py b/compiler/tests/04_nand_3_test.py index d751a8a3..87ba75a0 100644 --- a/compiler/tests/04_nand_3_test.py +++ b/compiler/tests/04_nand_3_test.py @@ -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" diff --git a/compiler/tests/04_nor_2_test.py b/compiler/tests/04_nor_2_test.py index 746891eb..d866cede 100644 --- a/compiler/tests/04_nor_2_test.py +++ b/compiler/tests/04_nor_2_test.py @@ -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" diff --git a/compiler/tests/04_pinv_test.py b/compiler/tests/04_pinv_test.py index ecbbb7e6..de20a27d 100644 --- a/compiler/tests/04_pinv_test.py +++ b/compiler/tests/04_pinv_test.py @@ -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" diff --git a/compiler/tests/04_wordline_driver_test.py b/compiler/tests/04_wordline_driver_test.py index d5f6a7c4..b1a5c470 100644 --- a/compiler/tests/04_wordline_driver_test.py +++ b/compiler/tests/04_wordline_driver_test.py @@ -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" diff --git a/compiler/tests/05_bitcell_array_test.py b/compiler/tests/05_bitcell_array_test.py index e794c72c..6ec0c7d4 100644 --- a/compiler/tests/05_bitcell_array_test.py +++ b/compiler/tests/05_bitcell_array_test.py @@ -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" diff --git a/compiler/tests/06_hierarchical_decoder_test.py b/compiler/tests/06_hierarchical_decoder_test.py index a087c5f3..649a1fd9 100644 --- a/compiler/tests/06_hierarchical_decoder_test.py +++ b/compiler/tests/06_hierarchical_decoder_test.py @@ -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" diff --git a/compiler/tests/06_hierarchical_predecode2x4_test.py b/compiler/tests/06_hierarchical_predecode2x4_test.py index 0114728e..551a1fb0 100644 --- a/compiler/tests/06_hierarchical_predecode2x4_test.py +++ b/compiler/tests/06_hierarchical_predecode2x4_test.py @@ -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" diff --git a/compiler/tests/06_hierarchical_predecode3x8_test.py b/compiler/tests/06_hierarchical_predecode3x8_test.py index 6458513e..50162d31 100644 --- a/compiler/tests/06_hierarchical_predecode3x8_test.py +++ b/compiler/tests/06_hierarchical_predecode3x8_test.py @@ -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" diff --git a/compiler/tests/07_single_level_column_mux_test.py b/compiler/tests/07_single_level_column_mux_test.py index c810b865..490a3497 100644 --- a/compiler/tests/07_single_level_column_mux_test.py +++ b/compiler/tests/07_single_level_column_mux_test.py @@ -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" diff --git a/compiler/tests/08_precharge_array_test.py b/compiler/tests/08_precharge_array_test.py index 66fcb193..308dc937 100644 --- a/compiler/tests/08_precharge_array_test.py +++ b/compiler/tests/08_precharge_array_test.py @@ -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" diff --git a/compiler/tests/09_sense_amp_array_test.py b/compiler/tests/09_sense_amp_array_test.py index 2974712e..80536e16 100644 --- a/compiler/tests/09_sense_amp_array_test.py +++ b/compiler/tests/09_sense_amp_array_test.py @@ -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" diff --git a/compiler/tests/10_write_driver_array_test.py b/compiler/tests/10_write_driver_array_test.py index 559107f8..ca289e30 100644 --- a/compiler/tests/10_write_driver_array_test.py +++ b/compiler/tests/10_write_driver_array_test.py @@ -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" diff --git a/compiler/tests/11_ms_flop_array_test.py b/compiler/tests/11_ms_flop_array_test.py index 33680a53..9f282278 100644 --- a/compiler/tests/11_ms_flop_array_test.py +++ b/compiler/tests/11_ms_flop_array_test.py @@ -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" diff --git a/compiler/tests/13_control_logic_test.py b/compiler/tests/13_control_logic_test.py index 37c39ca1..8d308ace 100644 --- a/compiler/tests/13_control_logic_test.py +++ b/compiler/tests/13_control_logic_test.py @@ -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" diff --git a/compiler/tests/14_logic_effort_dc_test.py b/compiler/tests/14_logic_effort_dc_test.py index 48e8b768..0ce27871 100644 --- a/compiler/tests/14_logic_effort_dc_test.py +++ b/compiler/tests/14_logic_effort_dc_test.py @@ -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" diff --git a/compiler/tests/15_tri_gate_array_test.py b/compiler/tests/15_tri_gate_array_test.py index ef388696..1b7c8440 100644 --- a/compiler/tests/15_tri_gate_array_test.py +++ b/compiler/tests/15_tri_gate_array_test.py @@ -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" diff --git a/compiler/tests/16_replica_bitline_test.py b/compiler/tests/16_replica_bitline_test.py index 2b0aaa9a..6e0d943e 100644 --- a/compiler/tests/16_replica_bitline_test.py +++ b/compiler/tests/16_replica_bitline_test.py @@ -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" diff --git a/compiler/tests/19_bank_test.py b/compiler/tests/19_bank_test.py index aef9068b..bfeeef61 100644 --- a/compiler/tests/19_bank_test.py +++ b/compiler/tests/19_bank_test.py @@ -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" diff --git a/compiler/tests/20_sram_1bank_test.py b/compiler/tests/20_sram_1bank_test.py index d1b553ae..261fa315 100644 --- a/compiler/tests/20_sram_1bank_test.py +++ b/compiler/tests/20_sram_1bank_test.py @@ -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" diff --git a/compiler/tests/20_sram_2bank_test.py b/compiler/tests/20_sram_2bank_test.py index b07bf1a5..ce0e1c07 100644 --- a/compiler/tests/20_sram_2bank_test.py +++ b/compiler/tests/20_sram_2bank_test.py @@ -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" diff --git a/compiler/tests/20_sram_4bank_test.py b/compiler/tests/20_sram_4bank_test.py index beacc5e2..8603cd8a 100644 --- a/compiler/tests/20_sram_4bank_test.py +++ b/compiler/tests/20_sram_4bank_test.py @@ -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" diff --git a/compiler/tests/21_timing_delay_test.py b/compiler/tests/21_hspice_delay_test.py similarity index 89% rename from compiler/tests/21_timing_delay_test.py rename to compiler/tests/21_hspice_delay_test.py index 8a129203..c1354790 100644 --- a/compiler/tests/21_timing_delay_test.py +++ b/compiler/tests/21_hspice_delay_test.py @@ -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() diff --git a/compiler/tests/21_timing_hold_test.py b/compiler/tests/21_hspice_hold_test.py similarity index 85% rename from compiler/tests/21_timing_hold_test.py rename to compiler/tests/21_hspice_hold_test.py index 78d4fe5b..533a0afd 100644 --- a/compiler/tests/21_timing_hold_test.py +++ b/compiler/tests/21_hspice_hold_test.py @@ -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__": diff --git a/compiler/tests/21_timing_setup_test.py b/compiler/tests/21_hspice_setup_test.py similarity index 85% rename from compiler/tests/21_timing_setup_test.py rename to compiler/tests/21_hspice_setup_test.py index 4011d6ad..6e264531 100644 --- a/compiler/tests/21_timing_setup_test.py +++ b/compiler/tests/21_hspice_setup_test.py @@ -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() diff --git a/compiler/tests/21_ngspice_delay_test.py b/compiler/tests/21_ngspice_delay_test.py new file mode 100644 index 00000000..50985119 --- /dev/null +++ b/compiler/tests/21_ngspice_delay_test.py @@ -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() diff --git a/compiler/tests/21_ngspice_hold_test.py b/compiler/tests/21_ngspice_hold_test.py new file mode 100644 index 00000000..f8c891ee --- /dev/null +++ b/compiler/tests/21_ngspice_hold_test.py @@ -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() diff --git a/compiler/tests/21_ngspice_setup_test.py b/compiler/tests/21_ngspice_setup_test.py new file mode 100644 index 00000000..79d1b218 --- /dev/null +++ b/compiler/tests/21_ngspice_setup_test.py @@ -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() diff --git a/compiler/tests/22_pex_func_test_with_pinv.py b/compiler/tests/22_pex_func_test_with_pinv.py index 58c40e18..f9410eea 100644 --- a/compiler/tests/22_pex_func_test_with_pinv.py +++ b/compiler/tests/22_pex_func_test_with_pinv.py @@ -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 diff --git a/compiler/tests/22_sram_func_test.py b/compiler/tests/22_sram_func_test.py index 5c7bc6c3..bc4b876b 100644 --- a/compiler/tests/22_sram_func_test.py +++ b/compiler/tests/22_sram_func_test.py @@ -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() diff --git a/compiler/tests/23_lib_sram_test.py b/compiler/tests/23_lib_sram_test.py index 3c2d226c..6ad3041a 100644 --- a/compiler/tests/23_lib_sram_test.py +++ b/compiler/tests/23_lib_sram_test.py @@ -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__": diff --git a/compiler/tests/24_lef_sram_test.py b/compiler/tests/24_lef_sram_test.py index 2a349502..5c08d72e 100644 --- a/compiler/tests/24_lef_sram_test.py +++ b/compiler/tests/24_lef_sram_test.py @@ -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__": diff --git a/compiler/tests/25_verilog_sram_test.py b/compiler/tests/25_verilog_sram_test.py index dc628081..cf042089 100644 --- a/compiler/tests/25_verilog_sram_test.py +++ b/compiler/tests/25_verilog_sram_test.py @@ -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() diff --git a/compiler/tests/30_openram_test.py b/compiler/tests/30_openram_test.py index ce0a2a05..575cd39b 100644 --- a/compiler/tests/30_openram_test.py +++ b/compiler/tests/30_openram_test.py @@ -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__": diff --git a/compiler/tests/header.py b/compiler/tests/header.py deleted file mode 100644 index 194a301d..00000000 --- a/compiler/tests/header.py +++ /dev/null @@ -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 "|==============================================================================|" diff --git a/compiler/tests/regress.py b/compiler/tests/regress.py index d0307116..5b958faf 100644 --- a/compiler/tests/regress.py +++ b/compiler/tests/regress.py @@ -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]) diff --git a/compiler/tests/sram_2_16_1_freepdk45.gds b/compiler/tests/sram_2_16_1_freepdk45.gds deleted file mode 100644 index 2be62057..00000000 Binary files a/compiler/tests/sram_2_16_1_freepdk45.gds and /dev/null differ diff --git a/compiler/tests/sram_2_16_1_freepdk45.lef b/compiler/tests/sram_2_16_1_freepdk45.lef deleted file mode 100644 index e69de29b..00000000 diff --git a/compiler/tests/testutils.py b/compiler/tests/testutils.py new file mode 100644 index 00000000..7b8e2cc6 --- /dev/null +++ b/compiler/tests/testutils.py @@ -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 "|==============================================================================|" diff --git a/compiler/utils.py b/compiler/utils.py index 0ba5a5b8..8916f24f 100644 --- a/compiler/utils.py +++ b/compiler/utils.py @@ -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 + + + + diff --git a/compiler/vector.py b/compiler/vector.py index 41180e10..b5273252 100644 --- a/compiler/vector.py +++ b/compiler/vector.py @@ -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) diff --git a/compiler/wire.py b/compiler/wire.py index 541fa50a..821dc3bd 100644 --- a/compiler/wire.py +++ b/compiler/wire.py @@ -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: diff --git a/technology/setup_scripts/setup_openram_freepdk45.py b/technology/setup_scripts/setup_openram_freepdk45.py index 6488d604..6c010ae9 100644 --- a/technology/setup_scripts/setup_openram_freepdk45.py +++ b/technology/setup_scripts/setup_openram_freepdk45.py @@ -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" ########################## diff --git a/technology/setup_scripts/setup_openram_scn3me_subm.py b/technology/setup_scripts/setup_openram_scn3me_subm.py index 2ea082a3..da5d1374 100644 --- a/technology/setup_scripts/setup_openram_scn3me_subm.py +++ b/technology/setup_scripts/setup_openram_scn3me_subm.py @@ -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