Two bank SRAMs working in both technologies.

This commit is contained in:
Matt Guthaus 2017-09-29 16:22:13 -07:00
parent d29dd03373
commit e06e1691c8
41 changed files with 20945 additions and 19280 deletions

View File

@ -39,7 +39,7 @@ class bank(design.design):
self.num_banks = num_banks self.num_banks = num_banks
# The local control signals are gated when we have bank select logic, # The local control signals are gated when we have bank select logic,
# so this prefix will be added to all of the signals. # so this prefix will be added to all of the input signals.
if self.num_banks>1: if self.num_banks>1:
self.prefix="gated_" self.prefix="gated_"
else: else:
@ -59,6 +59,8 @@ class bank(design.design):
# Can remove the following, but it helps for debug! # Can remove the following, but it helps for debug!
self.add_lvs_correspondence_points() self.add_lvs_correspondence_points()
self.offset_all_coordinates()
self.DRC_LVS() self.DRC_LVS()
def add_pins(self): def add_pins(self):
@ -71,9 +73,9 @@ class bank(design.design):
# For more than one bank, we have a bank select and name # For more than one bank, we have a bank select and name
# the signals gated_*. # the signals gated_*.
if(self.num_banks > 1): if(self.num_banks > 1):
self.add_pin("bank_select") self.add_pin("bank_sel")
for pin in ["s_en","w_en","tri_en_bar","tri_en", for pin in ["s_en","w_en","tri_en_bar","tri_en",
"clk_bar","clk","vdd","gnd"]: "clk_bar","clk_buf","vdd","gnd"]:
self.add_pin(pin) self.add_pin(pin)
def route_layout(self): def route_layout(self):
@ -91,7 +93,7 @@ class bank(design.design):
self.route_vdd_supply() self.route_vdd_supply()
self.route_gnd_supply() self.route_gnd_supply()
self.offset_all_coordinates()
def add_modules(self): def add_modules(self):
@ -135,7 +137,7 @@ class bank(design.design):
# Number of control lines in the bus # Number of control lines in the bus
self.num_control_lines = 6 self.num_control_lines = 6
# The order of the control signals on the control bus: # The order of the control signals on the control bus:
self.input_control_signals = ["clk", "tri_en_bar", "tri_en", "clk_bar", "w_en", "s_en"] self.input_control_signals = ["clk_buf", "tri_en_bar", "tri_en", "clk_bar", "w_en", "s_en"]
# These will be outputs of the gaters if this is multibank # These will be outputs of the gaters if this is multibank
if self.num_banks>1: if self.num_banks>1:
self.control_signals = ["gated_"+str for str in self.input_control_signals] self.control_signals = ["gated_"+str for str in self.input_control_signals]
@ -158,8 +160,8 @@ class bank(design.design):
# Overall central bus gap. It includes all the column mux lines, # Overall central bus gap. It includes all the column mux lines,
# control lines, address flop to decoder lines and a GND power rail in M2 # control lines, address flop to decoder lines and a GND power rail in M2
# one pitch on the right on the right of the control lines # 1.5 pitches on the right on the right of the control lines for vias (e.g. column mux addr lines)
self.start_of_right_central_bus = -self.m2_pitch * (self.num_control_lines + 1) self.start_of_right_central_bus = -self.m2_pitch * (self.num_control_lines + 1.5)
# one pitch on the right on the addr lines and one on the right of the gnd rail # one pitch on the right on the addr lines and one on the right of the gnd rail
self.start_of_left_central_bus = self.start_of_right_central_bus - self.m2_pitch*(self.num_addr_lines+2) - self.gnd_rail_width self.start_of_left_central_bus = self.start_of_right_central_bus - self.m2_pitch*(self.num_addr_lines+2) - self.gnd_rail_width
# add a pitch on each end and around the gnd rail # add a pitch on each end and around the gnd rail
@ -397,7 +399,7 @@ class bank(design.design):
temp.append("dec_out[{0}]".format(i)) temp.append("dec_out[{0}]".format(i))
for i in range(self.num_rows): for i in range(self.num_rows):
temp.append("wl[{0}]".format(i)) temp.append("wl[{0}]".format(i))
temp.append(self.prefix+"clk") temp.append(self.prefix+"clk_buf")
temp.append("vdd") temp.append("vdd")
temp.append("gnd") temp.append("gnd")
self.connect_inst(temp) self.connect_inst(temp)
@ -426,7 +428,7 @@ class bank(design.design):
temp.extend(["sel[1]","sel[0]"]) temp.extend(["sel[1]","sel[0]"])
else: else:
temp.extend(["A[{0}]".format(i),"A_bar[{0}]".format(i)]) temp.extend(["A[{0}]".format(i),"A_bar[{0}]".format(i)])
temp.append(self.prefix+"clk") temp.append(self.prefix+"clk_buf")
temp.extend(["vdd", "gnd"]) temp.extend(["vdd", "gnd"])
self.connect_inst(temp) self.connect_inst(temp)
@ -482,9 +484,9 @@ class bank(design.design):
self.add_mod(self.nand2) self.add_mod(self.nand2)
# left of gnd rail is the "bus start" # left of gnd rail is the "bus start"
bus_start = self.gnd_x_offset - 2*drc["minwidth_metal2"] bus_start = self.gnd_x_offset - drc["metal2_to_metal2"]
xoffset_nand = bus_start - self.nand2.width - self.inv4x.width - 2*self.m2_pitch xoffset_nand = bus_start - self.nand2.width - self.inv4x.width - drc["pwell_to_nwell"]
xoffset_nor = bus_start - self.nor2.width - self.inv4x.width - 2*self.m2_pitch xoffset_nor = bus_start - self.nor2.width - self.inv4x.width - drc["pwell_to_nwell"]
xoffset_inv = bus_start - self.inv4x.width xoffset_inv = bus_start - self.inv4x.width
xoffset_bank_sel_inv = xoffset_nor - self.inv.width - 3*self.m2_pitch xoffset_bank_sel_inv = xoffset_nor - self.inv.width - 3*self.m2_pitch
xoffset_inputs = xoffset_bank_sel_inv - 6*self.m2_pitch xoffset_inputs = xoffset_bank_sel_inv - 6*self.m2_pitch
@ -500,32 +502,38 @@ class bank(design.design):
# bank_sel is vertical wire # bank_sel is vertical wire
xoffset_bank_sel = xoffset_bank_sel_inv xoffset_bank_sel = xoffset_bank_sel_inv
bank_sel_line_pos = vector(xoffset_bank_sel, self.min_point)
self.add_label_pin(text="bank_sel", self.add_label_pin(text="bank_sel",
layer="metal2", layer="metal2",
offset=vector(xoffset_bank_sel, self.min_point), offset=bank_sel_line_pos,
width=self.m2_width, width=self.m2_width,
height=self.decoder_min_point-self.min_point-self.m2_pitch) height=self.decoder_min_point-self.min_point-self.m2_pitch)
in_pin = bank_sel_inv.get_pin("A").ll()
self.add_via(layers=("metal1","via1","metal2"), bank_sel_inv_in_pos = bank_sel_inv.get_pin("A").lc()
offset=in_pin) self.add_center_via(layers=("metal1","via1","metal2"),
self.add_layout_pin(text="bank_sel", offset=bank_sel_inv_in_pos,
layer="metal3", rotate=90)
offset=vector(self.left_vdd_x_offset, self.min_point),
width=xoffset_bank_sel - self.left_vdd_x_offset, bank_sel_line_pos = vector(xoffset_bank_sel + 0.5*self.m2_width, self.min_point)
height=self.m3_width) bank_sel_pin_pos=vector(self.left_vdd_x_offset, self.min_point)
self.add_via(layers=("metal2","via2","metal3"), self.add_center_layout_pin(text="bank_sel",
offset=vector(xoffset_bank_sel_inv, self.min_point)) layer="metal3",
start=bank_sel_pin_pos,
end=bank_sel_line_pos)
self.add_center_via(layers=("metal2","via2","metal3"),
offset=bank_sel_line_pos,
rotate=90)
# bank_sel_bar is vertical wire # bank_sel_bar is vertical wire
xoffset_bank_sel_bar = xoffset_bank_sel_inv+self.inv.width-self.m2_width xoffset_bank_sel_bar = bank_sel_inv.get_pin("Z").rx()
self.add_label_pin(text="bank_sel_bar", self.add_label_pin(text="bank_sel_bar",
layer="metal2", layer="metal2",
offset=vector(xoffset_bank_sel_bar, self.min_point), offset=vector(xoffset_bank_sel_bar, self.min_point),
width=self.m2_width, width=self.m2_width,
height=2*self.inv.height) height=2*self.inv.height)
out_pin = bank_sel_inv.get_pin("Z").lr() bank_sel_out_pin = bank_sel_inv.get_pin("Z").rc()
self.add_via(layers=("metal1","via1","metal2"), self.add_center_via(layers=("metal1","via1","metal2"),
offset=out_pin-vector(self.m2_width,0)) offset=bank_sel_out_pin)
@ -545,7 +553,7 @@ class bank(design.design):
# These require OR (nor2+inv) gates since they are active low. # These require OR (nor2+inv) gates since they are active low.
# (writes occur on clk low) # (writes occur on clk low)
if input_name in ("clk", "tri_en_bar"): if input_name in ("clk_buf", "tri_en_bar"):
logic_inst=self.add_inst(name=name_nor, logic_inst=self.add_inst(name=name_nor,
mod=self.nor2, mod=self.nor2,
@ -592,43 +600,43 @@ class bank(design.design):
self.add_path("metal1", [pre, out_position, in_position, post]) self.add_path("metal1", [pre, out_position, in_position, post])
# Connect the inverter output to the central bus # Connect the inverter output to the central bus
out_pin = inv_inst.get_pin("Z") out_pos = inv_inst.get_pin("Z").rc() - vector(0.5*self.m1m2_via.height,0)
bus_pos = vector(self.central_line_xoffset[gated_name], out_pin.rc().y) bus_pos = vector(self.central_line_xoffset[gated_name] + 0.5*self.m2_width, out_pos.y)
self.add_path("metal3",[out_pin.rc(), bus_pos]) self.add_path("metal3",[out_pos, bus_pos])
self.add_via(layers=("metal2", "via2", "metal3"), self.add_center_via(layers=("metal2", "via2", "metal3"),
offset=bus_pos - vector(0,0.5*self.m2m3_via.height)) offset=bus_pos,
self.add_via(layers=("metal1", "via1", "metal2"), rotate=90)
offset=out_pin.lr() - self.via_shift_offset, self.add_center_via(layers=("metal1", "via1", "metal2"),
rotate=90) offset=out_pos,
self.add_via(layers=("metal2", "via2", "metal3"), rotate=90)
offset=out_pin.lr() - self.via_shift_offset, self.add_center_via(layers=("metal2", "via2", "metal3"),
rotate=90) offset=out_pos,
rotate=90)
# Connect the logic B input to bank_sel/bank_sel_bar # Connect the logic B input to bank_sel/bank_sel_bar
logic_pin = logic_inst.get_pin("B") logic_pin = logic_inst.get_pin("B")
input_pos = vector(xoffset_bank_signal,logic_pin.cy()) input_pos = vector(xoffset_bank_signal,logic_pin.cy())
self.add_path("metal2",[logic_pin.lc(), input_pos]) self.add_path("metal2",[logic_pin.lc(), input_pos])
self.add_via(layers=("metal1", "via1", "metal2"), self.add_center_via(layers=("metal1", "via1", "metal2"),
offset=logic_pin.ll()-self.via_shift_offset, offset=logic_pin.lc(),
rotate=90) rotate=90)
# Connect the logic A input to the input pin # Connect the logic A input to the input pin
logic_pos = logic_inst.get_pin("A").ll() logic_pos = logic_inst.get_pin("A").lc()
input_pos = vector(self.left_vdd_x_offset,logic_pos.y) input_pos = vector(self.left_vdd_x_offset,logic_pos.y)
self.add_via(layers=("metal1", "via1", "metal2"), self.add_center_via(layers=("metal1", "via1", "metal2"),
offset=logic_pos-self.via_shift_offset, offset=logic_pos,
rotate=90) rotate=90)
self.add_via(layers=("metal2", "via2", "metal3"), self.add_center_via(layers=("metal2", "via2", "metal3"),
offset=logic_pos-self.via_shift_offset, offset=logic_pos,
rotate=90) rotate=90)
self.add_layout_pin(text=input_name, self.add_center_layout_pin(text=input_name,
layer="metal3", layer="metal3",
offset=vector(self.left_vdd_x_offset,logic_pos.y - self.via_shift_offset.y), start=input_pos,
height=self.m3_width, end=logic_pos)
width=logic_pos.x-self.left_vdd_x_offset)
@ -647,6 +655,7 @@ class bank(design.design):
self.add_path("metal1",[left_vdd_pos,vdd_pin.rc()]) self.add_path("metal1",[left_vdd_pos,vdd_pin.rc()])
def setup_layout_constraints(self): def setup_layout_constraints(self):
""" Calculating layout constraints, width, height etc """ """ Calculating layout constraints, width, height etc """
@ -665,7 +674,7 @@ class bank(design.design):
if self.num_banks>1: if self.num_banks>1:
self.min_point = min(self.decoder_min_point - self.num_control_lines * self.bitcell.height, tri_gate_min_point) self.min_point = min(self.decoder_min_point - self.num_control_lines * self.bitcell.height, tri_gate_min_point)
else: else:
self.min_point = min(addr_min_point, tri_gate_min_point) self.min_point = min(self.decoder_min_point, addr_min_point, tri_gate_min_point)
# The max point is always the top of the precharge bitlines # The max point is always the top of the precharge bitlines
@ -767,22 +776,37 @@ class bank(design.design):
""" Routing of sense amp output to tri_gate input """ """ Routing of sense amp output to tri_gate input """
for i in range(self.word_size): for i in range(self.word_size):
# Connection of data_out of sense amp to data_ in of msf_data_out # Connection of data_out of sense amp to data_ in of msf_data_out
tri_gate_in = self.tri_gate_array_inst.get_pin("in[{}]".format(i)).bc() tri_gate_in = self.tri_gate_array_inst.get_pin("in[{}]".format(i)).bc()
sa_data_out = self.sense_amp_array_inst.get_pin("data[{}]".format(i)).rc() # rc to get enough overlap sa_data_out = self.sense_amp_array_inst.get_pin("data[{}]".format(i)).bc()
startY = self.tri_gate_array_inst.ll().y - 2*drc["minwidth_metal3"] + 0.5*self.m1_width # if we need a bend or not
start = vector(tri_gate_in.x - 3 * drc["minwidth_metal3"], startY) if tri_gate_in.x-sa_data_out.x>self.m2_pitch:
# We'll connect to the bottom of the SA pin
bendX = sa_data_out.x
else:
# We'll connect to the left of the SA pin
sa_data_out = self.sense_amp_array_inst.get_pin("data[{}]".format(i)).lc()
bendX = tri_gate_in.x - 3*self.m3_width
m3_min = vector([drc["minwidth_metal3"]] * 2) bendY = tri_gate_in.y - 2*self.m2_width
mid1 = tri_gate_in.scale(1,0) + sa_data_out.scale(0,1) + m3_min.scale(-3, 1)
mid2 = sa_data_out + m3_min.scale(0.5, 1)
self.add_path("metal3", [start, mid1, mid2])
mid3 = [tri_gate_in.x, startY] # Connection point of M2 and M3 paths, below the tri gate and
self.add_path("metal2", [start, mid3, tri_gate_in]) # to the left of the tri gate input
bend = vector(bendX, bendY)
offset = start - vector([0.5*drc["minwidth_metal3"]] * 2) # Connect an M2 path to the gate
mid3 = [tri_gate_in.x, bendY] # guarantee down then left
self.add_path("metal2", [bend, mid3, tri_gate_in])
# connect up then right to sense amp
mid1 = vector(bendX,sa_data_out.y)
self.add_path("metal3", [bend, mid1, sa_data_out])
offset = bend - vector([0.5*drc["minwidth_metal3"]] * 2)
self.add_via(("metal2", "via2", "metal3"),offset) self.add_via(("metal2", "via2", "metal3"),offset)
def route_tri_gate_out(self): def route_tri_gate_out(self):
@ -797,7 +821,8 @@ class bank(design.design):
height=tri_gate_out_position.y - self.min_point) height=tri_gate_out_position.y - self.min_point)
self.add_layout_pin(text="DATA[{}]".format(i), self.add_layout_pin(text="DATA[{}]".format(i),
layer="metal2", layer="metal2",
offset=data_line_position) offset=data_line_position,
height=2*self.m2_width)
def route_row_decoder(self): def route_row_decoder(self):
""" Routes the row decoder inputs and supplies """ """ Routes the row decoder inputs and supplies """
@ -830,16 +855,24 @@ class bank(design.design):
# Route the power and ground, but only BELOW the y=0 since the # Route the power and ground, but only BELOW the y=0 since the
# others are connected with the wordline driver. # others are connected with the wordline driver.
# These must be on M3 to not interfere with column mux address pins.
for gnd_pin in self.row_decoder_inst.get_pins("gnd"): for gnd_pin in self.row_decoder_inst.get_pins("gnd"):
if gnd_pin.uy()>0: if gnd_pin.uy()>0:
continue continue
driver_gnd_position = gnd_pin.rc() decoder_gnd_position = gnd_pin.rc()
gnd_rail_via = vector(self.gnd_x_offset, driver_gnd_position.y + 0.5*self.m1m2_via.width) via_position = decoder_gnd_position + vector(0.5*self.m1m2_via.height+drc["metal2_to_metal2"],0)
gnd_rail_position = vector(self.gnd_x_offset, driver_gnd_position.y) gnd_rail_position = vector(self.gnd_x_offset, decoder_gnd_position.y)
self.add_path("metal1", [driver_gnd_position, gnd_rail_position]) self.add_path("metal1", [decoder_gnd_position, via_position])
self.add_via(layers=("metal1","via1","metal2"), self.add_path("metal3", [via_position, gnd_rail_position])
offset=gnd_rail_via, self.add_center_via(layers=("metal1","via1","metal2"),
rotate=270) offset=via_position,
rotate=90)
self.add_center_via(layers=("metal2","via2","metal3"),
offset=via_position,
rotate=90)
self.add_center_via(layers=("metal2","via2","metal3"),
offset=gnd_rail_position,
rotate=270)
# route the vdd rails # route the vdd rails
for vdd_pin in self.row_decoder_inst.get_pins("vdd"): for vdd_pin in self.row_decoder_inst.get_pins("vdd"):
@ -894,15 +927,15 @@ class bank(design.design):
return return
# Connect the select lines to the column mux # Connect the select lines to the column mux
# These must be in metal3 so that they don't overlap any gnd lines from decoders
for i in range(2**self.col_addr_size): for i in range(2**self.col_addr_size):
name = "sel[{}]".format(i) name = "sel[{}]".format(i)
col_addr_line_position = self.col_mux_array_inst.get_pin(name).lc() mux_addr_position = self.col_mux_array_inst.get_pin(name).lc()
wire_offset = vector(self.central_line_xoffset[name]+self.m2_width, col_addr_line_position.y) wire_position = vector(self.central_line_xoffset[name]+0.5*self.m2_width, mux_addr_position.y)
self.add_path("metal1", [col_addr_line_position,wire_offset]) self.add_path("metal1", [wire_position,mux_addr_position])
contact_offset = wire_offset - vector(0,0.5*drc["minwidth_metal2"]) self.add_center_via(layers=("metal1", "via1", "metal2"),
self.add_via(layers=("metal1", "via1", "metal2"), offset=wire_position,
offset=contact_offset, rotate=90)
rotate=90)
# Take care of the column address decoder routing # Take care of the column address decoder routing
# If there is a 2:4 decoder for column select lines # If there is a 2:4 decoder for column select lines
@ -950,13 +983,11 @@ class bank(design.design):
mid_position = vector(in_position.x,dout_position.y) mid_position = vector(in_position.x,dout_position.y)
self.add_path("metal3",[dout_position, mid_position, in_position]) self.add_path("metal3",[dout_position, mid_position, in_position])
dout_via = self.msf_address_inst.get_pin("dout[{}]".format(ff_index)).lr() self.add_center_via(layers=("metal2", "via2", "metal3"),
in_via = self.col_decoder_inst.get_pin("in[{}]".format(i)).ul() offset=dout_position,
self.add_via(layers=("metal2", "via2", "metal3"), rotate=90)
offset=dout_via, self.add_center_via(layers=("metal2", "via2", "metal3"),
rotate=90) offset=in_position)
self.add_via(layers=("metal2", "via2", "metal3"),
offset=in_via)
@ -1000,13 +1031,17 @@ class bank(design.design):
# Create the address input pins # Create the address input pins
for i in range(self.addr_size): for i in range(self.addr_size):
msf_din_position = self.msf_address_inst.get_pin("din[{}]".format(i)).ll() msf_din_pins = self.msf_address_inst.get_pins("din[{}]".format(i))
for pin in msf_din_pins:
if pin.layer=="metal3":
msf_din_position=pin.ll()
break
address_position = vector(self.left_vdd_x_offset, msf_din_position.y) address_position = vector(self.left_vdd_x_offset, msf_din_position.y)
self.add_layout_pin(text="ADDR[{}]".format(i), self.add_layout_pin(text="ADDR[{}]".format(i),
layer="metal2", layer="metal3",
offset=address_position, offset=address_position,
width=msf_din_position.x - self.left_vdd_x_offset, width=msf_din_position.x - self.left_vdd_x_offset)
height=drc["minwidth_metal2"])
for i in range(self.row_addr_size): for i in range(self.row_addr_size):
@ -1087,12 +1122,12 @@ class bank(design.design):
data_name = "data[{}]".format(i) data_name = "data[{}]".format(i)
data_pin = self.sense_amp_array_inst.get_pin(data_name) data_pin = self.sense_amp_array_inst.get_pin(data_name)
self.add_label(text="data_out[{}]".format(i), self.add_label(text="data_out[{}]".format(i),
layer="metal2", layer="metal3",
offset=data_pin.ll()) offset=data_pin.ll())
def route_control_lines(self): def route_control_lines(self):
""" Rout the control lines of the entire bank """ """ Route the control lines of the entire bank """
# Make a list of tuples that we will connect. # Make a list of tuples that we will connect.
# From control signal to the module pin # From control signal to the module pin
@ -1107,16 +1142,15 @@ class bank(design.design):
connection.append((self.prefix+"s_en", self.sense_amp_array_inst.get_pin("en").lc())) connection.append((self.prefix+"s_en", self.sense_amp_array_inst.get_pin("en").lc()))
for (control_signal, pin_position) in connection: for (control_signal, pin_position) in connection:
control_x_offset = self.central_line_xoffset[control_signal] + self.m2_width control_position = vector(self.central_line_xoffset[control_signal] + 0.5*self.m2_width, pin_position.y)
control_position = vector(control_x_offset, pin_position.y)
self.add_path("metal1", [control_position, pin_position]) self.add_path("metal1", [control_position, pin_position])
via_offset = vector(control_x_offset, pin_position.y - 0.5*drc["minwidth_metal2"]) #via_offset = vector(control_x_offset, pin_position.y - 0.5*drc["minwidth_metal2"])
self.add_via(layers=("metal1", "via1", "metal2"), self.add_center_via(layers=("metal1", "via1", "metal2"),
offset=via_offset, offset=control_position,
rotate=90) rotate=90)
# clk to msf address # clk to msf address
control_signal = self.prefix+"clk" control_signal = self.prefix+"clk_buf"
pin_position = self.msf_address_inst.get_pin("clk").uc() pin_position = self.msf_address_inst.get_pin("clk").uc()
mid_position = pin_position + vector(0,self.m1_pitch) mid_position = pin_position + vector(0,self.m1_pitch)
control_x_offset = self.central_line_xoffset[control_signal] control_x_offset = self.central_line_xoffset[control_signal]
@ -1127,7 +1161,7 @@ class bank(design.design):
offset=control_via_position) offset=control_via_position)
# clk to wordline_driver # clk to wordline_driver
control_signal = self.prefix+"clk" control_signal = self.prefix+"clk_buf"
pin_position = self.wordline_driver_inst.get_pin("en").uc() pin_position = self.wordline_driver_inst.get_pin("en").uc()
mid_position = pin_position + vector(0,self.m1_pitch) mid_position = pin_position + vector(0,self.m1_pitch)
control_x_offset = self.central_line_xoffset[control_signal] control_x_offset = self.central_line_xoffset[control_signal]

View File

@ -217,9 +217,12 @@ def run_lvs(name, gds_name, sp_name):
test = re.compile("WARNING:") test = re.compile("WARNING:")
extwarnings = filter(test.search, results) extwarnings = filter(test.search, results)
for e in extwarnings: for e in extwarnings:
debug.error(e.strip("\n")) debug.warning(e.strip("\n"))
ext_errors = len(exterrors) + len(extwarnings) # MRG - 9/26/17 - Change this to exclude warnings because of
# multiple labels on different pins in column mux.
ext_errors = len(exterrors)
ext_warnings = len(extwarnings)
# also check the output file # also check the output file
f = open(outfile, "r") f = open(outfile, "r")
@ -234,7 +237,8 @@ def run_lvs(name, gds_name, sp_name):
out_errors = len(stdouterrors) out_errors = len(stdouterrors)
return summary_errors + out_errors + ext_errors total_errors = summary_errors + out_errors + ext_errors
return total_errors
def run_pex(name, gds_name, sp_name, output=None): def run_pex(name, gds_name, sp_name, output=None):

View File

@ -73,7 +73,7 @@ class delay():
self.sf.write("* SRAM output loads\n") self.sf.write("* SRAM output loads\n")
for i in range(self.word_size): for i in range(self.word_size):
self.sf.write("CD{0} D[{0}] 0 {1}f\n".format(i,load)) self.sf.write("CD{0} d[{0}] 0 {1}f\n".format(i,load))
# add access transistors for data-bus # add access transistors for data-bus
self.sf.write("* Transmission Gates for data-bus and control signals\n") self.sf.write("* Transmission Gates for data-bus and control signals\n")
@ -85,12 +85,12 @@ class delay():
if i == self.probe_data: if i == self.probe_data:
stimuli.gen_data(stim_file=self.sf, stimuli.gen_data(stim_file=self.sf,
clk_times=self.cycle_times, clk_times=self.cycle_times,
sig_name="DATA[{0}]".format(i), sig_name="data[{0}]".format(i),
period=period, period=period,
slew=slew) slew=slew)
else: else:
stimuli.gen_constant(stim_file=self.sf, stimuli.gen_constant(stim_file=self.sf,
sig_name="D[{0}]".format(i), sig_name="d[{0}]".format(i),
v_val=self.gnd) v_val=self.gnd)
stimuli.gen_addr(self.sf, stimuli.gen_addr(self.sf,
@ -127,7 +127,7 @@ class delay():
self.sf.write("* Measure statements for delay and power\n") self.sf.write("* Measure statements for delay and power\n")
trig_name = "clk" trig_name = "clk"
targ_name = "{0}".format("D[{0}]".format(self.probe_data)) targ_name = "{0}".format("d[{0}]".format(self.probe_data))
trig_val = targ_val = 0.5 * self.vdd trig_val = targ_val = 0.5 * self.vdd
# add measure statments for delay0 # add measure statments for delay0
# delay the target to measure after the negetive edge # delay the target to measure after the negetive edge

View File

@ -181,13 +181,13 @@ def gen_csb(stim_file, clk_times, period, slew):
""" Generates the PWL CSb signal""" """ Generates the PWL CSb signal"""
# values for NOP, W1, W0, W1, R0, W1, W0, R1, NOP # values for NOP, W1, W0, W1, R0, W1, W0, R1, NOP
values = [1, 0, 0, 0, 0, 0, 0, 0, 1] values = [1, 0, 0, 0, 0, 0, 0, 0, 1]
gen_pwl(stim_file, "CSb", clk_times, values, period, slew, 0.05) gen_pwl(stim_file, "csb", clk_times, values, period, slew, 0.05)
def gen_web(stim_file, clk_times, period, slew): def gen_web(stim_file, clk_times, period, slew):
""" Generates the PWL WEb signal""" """ Generates the PWL WEb signal"""
# values for NOP, W1, W0, W1, R0, W1, W0, R1, NOP # values for NOP, W1, W0, W1, R0, W1, W0, R1, NOP
values = [1, 0, 0, 0, 1, 0, 0, 1, 1] values = [1, 0, 0, 0, 1, 0, 0, 1, 1]
gen_pwl(stim_file, "WEb", clk_times, values, period, slew, 0.05) gen_pwl(stim_file, "web", clk_times, values, period, slew, 0.05)
values = [1, 0, 0, 0, 1, 0, 0, 1, 1] values = [1, 0, 0, 0, 1, 0, 0, 1, 1]
gen_pwl(stim_file, "acc_en", clk_times, values, period, slew, 0) gen_pwl(stim_file, "acc_en", clk_times, values, period, slew, 0)
@ -198,7 +198,7 @@ def gen_oeb(stim_file, clk_times, period, slew):
""" Generates the PWL WEb signal""" """ Generates the PWL WEb signal"""
# values for NOP, W1, W0, W1, R0, W1, W0, R1, NOP # values for NOP, W1, W0, W1, R0, W1, W0, R1, NOP
values = [1, 1, 1, 1, 0, 1, 1, 0, 1] values = [1, 1, 1, 1, 0, 1, 1, 0, 1]
gen_pwl(stim_file, "OEb", clk_times, values, period, slew, 0.05) gen_pwl(stim_file, "oeb", clk_times, values, period, slew, 0.05)

View File

@ -17,7 +17,7 @@ class contact(design.design):
dimensions[0], dimensions[0],
dimensions[1]) dimensions[1])
design.design.__init__(self, name) design.design.__init__(self, name)
debug.info(3, "create contact object {0}".format(name)) debug.info(4, "create contact object {0}".format(name))
self.layer_stack = layer_stack self.layer_stack = layer_stack
self.dimensions = dimensions self.dimensions = dimensions

View File

@ -47,7 +47,6 @@ class control_logic(design.design):
self.nor2 = nor_2() self.nor2 = nor_2()
self.add_mod(self.nor2) self.add_mod(self.nor2)
# Special gates: inverters for buffering # Special gates: inverters for buffering
self.inv = self.inv1 = pinv() self.inv = self.inv1 = pinv()
self.add_mod(self.inv1) self.add_mod(self.inv1)
@ -81,20 +80,20 @@ class control_logic(design.design):
self.m1m2_via = contact(layer_stack=("metal1", "via1", "metal2")) self.m1m2_via = contact(layer_stack=("metal1", "via1", "metal2"))
self.m2m3_via = contact(layer_stack=("metal2", "via2", "metal3")) self.m2m3_via = contact(layer_stack=("metal2", "via2", "metal3"))
# For different layer width vias
self.m1m2_offset_fix = vector(0,0.5*(drc["minwidth_metal2"]-drc["minwidth_metal1"]))
# M1/M2 routing pitch is based on contacted pitch # M1/M2 routing pitch is based on contacted pitch
self.m1_pitch = max(self.m1m2_via.width,self.m1m2_via.height) + max(drc["metal1_to_metal1"],drc["metal2_to_metal2"]) self.m1_pitch = max(self.m1m2_via.width,self.m1m2_via.height) + max(drc["metal1_to_metal1"],drc["metal2_to_metal2"])
self.m2_pitch = max(self.m2m3_via.width,self.m2m3_via.height) + max(drc["metal2_to_metal2"],drc["metal3_to_metal3"]) self.m2_pitch = max(self.m2m3_via.width,self.m2m3_via.height) + max(drc["metal2_to_metal2"],drc["metal3_to_metal3"])
# Have the cell gap leave enough room to route an M1 wire. # Have the cell gap leave enough room to route an M2 wire.
# Some cells may have pwell/nwell spacing problems too when the wells are different heights. # Some cells may have pwell/nwell spacing problems too when the wells are different heights.
self.cell_gap = max(self.m1_pitch,drc["pwell_to_nwell"]) self.cell_gap = max(self.m2_pitch,drc["pwell_to_nwell"])
# This corrects the offset pitch difference between M2 and M1 # Amount to shift a 90 degree rotated via from center-line path routing to it's offset
self.offset_fix = vector(0.5*(drc["minwidth_metal2"]-drc["minwidth_metal1"]),0) self.m1m2_via_offset = vector(self.m1m2_via.first_layer_height,-0.5*drc["minwidth_metal2"])
self.m2m3_via_offset = vector(self.m2m3_via.first_layer_height,-0.5*drc["minwidth_metal3"])
# Amount to shift a via from center-line path routing to it's offset
self.m1m2_via_offset = vector(self.m1m2_via.height,-0.5*drc["minwidth_metal2"])
self.m2m3_via_offset = vector(self.m2m3_via.height,-0.5*drc["minwidth_metal3"])
# First RAIL Parameters: gnd, oe, oebar, cs, we, clk_buf, clk_bar # First RAIL Parameters: gnd, oe, oebar, cs, we, clk_buf, clk_bar
self.rail_1_start_x = 0 self.rail_1_start_x = 0
@ -127,6 +126,8 @@ class control_logic(design.design):
self.add_rbl(0) self.add_rbl(0)
self.add_layout_pins() self.add_layout_pins()
self.add_lvs_correspondence_points()
self.height = max(self.replica_bitline.width, 3 * self.inv1.height, self.msf_offset.y) self.height = max(self.replica_bitline.width, 3 * self.inv1.height, self.msf_offset.y)
self.width = self.replica_bitline_offset.x + self.replica_bitline.height self.width = self.replica_bitline_offset.x + self.replica_bitline.height
@ -146,10 +147,10 @@ class control_logic(design.design):
def add_control_flops(self): def add_control_flops(self):
""" Add the control signal flops for OEb, WEb, CSb. """ """ Add the control signal flops for OEb, WEb, CSb. """
self.msf_offset = vector(0, self.inv.height+self.msf_control.width+2*self.m2_pitch) self.msf_offset = vector(0, self.inv.height+self.msf_control.width+2*self.m2_pitch)
self.msf=self.add_inst(name="msf_control", self.msf_inst=self.add_inst(name="msf_control",
mod=self.msf_control, mod=self.msf_control,
offset=self.msf_offset, offset=self.msf_offset,
rotate=270) rotate=270)
# don't change this order. This pins are meant for internal connection of msf array inside the control logic. # don't change this order. This pins are meant for internal connection of msf array inside the control logic.
# These pins are connecting the msf_array inside of control_logic. # These pins are connecting the msf_array inside of control_logic.
temp = ["oeb", "csb", "web", temp = ["oeb", "csb", "web",
@ -177,20 +178,19 @@ class control_logic(design.design):
pin_set = ["oeb","csb","web"] pin_set = ["oeb","csb","web"]
for (i,pin_name) in zip(range(3),pin_set): for (i,pin_name) in zip(range(3),pin_set):
subpin_name="din[{}]".format(i) subpin_name="din[{}]".format(i)
pin=self.msf.get_pin(subpin_name) pins=self.msf_inst.get_pins(subpin_name)
#pin=self.msf_control.get_pin("din[{}]".format(i)) for pin in pins:
self.add_layout_pin(text=pin_name, if pin.layer=="metal3":
layer="metal2", self.add_layout_pin(text=pin_name,
offset=pin.ll(), layer="metal3",
width=pin.width(), offset=pin.ll(),
height=pin.height()) width=pin.width(),
height=pin.height())
pin=self.clk_inv1.get_pin("A") pin=self.clk_inv1.get_pin("A")
self.add_layout_pin(text="clk", self.add_layout_pin(text="clk",
layer="metal1", layer="metal1",
offset=pin.ll(), offset=pin.ll())
width=pin.width(),
height=pin.height())
pin=self.clk_inv1.get_pin("gnd") pin=self.clk_inv1.get_pin("gnd")
self.add_layout_pin(text="gnd", self.add_layout_pin(text="gnd",
@ -354,31 +354,33 @@ class control_logic(design.design):
width=drc["minwidth_metal2"], width=drc["minwidth_metal2"],
height=control_rail_height) height=control_rail_height)
else: else:
self.add_rect(layer="metal2", # just for LVS correspondence...
offset=offset, self.add_label_pin(text=self.rail_1_names[i],
width=drc["minwidth_metal2"], layer="metal2",
height=control_rail_height) offset=offset,
width=drc["minwidth_metal2"],
height=control_rail_height)
self.rail_1_x_offsets[self.rail_1_names[i]]=offset.x + 0.5*drc["minwidth_metal2"] # center offset self.rail_1_x_offsets[self.rail_1_names[i]]=offset.x + 0.5*drc["minwidth_metal2"] # center offset
# pins are in order ["oeb","csb","web"] # 0 1 2 # pins are in order ["oeb","csb","web"] # 0 1 2
self.connect_rail_from_left_m2m3(self.msf,"dout_bar[0]","oe") self.connect_rail_from_left_m2m3(self.msf_inst,"dout_bar[0]","oe")
self.connect_rail_from_left_m2m3(self.msf,"dout[0]","oe_bar") self.connect_rail_from_left_m2m3(self.msf_inst,"dout[0]","oe_bar")
self.connect_rail_from_left_m2m3(self.msf,"dout_bar[1]","cs") self.connect_rail_from_left_m2m3(self.msf_inst,"dout_bar[1]","cs")
self.connect_rail_from_left_m2m3(self.msf,"dout_bar[2]","we") self.connect_rail_from_left_m2m3(self.msf_inst,"dout_bar[2]","we")
# Connect the gnd and vdd of the control # Connect the gnd and vdd of the control
gnd_pins = self.msf.get_pins("gnd") gnd_pins = self.msf_inst.get_pins("gnd")
for p in gnd_pins: for p in gnd_pins:
if p.layer != "metal2": if p.layer != "metal2":
continue continue
gnd_pin = p.rc() gnd_pin = p.rc()
gnd_rail_position = vector(self.rail_1_x_offsets["gnd"], gnd_pin.y) gnd_rail_position = vector(self.rail_1_x_offsets["gnd"], gnd_pin.y)
self.add_wire(("metal1","via1","metal2"),[gnd_pin, gnd_rail_position, gnd_rail_position - vector(0,self.m2_pitch)]) self.add_wire(("metal3","via2","metal2"),[gnd_pin, gnd_rail_position, gnd_rail_position - vector(0,self.m2_pitch)])
self.add_via(layers=("metal1","via1","metal2"), self.add_via(layers=("metal2","via2","metal3"),
offset=gnd_pin + self.m1m2_via_offset, offset=gnd_pin + self.m2m3_via_offset,
rotate=90) rotate=90)
vdd_pins = self.msf.get_pins("vdd") vdd_pins = self.msf_inst.get_pins("vdd")
for p in vdd_pins: for p in vdd_pins:
if p.layer != "metal1": if p.layer != "metal1":
continue continue
@ -449,6 +451,7 @@ class control_logic(design.design):
in_pin = inst.get_pin(pin).rc() in_pin = inst.get_pin(pin).rc()
rail_position = vector(self.rail_1_x_offsets[rail], in_pin.y) rail_position = vector(self.rail_1_x_offsets[rail], in_pin.y)
self.add_wire(("metal3","via2","metal2"),[in_pin, rail_position, rail_position - vector(0,self.m2_pitch)]) self.add_wire(("metal3","via2","metal2"),[in_pin, rail_position, rail_position - vector(0,self.m2_pitch)])
# This via is needed for clk_bar, but is extraneous for the output signals
self.add_via(layers=("metal1","via1","metal2"), self.add_via(layers=("metal1","via1","metal2"),
offset=in_pin + self.m1m2_via_offset, offset=in_pin + self.m1m2_via_offset,
rotate=90) rotate=90)
@ -501,17 +504,28 @@ class control_logic(design.design):
self.connect_rail_from_left_m2m3(self.clk_bar,"Z","clk_bar") self.connect_rail_from_left_m2m3(self.clk_bar,"Z","clk_bar")
# clk_buf to msf control flops # clk_buf to msf control flops
msf_clk_pin = self.msf.get_pin("clk").bc() msf_clk_pin = self.msf_inst.get_pin("clk").bc()
mid1 = msf_clk_pin - vector(0,self.m2_pitch) mid1 = msf_clk_pin - vector(0,self.m2_pitch)
clk_buf_rail_position = vector(self.rail_1_x_offsets["clk_buf"], mid1.y) clk_buf_rail_position = vector(self.rail_1_x_offsets["clk_buf"], mid1.y)
# route on M2 to allow vdd connection # route on M2 to allow vdd connection
self.add_wire(("metal2","via1","metal1"),[msf_clk_pin, mid1, clk_buf_rail_position]) self.add_wire(("metal2","via1","metal1"),[msf_clk_pin, mid1, clk_buf_rail_position])
def connect_pin_to_output_pin(self, inst, pin_name, out_name): def connect_right_pin_to_output_pin(self, inst, pin_name, out_name):
""" Create an output pin on the bottom side from the pin of a given instance. """ """ Create an output pin on the bottom side from the pin of a given instance. """
out_pin = inst.get_pin(pin_name).center() out_pin = inst.get_pin(pin_name).ur()
self.add_via(layers=("metal1","via1","metal2"), self.add_via(layers=("metal1","via1","metal2"),
offset=out_pin + self.m1m2_via_offset, offset=out_pin + vector(self.m1m2_via.height,-self.m1m2_via.first_layer_width) - self.m1m2_offset_fix,
rotate=90)
self.add_layout_pin(text=out_name,
layer="metal2",
offset=out_pin.scale(1,0),
height=out_pin.y)
def connect_left_pin_to_output_pin(self, inst, pin_name, out_name):
""" Create an output pin on the bottom side from the pin of a given instance. """
out_pin = inst.get_pin(pin_name).ul()
self.add_via(layers=("metal1","via1","metal2"),
offset=out_pin + vector(self.m1m2_via.height,-self.m1m2_via.first_layer_width) - self.m1m2_offset_fix,
rotate=90) rotate=90)
self.add_layout_pin(text=out_name, self.add_layout_pin(text=out_name,
layer="metal2", layer="metal2",
@ -520,10 +534,10 @@ class control_logic(design.design):
def add_output_routing(self): def add_output_routing(self):
""" Output pin routing """ """ Output pin routing """
self.connect_pin_to_output_pin(self.tri_en, "Z", "tri_en") self.connect_right_pin_to_output_pin(self.tri_en, "Z", "tri_en")
self.connect_pin_to_output_pin(self.tri_en_bar, "Z", "tri_en_bar") self.connect_right_pin_to_output_pin(self.tri_en_bar, "Z", "tri_en_bar")
self.connect_pin_to_output_pin(self.w_en, "Z", "w_en") self.connect_right_pin_to_output_pin(self.w_en, "Z", "w_en")
self.connect_pin_to_output_pin(self.s_en, "Z", "s_en") self.connect_left_pin_to_output_pin(self.s_en, "Z", "s_en")
def add_supply_routing(self): def add_supply_routing(self):
@ -614,3 +628,24 @@ class control_logic(design.design):
width=rows_end-rows_start, width=rows_end-rows_start,
height=well_width) height=well_width)
def add_lvs_correspondence_points(self):
""" This adds some points for easier debugging if LVS goes wrong.
These should probably be turned off by default though, since extraction
will show these as ports in the extracted netlist.
"""
pin=self.clk_inv1.get_pin("Z")
self.add_label_pin(text="clk1_bar",
layer="metal1",
offset=pin.ll(),
height=pin.height(),
width=pin.width())
pin=self.clk_inv2.get_pin("Z")
self.add_label_pin(text="clk2",
layer="metal1",
offset=pin.ll(),
height=pin.height(),
width=pin.width())

View File

@ -43,11 +43,11 @@ class instance(geometry):
self.compute_boundary(offset,mirror,rotate) self.compute_boundary(offset,mirror,rotate)
debug.info(3, "creating instance: " + self.name) debug.info(4, "creating instance: " + self.name)
def gds_write_file(self, newLayout): def gds_write_file(self, newLayout):
"""Recursively writes all the sub-modules in this instance""" """Recursively writes all the sub-modules in this instance"""
debug.info(3, "writing instance: " + self.name) debug.info(4, "writing instance: " + self.name)
# make sure to write out my module/structure # make sure to write out my module/structure
# (it will only be written the first time though) # (it will only be written the first time though)
self.mod.gds_write_file(self.gds) self.mod.gds_write_file(self.gds)
@ -172,7 +172,7 @@ class path(geometry):
def gds_write_file(self, newLayout): def gds_write_file(self, newLayout):
"""Writes the path to GDS""" """Writes the path to GDS"""
debug.info(3, "writing path (" + str(self.layerNumber) + "): " + self.coordinates) debug.info(4, "writing path (" + str(self.layerNumber) + "): " + self.coordinates)
newLayout.addPath(layerNumber=self.layerNumber, newLayout.addPath(layerNumber=self.layerNumber,
purposeNumber=0, purposeNumber=0,
coordinates=self.coordinates, coordinates=self.coordinates,
@ -205,11 +205,11 @@ class label(geometry):
self.size = 0 self.size = 0
debug.info(3,"creating label " + self.text + " " + str(self.layerNumber) + " " + str(self.offset)) debug.info(4,"creating label " + self.text + " " + str(self.layerNumber) + " " + str(self.offset))
def gds_write_file(self, newLayout): def gds_write_file(self, newLayout):
"""Writes the text label to GDS""" """Writes the text label to GDS"""
debug.info(3, "writing label (" + str(self.layerNumber) + "): " + self.text) debug.info(4, "writing label (" + str(self.layerNumber) + "): " + self.text)
newLayout.addText(text=self.text, newLayout.addText(text=self.text,
layerNumber=self.layerNumber, layerNumber=self.layerNumber,
purposeNumber=0, purposeNumber=0,
@ -238,13 +238,13 @@ class rectangle(geometry):
self.width = self.size.x self.width = self.size.x
self.height = self.size.y self.height = self.size.y
debug.info(3, "creating rectangle (" + str(self.layerNumber) + "): " debug.info(4, "creating rectangle (" + str(self.layerNumber) + "): "
+ str(self.width) + "x" + str(self.height) + " @ " + str(self.offset)) + str(self.width) + "x" + str(self.height) + " @ " + str(self.offset))
def gds_write_file(self, newLayout): def gds_write_file(self, newLayout):
"""Writes the rectangular shape to GDS""" """Writes the rectangular shape to GDS"""
debug.info(3, "writing rectangle (" + str(self.layerNumber) + "):" debug.info(4, "writing rectangle (" + str(self.layerNumber) + "):"
+ str(self.width) + "x" + str(self.height) + " @ " + str(self.offset)) + str(self.width) + "x" + str(self.height) + " @ " + str(self.offset))
newLayout.addBox(layerNumber=self.layerNumber, newLayout.addBox(layerNumber=self.layerNumber,
purposeNumber=0, purposeNumber=0,

View File

@ -91,9 +91,6 @@ class hierarchical_decoder(design.design):
self.metal2_spacing = self.metal2_extend_contact + drc["metal2_to_metal2"] self.metal2_spacing = self.metal2_extend_contact + drc["metal2_to_metal2"]
self.metal2_pitch = self.metal2_spacing + drc["minwidth_metal2"] self.metal2_pitch = self.metal2_spacing + drc["minwidth_metal2"]
self.via_shift = (self.m1m2_via.second_layer_width - self.m1m2_via.first_layer_width) / 2 self.via_shift = (self.m1m2_via.second_layer_width - self.m1m2_via.first_layer_width) / 2
# used to shift contact when connecting to NAND3 C pin down
self.contact_shift = (self.m1m2_via.first_layer_width - self.m1m2_via.contact_width) / 2
self.predec_groups = [] # This array is a 2D array. self.predec_groups = [] # This array is a 2D array.
@ -483,19 +480,17 @@ class hierarchical_decoder(design.design):
yoffset_A = current_inv_height + a_pin.by() yoffset_A = current_inv_height + a_pin.by()
yoffset_B = current_inv_height + b_pin.by() yoffset_B = current_inv_height + b_pin.by()
yoffset_C = current_inv_height + c_pin.by() yoffset_C = current_inv_height + c_pin.by()
contact_C_yoffset = yoffset_C - self.contact_shift
else: else:
base = current_inv_height + self.inv.height - drc["minwidth_metal1"] base = current_inv_height + self.inv.height - drc["minwidth_metal1"]
yoffset_A = base - a_pin.by() yoffset_A = base - a_pin.by()
yoffset_B = base - b_pin.by() yoffset_B = base - b_pin.by()
yoffset_C = base - c_pin.by() yoffset_C = base - c_pin.by()
contact_C_yoffset = yoffset_C
row_index = row_index + 1 row_index = row_index + 1
self.connect_rail(vector(self.rail_x_offsets[index_A], yoffset_A)) self.connect_rail(vector(self.rail_x_offsets[index_A], yoffset_A))
self.connect_rail(vector(self.rail_x_offsets[index_B], yoffset_B)) self.connect_rail(vector(self.rail_x_offsets[index_B], yoffset_B))
self.connect_rail(vector(self.rail_x_offsets[index_C], yoffset_C)) # contact_C_y_offset self.connect_rail(vector(self.rail_x_offsets[index_C], yoffset_C))
def route_vdd_gnd(self): def route_vdd_gnd(self):
""" Add a pin for each row of vdd/gnd which are must-connects next level up. """ """ Add a pin for each row of vdd/gnd which are must-connects next level up. """

View File

@ -116,12 +116,11 @@ class hierarchical_predecode(design.design):
name = "Xpre_inv[{0}]".format(inv_num) name = "Xpre_inv[{0}]".format(inv_num)
if (inv_num % 2 == 0): if (inv_num % 2 == 0):
y_off = inv_num * (self.inv.height) y_off = inv_num * (self.inv.height)
offset = vector(self.x_off_inv_1, y_off)
mirror = "R0" mirror = "R0"
else: else:
y_off = (inv_num + 1) * (self.inv.height) y_off = (inv_num + 1) * (self.inv.height)
offset = vector(self.x_off_inv_1, y_off)
mirror="MX" mirror="MX"
offset = vector(self.x_off_inv_1, y_off)
self.add_inst(name=name, self.add_inst(name=name,
mod=self.inv, mod=self.inv,
offset=offset, offset=offset,
@ -133,62 +132,62 @@ class hierarchical_predecode(design.design):
def add_output_inverters(self): def add_output_inverters(self):
""" Create inverters for the inverted output decode signals. """ """ Create inverters for the inverted output decode signals. """
self.decode_out_positions = [] self.inv_inst = []
z_pin = self.inv.get_pin("Z") z_pin = self.inv.get_pin("Z")
for inv_num in range(self.number_of_outputs): for inv_num in range(self.number_of_outputs):
name = "Xpre2x4_nand_inv[{}]".format(inv_num) name = "Xpre_nand_inv[{}]".format(inv_num)
if (inv_num % 2 == 0): if (inv_num % 2 == 0):
y_factor = inv_num y_off = inv_num * self.inv.height
mirror = "R0" mirror = "R0"
y_dir = 1
else: else:
y_factor =inv_num + 1 y_off =(inv_num + 1)*self.inv.height
mirror = "MX" mirror = "MX"
y_dir = -1 offset = vector(self.x_off_inv_2, y_off)
base = vector(self.x_off_inv_2, self.inv.height * y_factor) self.inv_inst.append(self.add_inst(name=name,
self.add_inst(name=name, mod=self.inv,
mod=self.inv, offset=offset,
offset=base, mirror=mirror))
mirror=mirror)
self.connect_inst(["Z[{}]".format(inv_num), self.connect_inst(["Z[{}]".format(inv_num),
"out[{}]".format(inv_num), "out[{}]".format(inv_num),
"vdd", "gnd"]) "vdd", "gnd"])
z_pin = self.inv.get_pin("Z") z_pin = self.inv_inst[-1].get_pin("Z")
self.add_layout_pin(text="out[{}]".format(inv_num), self.add_layout_pin(text="out[{}]".format(inv_num),
layer="metal1", layer="metal1",
offset=base+z_pin.ll().scale(1,y_dir), offset=z_pin.ll(),
width=z_pin.width(), width=z_pin.width(),
height=z_pin.height()*y_dir) height=z_pin.height())
def add_nand(self,connections): def add_nand(self,connections):
""" Create the NAND stage for the decodes """ """ Create the NAND stage for the decodes """
z_pin = self.nand.get_pin("Z") self.nand_inst = []
a_pin = self.inv.get_pin("A")
for nand_input in range(self.number_of_outputs): for nand_input in range(self.number_of_outputs):
inout = str(self.number_of_inputs)+"x"+str(self.number_of_outputs) inout = str(self.number_of_inputs)+"x"+str(self.number_of_outputs)
name = "Xpre{0}_nand[{1}]".format(inout,nand_input) name = "Xpre{0}_nand[{1}]".format(inout,nand_input)
rect_height = z_pin.uy()-a_pin.by()
if (nand_input % 2 == 0): if (nand_input % 2 == 0):
y_off = nand_input * (self.nand.height) y_off = nand_input * self.inv.height
mirror = "R0" mirror = "R0"
rect_offset = vector(self.x_off_nand + self.nand.width,
y_off + z_pin.uy() - rect_height)
else: else:
y_off = (nand_input + 1) * (self.nand.height) y_off = (nand_input + 1) * self.inv.height
mirror = "MX" mirror = "MX"
rect_offset =vector(self.x_off_nand + self.nand.width, offset = vector(self.x_off_nand, y_off)
y_off - z_pin.uy()) self.nand_inst.append(self.add_inst(name=name,
self.add_inst(name=name, mod=self.nand,
mod=self.nand, offset=offset,
offset=[self.x_off_nand, y_off], mirror=mirror))
mirror=mirror)
self.add_rect(layer="metal1",
offset=rect_offset,
width=self.metal1_width,
height=rect_height)
self.connect_inst(connections[nand_input]) self.connect_inst(connections[nand_input])
z_pin = self.nand_inst[nand_input].get_pin("Z")
a_pin = self.inv_inst[nand_input].get_pin("A")
y_min = min(z_pin.by(),a_pin.by())
y_max = max(z_pin.uy(),a_pin.uy())
offset = vector(z_pin.rx(),y_min)
self.add_rect(layer="metal1",
offset=offset,
width=self.metal1_width,
height=y_max-y_min)
def route(self): def route(self):
self.route_input_inverters() self.route_input_inverters()

View File

@ -104,8 +104,12 @@ class layout:
return inst return inst
return None return None
def add_rect(self, layer, offset, width, height): def add_rect(self, layer, offset, width=0, height=0):
"""Adds a rectangle on a given layer,offset with width and height""" """Adds a rectangle on a given layer,offset with width and height"""
if width==0:
width=drc["minwidth_{}".format(layer)]
if height==0:
height=drc["minwidth_{}".format(layer)]
# negative layers indicate "unused" layers in a given technology # negative layers indicate "unused" layers in a given technology
layerNumber = techlayer[layer] layerNumber = techlayer[layer]
if layerNumber >= 0: if layerNumber >= 0:
@ -116,10 +120,18 @@ class layout:
def get_pin(self, text): def get_pin(self, text):
""" Return the pin or list of pins """ """ Return the pin or list of pins """
debug.check(len(self.pin_map[text])==1,"Should use a pin iterator since more than one pin.") try:
# If we have one pin, return it and not the list. if len(self.pin_map[text])>1:
# Otherwise, should use get_pins() debug.warning("Should use a pin iterator since more than one pin {}".format(text))
return self.pin_map[text][0] # If we have one pin, return it and not the list.
# Otherwise, should use get_pins()
return self.pin_map[text][0]
except Exception as e:
#print e
self.gds_write("missing_pin.gds")
debug.error("No pin found with name {0} on {1}. Saved as missing_pin.gds.".format(text,self.name),-1)
def get_pins(self, text): def get_pins(self, text):
""" Return a pin list (instead of a single pin) """ """ Return a pin list (instead of a single pin) """
@ -136,6 +148,30 @@ class layout:
new_name = pin.name new_name = pin.name
self.add_layout_pin(new_name, pin.layer, pin.ll(), pin.width(), pin.height()) self.add_layout_pin(new_name, pin.layer, pin.ll(), pin.width(), pin.height())
def add_center_layout_pin(self, text, layer, start, end):
""" Creates a path like pin with center-line convention """
debug.check(start.x==end.x or start.y==end.y,"Cannot have a non-manhatten layout pin.")
minwidth_layer = drc["minwidth_{}".format(layer)]
# one of these will be zero
width = max(start.x,end.x) - min(start.x,end.x)
height = max(start.y,end.y) - min(start.y,end.y)
ll_offset = vector(min(start.x,end.x),min(start.y,end.y))
# Shift it down 1/2 a width in the 0 dimension
if height==0:
ll_offset -= vector(0,0.5*minwidth_layer)
if width==0:
ll_offset -= vector(0.5*minwidth_layer,0)
# This makes sure it is long enough, but also it is not 0 width!
height = max(minwidth_layer,height)
width = max(minwidth_layer,width)
self.add_layout_pin(text, layer, ll_offset, width, height)
def add_layout_pin(self, text, layer, offset, width=None, height=None): def add_layout_pin(self, text, layer, offset, width=None, height=None):
"""Create a labeled pin """ """Create a labeled pin """
@ -186,6 +222,7 @@ class layout:
def add_label(self, text, layer, offset=[0,0],zoom=-1): def add_label(self, text, layer, offset=[0,0],zoom=-1):
"""Adds a text label on the given layer,offset, and zoom level""" """Adds a text label on the given layer,offset, and zoom level"""
# negative layers indicate "unused" layers in a given technology # negative layers indicate "unused" layers in a given technology
debug.info(5,"add label " + str(text) + " " + layer + " " + str(offset))
layerNumber = techlayer[layer] layerNumber = techlayer[layer]
if layerNumber >= 0: if layerNumber >= 0:
self.objs.append(geometry.label(text, layerNumber, offset, zoom)) self.objs.append(geometry.label(text, layerNumber, offset, zoom))
@ -195,7 +232,7 @@ class layout:
def add_path(self, layer, coordinates, width=None): def add_path(self, layer, coordinates, width=None):
"""Connects a routing path on given layer,coordinates,width.""" """Connects a routing path on given layer,coordinates,width."""
debug.info(3,"add path " + str(layer) + " " + str(coordinates)) debug.info(4,"add path " + str(layer) + " " + str(coordinates))
import path import path
# NOTE: (UNTESTED) add_path(...) is currently not used # NOTE: (UNTESTED) add_path(...) is currently not used
# negative layers indicate "unused" layers in a given technology # negative layers indicate "unused" layers in a given technology
@ -215,7 +252,7 @@ class layout:
the coordinates. the coordinates.
""" """
import route import route
debug.info(3,"add route " + str(layers) + " " + str(coordinates)) debug.info(4,"add route " + str(layers) + " " + str(coordinates))
# add an instance of our path that breaks down into rectangles and contacts # add an instance of our path that breaks down into rectangles and contacts
route.route(obj=self, route.route(obj=self,
layer_stack=layers, layer_stack=layers,
@ -236,7 +273,16 @@ class layout:
return self.add_via(layers=layers, return self.add_via(layers=layers,
offset=offset, offset=offset,
size=size, size=size,
mirror=mirror,rotate=rotate) mirror=mirror,
rotate=rotate)
def add_center_contact(self, layers, offset, size=[1,1], mirror="R0", rotate=0):
""" This is just an alias for a via."""
return self.add_centered_via(layers=layers,
offset=offset,
size=size,
mirror=mirror,
rotate=rotate)
def add_via(self, layers, offset, size=[1,1], mirror="R0", rotate=0): def add_via(self, layers, offset, size=[1,1], mirror="R0", rotate=0):
""" Add a three layer via structure. """ """ Add a three layer via structure. """
@ -253,6 +299,39 @@ class layout:
self.connect_inst([]) self.connect_inst([])
return via return via
def add_center_via(self, layers, offset, size=[1,1], mirror="R0", rotate=0):
""" Add a three layer via structure by the center coordinate accounting for mirroring and rotation. """
import contact
via = contact.contact(layer_stack=layers,
dimensions=size)
debug.check(mirror=="R0","Use rotate to rotate vias instead of mirror.")
height = via.height
width = via.width
if rotate==0:
corrected_offset = offset + vector(-0.5*width,-0.5*height)
elif rotate==90:
corrected_offset = offset + vector(0.5*height,-0.5*width)
elif rotate==180:
corrected_offset = offset + vector(-0.5*width,0.5*height)
elif rotate==270:
corrected_offset = offset + vector(-0.5*height,0.5*width)
else:
debug.error("Invalid rotation argument.",-1)
self.add_mod(via)
self.add_inst(name=via.name,
mod=via,
offset=corrected_offset,
mirror=mirror,
rotate=rotate)
# We don't model the logical connectivity of wires/paths
self.connect_inst([])
return via
def add_ptx(self, offset, mirror="R0", rotate=0, width=1, mults=1, tx_type="nmos"): def add_ptx(self, offset, mirror="R0", rotate=0, width=1, mults=1, tx_type="nmos"):
"""Adds a ptx module to the design.""" """Adds a ptx module to the design."""
import ptx import ptx
@ -278,14 +357,14 @@ class layout:
reader = gdsMill.Gds2reader(self.gds) reader = gdsMill.Gds2reader(self.gds)
reader.loadFromFile(self.gds_file) reader.loadFromFile(self.gds_file)
else: else:
debug.info(3, "creating structure %s" % self.name) debug.info(4, "creating structure %s" % self.name)
self.gds = gdsMill.VlsiLayout(name=self.name, units=GDS["unit"]) self.gds = gdsMill.VlsiLayout(name=self.name, units=GDS["unit"])
def print_gds(self, gds_file=None): def print_gds(self, gds_file=None):
"""Print the gds file (not the vlsi class) to the terminal """ """Print the gds file (not the vlsi class) to the terminal """
if gds_file == None: if gds_file == None:
gds_file = self.gds_file gds_file = self.gds_file
debug.info(3, "Printing %s" % gds_file) debug.info(4, "Printing %s" % gds_file)
arrayCellLayout = gdsMill.VlsiLayout(units=GDS["unit"]) arrayCellLayout = gdsMill.VlsiLayout(units=GDS["unit"])
reader = gdsMill.Gds2reader(arrayCellLayout, debugToTerminal=1) reader = gdsMill.Gds2reader(arrayCellLayout, debugToTerminal=1)
reader.loadFromFile(gds_file) reader.loadFromFile(gds_file)

View File

@ -80,12 +80,13 @@ class ms_flop_array(design.design):
width=gnd_pin.width(), width=gnd_pin.width(),
height=gnd_pin.height()) height=gnd_pin.height())
din_pin = self.ms_inst[i].get_pin("din") din_pins = self.ms_inst[i].get_pins("din")
self.add_layout_pin(text="din[{}]".format(i), for din_pin in din_pins:
layer="metal2", self.add_layout_pin(text="din[{}]".format(i),
offset=din_pin.ll(), layer=din_pin.layer,
width=din_pin.width(), offset=din_pin.ll(),
height=din_pin.height()) width=din_pin.width(),
height=din_pin.height())
dout_pin = self.ms_inst[i].get_pin("dout") dout_pin = self.ms_inst[i].get_pin("dout")
self.add_layout_pin(text="dout[{}]".format(i), self.add_layout_pin(text="dout[{}]".format(i),

View File

@ -63,28 +63,20 @@ class nand_2(design.design):
# transistors are created here but not yet placed or added as a module # transistors are created here but not yet placed or added as a module
def create_ptx(self): def create_ptx(self):
""" Add required modules """ """ Add required modules """
self.nmos1 = ptx(width=self.nmos_size, self.nmos = ptx(width=self.nmos_size,
mults=self.tx_mults, mults=self.tx_mults,
tx_type="nmos") tx_type="nmos")
self.add_mod(self.nmos1) self.add_mod(self.nmos)
self.nmos2 = ptx(width=self.nmos_size,
mults=self.tx_mults,
tx_type="nmos")
self.add_mod(self.nmos2)
self.pmos1 = ptx(width=self.pmos_size, self.pmos = ptx(width=self.pmos_size,
mults=self.tx_mults, mults=self.tx_mults,
tx_type="pmos") tx_type="pmos")
self.add_mod(self.pmos1) self.add_mod(self.pmos)
self.pmos2 = ptx(width=self.pmos_size,
mults=self.tx_mults,
tx_type="pmos")
self.add_mod(self.pmos2)
def setup_layout_constants(self): def setup_layout_constants(self):
""" Calculate the layout constraints """ """ Calculate the layout constraints """
self.well_width = self.pmos1.active_position.x \ self.well_width = self.pmos.active_position.x \
+ 2 * self.pmos1.active_width \ + 2 * self.pmos.active_width \
+ drc["active_to_body_active"] + \ + drc["active_to_body_active"] + \
drc["well_enclosure_active"] drc["well_enclosure_active"]
@ -116,44 +108,44 @@ class nand_2(design.design):
# determines the spacing between the edge and nmos (rail to active # determines the spacing between the edge and nmos (rail to active
# metal or poly_to_poly spacing) # metal or poly_to_poly spacing)
edge_to_nmos = max(drc["metal1_to_metal1"] edge_to_nmos = max(drc["metal1_to_metal1"]
- self.nmos1.active_contact_positions[0].y, - self.nmos.active_contact_positions[0].y,
0.5 * (drc["poly_to_poly"] - drc["minwidth_metal1"]) 0.5 * (drc["poly_to_poly"] - drc["minwidth_metal1"])
- self.nmos1.poly_positions[0].y) - self.nmos.poly_positions[0].y)
# determine the position of the first transistor from the left # determine the position of the first transistor from the left
self.nmos_position1 = vector(0, 0.5 * drc["minwidth_metal1"] + edge_to_nmos) self.nmos_position1 = vector(0, 0.5 * drc["minwidth_metal1"] + edge_to_nmos)
offset = self.nmos_position1+ vector(0,self.nmos1.height) offset = self.nmos_position1+ vector(0,self.nmos.height)
self.add_inst(name="nmos1", self.add_inst(name="nmos1",
mod=self.nmos1, mod=self.nmos,
offset=offset, offset=offset,
mirror="MX") mirror="MX")
self.connect_inst(["Z", "A", "net1", "gnd"]) self.connect_inst(["Z", "A", "net1", "gnd"])
self.nmos_position2 = vector(self.nmos2.active_width - self.nmos2.active_contact.width, self.nmos_position2 = vector(self.nmos.active_width - self.nmos.active_contact.width,
self.nmos_position1.y) self.nmos_position1.y)
offset = self.nmos_position2 + vector(0,self.nmos2.height) offset = self.nmos_position2 + vector(0,self.nmos.height)
self.add_inst(name="nmos2", self.add_inst(name="nmos2",
mod=self.nmos2, mod=self.nmos,
offset=offset, offset=offset,
mirror="MX") mirror="MX")
self.connect_inst(["net1", "B", "gnd", "gnd"]) self.connect_inst(["net1", "B", "gnd", "gnd"])
# determines the spacing between the edge and pmos # determines the spacing between the edge and pmos
edge_to_pmos = max(drc["metal1_to_metal1"] \ edge_to_pmos = max(drc["metal1_to_metal1"] \
- self.pmos1.active_contact_positions[0].y, - self.pmos.active_contact_positions[0].y,
0.5 * drc["poly_to_poly"] - 0.5 * drc["minwidth_metal1"] \ 0.5 * drc["poly_to_poly"] - 0.5 * drc["minwidth_metal1"] \
- self.pmos1.poly_positions[0].y) - self.pmos.poly_positions[0].y)
self.pmos_position1 = vector(0, self.height - 0.5 * drc["minwidth_metal1"] self.pmos_position1 = vector(0, self.height - 0.5 * drc["minwidth_metal1"]
- edge_to_pmos - self.pmos1.height) - edge_to_pmos - self.pmos.height)
self.add_inst(name="pmos1", self.add_inst(name="pmos1",
mod=self.pmos1, mod=self.pmos,
offset=self.pmos_position1) offset=self.pmos_position1)
self.connect_inst(["vdd", "A", "Z", "vdd"]) self.connect_inst(["vdd", "A", "Z", "vdd"])
self.pmos_position2 = vector(self.nmos_position2.x, self.pmos_position1.y) self.pmos_position2 = vector(self.nmos_position2.x, self.pmos_position1.y)
self.add_inst(name="pmos2", self.add_inst(name="pmos2",
mod=self.pmos2, mod=self.pmos,
offset=self.pmos_position2) offset=self.pmos_position2)
self.connect_inst(["Z", "B", "vdd", "vdd"]) self.connect_inst(["Z", "B", "vdd", "vdd"])
@ -162,20 +154,20 @@ class nand_2(design.design):
# create well contacts # create well contacts
layer_stack = ("active", "contact", "metal1") layer_stack = ("active", "contact", "metal1")
xoffset = (self.nmos_position2.x + self.pmos1.active_position.x xoffset = (self.nmos_position2.x + self.pmos.active_position.x
+ self.pmos1.active_width + drc["active_to_body_active"]) + self.pmos.active_width + drc["active_to_body_active"])
yoffset = (self.pmos_position1.y + yoffset = (self.pmos_position1.y +
self.pmos1.active_contact_positions[0].y) self.pmos.active_contact_positions[0].y)
offset = self.nwell_contact_position = vector(xoffset, yoffset) offset = self.nwell_contact_position = vector(xoffset, yoffset)
self.pwell_contact=self.add_contact(layer_stack,offset,(1,self.nmos1.num_of_tacts)) self.pwell_contact=self.add_contact(layer_stack,offset,(1,self.nmos.num_contacts))
xoffset = (self.nmos_position2.x + self.nmos1.active_position.x xoffset = (self.nmos_position2.x + self.nmos.active_position.x
+ self.nmos1.active_width + drc["active_to_body_active"]) + self.nmos.active_width + drc["active_to_body_active"])
yoffset = (self.nmos_position1.y + self.nmos1.height yoffset = (self.nmos_position1.y + self.nmos.height
- self.nmos1.active_contact_positions[0].y - self.nmos.active_contact_positions[0].y
- self.nmos1.active_contact.height) - self.nmos.active_contact.height)
offset = self.pwell_contact_position = vector(xoffset, yoffset) offset = self.pwell_contact_position = vector(xoffset, yoffset)
self.nwell_contact=self.add_contact(layer_stack,offset,(1,self.pmos1.num_of_tacts)) self.nwell_contact=self.add_contact(layer_stack,offset,(1,self.pmos.num_contacts))
def connect_well_contacts(self): def connect_well_contacts(self):
""" Connect well contacts to vdd and gnd rail """ """ Connect well contacts to vdd and gnd rail """
@ -189,7 +181,7 @@ class nand_2(design.design):
width=drc["minwidth_metal1"], width=drc["minwidth_metal1"],
height=well_tap_length) height=well_tap_length)
well_tap_length = self.nmos1.active_height well_tap_length = self.nmos.active_height
offset = (self.pwell_contact_position.scale(1,0) offset = (self.pwell_contact_position.scale(1,0)
+ self.pwell_contact.second_layer_position.scale(1,0) + self.pwell_contact.second_layer_position.scale(1,0)
- self.pwell_contact.first_layer_position.scale(1,0)) - self.pwell_contact.first_layer_position.scale(1,0))
@ -199,22 +191,22 @@ class nand_2(design.design):
def connect_rails(self): def connect_rails(self):
""" Connect transistor pmos drains to vdd and nmos drains to gnd rail """ """ Connect transistor pmos drains to vdd and nmos drains to gnd rail """
correct = vector(self.pmos1.active_contact.width - drc["minwidth_metal1"], correct = vector(self.pmos.active_contact.width - drc["minwidth_metal1"],
0).scale(.5,0) 0).scale(.5,0)
poffset = self.pmos_position1 + self.pmos1.active_contact_positions[0] + correct poffset = self.pmos_position1 + self.pmos.active_contact_positions[0] + correct
temp_height = self.height - poffset.y temp_height = self.height - poffset.y
self.add_rect(layer="metal1", self.add_rect(layer="metal1",
offset=poffset, width=drc["minwidth_metal1"], offset=poffset, width=drc["minwidth_metal1"],
height=temp_height) height=temp_height)
poffset = vector(2 * self.pmos_position2.x + correct.x poffset = vector(2 * self.pmos_position2.x + correct.x
+ self.pmos2.active_contact_positions[0].x , poffset.y) + self.pmos.active_contact_positions[0].x , poffset.y)
self.add_rect(layer="metal1", self.add_rect(layer="metal1",
offset=poffset, offset=poffset,
width=drc["minwidth_metal1"], width=drc["minwidth_metal1"],
height=temp_height) height=temp_height)
poffset = self.nmos_position1 + self.nmos1.active_contact_positions[0] + correct poffset = self.nmos_position1 + self.nmos.active_contact_positions[0] + correct
self.add_rect(layer="metal1", self.add_rect(layer="metal1",
offset=poffset.scale(1,0), offset=poffset.scale(1,0),
width=drc["minwidth_metal1"], width=drc["minwidth_metal1"],
@ -228,40 +220,40 @@ class nand_2(design.design):
def connect_poly(self): def connect_poly(self):
""" poly connection """ """ poly connection """
yoffset_nmos1 = (self.nmos_position1.y yoffset_nmos1 = (self.nmos_position1.y
+ self.nmos1.poly_positions[0].y + self.nmos.poly_positions[0].y
+ self.nmos1.poly_height) + self.nmos.poly_height)
poly_length = (self.pmos_position1.y + self.pmos1.poly_positions[0].y poly_length = (self.pmos_position1.y + self.pmos.poly_positions[0].y
- yoffset_nmos1 + drc["minwidth_poly"]) - yoffset_nmos1 + drc["minwidth_poly"])
for position in self.pmos1.poly_positions: for position in self.pmos.poly_positions:
offset = vector(position.x, offset = vector(position.x,
yoffset_nmos1 - 0.5 * drc["minwidth_poly"]) yoffset_nmos1 - 0.5 * drc["minwidth_poly"])
self.add_rect(layer="poly", self.add_rect(layer="poly",
offset=offset, width=drc["minwidth_poly"], offset=offset, width=drc["minwidth_poly"],
height=poly_length) height=poly_length)
self.add_rect(layer="poly", self.add_rect(layer="poly",
offset=[offset.x + self.pmos1.active_contact.width + 2 * drc["minwidth_poly"], offset=[offset.x + self.pmos.active_contact.width + 2 * drc["minwidth_poly"],
offset.y], offset.y],
width=drc["minwidth_poly"], width=drc["minwidth_poly"],
height=poly_length) height=poly_length)
def connect_drains(self): def connect_drains(self):
""" Connect pmos and nmos drains. The output will be routed to this connection point. """ """ Connect pmos and nmos drains. The output will be routed to this connection point. """
yoffset = self.nmos_position1.y + self.nmos1.active_contact_positions[0].y yoffset = self.nmos_position1.y + self.nmos.active_contact_positions[0].y
drain_length = (self.height + self.pmos1.active_contact_positions[0].y drain_length = (self.height + self.pmos.active_contact_positions[0].y
- yoffset - self.pmos1.height + 0.5 * drc["minwidth_metal2"]) - yoffset - self.pmos.height + 0.5 * drc["minwidth_metal2"])
for position in self.pmos1.active_contact_positions[1:][::2]: for position in self.pmos.active_contact_positions[1:][::2]:
start = self.drain_position = vector(position.x + 0.5 * drc["minwidth_metal1"] start = self.drain_position = vector(position.x + 0.5 * drc["minwidth_metal1"]
+ self.pmos_position2.x + self.pmos_position2.x
+ self.pmos2.active_contact.first_layer_position.x + self.pmos.active_contact.first_layer_position.x
+ self.pmos2.active_contact.width / 2, + self.pmos.active_contact.width / 2,
yoffset) yoffset)
mid1 = vector(start.x, mid1 = vector(start.x,
self.height - drc["minwidth_metal2"] - drc["metal2_to_metal2"] - self.height - drc["minwidth_metal2"] - drc["metal2_to_metal2"] -
self.pmos_size - drc["metal1_to_metal1"] - 0.5 * drc["minwidth_metal1"]) self.pmos_size - drc["metal1_to_metal1"] - 0.5 * drc["minwidth_metal1"])
end = vector(position.x + 0.5 * drc["minwidth_metal1"] end = vector(position.x + 0.5 * drc["minwidth_metal1"]
+ self.pmos2.active_contact.second_layer_position.x, + self.pmos.active_contact.second_layer_position.x,
self.pmos_position1.y + self.pmos1.active_contact_positions[0].y) self.pmos_position1.y + self.pmos.active_contact_positions[0].y)
mid2 = vector(end.x, mid1.y) mid2 = vector(end.x, mid1.y)
self.add_path("metal1",[start, mid1, mid2, end]) self.add_path("metal1",[start, mid1, mid2, end])
@ -279,19 +271,19 @@ class nand_2(design.design):
def route_input_gate_A(self): def route_input_gate_A(self):
""" routing for input A """ """ routing for input A """
xoffset = self.pmos1.poly_positions[0].x xoffset = self.pmos.poly_positions[0].x
yoffset = (self.height yoffset = (self.height
- (drc["minwidth_metal1"] - (drc["minwidth_metal1"]
+ drc["metal1_to_metal1"] + drc["metal1_to_metal1"]
+ self.pmos2.active_height + self.pmos.active_height
+ drc["metal1_to_metal1"] + drc["metal1_to_metal1"]
+ self.pmos2.active_contact.second_layer_width)) + self.pmos.active_contact.second_layer_width))
if (self.nmos_size == drc["minwidth_tx"]): if (self.nmos_size == drc["minwidth_tx"]):
yoffset = (self.pmos_position1.y yoffset = (self.pmos_position1.y
+ self.pmos1.poly_positions[0].y + self.pmos.poly_positions[0].y
+ drc["poly_extend_active"] + drc["poly_extend_active"]
- (self.pmos1.active_contact.height - (self.pmos.active_contact.height
- self.pmos1.active_height) / 2 - self.pmos.active_height) / 2
- drc["metal1_to_metal1"] - drc["metal1_to_metal1"]
- self.poly_contact.width) - self.poly_contact.width)
@ -307,7 +299,7 @@ class nand_2(design.design):
width=self.poly_contact.first_layer_position.y + drc["minwidth_poly"], width=self.poly_contact.first_layer_position.y + drc["minwidth_poly"],
height=self.poly_contact.first_layer_width) height=self.poly_contact.first_layer_width)
input_length = (self.pmos1.poly_positions[0].x input_length = (self.pmos.poly_positions[0].x
- self.poly_contact.height) - self.poly_contact.height)
yoffset += self.poly_contact.via_layer_position.x yoffset += self.poly_contact.via_layer_position.x
offset = self.input_position1 = vector(0, yoffset) offset = self.input_position1 = vector(0, yoffset)
@ -319,16 +311,16 @@ class nand_2(design.design):
def route_input_gate_B(self): def route_input_gate_B(self):
""" routing for input B """ """ routing for input B """
xoffset = (self.pmos2.poly_positions[0].x xoffset = (self.pmos.poly_positions[0].x
+ self.pmos_position2.x + drc["minwidth_poly"]) + self.pmos_position2.x + drc["minwidth_poly"])
yoffset = (drc["minwidth_metal1"] yoffset = (drc["minwidth_metal1"]
+ drc["metal1_to_metal1"] + drc["metal1_to_metal1"]
+ self.nmos2.active_height + self.nmos.active_height
+ drc["minwidth_metal1"]) + drc["minwidth_metal1"])
if (self.nmos_size == drc["minwidth_tx"]): if (self.nmos_size == drc["minwidth_tx"]):
yoffset = (self.nmos_position1.y yoffset = (self.nmos_position1.y
+ self.nmos1.poly_positions[0].y + self.nmos.poly_positions[0].y
+ self.nmos1.poly_height + self.nmos.poly_height
+ drc["metal1_to_metal1"]) + drc["metal1_to_metal1"])
offset = [xoffset, yoffset] offset = [xoffset, yoffset]
self.add_contact(layers=("poly", "contact", "metal1"), self.add_contact(layers=("poly", "contact", "metal1"),
@ -336,7 +328,7 @@ class nand_2(design.design):
size=(1,1), size=(1,1),
rotate=90) rotate=90)
input_length = self.pmos2.poly_positions[0].x - self.poly_contact.height input_length = self.pmos.poly_positions[0].x - self.poly_contact.height
input_position2 = vector(xoffset - self.poly_contact.width, input_position2 = vector(xoffset - self.poly_contact.width,
yoffset + self.poly_contact.via_layer_position.x) yoffset + self.poly_contact.via_layer_position.x)
self.add_layout_pin(text="B", self.add_layout_pin(text="B",
@ -347,8 +339,8 @@ class nand_2(design.design):
def route_output(self): def route_output(self):
""" routing for output Z """ """ routing for output Z """
yoffset = (self.nmos1.height - 2 * drc["minwidth_metal1"] / 3 + yoffset = (self.nmos.height - 2 * drc["minwidth_metal1"] / 3 +
(self.height - self.pmos1.height - self.nmos1.height - drc["minwidth_metal1"]) / 2 ) (self.height - self.pmos.height - self.nmos.height - drc["minwidth_metal1"]) / 2 )
xoffset = self.drain_position.x xoffset = self.drain_position.x
offset = vector(xoffset, yoffset) offset = vector(xoffset, yoffset)
output_length = self.width - xoffset output_length = self.width - xoffset
@ -360,11 +352,11 @@ class nand_2(design.design):
def extend_wells(self): def extend_wells(self):
""" Extension of well """ """ Extension of well """
middle_point = (self.nmos_position1.y + self.nmos1.pwell_position.y middle_point = (self.nmos_position1.y + self.nmos.pwell_position.y
+ self.nmos1.well_height + self.nmos.well_height
+ (self.pmos_position1.y + self.pmos1.nwell_position.y + (self.pmos_position1.y + self.pmos.nwell_position.y
- self.nmos_position1.y - self.nmos1.pwell_position.y - self.nmos_position1.y - self.nmos.pwell_position.y
- self.nmos1.well_height) / 2) - self.nmos.well_height) / 2)
offset = self.nwell_position = vector(0, middle_point) offset = self.nwell_position = vector(0, middle_point)
self.nwell_height = self.height - middle_point self.nwell_height = self.height - middle_point
self.add_rect(layer="nwell", self.add_rect(layer="nwell",
@ -389,38 +381,38 @@ class nand_2(design.design):
def extend_active(self): def extend_active(self):
""" Extension of active region """ """ Extension of active region """
self.active_width = (self.pmos1.active_width self.active_width = (self.pmos.active_width
+ drc["active_to_body_active"] + drc["active_to_body_active"]
+ self.pmos1.active_contact.width) + self.pmos.active_contact.width)
offset = (self.pmos1.active_position offset = (self.pmos.active_position
+ self.pmos_position2.scale(1,0) + self.pmos_position2.scale(1,0)
+ self.pmos_position1.scale(0,1)) + self.pmos_position1.scale(0,1))
self.add_rect(layer="active", self.add_rect(layer="active",
offset=offset, offset=offset,
width=self.active_width, width=self.active_width,
height=self.pmos1.active_height) height=self.pmos.active_height)
offset = offset + vector(self.pmos1.active_width, 0) offset = offset + vector(self.pmos.active_width, 0)
width = self.active_width - self.pmos1.active_width width = self.active_width - self.pmos.active_width
self.add_rect(layer="nimplant", self.add_rect(layer="nimplant",
offset=offset, offset=offset,
width=width, width=width,
height=self.pmos1.active_height) height=self.pmos.active_height)
offset = vector(self.nmos_position2.x + self.nmos1.active_position.x, offset = vector(self.nmos_position2.x + self.nmos.active_position.x,
self.nmos_position1.y - self.nmos1.active_height self.nmos_position1.y - self.nmos.active_height
- self.nmos1.active_position.y + self.nmos1.height) - self.nmos.active_position.y + self.nmos.height)
self.add_rect(layer="active", self.add_rect(layer="active",
offset=offset, offset=offset,
width=self.active_width, width=self.active_width,
height=self.nmos1.active_height) height=self.nmos.active_height)
offset = offset + vector(self.nmos1.active_width,0) offset = offset + vector(self.nmos.active_width,0)
width = self.active_width - self.nmos1.active_width width = self.active_width - self.nmos.active_width
self.add_rect(layer="pimplant", self.add_rect(layer="pimplant",
offset=offset, offset=offset,
width=width, width=width,
height=self.nmos1.active_height) height=self.nmos.active_height)
def input_load(self): def input_load(self):

View File

@ -63,19 +63,17 @@ class nand_3(design.design):
def create_ptx(self): def create_ptx(self):
""" Create ptx but not yet placed""" """ Create ptx but not yet placed"""
# If full contacts, this will interfere with the C input in SCMOS
self.nmos = ptx(width=self.nmos_size, self.nmos = ptx(width=self.nmos_size,
mults=self.tx_mults, mults=self.tx_mults,
tx_type="nmos") tx_type="nmos",
self.add_mod(self.nmos) num_contacts=1)
self.add_mod(self.nmos)
self.add_mod(self.nmos) self.add_mod(self.nmos)
self.pmos = ptx(width=self.pmos_size, self.pmos = ptx(width=self.pmos_size,
mults=self.tx_mults, mults=self.tx_mults,
tx_type="pmos") tx_type="pmos")
self.add_mod(self.pmos) self.add_mod(self.pmos)
self.add_mod(self.pmos)
self.add_mod(self.pmos)
def setup_layout_constants(self): def setup_layout_constants(self):
""" setup layout constraints """ """ setup layout constraints """
@ -183,7 +181,7 @@ class nand_3(design.design):
+ self.pmos.active_width + drc["active_to_body_active"]) + self.pmos.active_width + drc["active_to_body_active"])
yoffset = self.pmos_position1.y + self.pmos.active_contact_positions[0].y yoffset = self.pmos_position1.y + self.pmos.active_contact_positions[0].y
self.nwell_contact_position = vector(xoffset, yoffset) self.nwell_contact_position = vector(xoffset, yoffset)
self.nwell_contact=self.add_contact(layer_stack,self.nwell_contact_position,(1,self.pmos.num_of_tacts)) self.nwell_contact=self.add_contact(layer_stack,self.nwell_contact_position,(1,self.pmos.num_contacts))
xoffset = self.nmos_position3.x + (self.nmos.active_position.x xoffset = self.nmos_position3.x + (self.nmos.active_position.x
+ self.nmos.active_width + self.nmos.active_width
@ -192,7 +190,7 @@ class nand_3(design.design):
- self.nmos.active_contact_positions[0].y - self.nmos.active_contact_positions[0].y
- self.nmos.active_contact.height) - self.nmos.active_contact.height)
self.pwell_contact_position = vector(xoffset, yoffset) self.pwell_contact_position = vector(xoffset, yoffset)
self.pwell_contact=self.add_contact(layer_stack,self.pwell_contact_position,(1,self.nmos.num_of_tacts)) self.pwell_contact=self.add_contact(layer_stack,self.pwell_contact_position,(1,self.nmos.num_contacts))
def connect_well_contacts(self): def connect_well_contacts(self):
""" Connect well contacts to vdd and gnd rail """ """ Connect well contacts to vdd and gnd rail """
@ -314,7 +312,6 @@ class nand_3(design.design):
def route_input_gate_A(self): def route_input_gate_A(self):
""" routing for input A """ """ routing for input A """
offset = self.pmos_position1 + self.pmos.poly_positions[0] - vector(0,self.poly_contact.height) offset = self.pmos_position1 + self.pmos.poly_positions[0] - vector(0,self.poly_contact.height)
via_offset = offset + self.poly_contact.first_layer_position.scale(-1,0) - vector(self.poly_contact.first_layer_width,0) + vector(drc["minwidth_poly"],0) via_offset = offset + self.poly_contact.first_layer_position.scale(-1,0) - vector(self.poly_contact.first_layer_width,0) + vector(drc["minwidth_poly"],0)
@ -330,7 +327,6 @@ class nand_3(design.design):
def route_input_gate_B(self): def route_input_gate_B(self):
""" routing for input B """ """ routing for input B """
offset = self.pmos_position2 + self.pmos.poly_positions[0] - vector(0,self.poly_contact.height+1*(self.m1m2_via.width+drc["metal1_to_metal1"])) offset = self.pmos_position2 + self.pmos.poly_positions[0] - vector(0,self.poly_contact.height+1*(self.m1m2_via.width+drc["metal1_to_metal1"]))
via_offset = offset + self.poly_contact.first_layer_position.scale(-1,0) - vector(self.poly_contact.first_layer_width,0) + vector(drc["minwidth_poly"],0) via_offset = offset + self.poly_contact.first_layer_position.scale(-1,0) - vector(self.poly_contact.first_layer_width,0) + vector(drc["minwidth_poly"],0)

View File

@ -10,7 +10,7 @@ class nor_2(design.design):
""" """
This module generates gds of a parametrically sized 2_input nor. This module generates gds of a parametrically sized 2_input nor.
This model use ptx to generate a 2_input nand within a cetrain height. This model use ptx to generate a 2_input nor within a cetrain height.
The 2_input nor cell_height should be the same as the 6t library cell. The 2_input nor cell_height should be the same as the 6t library cell.
If pmos can not fit in the given vertical space, it will be folded If pmos can not fit in the given vertical space, it will be folded
based so that it takes minmium horiztonal space. based so that it takes minmium horiztonal space.
@ -27,6 +27,8 @@ class nor_2(design.design):
design.design.__init__(self, name) design.design.__init__(self, name)
debug.info(2, "create nor_2 structure {0} with size of {1}".format(name, nmos_width)) debug.info(2, "create nor_2 structure {0} with size of {1}".format(name, nmos_width))
debug.check(nmos_width==drc["minwidth_tx"], "Need to rewrite nor2 for sizing.")
self.nmos_width = nmos_width self.nmos_width = nmos_width
self.height = height self.height = height
@ -47,9 +49,9 @@ class nor_2(design.design):
# These aren't for instantiating, but we use them to get the dimensions # These aren't for instantiating, but we use them to get the dimensions
self.nwell_contact = contact.contact(layer_stack=("active", "contact", "metal1"), self.nwell_contact = contact.contact(layer_stack=("active", "contact", "metal1"),
dimensions=(1, self.pmos1.num_of_tacts)) dimensions=(1, self.pmos.num_contacts))
self.pwell_contact = contact.contact(layer_stack=("active", "contact", "metal1"), self.pwell_contact = contact.contact(layer_stack=("active", "contact", "metal1"),
dimensions=(1, self.nmos1.num_of_tacts)) dimensions=(1, self.nmos.num_contacts))
self.setup_layout_constants() self.setup_layout_constants()
self.add_rails() self.add_rails()
@ -64,7 +66,7 @@ class nor_2(design.design):
nmos_mults = 1 nmos_mults = 1
for pmos_mults in range(1, 5): for pmos_mults in range(1, 5):
nmos_size = self.nmos_width nmos_size = self.nmos_width
pmos_size = 4 * self.nmos_width / pmos_mults pmos_size = 3 * self.nmos_width / pmos_mults
test_nmos = ptx(width=nmos_size, test_nmos = ptx(width=nmos_size,
mults=nmos_mults, mults=nmos_mults,
tx_type="nmos") tx_type="nmos")
@ -72,25 +74,15 @@ class nor_2(design.design):
mults=pmos_mults, mults=pmos_mults,
tx_type="nmos") tx_type="nmos")
# this how the position is done for now # FIXME: This is a hack because the old code sucked and didn't work.
# postion noms and pmos and put A at 0.3 of the margin of it and put B and the 3rd m1 track above it # We will rewrite the entire module soon.
# if there is no left space then it means the nmos is too big, we # compute the remaining space roughly including rails and tx heights
# need to increase the mults number track_space = self.height - test_nmos.height + test_pmos.height - drc["metal1_to_metal1"] - drc["minwidth_metal1"]
gate_to_gate = drc["poly_to_poly"] - drc["minwidth_metal1"] # 3 contacted track space
edge_to_nmos = max(drc["metal1_to_metal1"] - test_nmos.active_contact_positions[0].y, if track_space > 3*(self.m1m2_via.height + drc["metal1_to_metal1"]):
0.5 * gate_to_gate - test_nmos.poly_positions[0].y)
edge_to_pmos = max(drc["metal1_to_metal1"] - test_pmos.active_contact_positions[0].y,
0.5 * gate_to_gate - test_pmos.poly_positions[0].y)
route_margin = 0.5 * (self.poly_contact.second_layer_width
+ drc["minwidth_metal1"]) + drc["metal1_to_metal1"]
pmos_loc = vector(0, self.height - 0.5 * drc["minwidth_metal1"]
- edge_to_pmos - test_pmos.height)
nmos_loc = vector(0, 0.5 * drc["minwidth_metal1"] + edge_to_nmos)
leftspace = (0.7 * (pmos_loc.y - nmos_loc.y)
- 3 * route_margin - 2 * drc["metal1_to_metal1"])
if leftspace >= 0:
break break
self.nmos_size = nmos_size self.nmos_size = nmos_size
self.pmos_size = pmos_size self.pmos_size = pmos_size
self.nmos_mults = nmos_mults self.nmos_mults = nmos_mults
@ -98,23 +90,15 @@ class nor_2(design.design):
def create_modules(self): def create_modules(self):
"""transistors are created as modules""" """transistors are created as modules"""
self.nmos1 = ptx(width=self.nmos_size, self.nmos = ptx(width=self.nmos_size,
mults=self.nmos_mults, mults=self.nmos_mults,
tx_type="nmos") tx_type="nmos")
self.add_mod(self.nmos1) self.add_mod(self.nmos)
self.nmos2 = ptx(width=self.nmos_size,
mults=self.nmos_mults,
tx_type="nmos")
self.add_mod(self.nmos2)
self.pmos1 = ptx(width=self.pmos_size, self.pmos = ptx(width=self.pmos_size,
mults=self.pmos_mults, mults=self.pmos_mults,
tx_type="pmos") tx_type="pmos")
self.add_mod(self.pmos1) self.add_mod(self.pmos)
self.pmos2 = ptx(width=self.pmos_size,
mults=self.pmos_mults,
tx_type="pmos")
self.add_mod(self.pmos2)
def setup_layout_constants(self): def setup_layout_constants(self):
@ -122,30 +106,32 @@ class nor_2(design.design):
# determines the spacing between the edge and nmos (rail to active # determines the spacing between the edge and nmos (rail to active
# metal or poly_to_poly spacing) # metal or poly_to_poly spacing)
half_gate_to_gate = 0.5 * (drc["poly_to_poly"] - drc["minwidth_metal1"]) half_gate_to_gate = 0.5 * (drc["poly_to_poly"] - drc["minwidth_metal1"])
edge_to_nmos = max(drc["metal1_to_metal1"] - self.nmos1.active_contact_positions[0].y, edge_to_nmos = max(drc["metal1_to_metal1"] - self.nmos.active_contact_positions[0].y,
half_gate_to_gate - self.nmos1.poly_positions[0].y) half_gate_to_gate - self.nmos.poly_positions[0].y)
# determine the position of the first transistor from the left # determine the position of the first transistor from the left
self.nmos_loc1 = vector(0, 0.5 * drc["minwidth_metal1"] + edge_to_nmos) self.nmos_position1 = vector(0,
offset = self.nmos_loc1 + vector(0,self.nmos1.height) 0.5 * drc["minwidth_metal1"] + edge_to_nmos)
offset = self.nmos_position1 + vector(0,self.nmos.height)
x = vector(self.nmos2.active_width - self.nmos2.active_contact.width, 0) x = vector(self.nmos.active_width - self.nmos.active_contact.width, 0)
self.nmos_loc2 = x + self.nmos_loc1.scale(0,1) self.nmos_position2 = x + self.nmos_position1.scale(0,1)
# determines the spacing between the edge and pmos # determines the spacing between the edge and pmos
edge_to_pmos = max(drc["metal1_to_metal1"] - self.pmos1.active_contact_positions[0].y, edge_to_pmos = max(drc["metal1_to_metal1"] - self.pmos.active_contact_positions[0].y,
half_gate_to_gate - self.pmos1.poly_positions[0].y) half_gate_to_gate - self.pmos.poly_positions[0].y)
self.pmos_loc1 = vector(0, self.height - 0.5 * drc["minwidth_metal1"] self.pmos_position1 = vector(0,
- edge_to_pmos - self.pmos1.height) self.height - 0.5 * drc["minwidth_metal1"]
self.pmos_loc2 = self.pmos_loc1 + vector(self.pmos1.width,0) - edge_to_pmos - self.pmos.height)
self.pmos_position2 = self.pmos_position1 + vector(self.pmos.width,0)
self.well_width = max(self.pmos_loc2.x + self.pmos2.active_position.x self.well_width = max(self.pmos_position2.x + self.pmos.active_position.x
+ self.pmos2.active_width + self.pmos.active_width
+ drc["active_to_body_active"] + self.nwell_contact.width + drc["active_to_body_active"] + self.nwell_contact.width
+ drc["well_enclosure_active"], + drc["well_enclosure_active"],
self.nmos_loc2.x + self.nmos2.active_position.x self.nmos_position2.x + self.nmos.active_position.x
+ self.nmos2.active_width + self.nmos.active_width
+ drc["active_to_body_active"] + drc["well_enclosure_active"]) + drc["active_to_body_active"] + drc["well_enclosure_active"])
self.width = self.well_width self.width = self.well_width
def add_rails(self): def add_rails(self):
@ -153,93 +139,92 @@ class nor_2(design.design):
rail_height = drc["minwidth_metal1"] rail_height = drc["minwidth_metal1"]
self.rail_height = rail_height self.rail_height = rail_height
# Relocate the origin # Relocate the origin
self.gnd_loc = vector(0, - 0.5 * drc["minwidth_metal1"]) self.gnd_position = vector(0, - 0.5 * drc["minwidth_metal1"])
self.add_layout_pin(text="gnd", self.add_layout_pin(text="gnd",
layer="metal1", layer="metal1",
offset=self.gnd_loc, offset=self.gnd_position,
width=rail_width, width=rail_width,
height=rail_height) height=rail_height)
self.vdd_loc = self.gnd_loc + vector(0, self.height) self.vdd_position = self.gnd_position + vector(0, self.height)
self.add_layout_pin(text="vdd", self.add_layout_pin(text="vdd",
layer="metal1", layer="metal1",
offset=self.vdd_loc, offset=self.vdd_position,
width=rail_width, width=rail_width,
height=rail_height) height=rail_height)
def add_ptx(self): def add_ptx(self):
""" transistors are placed in the layout""" """ transistors are placed in the layout"""
offset = self.nmos_loc1 + vector(0, self.nmos1.height) offset = self.nmos_position1 + vector(0, self.nmos.height)
self.add_inst(name="nmos1", self.add_inst(name="nmos1",
mod=self.nmos1, mod=self.nmos,
offset=offset, offset=offset,
mirror="MX") mirror="MX")
self.connect_inst(["Z", "A", "gnd", "gnd"]) self.connect_inst(["Z", "A", "gnd", "gnd"])
offset = self.nmos_loc2 + vector(0, self.nmos2.height) offset = self.nmos_position2 + vector(0, self.nmos.height)
self.add_inst(name="nmos2", self.add_inst(name="nmos2",
mod=self.nmos2, mod=self.nmos,
offset=offset, offset=offset,
mirror="MX") mirror="MX")
self.connect_inst(["Z", "B", "gnd", "gnd"]) self.connect_inst(["Z", "B", "gnd", "gnd"])
offset = self.pmos_loc1 offset = self.pmos_position1
self.add_inst(name="pmos1", self.add_inst(name="pmos1",
mod=self.pmos1, mod=self.pmos,
offset=offset) offset=offset)
self.connect_inst(["vdd", "A", "net1", "vdd"]) self.connect_inst(["vdd", "A", "net1", "vdd"])
offset = self.pmos_loc2 offset = self.pmos_position2
self.add_inst(name="pmos2", self.add_inst(name="pmos2",
mod=self.pmos2, mod=self.pmos,
offset=offset) offset=offset)
self.connect_inst(["net1", "B", "Z", "vdd"]) self.connect_inst(["net1", "B", "Z", "vdd"])
def add_well_contacts(self): def add_well_contacts(self):
layer_stack = ("active", "contact", "metal1") layer_stack = ("active", "contact", "metal1")
xoffset = (self.pmos_loc2.x + self.pmos1.active_position.x xoffset = (self.pmos_position2.x + self.pmos.active_position.x
+ self.pmos1.active_width + drc["active_to_body_active"]) + self.pmos.active_width + drc["active_to_body_active"])
yoffset = (self.pmos_loc1.y yoffset = (self.pmos_position1.y
+ self.pmos1.active_contact_positions[0].y) + self.pmos.active_contact_positions[0].y)
self.nwell_contact_loc = vector(xoffset, yoffset) self.nwell_contact_position = vector(xoffset, yoffset)
self.nwell_contact=self.add_contact(layer_stack,self.nwell_contact_loc,(1,self.pmos1.num_of_tacts)) self.nwell_contact=self.add_contact(layer_stack,self.nwell_contact_position,(1,self.pmos.num_contacts))
xoffset = self.nmos_loc2.x + (self.nmos1.active_position.x xoffset = self.nmos_position2.x + (self.nmos.active_position.x
+ self.nmos1.active_width + self.nmos.active_width
+ drc["active_to_body_active"]) + drc["active_to_body_active"])
yoffset = (self.nmos_loc1.y + self.nmos1.height yoffset = (self.nmos_position1.y + self.nmos.height
- self.nmos1.active_contact_positions[0].y - self.nmos.active_contact_positions[0].y
- self.nmos1.active_contact.height) - self.nmos.active_contact.height)
self.pwell_contact_loc = vector(xoffset, yoffset) self.pwell_contact_position = vector(xoffset, yoffset)
self.pwell_contact=self.add_contact(layer_stack,self.pwell_contact_loc,(1,self.nmos1.num_of_tacts)) self.pwell_contact=self.add_contact(layer_stack,self.pwell_contact_position,(1,self.nmos.num_contacts))
def route(self): def route(self):
self.route_pins() self.route_pins()
self.connect_well_contacts() self.connect_well_contacts()
M1_track = (self.B_loc.y + drc["metal1_to_metal1"] M1_track = self.B_position.y + max(drc["minwidth_metal2"], self.poly_contact.second_layer_width) + drc["metal2_to_metal2"]
+ .5 * (self.poly_contact.second_layer_width
+ drc["minwidth_metal1"]))
self.connect_tx(M1_track) self.connect_tx(M1_track)
self.connect_poly() self.connect_poly()
def connect_well_contacts(self): def connect_well_contacts(self):
""" Connect well contacts to vdd and gnd rail """ """ Connect well contacts to vdd and gnd rail """
well_tap_length = self.height - self.nwell_contact_loc.y well_tap_length = self.height - self.nwell_contact_position.y
xoffset = (self.nwell_contact_loc.x xoffset = (self.nwell_contact_position.x
+ self.nwell_contact.second_layer_position.x + self.nwell_contact.second_layer_position.x
- self.nwell_contact.first_layer_position.x) - self.nwell_contact.first_layer_position.x)
offset = [xoffset, self.nwell_contact_loc.y] offset = [xoffset, self.nwell_contact_position.y]
self.add_rect(layer="metal1", self.add_rect(layer="metal1",
offset=offset, offset=offset,
width=drc["minwidth_metal1"], width=drc["minwidth_metal1"],
height=well_tap_length) height=well_tap_length)
offset = (self.pwell_contact_loc.scale(1,0) offset = (self.pwell_contact_position.scale(1,0)
+ self.pwell_contact.second_layer_position.scale(1,0) + self.pwell_contact.second_layer_position.scale(1,0)
- self.pwell_contact.first_layer_position.scale(1,0)) - self.pwell_contact.first_layer_position.scale(1,0))
well_tap_length = self.pwell_contact_loc.y well_tap_length = self.pwell_contact_position.y
self.add_rect(layer="metal1", self.add_rect(layer="metal1",
offset=offset, offset=offset,
width=drc["minwidth_metal1"], width=drc["minwidth_metal1"],
@ -248,49 +233,49 @@ class nor_2(design.design):
def connect_tx(self, M1_track): def connect_tx(self, M1_track):
"""Connect transistor pmos drains to vdd and nmos drains to gnd rail""" """Connect transistor pmos drains to vdd and nmos drains to gnd rail"""
# the first pmos drain to Vdd # the first pmos drain to Vdd
for i in range(len(self.pmos1.active_contact_positions)): for i in range(len(self.pmos.active_contact_positions)):
contact_pos = self.pmos_loc1 + self.pmos1.active_contact_positions[i] contact_pos = self.pmos_position1 + self.pmos.active_contact_positions[i]
if i % 2 == 0: if i % 2 == 0:
correct = self.pmos1.active_contact.second_layer_position.scale(1,0) correct = self.pmos.active_contact.second_layer_position.scale(1,0)
drain_posistion = contact_pos + correct drain_posistion = contact_pos + correct
height = self.vdd_loc.y - drain_posistion.y height = self.vdd_position.y - drain_posistion.y
self.add_rect(layer="metal1", self.add_rect(layer="metal1",
offset=drain_posistion, offset=drain_posistion,
width=drc["minwidth_metal1"], width=drc["minwidth_metal1"],
height=height) height=height)
else: else:
# source to pmos2 # source to pmos2
correct = (self.pmos1.active_contact.second_layer_position.scale(1,0) correct = (self.pmos.active_contact.second_layer_position.scale(1,0)
+ vector(self.pmos1.active_contact.second_layer_width, + vector(self.pmos.active_contact.second_layer_width,
0).scale(.5,0)) 0).scale(0.5,0))
source_loc = contact_pos + correct source_position = contact_pos + correct
mid = [self.pmos_loc2.x, M1_track] mid = [self.pmos_position2.x, M1_track]
self.add_path("metal1", [source_loc, mid]) self.add_path("metal1", [source_position, mid])
# the second pmos # the second pmos
for i in range(len(self.pmos2.active_contact_positions)): for i in range(len(self.pmos.active_contact_positions)):
if i % 2 == 0: if i % 2 == 0:
# source to pmos2 # source to pmos2
pmos_active =self.pmos_loc2+self.pmos2.active_contact_positions[i] pmos_active =self.pmos_position2+self.pmos.active_contact_positions[i]
correct= (self.pmos2.active_contact.second_layer_position.scale(1,0) correct= (self.pmos.active_contact.second_layer_position.scale(1,0)
+ vector(0.5 * self.pmos2.active_contact.second_layer_width,0)) + vector(0.5 * self.pmos.active_contact.second_layer_width,0))
source_loc = pmos_active + correct source_position = pmos_active + correct
mid = [self.pmos_loc2.x, M1_track] mid = [self.pmos_position2.x, M1_track]
self.add_path("metal1", [source_loc, mid]) self.add_path("metal1", [source_position, mid])
# two nmos source to gnd # two nmos source to gnd
source_posistion1 = (self.nmos_loc1 source_posistion1 = (self.nmos_position1
+ self.nmos1.active_contact_positions[0] + self.nmos.active_contact_positions[0]
+ self.nmos1.active_contact.second_layer_position.scale(1,0)) + self.nmos.active_contact.second_layer_position.scale(1,0))
height = self.gnd_loc.y - source_posistion1.y height = self.gnd_position.y - source_posistion1.y
self.add_rect(layer="metal1", self.add_rect(layer="metal1",
offset=source_posistion1, offset=source_posistion1,
width=drc["minwidth_metal1"], width=drc["minwidth_metal1"],
height=height) height=height)
source_posistion2 = (self.nmos_loc2 source_posistion2 = (self.nmos_position2
+ self.nmos2.active_contact_positions[1] + self.nmos.active_contact_positions[1]
+ self.nmos2.active_contact.second_layer_position.scale(1,0)) + self.nmos.active_contact.second_layer_position.scale(1,0))
height = self.gnd_loc.y - source_posistion2.y height = self.gnd_position.y - source_posistion2.y
self.add_rect(layer="metal1", self.add_rect(layer="metal1",
offset=source_posistion2, offset=source_posistion2,
width=drc["minwidth_metal1"], width=drc["minwidth_metal1"],
@ -299,29 +284,29 @@ class nor_2(design.design):
def connect_poly(self): def connect_poly(self):
"""connect connect poly between nmos and pmos""" """connect connect poly between nmos and pmos"""
# connect pmos1 poly # connect pmos1 poly
nmos_gate = (self.nmos_loc1 nmos_gate = (self.nmos_position1
+ self.nmos1.poly_positions[0] + self.nmos.poly_positions[0]
+ vector(0.5 * drc["minwidth_poly"], 0)) + vector(0.5 * drc["minwidth_poly"], 0))
for i in range(len(self.pmos1.poly_positions)): for i in range(len(self.pmos.poly_positions)):
pmos_gate = (self.pmos_loc1 pmos_gate = (self.pmos_position1
+ self.pmos1.poly_positions[i] + self.pmos.poly_positions[i]
+ vector(0.5 * drc["minwidth_poly"], 0)) + vector(0.5 * drc["minwidth_poly"], 0))
mid1 = [pmos_gate.x, pmos_gate.y - drc["poly_to_active"]] mid1 = [pmos_gate.x, pmos_gate.y - drc["poly_to_active"]]
self.add_path("poly", [nmos_gate, mid1, pmos_gate]) self.add_path("poly", [nmos_gate, mid1, pmos_gate])
# connect pmos2 poly # connect pmos2 poly
nmos_gate = vector(self.nmos_loc2[0] nmos_gate = vector(self.nmos_position2[0]
+ self.nmos2.poly_positions[0].x + self.nmos.poly_positions[0].x
+ 0.5 * drc["minwidth_poly"], + 0.5 * drc["minwidth_poly"],
self.nmos_loc1.y self.nmos_position1.y
+ self.nmos1.poly_positions[0].y) + self.nmos.poly_positions[0].y)
for i in range(len(self.pmos2.poly_positions)): for i in range(len(self.pmos.poly_positions)):
pmos_gate = (self.pmos_loc2 pmos_gate = (self.pmos_position2
+ self.pmos2.poly_positions[i] + self.pmos.poly_positions[i]
+ vector(0.5 * drc["minwidth_poly"], 0)) + vector(0.5 * drc["minwidth_poly"], 0))
mid1 = vector(pmos_gate.x, mid1 = vector(pmos_gate.x,
nmos_gate.y + self.nmos2.height nmos_gate.y + self.nmos.height
+ drc["poly_to_active"]) + drc["poly_to_active"])
self.add_path("poly", [nmos_gate, mid1, pmos_gate]) self.add_path("poly", [nmos_gate, mid1, pmos_gate])
def route_pins(self): def route_pins(self):
@ -334,40 +319,40 @@ class nor_2(design.design):
def route_input_A(self): def route_input_A(self):
"""create input A layout""" """create input A layout"""
xoffset = self.nmos1.poly_positions[0].x xoffset = self.nmos.poly_positions[0].x
yoffset = self.nmos_loc1.y + self.nmos1.height \ # HACK: added 1.5, since we're going to rewrite this.
+ 0.3 * (self.pmos_loc1.y - self.nmos_loc1.y \ yoffset = self.nmos_position1.y + drc["well_enclosure_active"] + self.nmos.active_height + 1.5*self.poly_contact.height
- self.nmos1.height) self.A_position = vector(xoffset, yoffset)
self.A_loc = vector(xoffset, yoffset)
# gate input # gate input
offset = self.A_loc - vector(0, self.poly_contact.width) offset = self.A_position - vector(0, 0.5 * self.poly_contact.width)
self.add_contact(layers=("poly", "contact", "metal1"), self.add_contact(layers=("poly", "contact", "metal1"),
offset=offset, offset=offset,
rotate=90) rotate=90)
# connect gate input to tx gate # connect gate input to tx gate
offset = self.A_loc - vector(self.poly_contact.first_layer_position.y, offset = self.A_position - vector(self.poly_contact.first_layer_position.y,
self.poly_contact.width) 0.5 * self.poly_contact.width)
self.add_rect(layer="poly", self.add_rect(layer="poly",
offset=offset, offset=offset,
width=self.poly_contact.first_layer_position.y + drc["minwidth_poly"], width=self.poly_contact.first_layer_position.y + drc["minwidth_poly"],
height=self.poly_contact.first_layer_width) height=self.poly_contact.first_layer_width)
# extend the metal to the boundary of the cell # extend the metal to the boundary of the cell
input_length = self.A_loc.x input_length = self.A_position.x
offset = [0, self.A_loc.y - drc["minwidth_metal1"]] offset = [0, self.A_position.y - 0.5 * drc["minwidth_metal1"]]
self.add_layout_pin(text="A", self.add_layout_pin(text="A",
layer="metal1", layer="metal1",
offset=offset, offset=offset,
width=input_length, width=input_length,
height=drc["minwidth_metal1"]) height=drc["minwidth_metal1"])
def route_input_B(self): def route_input_B(self):
"""create input B layout """ """create input B layout """
xoffset = self.pmos2.poly_positions[0].x + self.pmos_loc2.x xoffset = self.pmos.poly_positions[0].x \
yoffset = self.A_loc.y + 0.5 * (self.poly_contact.second_layer_width \ + self.pmos_position2.x
+ drc["minwidth_metal1"]) + drc["metal1_to_metal1"] yoffset = self.A_position.y \
self.B_loc = vector(xoffset, yoffset) + max(drc["minwidth_metal2"], self.poly_contact.second_layer_width) + drc["metal2_to_metal2"]
offset = self.B_loc - vector(0, 0.5 * self.poly_contact.width) self.B_position = vector(xoffset, yoffset)
offset = self.B_position - vector(0, 0.5 * self.poly_contact.width)
self.add_contact(layers=("poly", "contact", "metal1"), self.add_contact(layers=("poly", "contact", "metal1"),
offset=offset, offset=offset,
rotate=90) rotate=90)
@ -377,53 +362,55 @@ class nor_2(design.design):
width=-(self.poly_contact.first_layer_position.y + drc["minwidth_poly"]), width=-(self.poly_contact.first_layer_position.y + drc["minwidth_poly"]),
height=self.poly_contact.first_layer_width) height=self.poly_contact.first_layer_width)
self.add_layout_pin(text="B", self.add_layout_pin(text="B",
layer="metal1", layer="metal1",
offset=[0, self.B_loc.y - 0.5 * drc["minwidth_metal1"]], offset=[0,
width=self.B_loc.x, self.B_position.y - 0.5 * drc["minwidth_metal1"]],
height=drc["minwidth_metal1"]) width=self.B_position.x,
height=drc["minwidth_metal1"])
def route_output(self): def route_output(self):
"""route the output to nmos pmos """ """route the output to nmos pmos """
self.Z_loc = vector(self.width, self.A_loc.y) self.Z_position = vector(self.width, self.A_position.y)
# route nmos drain to Z # route nmos drain to Z
nmos_contact = (self.nmos_loc1 nmos_contact = (self.nmos_position1
+ self.nmos1.active_contact_positions[1] + self.nmos.active_contact_positions[1]
+ self.nmos1.active_contact.second_layer_position + self.nmos.active_contact.second_layer_position
+ vector(self.nmos1.active_contact.second_layer_width,0).scale(0.5, 0)) + vector(self.nmos.active_contact.second_layer_width,
mid = [nmos_contact.x, self.A_loc.y] 0).scale(0.5, 0))
self.add_path("metal1", [self.Z_loc, mid, nmos_contact]) 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): for i in range(len(self.pmos.poly_positions) + 1):
if i % 2 == 1: if i % 2 == 1:
# pmos2 drain to Z # pmos2 drain to Z
pmos_contact = (self.pmos_loc2 pmos_contact = (self.pmos_position2
+ self.pmos1.active_contact_positions[i] + self.pmos.active_contact_positions[i]
+ self.pmos2.active_contact.second_layer_position.scale(1, 0) + self.pmos.active_contact.second_layer_position.scale(1, 0)
+ vector(self.pmos2.active_contact.second_layer_width,0).scale(0.5, 0)) + vector(self.pmos.active_contact.second_layer_width,
0).scale(0.5, 0))
offset = pmos_contact - vector(0.5 * self.m1m2_via.width, 0) offset = pmos_contact - vector(0.5 * self.m1m2_via.width, 0)
self.add_via(layers=("metal1", "via1", "metal2"), self.add_via(layers=("metal1", "via1", "metal2"),
offset=offset) offset=offset)
mid = [pmos_contact.x, self.Z_loc.y] mid = [pmos_contact.x, self.Z_position.y]
self.add_wire(("metal1", "via1", "metal2"), self.add_wire(("metal1", "via1", "metal2"),
[self.Z_loc, mid, pmos_contact]) [self.Z_position, mid, pmos_contact])
self.add_layout_pin(text="Z", self.add_layout_pin(text="Z",
layer="metal1", layer="metal1",
offset=mid - vector(0,0.5*drc["minwidth_metal1"]), offset=mid - vector(0,0.5*drc["minwidth_metal1"]),
width=self.Z_loc.x-mid[0], width=self.Z_position.x-mid[0],
height=drc["minwidth_metal1"]) height=drc["minwidth_metal1"])
def extend_wells(self): def extend_wells(self):
""" extend well for well contact""" """ extend well for well contact"""
middle_point = (self.nmos_loc1.y middle_point = (self.nmos_position1.y
+ self.nmos1.pwell_position.y + self.nmos.pwell_position.y
+ self.nmos1.well_height + self.nmos.well_height
+ (self.pmos_loc1.y + (self.pmos_position1.y
+ self.pmos1.nwell_position.y + self.pmos.nwell_position.y
- self.nmos_loc1.y - self.nmos_position1.y
- self.nmos1.pwell_position.y - self.nmos.pwell_position.y
- self.nmos1.well_height) / 2 ) - self.nmos.well_height) / 2 )
self.nwell_position = vector(0, middle_point) self.nwell_position = vector(0, middle_point)
self.nwell_height = self.height - middle_point self.nwell_height = self.height - middle_point
self.add_rect(layer="nwell", self.add_rect(layer="nwell",
@ -448,34 +435,34 @@ class nor_2(design.design):
def extend_active(self): def extend_active(self):
""" extend active for well contact""" """ extend active for well contact"""
self.active_width = self.pmos1.active_width \ self.active_width = self.pmos.active_width \
+ drc["active_to_body_active"] \ + drc["active_to_body_active"] \
+ self.pmos1.active_contact.width + self.pmos.active_contact.width
offset = (self.pmos_loc2.scale(1,0) offset = (self.pmos_position2.scale(1,0)
+ self.pmos_loc1.scale(0,1) + self.pmos_position1.scale(0,1)
+ self.pmos1.active_position) + self.pmos.active_position)
self.add_rect(layer="active", self.add_rect(layer="active",
offset=offset, offset=offset,
width=self.active_width, width=self.active_width,
height=self.pmos1.active_height) height=self.pmos.active_height)
offset = offset + vector(self.pmos1.active_width, 0) offset = offset + vector(self.pmos.active_width, 0)
width = self.active_width - self.pmos1.active_width width = self.active_width - self.pmos.active_width
self.add_rect(layer="nimplant", self.add_rect(layer="nimplant",
offset=offset, offset=offset,
width=width, width=width,
height=self.pmos1.active_height) height=self.pmos.active_height)
offset = (self.nmos1.active_position.scale(1,-1) offset = (self.nmos.active_position.scale(1,-1)
+ self.nmos_loc2.scale(1,0) + self.nmos_position2.scale(1,0)
+ self.nmos_loc1.scale(0,1) + self.nmos_position1.scale(0,1)
+ vector(0, self.nmos1.height - self.nmos1.active_height)) + vector(0, self.nmos.height - self.nmos.active_height))
self.add_rect(layer="active", self.add_rect(layer="active",
offset=offset, offset=offset,
width=self.active_width, width=self.active_width,
height=self.nmos1.active_height) height=self.nmos.active_height)
offset = offset + vector(self.nmos1.active_width,0) offset = offset + vector(self.nmos.active_width,0)
width = self.active_width - self.nmos1.active_width width = self.active_width - self.nmos.active_width
self.add_rect(layer="pimplant", self.add_rect(layer="pimplant",
offset=offset, offset=offset,
width=width, width=width,
height=self.nmos1.active_height) height=self.nmos.active_height)

View File

@ -31,7 +31,7 @@ class pin_layout:
def __eq__(self, other): def __eq__(self, other):
""" Check if these are the same pins for duplicate checks """ """ Check if these are the same pins for duplicate checks """
if isinstance(other, self.__class__): if isinstance(other, self.__class__):
return (self.layer==other.layer and self.rect == other.rect) return (self.name==other.name and self.layer==other.layer and self.rect == other.rect)
else: else:
return False return False

View File

@ -53,9 +53,9 @@ class pinv(design.design):
# These aren't for instantiating, but we use them to get the dimensions # These aren't for instantiating, but we use them to get the dimensions
self.nwell_contact = contact.contact(layer_stack=("active", "contact", "metal1"), self.nwell_contact = contact.contact(layer_stack=("active", "contact", "metal1"),
dimensions=(1, self.pmos.num_of_tacts)) dimensions=(1, self.pmos.num_contacts))
self.pwell_contact = contact.contact(layer_stack=("active", "contact", "metal1"), self.pwell_contact = contact.contact(layer_stack=("active", "contact", "metal1"),
dimensions=(1, self.nmos.num_of_tacts)) dimensions=(1, self.nmos.num_contacts))
self.extend_wells() self.extend_wells()
self.extend_active() self.extend_active()
@ -96,15 +96,15 @@ class pinv(design.design):
"""Intiializes a ptx object""" """Intiializes a ptx object"""
self.nmos = ptx(width=self.nmos_size, self.nmos = ptx(width=self.nmos_size,
mults=self.tx_mults, mults=self.tx_mults,
tx_type="nmos") tx_type="nmos",
self.nmos.connect_fingered_poly() connect_active=True,
self.nmos.connect_fingered_active() connect_poly=True)
self.add_mod(self.nmos) self.add_mod(self.nmos)
self.pmos = ptx(width=self.pmos_size, self.pmos = ptx(width=self.pmos_size,
mults=self.tx_mults, mults=self.tx_mults,
tx_type="pmos") tx_type="pmos",
self.pmos.connect_fingered_poly() connect_active=True,
self.pmos.connect_fingered_active() connect_poly=True)
self.add_mod(self.pmos) self.add_mod(self.pmos)
def setup_layout_constants(self): def setup_layout_constants(self):
@ -333,14 +333,14 @@ class pinv(design.design):
- self.nwell_contact.width, - self.nwell_contact.width,
self.pmos.active_contact_positions[0].y) self.pmos.active_contact_positions[0].y)
self.nwell_contact_position = self.pmos_position + well_contact_offset 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)) self.nwell_contact=self.add_contact(layer_stack,self.nwell_contact_position,(1,self.pmos.num_contacts))
well_contact_offset = vector(self.nmos.active_position.x well_contact_offset = vector(self.nmos.active_position.x
+ self.active_width + self.active_width
- self.pwell_contact.width, - self.pwell_contact.width,
self.nmos.active_contact_positions[0].y) self.nmos.active_contact_positions[0].y)
self.pwell_contact_position = self.nmos_position + well_contact_offset 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)) self.pwell_contact=self.add_contact(layer_stack,self.pwell_contact_position,(1,self.nmos.num_contacts))
def connect_well_contacts(self): def connect_well_contacts(self):
"""Connects the well taps to its respective power rails""" """Connects the well taps to its respective power rails"""

View File

@ -55,8 +55,8 @@ class precharge(design.design):
self.temp_pmos = ptx(width=self.beta * self.ptx_width, self.temp_pmos = ptx(width=self.beta * self.ptx_width,
mults=2, mults=2,
tx_type="pmos") tx_type="pmos")
self.temp_pmos.remove_source_connect() #self.temp_pmos.remove_source_connect()
self.temp_pmos.remove_drain_connect() #self.temp_pmos.remove_drain_connect()
def create_contacts(self): def create_contacts(self):
"""Initializes all required contacts/vias for this module""" """Initializes all required contacts/vias for this module"""

View File

@ -11,16 +11,25 @@ class ptx(design.design):
Creates a simple MOS transistor. poly_positions are the ll of the poly gate. active_contact_positions Creates a simple MOS transistor. poly_positions are the ll of the poly gate. active_contact_positions
is an array of the positions of the ll of active contacts (left to right) is an array of the positions of the ll of active contacts (left to right)
""" """
def __init__(self, width=drc["minwidth_tx"], mults=1, tx_type="nmos"): def __init__(self, width=drc["minwidth_tx"], mults=1, tx_type="nmos", connect_active=False, connect_poly=False, num_contacts=None):
name = "{0}_m{1}_w{2}".format(tx_type, mults, width) name = "{0}_m{1}_w{2}".format(tx_type, mults, width)
# remove periods for newer spice compatibility if connect_active:
name=re.sub('\.','_',name) name += "_a"
if connect_poly:
name += "_p"
if num_contacts:
name += "_c{}".format(num_contacts)
name=re.sub('\.','_',name) # remove periods for newer spice compatibility
design.design.__init__(self, name) design.design.__init__(self, name)
debug.info(3, "create ptx structure {0}".format(name)) debug.info(3, "create ptx structure {0}".format(name))
self.tx_type = tx_type self.tx_type = tx_type
self.mults = mults self.mults = mults
self.gate_width = width self.gate_width = width
self.connect_active = connect_active
self.connect_poly = connect_poly
self.num_contacts = num_contacts
self.add_pins() self.add_pins()
self.create_layout() self.create_layout()
@ -34,22 +43,26 @@ class ptx(design.design):
def create_layout(self): def create_layout(self):
self.setup_layout_constants() self.setup_layout_constants()
if self.num_contacts==None:
self.num_contacts=self.calculate_num_contacts()
# This is not actually instantiated but used for calculations # This is not actually instantiated but used for calculations
self.num_of_tacts = self.calculate_num_of_tacts()
self.active_contact = contact(layer_stack=("active", "contact", "metal1"), self.active_contact = contact(layer_stack=("active", "contact", "metal1"),
dimensions=(1, self.num_of_tacts)) dimensions=(1, self.num_contacts))
self.add_active() self.add_active()
self.add_implants() self.add_implants()
self.add_poly() self.add_poly()
self.add_active_contacts() self.add_active_contacts()
# rather than connect these, we let the user of the ptx
# decide to call them. # offset this BEFORE we add the active/poly connections
# self.determine_active_wire_location()
# self.connect_fingered_active()
# self.connect_fingered_poly()
self.offset_all_coordinates() self.offset_all_coordinates()
if self.connect_active:
self.connect_fingered_active()
if self.connect_poly:
self.connect_fingered_poly()
def offset_attributes(self, coordinate): def offset_attributes(self, coordinate):
"""Translates all stored 2d cartesian coordinates within the """Translates all stored 2d cartesian coordinates within the
attr dictionary""" attr dictionary"""
@ -127,6 +140,7 @@ class ptx(design.design):
self.well_height = max(self.gate_width + 2 * (drc["well_enclosure_active"]), self.well_height = max(self.gate_width + 2 * (drc["well_enclosure_active"]),
drc["minwidth_well"]) drc["minwidth_well"])
def connect_fingered_poly(self): def connect_fingered_poly(self):
poly_connect_length = self.poly_positions[-1].x + self.poly_width \ poly_connect_length = self.poly_positions[-1].x + self.poly_width \
- self.poly_positions[0].x - self.poly_positions[0].x
@ -138,6 +152,10 @@ class ptx(design.design):
height=drc["minwidth_poly"]) height=drc["minwidth_poly"])
self.poly_connect_index = len(self.objs) - 1 self.poly_connect_index = len(self.objs) - 1
# change the name so it is unique and specifies drain/srouce (p) routed
self.name = self.name + "_p"
def pairwise(self, iterable): def pairwise(self, iterable):
#"s -> (s0,s1), (s1,s2), (s2, s3), ..." #"s -> (s0,s1), (s1,s2), (s2, s3), ..."
from itertools import tee, izip from itertools import tee, izip
@ -258,14 +276,13 @@ class ptx(design.design):
width=xlength, width=xlength,
height=ylength) height=ylength)
def calculate_num_of_tacts(self): def calculate_num_contacts(self):
""" Calculates the possible number of source/drain contacts in a column """ """ Calculates the possible number of source/drain contacts in a column """
possible_length = self.active_height \ # Used for over-riding the contact dimensions
- 2 * drc["active_extend_contact"] possible_length = self.active_height - 2 * drc["active_extend_contact"]
y = 1 y = 1
while True: while True:
temp_length = (y * drc["minwidth_contact"]) \ temp_length = (y * drc["minwidth_contact"]) + ((y - 1) * drc["contact_to_contact"])
+ ((y - 1) * drc["contact_to_contact"])
if round(possible_length - temp_length, 6) < 0: if round(possible_length - temp_length, 6) < 0:
return y - 1 return y - 1
y += 1 y += 1
@ -279,7 +296,7 @@ class ptx(design.design):
offset = vector(contact_xoffset, contact_yoffset) offset = vector(contact_xoffset, contact_yoffset)
self.add_contact(layers=("active", "contact", "metal1"), self.add_contact(layers=("active", "contact", "metal1"),
offset=offset, offset=offset,
size=(1, self.num_of_tacts)) size=(1, self.num_contacts))
self.active_contact_positions.append(offset) self.active_contact_positions.append(offset)
# middle contact columns # middle contact columns
@ -291,7 +308,7 @@ class ptx(design.design):
offset = vector(contact_xoffset, contact_yoffset) offset = vector(contact_xoffset, contact_yoffset)
self.add_contact(layers=("active", "contact", "metal1"), self.add_contact(layers=("active", "contact", "metal1"),
offset=offset, offset=offset,
size=(1, self.num_of_tacts)) size=(1, self.num_contacts))
self.active_contact_positions.append(offset) self.active_contact_positions.append(offset)
@ -302,40 +319,42 @@ class ptx(design.design):
offset = vector(contact_xoffset, contact_yoffset) offset = vector(contact_xoffset, contact_yoffset)
self.add_contact(layers=("active", "contact", "metal1"), self.add_contact(layers=("active", "contact", "metal1"),
offset=offset, offset=offset,
size=(1, self.num_of_tacts)) size=(1, self.num_contacts))
self.active_contact_positions.append(offset) self.active_contact_positions.append(offset)
def remove_drain_connect(self): # def remove_drain_connect(self):
# FIXME: This is horrible exception handling! # debug.info(3,"Removing drain on {}".format(self.name))
try: # # FIXME: This is horrible exception handling!
del self.insts[self.drain_connect_index] # try:
del self.drain_connect_index # del self.insts[self.drain_connect_index]
self.offset_all_coordinates() # del self.drain_connect_index
# change the name so it is unique # self.offset_all_coordinates()
self.name = self.name + "_rd" # # change the name so it is unique
except: # self.name = self.name + "_rd"
pass # except:
# pass
def remove_source_connect(self): # def remove_source_connect(self):
# FIXME: This is horrible exception handling! # debug.info(3,"Removing source on {}".format(self.name))
try: # # FIXME: This is horrible exception handling!
del self.insts[self.source_connect_index] # try:
del self.source_connect_index # del self.insts[self.source_connect_index]
if isinstance(self.drain_connect_index, int): # del self.source_connect_index
self.drain_connect_index -= 1 # if isinstance(self.drain_connect_index, int):
self.offset_all_coordinates() # self.drain_connect_index -= 1
# change the name so it is unique # self.offset_all_coordinates()
self.name = self.name + "_rs" # # change the name so it is unique
except: # self.name = self.name + "_rs"
pass # except:
# pass
def remove_poly_connect(self): # def remove_poly_connect(self):
# FIXME: This is horrible exception handling! # # FIXME: This is horrible exception handling!
try: # try:
del self.objs[self.poly_connect_index] # del self.objs[self.poly_connect_index]
self.offset_all_coordinates() # self.offset_all_coordinates()
# change the name so it is unique # # change the name so it is unique
self.name = self.name + "_rp" # self.name = self.name + "_rp"
except: # except:
pass # pass

View File

@ -72,7 +72,7 @@ class replica_bitline(design.design):
self.rbl_offset = self.bitcell_offset self.rbl_offset = self.bitcell_offset
self.height = self.rbl_offset.y + self.rbl.height self.height = self.rbl_offset.y + self.rbl.height + self.m2_pitch
self.width = self.rbl_offset.x + self.bitcell.width self.width = self.rbl_offset.x + self.bitcell.width
@ -256,7 +256,7 @@ class replica_bitline(design.design):
self.add_rect(layer="metal2", self.add_rect(layer="metal2",
offset=gnd_start, offset=gnd_start,
width=drc["minwidth_metal2"], width=drc["minwidth_metal2"],
height=self.rbl.height+self.bitcell.height+self.inv.width) height=self.rbl.height+self.bitcell.height+self.inv.width+self.m2_pitch)
self.add_layout_pin(text="gnd", self.add_layout_pin(text="gnd",
layer="metal1", layer="metal1",
offset=gnd_start.scale(1,0), offset=gnd_start.scale(1,0),
@ -296,8 +296,8 @@ class replica_bitline(design.design):
gnd_pin = pin gnd_pin = pin
gnd_end = gnd_pin.uc() gnd_end = gnd_pin.uc()
# Add a couple midpoints so that the wire will drop a via and then route horizontal on M1 # Add a couple midpoints so that the wire will drop a via and then route horizontal on M1
gnd_mid1 = gnd_start + vector(0,2*drc["metal2_to_metal2"]) gnd_mid1 = gnd_start + vector(0,self.m2_pitch)
gnd_mid2 = gnd_end + vector(0,2*drc["metal2_to_metal2"]) gnd_mid2 = gnd_end + vector(0,self.m2_pitch)
self.add_wire(("metal1","via1","metal2"), [gnd_start, gnd_mid1, gnd_mid2, gnd_end]) self.add_wire(("metal1","via1","metal2"), [gnd_start, gnd_mid1, gnd_mid2, gnd_end])

View File

@ -11,7 +11,7 @@ class sense_amp(design.design):
Sense amplifier to read a pair of bit-lines. Sense amplifier to read a pair of bit-lines.
""" """
pin_names = ["BL", "BR", "Dout", "SCLK", "vdd", "gnd"] pin_names = ["bl", "br", "dout", "en", "vdd", "gnd"]
(width,height) = utils.get_libcell_size("sense_amp", GDS["unit"], layer["boundary"]) (width,height) = utils.get_libcell_size("sense_amp", GDS["unit"], layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "sense_amp", GDS["unit"], layer["boundary"]) pin_map = utils.get_libcell_pins(pin_names, "sense_amp", GDS["unit"], layer["boundary"])

View File

@ -51,9 +51,9 @@ class sense_amp_array(design.design):
def add_sense_amp(self): def add_sense_amp(self):
bl_pin = self.amp.get_pin("BL") bl_pin = self.amp.get_pin("bl")
br_pin = self.amp.get_pin("BR") br_pin = self.amp.get_pin("br")
dout_pin = self.amp.get_pin("Dout") dout_pin = self.amp.get_pin("dout")
for i in range(0,self.row_size,self.words_per_row): for i in range(0,self.row_size,self.words_per_row):
@ -83,7 +83,7 @@ class sense_amp_array(design.design):
height=br_pin.height()) height=br_pin.height())
self.add_layout_pin(text="data[{0}]".format(i/self.words_per_row), self.add_layout_pin(text="data[{0}]".format(i/self.words_per_row),
layer="metal2", layer="metal3",
offset=dout_offset, offset=dout_offset,
width=dout_pin.width(), width=dout_pin.width(),
height=dout_pin.height()) height=dout_pin.height())
@ -110,7 +110,7 @@ class sense_amp_array(design.design):
height=drc["minwidth_metal1"]) height=drc["minwidth_metal1"])
# add sclk rail across entire array # add sclk rail across entire array
sclk_offset = self.amp.get_pin("SCLK").ll().scale(0,1) sclk_offset = self.amp.get_pin("en").ll().scale(0,1)
self.add_layout_pin(text="en", self.add_layout_pin(text="en",
layer="metal1", layer="metal1",
offset=sclk_offset, offset=sclk_offset,

View File

@ -29,6 +29,10 @@ class sram(design.design):
self.mod_bitcell = getattr(c, OPTS.config.bitcell) self.mod_bitcell = getattr(c, OPTS.config.bitcell)
self.bitcell = self.mod_bitcell() self.bitcell = self.mod_bitcell()
c = reload(__import__(OPTS.config.ms_flop))
self.mod_ms_flop = getattr(c, OPTS.config.ms_flop)
self.ms_flop = self.mod_ms_flop()
# reset the static duplicate name checker for unit tests # reset the static duplicate name checker for unit tests
# in case we create more than one SRAM # in case we create more than one SRAM
@ -46,13 +50,21 @@ class sram(design.design):
# These aren't for instantiating, but we use them to get the dimensions # These aren't for instantiating, but we use them to get the dimensions
self.poly_contact = contact(layer_stack=("poly", "contact", "metal1")) self.poly_contact = contact(layer_stack=("poly", "contact", "metal1"))
self.poly_contact_offset = vector(0.5*self.poly_contact.width,0.5*self.poly_contact.height)
self.m1m2_via = contact(layer_stack=("metal1", "via1", "metal2")) self.m1m2_via = contact(layer_stack=("metal1", "via1", "metal2"))
self.m2m3_via = contact(layer_stack=("metal2", "via2", "metal3")) self.m2m3_via = contact(layer_stack=("metal2", "via2", "metal3"))
# M1/M2 routing pitch is based on contacted pitch # For different layer width vias
self.m2m3_offset_fix = vector(0,0.5*(drc["minwidth_metal3"]-drc["minwidth_metal2"]))
self.m1_width = drc["minwidth_metal1"]
self.m2_width = drc["minwidth_metal2"]
self.m3_width = drc["minwidth_metal3"]
# M1/M2 routing pitch is based on contacted pitch of the biggest layer
self.m1_pitch = max(self.m1m2_via.width,self.m1m2_via.height) + max(drc["metal1_to_metal1"],drc["metal2_to_metal2"]) self.m1_pitch = max(self.m1m2_via.width,self.m1m2_via.height) + max(drc["metal1_to_metal1"],drc["metal2_to_metal2"])
self.m2_pitch = max(self.m2m3_via.width,self.m2m3_via.height) + max(drc["metal2_to_metal2"],drc["metal3_to_metal3"]) self.m2_pitch = max(self.m2m3_via.width,self.m2m3_via.height) + max(drc["metal2_to_metal2"],drc["metal3_to_metal3"])
self.m3_pitch = max(self.m2m3_via.width,self.m2m3_via.height) + max(drc["metal2_to_metal2"],drc["metal3_to_metal3"])
self.control_size = 6 self.control_size = 6
self.bank_to_bus_distance = 5*drc["minwidth_metal3"] self.bank_to_bus_distance = 5*drc["minwidth_metal3"]
@ -60,6 +72,10 @@ class sram(design.design):
self.compute_sizes() self.compute_sizes()
self.add_pins() self.add_pins()
self.create_layout() self.create_layout()
# Can remove the following, but it helps for debug!
self.add_lvs_correspondence_points()
self.DRC_LVS() self.DRC_LVS()
def compute_sizes(self): def compute_sizes(self):
@ -126,7 +142,11 @@ class sram(design.design):
self.add_pin("DATA[{0}]".format(i)) self.add_pin("DATA[{0}]".format(i))
for i in range(self.addr_size): for i in range(self.addr_size):
self.add_pin("ADDR[{0}]".format(i)) self.add_pin("ADDR[{0}]".format(i))
for pin in ["CSb","WEb","OEb","clk","vdd","gnd"]:
self.control_logic_inputs=["CSb", "WEb", "OEb", "clk"]
self.control_logic_outputs=["s_en", "w_en", "tri_en", "tri_en_bar", "clk_bar", "clk_buf"]
for pin in self.control_logic_inputs+["vdd","gnd"]:
self.add_pin(pin) self.add_pin(pin)
def create_layout(self): def create_layout(self):
@ -138,32 +158,358 @@ class sram(design.design):
self.add_single_bank_modules() self.add_single_bank_modules()
self.add_single_bank_pins() self.add_single_bank_pins()
self.route_single_bank() self.route_single_bank()
elif self.num_banks == 2:
self.add_two_bank_modules()
self.route_two_banks()
else: else:
self.add_multi_bank_modules() self.add_multi_bank_modules()
self.route_top_banks() self.add_multi_bank_pins()
return
self.route_2or4_banks()
if self.num_banks > 2: if self.num_banks > 2:
self.route_bottom_banks() self.route_4_banks()
self.route_bank_and_control()
self.route_supplies()
def add_two_bank_modules(self):
""" Adds the modules and the buses to the top level """
########################
# First, compute all of the offsets
########################
self.num_vertical_line = self.bank_addr_size + self.control_size + self.num_banks + 1
self.num_horizontal_line = self.word_size
self.vertical_bus_width = self.m2_pitch*self.num_vertical_line
self.data_bus_height = self.m3_pitch*self.num_horizontal_line
self.control_bus_height = self.m1_pitch*(self.control_size+2)
self.supply_bus_height = self.m1_pitch*2 # 2 for vdd/gnd placed with control bus
# Sanity check to ensure we can fit the control logic above a single bank (0.9 is a hack really)
debug.check(self.bank.width + self.vertical_bus_width > 0.9*self.control_logic.width, "Bank is too small compared to control logic.")
# This depends on the bus widths, but nothing else
self.add_top_banks()
self.vertical_bus_height = self.bank.height + self.bank_to_bus_distance + self.data_bus_height + self.control_bus_height
self.vertical_bus_offset = vector(self.bank.width + self.bank_to_bus_distance, 2*self.power_rail_pitch)
self.data_bus_width = 2*(self.bank.width + self.bank_to_bus_distance) + self.vertical_bus_width
self.data_bus_offset = vector(0, 2*self.power_rail_pitch + self.bank.height + self.bank_to_bus_distance)
self.supply_bus_width = self.data_bus_width
self.supply_bus_offset = vector(0, self.data_bus_offset.y + self.data_bus_height)
self.control_bus_width = self.bank.width + self.bank_to_bus_distance + self.vertical_bus_width
self.control_bus_offset = vector(0, self.supply_bus_offset.y + self.supply_bus_height)
self.bank_sel_bus_offset = self.vertical_bus_offset + vector(self.m2_pitch*self.control_size,0)
# The address bus extends down through the power rails, but control and bank_sel bus don't
self.addr_bus_height = self.vertical_bus_height + 2*self.power_rail_pitch
self.addr_bus_offset = self.bank_sel_bus_offset.scale(1,0) + vector(self.m2_pitch*self.num_banks,0)
# Control is placed at the top above the control bus and everything
self.control_logic_position = vector(0, self.control_bus_offset.y + self.control_bus_height + self.m1_pitch)
# Bank select flops get put to the right of control logic above bank1 and the buses
# Leave a pitch to get the vdd rails up to M2
self.msb_address_position = vector(max(self.bank_inst[1].lx(),self.control_logic.width),
self.supply_bus_offset.y+self.supply_bus_height + 2*self.m1_pitch + self.msb_address.width)
########################
# Second, place the buses
########################
# Vertical bus
# The order of the control signals on the control bus:
self.control_bus_names = ["clk_buf", "tri_en_bar", "tri_en", "clk_bar", "w_en", "s_en"]
self.vert_control_bus_positions = self.create_bus(layer="metal2",
pitch=self.m2_pitch,
offset=self.vertical_bus_offset,
names=self.control_bus_names,
length=self.vertical_bus_height,
vertical=True)
self.addr_bus_names=[]
for i in range(self.addr_size):
self.addr_bus_names.append("ADDR[{}]".format(i))
self.vert_control_bus_positions.update(self.create_bus(layer="metal2",
pitch=self.m2_pitch,
offset=self.addr_bus_offset,
names=self.addr_bus_names,
length=self.addr_bus_height,
vertical=True,
make_pins=True))
self.bank_sel_bus_names = ["bank_sel[0]","bank_sel[1]"]
self.vert_control_bus_positions.update(self.create_bus(layer="metal2",
pitch=self.m2_pitch,
offset=self.bank_sel_bus_offset,
names=self.bank_sel_bus_names,
length=self.vertical_bus_height,
vertical=True))
# Horizontal data bus
self.data_bus_names = []
for i in range(0, self.word_size):
self.data_bus_names.append("DATA[{}]".format(i))
self.data_bus_positions = self.create_bus(layer="metal3",
pitch=self.m3_pitch,
offset=self.data_bus_offset,
names=self.data_bus_names,
length=self.data_bus_width,
vertical=False,
make_pins=True)
# Horizontal control logic bus
# vdd/gnd in bus go along whole SRAM
# FIXME: Fatten these wires?
self.horz_control_bus_positions = self.create_bus(layer="metal1",
pitch=self.m1_pitch,
offset=self.supply_bus_offset,
names=["vdd", "gnd"],
length=self.supply_bus_width,
vertical=False)
self.horz_control_bus_positions.update(self.create_bus(layer="metal1",
pitch=self.m1_pitch,
offset=self.control_bus_offset,
names=self.control_bus_names,
length=self.control_bus_width,
vertical=False))
########################
# Third, place the other logic (banks are done first to anchor the design)
########################
self.add_control_logic(position=self.control_logic_position, rotate=0)
self.msb_address_inst = self.add_inst(name="msb_address",
mod=self.msb_address,
offset=self.msb_address_position,
rotate=270)
self.msb_bank_sel_addr = "ADDR[{}]".format(self.addr_size-1)
self.connect_inst([self.msb_bank_sel_addr,"bank_sel[1]","bank_sel[0]","clk_buf", "vdd", "gnd"])
self.width= self.data_bus_width
self.height = self.control_logic_inst.uy()
def route_two_banks(self):
""" Route all of the signals for the two bank SRAM. """
# create the input control pins
for n in self.control_logic_inputs:
self.copy_layout_pin(self.control_logic_inst, n.lower(), n)
# connect the control logic to the control bus
for n in self.control_logic_outputs + ["vdd", "gnd"]:
pins = self.control_logic_inst.get_pins(n)
for pin in pins:
if pin.layer=="metal2":
pin_pos = pin.bc()
break
rail_pos = vector(pin_pos.x,self.horz_control_bus_positions[n].y)
self.add_path("metal2",[pin_pos,rail_pos])
self.add_center_via(("metal1","via1","metal2"),rail_pos)
# connect the control logic cross bar
for n in self.control_logic_outputs:
cross_pos = vector(self.vert_control_bus_positions[n].x,self.horz_control_bus_positions[n].y)
self.add_center_via(("metal1","via1","metal2"),cross_pos)
# connect the horizontal control bus to the vertical bus
# connect the data output to the data bus
for n in self.data_bus_names:
for i in range(2):
pin_pos = self.bank_inst[i].get_pin(n).uc()
rail_pos = vector(pin_pos.x,self.data_bus_positions[n].y)
self.add_path("metal2",[pin_pos,rail_pos])
self.add_center_via(("metal2","via2","metal3"),rail_pos)
self.route_single_msb_address()
# connect the banks to the vertical address bus
# connect the banks to the vertical control bus
for n in self.addr_bus_names + self.control_bus_names:
# Skip these from the horizontal bus
if n in ["vdd", "gnd"]: continue
# This will be the bank select, so skip it
if n == self.msb_bank_sel_addr: continue
pin0_pos = self.bank_inst[0].get_pin(n).rc()
pin1_pos = self.bank_inst[1].get_pin(n).lc()
rail_pos = vector(self.vert_control_bus_positions[n].x,pin0_pos.y)
self.add_path("metal3",[pin0_pos,pin1_pos])
self.add_center_via(("metal2","via2","metal3"),rail_pos)
# connect the bank select signals to the vertical bus
for i in range(2):
pin = self.bank_inst[i].get_pin("bank_sel")
pin_pos = pin.rc() if i==0 else pin.lc()
rail_pos = vector(self.vert_control_bus_positions["bank_sel[{}]".format(i)].x,pin_pos.y)
self.add_path("metal3",[pin_pos,rail_pos])
self.add_center_via(("metal2","via2","metal3"),rail_pos)
self.route_two_bank_supplies()
def route_two_bank_supplies(self):
""" Finish routing the power supplies for a 2-bank SRAM """
# control logic supplies done with control signals
self.route_major_supply_rails()
def route_single_msb_address(self):
""" Route one MSB address bit for 2-bank SRAM """
# connect the bank MSB flop supplies
vdd_pins = self.msb_address_inst.get_pins("vdd")
for vdd_pin in vdd_pins:
if vdd_pin.layer != "metal1": continue
vdd_pos = vdd_pin.bc()
down_pos = vdd_pos - vector(0,self.m1_pitch)
rail_pos = vector(vdd_pos.x,self.horz_control_bus_positions["vdd"].y)
self.add_path("metal1",[vdd_pos,down_pos])
self.add_center_via(("metal1","via1","metal2"),down_pos,rotate=90)
self.add_path("metal2",[down_pos,rail_pos])
self.add_center_via(("metal1","via1","metal2"),rail_pos)
gnd_pins = self.msb_address_inst.get_pins("gnd")
# Only add the ground connection to the lowest metal2 rail in the flop array
# FIXME: SCMOS doesn't have a vertical rail in the cell, or we could use those
lowest_y = None
for gnd_pin in gnd_pins:
if gnd_pin.layer != "metal2": continue
if lowest_y==None or gnd_pin.by()<lowest_y:
lowest_y=gnd_pin.by()
gnd_pos = gnd_pin.ur()
rail_pos = vector(gnd_pos.x,self.horz_control_bus_positions["gnd"].y)
self.add_path("metal2",[gnd_pos,rail_pos])
self.add_center_via(("metal1","via1","metal2"),rail_pos)
# connect the MSB flop to the address input bus
msb_pins = self.msb_address_inst.get_pins("din[0]")
for msb_pin in msb_pins:
if msb_pin.layer == "metal3":
msb_pin_pos = msb_pin.lc()
break
rail_pos = vector(self.vert_control_bus_positions[self.msb_bank_sel_addr].x,msb_pin_pos.y)
self.add_path("metal3",[msb_pin_pos,rail_pos])
self.add_center_via(("metal2","via2","metal3"),rail_pos)
# Connect the output bar to select 0
msb_out_pin = self.msb_address_inst.get_pin("dout_bar[0]")
msb_out_pos = msb_out_pin.rc()
out_extend_right_pos = msb_out_pos + vector(self.m2_pitch,0)
out_extend_up_pos = out_extend_right_pos + vector(0,self.m2_width)
rail_pos = vector(self.vert_control_bus_positions["bank_sel[0]"].x,out_extend_up_pos.y)
self.add_path("metal2",[msb_out_pos,out_extend_right_pos,out_extend_up_pos])
self.add_wire(("metal3","via2","metal2"),[out_extend_right_pos,out_extend_up_pos,rail_pos])
self.add_center_via(("metal2","via2","metal3"),rail_pos)
# Connect the output to select 1
msb_out_pin = self.msb_address_inst.get_pin("dout[0]")
msb_out_pos = msb_out_pin.rc()
out_extend_right_pos = msb_out_pos + vector(self.m2_pitch,0)
out_extend_down_pos = out_extend_right_pos - vector(0,2*self.m1_pitch)
rail_pos = vector(self.vert_control_bus_positions["bank_sel[1]"].x,out_extend_down_pos.y)
self.add_path("metal2",[msb_out_pos,out_extend_right_pos,out_extend_down_pos])
self.add_wire(("metal3","via2","metal2"),[out_extend_right_pos,out_extend_down_pos,rail_pos])
self.add_center_via(("metal2","via2","metal3"),rail_pos)
# Connect clk
clk_pin = self.msb_address_inst.get_pin("clk")
clk_pos = clk_pin.bc()
rail_pos = self.horz_control_bus_positions["clk_buf"]
bend_pos = vector(clk_pos.x,self.horz_control_bus_positions["clk_buf"].y)
self.add_path("metal1",[clk_pos,bend_pos,rail_pos])
def route_major_supply_rails(self):
""" Create rails at bottom. Connect veritcal rails to top and bottom. """
self.add_layout_pin(text="gnd",
layer="metal3",
offset=vector(0,0),
height=self.power_rail_width,
width=self.width)
self.add_layout_pin(text="vdd",
layer="metal1",
offset=vector(0,self.power_rail_pitch),
height=self.power_rail_width,
width=self.width)
# route bank vertical rails to top and bottom
for i in range(2):
vdd_pins = self.bank_inst[i].get_pins("vdd")
for vdd_pin in vdd_pins:
vdd_pos = vdd_pin.ul()
# Route to top
self.add_rect(layer="metal1",
offset=vdd_pos,
height=self.horz_control_bus_positions["vdd"].y-vdd_pos.y+0.5*self.m1_width,
width=vdd_pin.width())
# Route to bottom
self.add_rect(layer="metal1",
offset=vector(vdd_pos.x,self.power_rail_pitch),
height=self.bank_inst[0].by(),
width=vdd_pin.width())
gnd_pins = self.bank_inst[i].get_pins("gnd")
for gnd_pin in gnd_pins:
# Route to top
gnd_pos = gnd_pin.ul()
self.add_rect(layer="metal2",
offset=gnd_pos,
height=self.horz_control_bus_positions["gnd"].y-gnd_pos.y+0.5*self.m1_width,
width=gnd_pin.width())
# Add two vias for right now, should be right size power via
right_rail_pos = vector(gnd_pin.ur().x,self.horz_control_bus_positions["gnd"].y)
self.add_via(layers=("metal1","via1","metal2"),
offset=right_rail_pos - vector(0,0.5*self.m1_width),
rotate=90,
size=[1,3])
# Route to bottom
self.add_rect(layer="metal2",
offset=vector(gnd_pos.x,0),
height=self.bank_inst[0].by(),
width=gnd_pin.width())
# Add two vias for right now, should be right size power via
right_rail_pos = vector(gnd_pin.lr().x,0)
self.add_via(layers=("metal2","via2","metal3"),
offset=right_rail_pos,
rotate=90,
size=[2,3])
# connect the vertical rails along bottom of SRAM
pass
def create_multi_bank_modules(self): def create_multi_bank_modules(self):
""" Add the multibank address flops and bank decoder """ """ Create the multibank address flops and bank decoder """
self.msf_msb_address = self.mod_ms_flop_array(name="msf_msb_address", self.msb_address = self.mod_ms_flop_array(name="msb_address",
columns=self.num_banks/2, columns=1,
word_size=self.num_banks/2) word_size=self.num_banks/2)
self.add_mod(self.msf_msb_address) self.add_mod(self.msb_address)
self.msb_decoder = self.bank.decoder.pre2_4 if self.num_banks>2:
self.add_mod(self.msb_decoder) self.msb_decoder = self.bank.decoder.pre2_4
self.add_mod(self.msb_decoder)
def create_modules(self): def create_modules(self):
""" Create all the modules that will be used """ """ Create all the modules that will be used """
# Create the control logic module # Create the control logic module
self.control = self.mod_control_logic(num_rows=self.num_rows) self.control_logic = self.mod_control_logic(num_rows=self.num_rows)
self.add_mod(self.control) self.add_mod(self.control_logic)
# Create the bank module (up to four are instantiated) # Create the bank module (up to four are instantiated)
self.bank = bank(word_size=self.word_size, self.bank = bank(word_size=self.word_size,
@ -175,16 +521,17 @@ class sram(design.design):
# Conditionally create the # Conditionally create the
if(self.num_banks > 1): if(self.num_banks > 1):
self.create_multibank_modules() self.create_multi_bank_modules()
self.bank_count = 0 self.bank_count = 0
self.power_rail_width = self.bank.vdd_rail_width self.power_rail_width = self.bank.vdd_rail_width
self.sram_power_rail_gap = 4*self.bank.vdd_rail_width # Leave some extra space for the pitch
self.power_rail_pitch = self.bank.vdd_rail_width + 2*drc["metal3_to_metal3"]
def add_bank(self, position, x_flip, y_flip): def add_bank(self, bank_num, position, x_flip, y_flip):
""" Place a bank at the given position with orientations """ """ Place a bank at the given position with orientations """
# x_flip == 1 --> no flip in x_axis # x_flip == 1 --> no flip in x_axis
@ -208,7 +555,7 @@ class sram(design.design):
else: else:
bank_mirror = "R0" bank_mirror = "R0"
bank_inst=self.add_inst(name="bank{0}".format(self.bank_count), bank_inst=self.add_inst(name="bank{0}".format(bank_num),
mod=self.bank, mod=self.bank,
offset=position, offset=position,
mirror=bank_mirror, mirror=bank_mirror,
@ -220,66 +567,71 @@ class sram(design.design):
for i in range(self.bank_addr_size): for i in range(self.bank_addr_size):
temp.append("ADDR[{0}]".format(i)) temp.append("ADDR[{0}]".format(i))
if(self.num_banks > 1): if(self.num_banks > 1):
temp.append("bank_sel[{0}]".format(self.bank_count)) temp.append("bank_sel[{0}]".format(bank_num))
temp.extend(["s_en", "w_en", "tri_en_bar", "tri_en", temp.extend(["s_en", "w_en", "tri_en_bar", "tri_en",
"clk_bar","clk_buf" , "vdd", "gnd"]) "clk_bar","clk_buf" , "vdd", "gnd"])
self.connect_inst(temp) self.connect_inst(temp)
self.bank_count = self.bank_count + 1
return bank_inst return bank_inst
# FIXME: This should be in geometry.py or it's own class since it is # FIXME: This should be in geometry.py or it's own class since it is
# reusable # reusable
def create_bus(self, layer, offset, bits, height, rotate): def create_bus(self, layer, pitch, offset, names, length, vertical=False, make_pins=False):
""" Create a bus and place it according to rotate and """ Create a horizontal or vertical bus. It can be either just rectangles, or actual
return an array of line positions """ layout pins. It returns an map of line center line positions indexed by name. """
minwidth = "minwidth_{0}".format(layer) # half minwidth so we can return the center line offsets
m2m = "{0}_to_{0}".format(layer) half_minwidth = 0.5*drc["minwidth_{}".format(layer)]
line_width = drc[minwidth]
line_gap = 2*drc[m2m]
line_positions = [] line_positions = {}
bus_width = bits*(line_width + line_gap) if vertical:
if(rotate == 0): for i in range(len(names)):
for i in range(bits): line_offset = offset + vector(i*pitch,0)
line_offset = offset + vector(i*(line_width + line_gap),0) if make_pins:
self.add_rect(layer=layer, self.add_layout_pin(text=names[i],
offset=line_offset, layer=layer,
width=line_width, offset=line_offset,
height=height) height=length)
line_positions.append(line_offset) else:
elif(rotate == 270): self.add_rect(layer=layer,
for i in range(bits): offset=line_offset,
line_offset = offset - vector(0, (i+1)*line_width + i*line_gap) height=length)
self.add_rect(layer=layer, line_positions[names[i]]=line_offset+vector(half_minwidth,0)
offset=line_offset,
width=height,
height=line_width)
line_positions.append(line_offset)
else: else:
debug.error("Unimplemented rotation for create_bus") for i in range(len(names)):
line_offset = offset + vector(0,i*pitch + half_minwidth)
if make_pins:
self.add_layout_pin(text=names[i],
layer=layer,
offset=line_offset,
width=length)
else:
self.add_rect(layer=layer,
offset=line_offset,
width=length)
line_positions[names[i]]=line_offset+vector(0,half_minwidth)
return line_positions return line_positions
def calculate_bus_width(self, layer, bits):
""" Calculate the bus width """
minwidth = "minwidth_{0}".format(layer)
m2m = "{0}_to_{0}".format(layer)
line_width = drc[minwidth]
line_gap = 2*drc[m2m]
return bits*(line_width + line_gap) - line_gap
def add_control_logic(self, position, rotate): def add_control_logic(self, position, rotate):
""" Add and place control logic """ """ Add and place control logic """
self.control_logic_inst=self.add_inst(name="control", self.control_logic_inst=self.add_inst(name="control",
mod=self.control, mod=self.control_logic,
offset=position, offset=position,
rotate=rotate) rotate=rotate)
temp = ["CSb", "WEb", "OEb", "clk", "s_en", "w_en", "tri_en", self.connect_inst(self.control_logic_inputs + self.control_logic_outputs + ["vdd", "gnd"])
"tri_en_bar", "clk_bar", "clk_buf", "vdd", "gnd"]
self.connect_inst(temp)
def add_lvs_correspondence_points(self):
for n in self.control_bus_names:
self.add_label(text=n,
layer="metal2",
offset=self.vert_control_bus_positions[n])
for n in self.bank_sel_bus_names:
self.add_label(text=n,
layer="metal2",
offset=self.vert_control_bus_positions[n])
def add_single_bank_modules(self): def add_single_bank_modules(self):
""" """
@ -288,7 +640,7 @@ class sram(design.design):
""" """
# No orientation or offset # No orientation or offset
self.bank_inst = self.add_bank([0, 0], 1, 1) self.bank_inst = self.add_bank(0, [0, 0], 1, 1)
# Control logic is placed to the left of the blank even with the # Control logic is placed to the left of the blank even with the
# decoder bottom. A small gap is in the x-dimension. # decoder bottom. A small gap is in the x-dimension.
@ -298,7 +650,7 @@ class sram(design.design):
self.add_control_logic(position=pos, self.add_control_logic(position=pos,
rotate=90) rotate=90)
self.width = self.bank.width + self.control.height + control_gap self.width = self.bank.width + self.control_logic.height + control_gap
self.height = self.bank.height self.height = self.bank.height
def add_single_bank_pins(self): def add_single_bank_pins(self):
@ -319,161 +671,29 @@ class sram(design.design):
self.copy_layout_pin(self.bank_inst, "gnd") self.copy_layout_pin(self.bank_inst, "gnd")
def add_multi_bank_modules(self):
""" This creates either a 2 or 4 bank SRAM with control logic
and bank selection logic."""
self.bank_h = self.bank.height
self.bank_w = self.bank.width
self.num_vertical_line = self.bank_addr_size + self.control_size \
+ self.num_banks + self.num_banks/2
self.num_horizontal_line = self.word_size
self.vertical_bus_width = self.calculate_bus_width("metal2", self.num_vertical_line)
self.horizontal_bus_width = self.calculate_bus_width("metal3", self.num_horizontal_line)
self.vertical_bus_height = (self.num_banks/2)*(self.bank_h + self.bank_to_bus_distance) \
+ self.horizontal_bus_width
self.horizontal_bus_height = (2 * (self.bank_w + self.bank_to_bus_distance)
+ self.vertical_bus_width)
self.vertical_bus_offset = vector(self.bank_w + self.bank_to_bus_distance,
self.sram_power_rail_gap)
self.horizontal_bus_offset = vector(0,
self.bank_h + self.bank_to_bus_distance
+ self.sram_power_rail_gap
+ self.horizontal_bus_width)
# Vertical bus
self.vertical_line_positions = self.create_bus(layer="metal2",
offset=self.vertical_bus_offset,
bits=self.num_vertical_line,
height=self.vertical_bus_height,
rotate=0)
# Horizontal bus
self.horizontal_line_positions = self.create_bus(layer="metal3",
offset=self.horizontal_bus_offset,
bits=self.num_horizontal_line,
height=self.horizontal_bus_height,
rotate=270)
for i in range(0, self.word_size):
self.add_label(text="DATA[{0}]".format(i),
layer="metal3",
offset=self.horizontal_line_positions[i])
self.width = 2*(self.bank_w + self.bank_to_bus_distance) + self.vertical_bus_width
self.height = (self.num_banks/2)*(self.bank_h + self.bank_to_bus_distance) \
+ self.horizontal_bus_width + self.sram_power_rail_gap
# Add Control logic for Bank = 2 and Bank =4
control_bus_width = self.calculate_bus_width("metal1",
self.control_size + 2)
control_bus_height = (self.vertical_line_positions[self.control_size - 1].x
+ drc["minwidth_metal2"])
control_bus_offset = vector(0, self.height + control_bus_width
+ 4*drc["minwidth_metal3"])
self.control_bus_line_positions = self.create_bus(layer="metal1",
offset=control_bus_offset,
bits=self.control_size + 2,
height=control_bus_height,
rotate=270)
if (self.num_banks == 2):
self.control_position = vector(0, control_bus_offset.y
+ self.ms_flop_chars["width"])
self.add_control_logic(self.control_position, 0)
self.CSb_position = self.control_position + self.control.CSb_position
self.OEb_position = self.control_position + self.control.OEb_position
self.WEb_position = self.control_position + self.control.WEb_position
self.clk_position = self.control_position + self.control.clk_position
# Max point
self.max_point = self.control_position.y + self.ms_flop_chars["width"]
# MSB address
x_off = (self.bank_w + self.vertical_bus_width
+ 2 * self.bank_to_bus_distance
+ self.power_rail_width
+ 4 * drc["minwidth_metal3"])
y_off = self.height + 2 * self.ms_flop_chars["width"] + 4 * drc["minwidth_metal3"]
self.msf_msb_address_position = vector(x_off, y_off)
self.add_inst(name="msf_msb_address",
mod=self.msf_msb_address,
offset=self.msf_msb_address_position,
mirror="RO",
rotate=270)
temp = []
for i in range(self.num_banks/2):
temp.append("ADDR[{0}]".format(self.bank.addr_size + i))
if(self.num_banks == 4):
for i in range(self.num_banks/2):
temp.append("msb{0}".format(i))
temp.append("msb{0}_bar".format(i))
else:
temp.extend(["bank_sel[1]", "bank_sel[0]"])
temp.extend(["clk_buf", "vdd", "gnd"])
self.connect_inst(temp)
self.add_top_banks()
if self.num_banks == 4:
self.add_bottom_banks()
# Extension of Vertical Rail
self.create_bus(layer="metal2",
offset=[self.vertical_bus_offset.x,
self.height],
bits=self.num_vertical_line,
height=self.max_point - self.height,
rotate=0)
# Add ADDRESS labels to vertical line
for i in range(self.addr_size - int(math.log(self.num_banks, 2))):
index = self.control_size + int(math.log(self.num_banks, 2)) + i
self.add_label(text="ADDR[{}]".format(i),
layer="metal2",
offset=[self.vertical_line_positions[index].x,
self.max_point])
for i in range(int(math.log(self.num_banks, 2))):
self.add_label(text="ADDR[{}]".format(self.addr_size - i - 1),
layer="metal2",
offset=[self.vertical_line_positions[self.control_size + i].x,
self.max_point])
def add_top_banks(self): def add_top_banks(self):
# Placement of bank 0 # Placement of bank 0
self.bank_position_0 = vector(self.bank_w, self.bank_position_0 = vector(self.bank.width,
self.bank_h + self.sram_power_rail_gap) self.bank.height + 2*self.power_rail_pitch)
self.add_bank(self.bank_position_0, -1, -1) self.bank_inst=[self.add_bank(0,self.bank_position_0, -1, -1)]
# Placement of bank 1 # Placement of bank 1
x_off = self.bank_w + self.vertical_bus_width + 2*self.bank_to_bus_distance x_off = self.bank.width + self.vertical_bus_width + 2*self.bank_to_bus_distance
self.bank_position_1 = vector(x_off, self.bank_position_0.y) self.bank_position_1 = vector(x_off, self.bank_position_0.y)
self.add_bank(self.bank_position_1, -1, 1) self.bank_inst.append(self.add_bank(1,self.bank_position_1, -1, 1))
def add_bottom_banks(self): def add_bottom_banks(self):
# Placement of bank 2 # Placement of bank 2
y_off = (self.bank_h + self.horizontal_bus_width y_off = self.bank.height + self.horizontal_bus_width + 2*self.bank_to_bus_distance + self.power_rail_pitch
+2 * self.bank_to_bus_distance
+ self.sram_power_rail_gap)
bank_position_2 = vector(self.bank_position_0.x, y_off) bank_position_2 = vector(self.bank_position_0.x, y_off)
self.add_bank(bank_position_2, 1, -1) self.bank2=self.add_bank(bank_position_2, 1, -1)
# Placement of bank 3 # Placement of bank 3
bank_position_3 = vector(self.bank_position_1.x, bank_position_2.y) bank_position_3 = vector(self.bank_position_1.x, bank_position_2.y)
self.add_bank(bank_position_3, 1, 1) self.bank3=self.add_bank(bank_position_3, 1, 1)
self.msb_decoder_position = vector(bank_position_3.x + self.power_rail_width self.msb_decoder_position = vector(bank_position_3.x + self.power_rail_width + 4*drc["minwidth_metal3"] + self.msb_decoder.width,
+ 4 * drc["minwidth_metal3"] self.msf_msb_address_position.y + 4*drc["minwidth_metal3"])
+ self.msb_decoder.width,
self.msf_msb_address_position.y
+ 4 * drc["minwidth_metal3"])
self.add_inst(name="msb_decoder", self.add_inst(name="msb_decoder",
mod=self.msb_decoder, mod=self.msb_decoder,
@ -485,28 +705,23 @@ class sram(design.design):
temp.extend(["vdd", "gnd"]) temp.extend(["vdd", "gnd"])
self.connect_inst(temp) self.connect_inst(temp)
self.control_position = vector(0, self.msb_decoder_position.y self.control_position = vector(0, self.msb_decoder_position.y + self.msb_decoder.height)
+ self.msb_decoder.height)
self.add_control_logic(self.control_position, 0) self.add_control_logic(self.control_position, 0)
self.CSb_position = self.control_position + self.control.CSb_position
self.OEb_position = self.control_position + self.control.OEb_position
self.WEb_position = self.control_position + self.control.WEb_position
self.clk_position = self.control_position + self.control.clk_position
# Max point # Max point
self.max_point = self.msb_decoder_position.y + self.msb_decoder.height self.max_point = self.msb_decoder_position.y + self.msb_decoder.height
def route_top_banks(self): def route_2or4_banks(self):
""" Routing of top two banks """ """ Routing of top two banks """
addr_start_index = len(self.sram_property) + (self.num_banks / 2) return
addr_start_index = len(self.sram_property) + self.num_banks/2
bank_select_index = addr_start_index + self.bank.addr_size bank_select_index = addr_start_index + self.bank.addr_size
# control, data , address and bank_select connection # control, data , address and bank_select connection
for i in range(self.num_banks / 2): for i in range(self.num_banks / 2):
left_bank_index = 2 * i left_bank_index = 2*i
right_bank_index = 2 * i + 1 right_bank_index = 2*i + 1
for attr_index in range(len(self.sram_property)): for attr_index in range(len(self.sram_property)):
bank_attr = self.sram_property[attr_index] bank_attr = self.sram_property[attr_index]
@ -602,7 +817,7 @@ class sram(design.design):
out_pos = vector(dest_pin.cx(), in_pos.y) out_pos = vector(dest_pin.cx(), in_pos.y)
self.add_wire(("metal3","via2","metal2"),[in_pos, out_pos, out_pos - vector(0,self.m2_pitch)]) self.add_wire(("metal3","via2","metal2"),[in_pos, out_pos, out_pos - vector(0,self.m2_pitch)])
self.add_via(layers=("metal2","via2","metal3"), self.add_via(layers=("metal2","via2","metal3"),
offset=src_pin.lr(), offset=src_pin.lr() - self.m2m3_offset_fix,
rotate=90) rotate=90)
def connect_rail_from_left_m2m1(self, src_pin, dest_pin): def connect_rail_from_left_m2m1(self, src_pin, dest_pin):
@ -613,16 +828,9 @@ class sram(design.design):
def route_single_bank(self): def route_single_bank(self):
""" Route a single bank SRAM """ """ Route a single bank SRAM """
# left pin is on the control logic, right pin is on the bank for n in self.control_logic_outputs:
connections = [("clk_buf", "clk"), src_pin = self.control_logic_inst.get_pin(n)
("tri_en_bar", "tri_en_bar"), dest_pin = self.bank_inst.get_pin(n)
("tri_en", "tri_en"),
("clk_bar", "clk_bar"),
("w_en", "w_en"),
("s_en", "s_en")]
for (src,dest) in connections:
src_pin = self.control_logic_inst.get_pin(src)
dest_pin = self.bank_inst.get_pin(dest)
self.connect_rail_from_left_m2m3(src_pin, dest_pin) self.connect_rail_from_left_m2m3(src_pin, dest_pin)
src_pins = self.control_logic_inst.get_pins("vdd") src_pins = self.control_logic_inst.get_pins("vdd")

View File

@ -29,7 +29,7 @@ class nor_2_test(unittest.TestCase):
import tech import tech
debug.info(2, "Checking 2-input nor gate") debug.info(2, "Checking 2-input nor gate")
tx = nor_2.nor_2(nmos_width=2 * tech.drc["minwidth_tx"]) tx = nor_2.nor_2()
self.local_check(tx) self.local_check(tx)
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True

View File

@ -25,20 +25,20 @@ class multi_bank_test(unittest.TestCase):
import bank import bank
debug.info(1, "No column mux") debug.info(1, "No column mux")
a = bank.bank(word_size=4, num_words=16, words_per_row=1, num_banks=2, name="test_bank1") a = bank.bank(word_size=4, num_words=16, words_per_row=1, num_banks=2, name="bank1")
self.local_check(a) self.local_check(a)
debug.info(1, "Two way column mux") debug.info(1, "Two way column mux")
a = bank.bank(word_size=4, num_words=32, words_per_row=2, num_banks=2, name="test_bank2") #a = bank.bank(word_size=4, num_words=32, words_per_row=2, num_banks=2, name="bank2")
self.local_check(a) #self.local_check(a)
debug.info(1, "Four way column mux") debug.info(1, "Four way column mux")
a = bank.bank(word_size=4, num_words=64, words_per_row=4, num_banks=2, name="test_bank3") a = bank.bank(word_size=4, num_words=64, words_per_row=4, num_banks=2, name="bank3")
self.local_check(a) self.local_check(a)
# Eight way has a short circuit of one column mux select to gnd rail # Eight way has a short circuit of one column mux select to gnd rail
# debug.info(1, "Eight way column mux") # debug.info(1, "Eight way column mux")
# a = bank.bank(word_size=2, num_words=128, words_per_row=8, num_banks=2, name="test_bank4") # a = bank.bank(word_size=2, num_words=128, words_per_row=8, num_banks=2, name="bank4")
# self.local_check(a) # self.local_check(a)
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True

View File

@ -26,20 +26,20 @@ class single_bank_test(unittest.TestCase):
import bank import bank
debug.info(1, "No column mux") debug.info(1, "No column mux")
a = bank.bank(word_size=4, num_words=16, words_per_row=1, num_banks=1, name="test_bank1") a = bank.bank(word_size=4, num_words=16, words_per_row=1, num_banks=1, name="bank1")
self.local_check(a) self.local_check(a)
debug.info(1, "Two way column mux") debug.info(1, "Two way column mux")
a = bank.bank(word_size=4, num_words=32, words_per_row=2, num_banks=1, name="test_bank2") a = bank.bank(word_size=4, num_words=32, words_per_row=2, num_banks=1, name="bank2")
self.local_check(a) self.local_check(a)
debug.info(1, "Four way column mux") debug.info(1, "Four way column mux")
a = bank.bank(word_size=4, num_words=64, words_per_row=4, num_banks=1, name="test_bank3") a = bank.bank(word_size=4, num_words=64, words_per_row=4, num_banks=1, name="bank3")
self.local_check(a) self.local_check(a)
# Eight way has a short circuit of one column mux select to gnd rail # Eight way has a short circuit of one column mux select to gnd rail
# debug.info(1, "Eight way column mux") # debug.info(1, "Eight way column mux")
# a = bank.bank(word_size=2, num_words=128, words_per_row=8, num_banks=1, name="test_bank4") # a = bank.bank(word_size=2, num_words=128, words_per_row=8, num_banks=1, name="bank4")
# self.local_check(a) # self.local_check(a)
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True

View File

@ -26,19 +26,19 @@ class sram_1bank_test(unittest.TestCase):
import sram import sram
debug.info(1, "Single bank, no column mux with control logic") debug.info(1, "Single bank, no column mux with control logic")
a = sram.sram(word_size=4, num_words=16, num_banks=1, name="test_sram1") a = sram.sram(word_size=4, num_words=16, num_banks=1, name="sram1")
self.local_check(a) self.local_check(a)
debug.info(1, "Single bank two way column mux with control logic") debug.info(1, "Single bank two way column mux with control logic")
a = sram.sram(word_size=4, num_words=32, num_banks=1, name="test_sram2") a = sram.sram(word_size=4, num_words=32, num_banks=1, name="sram2")
self.local_check(a) self.local_check(a)
debug.info(1, "Single bank, four way column mux with control logic") debug.info(1, "Single bank, four way column mux with control logic")
a = sram.sram(word_size=4, num_words=64, num_banks=1, name="test_sram3") a = sram.sram(word_size=4, num_words=64, num_banks=1, name="sram3")
self.local_check(a) self.local_check(a)
# debug.info(1, "Single bank, eight way column mux with control logic") # debug.info(1, "Single bank, eight way column mux with control logic")
# a = sram.sram(word_size=2, num_words=128, num_banks=1, name="test_sram4") # a = sram.sram(word_size=2, num_words=128, num_banks=1, name="sram4")
# self.local_check(a) # self.local_check(a)
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True

View File

@ -26,19 +26,19 @@ class sram_2bank_test(unittest.TestCase):
import sram import sram
debug.info(1, "Two bank, no column mux with control logic") debug.info(1, "Two bank, no column mux with control logic")
a = sram.sram(word_size=4, num_words=32, num_banks=2, name="test_sram1") a = sram.sram(word_size=16, num_words=32, num_banks=2, name="sram1")
self.local_check(a) self.local_check(a)
debug.info(1, "Two bank two way column mux with control logic") debug.info(1, "Two bank two way column mux with control logic")
a = sram.sram(word_size=4, num_words=64, num_banks=2, name="test_sram2") a = sram.sram(word_size=16, num_words=64, num_banks=2, name="sram2")
self.local_check(a) self.local_check(a)
debug.info(1, "Two bank, four way column mux with control logic") debug.info(1, "Two bank, four way column mux with control logic")
a = sram.sram(word_size=4, num_words=128, num_banks=2, name="test_sram3") a = sram.sram(word_size=16, num_words=128, num_banks=2, name="sram3")
self.local_check(a) self.local_check(a)
# debug.info(1, "Two bank, eight way column mux with control logic") # debug.info(1, "Two bank, eight way column mux with control logic")
# a = sram.sram(word_size=2, num_words=256 num_banks=2, name="test_sram4") # a = sram.sram(word_size=2, num_words=256 num_banks=2, name="sram4")
# self.local_check(a) # self.local_check(a)
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True

View File

@ -26,19 +26,19 @@ class sram_4bank_test(unittest.TestCase):
import sram import sram
debug.info(1, "Four bank, no column mux with control logic") debug.info(1, "Four bank, no column mux with control logic")
a = sram.sram(word_size=4, num_words=32, num_banks=4, name="test_sram1") a = sram.sram(word_size=4, num_words=32, num_banks=4, name="sram1")
self.local_check(a) self.local_check(a)
debug.info(1, "Four bank two way column mux with control logic") debug.info(1, "Four bank two way column mux with control logic")
a = sram.sram(word_size=4, num_words=64, num_banks=4, name="test_sram2") a = sram.sram(word_size=4, num_words=64, num_banks=4, name="sram2")
self.local_check(a) self.local_check(a)
debug.info(1, "Four bank, four way column mux with control logic") debug.info(1, "Four bank, four way column mux with control logic")
a = sram.sram(word_size=4, num_words=128, num_banks=4, name="test_sram3") a = sram.sram(word_size=4, num_words=128, num_banks=4, name="sram3")
self.local_check(a) self.local_check(a)
# debug.info(1, "Four bank, eight way column mux with control logic") # debug.info(1, "Four bank, eight way column mux with control logic")
# a = sram.sram(word_size=2, num_words=256, num_banks=4, name="test_sram4") # a = sram.sram(word_size=2, num_words=256, num_banks=4, name="sram4")
# self.local_check(a) # self.local_check(a)
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True

View File

@ -32,7 +32,7 @@ class timing_sram_test(unittest.TestCase):
s = sram.sram(word_size=OPTS.config.word_size, s = sram.sram(word_size=OPTS.config.word_size,
num_words=OPTS.config.num_words, num_words=OPTS.config.num_words,
num_banks=OPTS.config.num_banks, num_banks=OPTS.config.num_banks,
name="test_sram1") name="sram1")
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True
@ -52,25 +52,25 @@ class timing_sram_test(unittest.TestCase):
data = d.analyze(probe_address, probe_data,slews,loads) data = d.analyze(probe_address, probe_data,slews,loads)
if OPTS.tech_name == "freepdk45": if OPTS.tech_name == "freepdk45":
golden_data = {'read1_power': 0.017787999999999998, golden_data = {'read1_power': 0.025791799999999997,
'read0_power': 0.017827, 'read0_power': 0.0260092,
'write0_power': 0.016626, 'write0_power': 0.0241064,
'delay1': [0.02616], 'delay1': [0.0475006],
'delay0': [0.10966999999999999], 'delay0': [0.1380874],
'min_period': 0.264, 'min_period': 0.322,
'write1_power': 0.015919000000000003, 'write1_power': 0.024207199999999998,
'slew0': [0.027029], 'slew0': [0.026617000000000002],
'slew1': [0.021002999999999997]} 'slew1': [0.0193804]}
elif OPTS.tech_name == "scn3me_subm": elif OPTS.tech_name == "scn3me_subm":
golden_data = {'read1_power': 4.5206, golden_data = {'read1_power': 3.1765,
'read0_power': 4.5492, 'read0_power': 3.1929,
'write0_power': 3.8564, 'write0_power': 2.874,
'delay1': [0.5985562], 'delay1': [0.8900045999999999],
'delay0': [1.3725000000000003], 'delay0': [1.9975000000000003],
'min_period': 4.531, 'min_period': 5.781,
'write1_power': 3.7291, 'write1_power': 2.6611,
'slew0': [1.3013000000000001], 'slew0': [1.2993000000000001],
'slew1': [1.0045]} 'slew1': [0.9903856]}
else: else:
self.assertTrue(False) # other techs fail self.assertTrue(False) # other techs fail
# Check if no too many or too few results # Check if no too many or too few results

View File

@ -30,7 +30,7 @@ class timing_sram_test(unittest.TestCase):
s = sram.sram(word_size=OPTS.config.word_size, s = sram.sram(word_size=OPTS.config.word_size,
num_words=OPTS.config.num_words, num_words=OPTS.config.num_words,
num_banks=OPTS.config.num_banks, num_banks=OPTS.config.num_banks,
name="test_sram1") name="sram1")
import delay import delay
@ -48,25 +48,25 @@ class timing_sram_test(unittest.TestCase):
data = d.analyze(probe_address, probe_data,slews,loads) data = d.analyze(probe_address, probe_data,slews,loads)
if OPTS.tech_name == "freepdk45": if OPTS.tech_name == "freepdk45":
golden_data = {'read1_power': 0.022260799999999997, golden_data = {'read1_power': 0.02527215,
'read0_power': 0.02274298, 'read0_power': 0.02573022,
'write0_power': 0.02000899, 'write0_power': 0.02237065,
'delay1': [0.026754629999999998], 'delay1': [0.04867785],
'delay0': [0.1126814], 'delay0': [0.1423512],
'min_period': 0.273, 'min_period': 0.332,
'write1_power': 0.01934197, 'write1_power': 0.02152122,
'slew0': [0.02760651], 'slew0': [0.0273352],
'slew1': [0.023076919999999997]} 'slew1': [0.021216870000000002]}
elif OPTS.tech_name == "scn3me_subm": elif OPTS.tech_name == "scn3me_subm":
golden_data = {'read1_power': 5.549996, golden_data = {'read1_power': 3.244839,
'read0_power': 4.781156, 'read0_power': 3.088234,
'write0_power': 3.931431, 'write0_power': 2.6857420000000003,
'delay1': [0.6227914], 'delay1': [0.9200643],
'delay0': [1.414657], 'delay0': [2.0509399999999998],
'min_period': 4.688, 'min_period': 6.563,
'write1_power': 3.409661, 'write1_power': 2.378355,
'slew0': [1.345377], 'slew0': [1.342019],
'slew1': [1.05667]} 'slew1': [1.040885]}
else: else:
self.assertTrue(False) # other techs fail self.assertTrue(False) # other techs fail

File diff suppressed because it is too large Load Diff

View File

@ -74,7 +74,7 @@ cell (sram_2_16_1_freepdk45){
dont_use : true; dont_use : true;
map_only : true; map_only : true;
dont_touch : true; dont_touch : true;
area : 799.659625; area : 692.2795;
bus(DATA){ bus(DATA){
bus_type : DATA; bus_type : DATA;
@ -92,10 +92,10 @@ cell (sram_2_16_1_freepdk45){
internal_power(){ internal_power(){
when : "OEb & !clk"; when : "OEb & !clk";
rise_power(scalar){ rise_power(scalar){
values("0.020625"); values("0.0287643");
} }
fall_power(scalar){ fall_power(scalar){
values("0.021124"); values("0.0284106");
} }
} }
timing(){ timing(){
@ -129,10 +129,10 @@ cell (sram_2_16_1_freepdk45){
internal_power(){ internal_power(){
when : "!OEb & !clk"; when : "!OEb & !clk";
rise_power(scalar){ rise_power(scalar){
values("0.023099"); values("0.0320149");
} }
fall_power(scalar){ fall_power(scalar){
values("0.023401"); values("0.0322925");
} }
} }
timing(){ timing(){
@ -140,24 +140,24 @@ cell (sram_2_16_1_freepdk45){
related_pin : "clk"; related_pin : "clk";
timing_type : falling_edge; timing_type : falling_edge;
cell_rise(CELL_TABLE) { cell_rise(CELL_TABLE) {
values("0.025, 0.026, 0.032",\ values("0.046, 0.046, 0.053",\
"0.026, 0.026, 0.033",\ "0.046, 0.047, 0.054",\
"0.03, 0.031, 0.037"); "0.051, 0.052, 0.059");
} }
cell_fall(CELL_TABLE) { cell_fall(CELL_TABLE) {
values("0.11, 0.11, 0.118",\ values("0.142, 0.143, 0.152",\
"0.11, 0.111, 0.119",\ "0.143, 0.144, 0.152",\
"0.114, 0.114, 0.122"); "0.148, 0.149, 0.158");
} }
rise_transition(CELL_TABLE) { rise_transition(CELL_TABLE) {
values("0.016, 0.017, 0.028",\ values("0.014, 0.015, 0.027",\
"0.016, 0.017, 0.028",\ "0.014, 0.015, 0.027",\
"0.016, 0.018, 0.028"); "0.014, 0.015, 0.027");
} }
fall_transition(CELL_TABLE) { fall_transition(CELL_TABLE) {
values("0.02, 0.022, 0.037",\ values("0.019, 0.02, 0.036",\
"0.02, 0.022, 0.037",\ "0.019, 0.02, 0.036",\
"0.021, 0.023, 0.037"); "0.019, 0.02, 0.036");
} }
} }
} }
@ -308,20 +308,20 @@ cell (sram_2_16_1_freepdk45){
timing_type :"min_pulse_width"; timing_type :"min_pulse_width";
related_pin : clk; related_pin : clk;
rise_constraint(scalar) { rise_constraint(scalar) {
values("0.166"); values("0.205");
} }
fall_constraint(scalar) { fall_constraint(scalar) {
values("0.166"); values("0.205");
} }
} }
timing(){ timing(){
timing_type :"minimum_period"; timing_type :"minimum_period";
related_pin : clk; related_pin : clk;
rise_constraint(scalar) { rise_constraint(scalar) {
values("0.332"); values("0.41");
} }
fall_constraint(scalar) { fall_constraint(scalar) {
values("0.332"); values("0.41");
} }
} }
} }

View File

@ -74,7 +74,7 @@ cell (sram_2_16_1_freepdk45){
dont_use : true; dont_use : true;
map_only : true; map_only : true;
dont_touch : true; dont_touch : true;
area : 799.659625; area : 692.2795;
bus(DATA){ bus(DATA){
bus_type : DATA; bus_type : DATA;
@ -140,14 +140,14 @@ cell (sram_2_16_1_freepdk45){
related_pin : "clk"; related_pin : "clk";
timing_type : falling_edge; timing_type : falling_edge;
cell_rise(CELL_TABLE) { cell_rise(CELL_TABLE) {
values("0.12, 0.121, 0.131",\ values("0.122, 0.123, 0.132",\
"0.12, 0.121, 0.131",\ "0.122, 0.123, 0.132",\
"0.12, 0.121, 0.131"); "0.122, 0.123, 0.132");
} }
cell_fall(CELL_TABLE) { cell_fall(CELL_TABLE) {
values("0.12, 0.121, 0.131",\ values("0.122, 0.123, 0.132",\
"0.12, 0.121, 0.131",\ "0.122, 0.123, 0.132",\
"0.12, 0.121, 0.131"); "0.122, 0.123, 0.132");
} }
rise_transition(CELL_TABLE) { rise_transition(CELL_TABLE) {
values("0.006, 0.007, 0.018",\ values("0.006, 0.007, 0.018",\

File diff suppressed because it is too large Load Diff

View File

@ -74,7 +74,7 @@ cell (sram_2_16_1_scn3me_subm){
dont_use : true; dont_use : true;
map_only : true; map_only : true;
dont_touch : true; dont_touch : true;
area : 102102.39; area : 89304.3;
bus(DATA){ bus(DATA){
bus_type : DATA; bus_type : DATA;
@ -92,10 +92,10 @@ cell (sram_2_16_1_scn3me_subm){
internal_power(){ internal_power(){
when : "OEb & !clk"; when : "OEb & !clk";
rise_power(scalar){ rise_power(scalar){
values("2.3875"); values("3.1588");
} }
fall_power(scalar){ fall_power(scalar){
values("2.5832"); values("3.4922");
} }
} }
timing(){ timing(){
@ -129,10 +129,10 @@ cell (sram_2_16_1_scn3me_subm){
internal_power(){ internal_power(){
when : "!OEb & !clk"; when : "!OEb & !clk";
rise_power(scalar){ rise_power(scalar){
values("2.9868"); values("3.9389");
} }
fall_power(scalar){ fall_power(scalar){
values("3.0093"); values("3.9642");
} }
} }
timing(){ timing(){
@ -140,24 +140,24 @@ cell (sram_2_16_1_scn3me_subm){
related_pin : "clk"; related_pin : "clk";
timing_type : falling_edge; timing_type : falling_edge;
cell_rise(CELL_TABLE) { cell_rise(CELL_TABLE) {
values("0.261, 0.343, 1.013",\ values("0.542, 0.626, 1.298",\
"0.264, 0.345, 1.019",\ "0.545, 0.628, 1.304",\
"0.311, 0.39, 1.062"); "0.594, 0.674, 1.35");
} }
cell_fall(CELL_TABLE) { cell_fall(CELL_TABLE) {
values("0.837, 0.945, 1.919",\ values("1.532, 1.634, 2.6",\
"0.841, 0.95, 1.925",\ "1.536, 1.639, 2.607",\
"0.878, 0.986, 1.96"); "1.587, 1.69, 2.657");
} }
rise_transition(CELL_TABLE) { rise_transition(CELL_TABLE) {
values("0.21, 0.354, 1.887",\ values("0.191, 0.337, 1.884",\
"0.214, 0.356, 1.888",\ "0.193, 0.338, 1.885",\
"0.313, 0.361, 1.889"); "0.195, 0.341, 1.884");
} }
fall_transition(CELL_TABLE) { fall_transition(CELL_TABLE) {
values("0.236, 0.445, 2.463",\ values("0.255, 0.448, 2.467",\
"0.236, 0.445, 2.462",\ "0.256, 0.447, 2.468",\
"0.235, 0.445, 2.454"); "0.256, 0.447, 2.454");
} }
} }
} }
@ -308,20 +308,20 @@ cell (sram_2_16_1_scn3me_subm){
timing_type :"min_pulse_width"; timing_type :"min_pulse_width";
related_pin : clk; related_pin : clk;
rise_constraint(scalar) { rise_constraint(scalar) {
values("3.75"); values("4.5315");
} }
fall_constraint(scalar) { fall_constraint(scalar) {
values("3.75"); values("4.5315");
} }
} }
timing(){ timing(){
timing_type :"minimum_period"; timing_type :"minimum_period";
related_pin : clk; related_pin : clk;
rise_constraint(scalar) { rise_constraint(scalar) {
values("7.5"); values("9.063");
} }
fall_constraint(scalar) { fall_constraint(scalar) {
values("7.5"); values("9.063");
} }
} }
} }

View File

@ -74,7 +74,7 @@ cell (sram_2_16_1_scn3me_subm){
dont_use : true; dont_use : true;
map_only : true; map_only : true;
dont_touch : true; dont_touch : true;
area : 102102.39; area : 89304.3;
bus(DATA){ bus(DATA){
bus_type : DATA; bus_type : DATA;
@ -140,14 +140,14 @@ cell (sram_2_16_1_scn3me_subm){
related_pin : "clk"; related_pin : "clk";
timing_type : falling_edge; timing_type : falling_edge;
cell_rise(CELL_TABLE) { cell_rise(CELL_TABLE) {
values("0.57, 0.617, 1.058",\ values("0.553, 0.6, 1.041",\
"0.57, 0.617, 1.058",\ "0.553, 0.6, 1.041",\
"0.57, 0.617, 1.058"); "0.553, 0.6, 1.041");
} }
cell_fall(CELL_TABLE) { cell_fall(CELL_TABLE) {
values("0.57, 0.617, 1.058",\ values("0.553, 0.6, 1.041",\
"0.57, 0.617, 1.058",\ "0.553, 0.6, 1.041",\
"0.57, 0.617, 1.058"); "0.553, 0.6, 1.041");
} }
rise_transition(CELL_TABLE) { rise_transition(CELL_TABLE) {
values("0.024, 0.081, 0.61",\ values("0.024, 0.081, 0.61",\