Rework hierarchical decoder to not be folded. Remove address from central bank bus and access via side pins now. Eight way column mux now works.

This commit is contained in:
Matt Guthaus 2018-03-19 15:11:42 -07:00
parent 1f81b24e96
commit bab92fcf38
9 changed files with 114 additions and 197 deletions

View File

@ -30,6 +30,8 @@ class design(hierarchy_spice.spice, hierarchy_layout.layout):
# These modules ensure unique names or have no changes if they # These modules ensure unique names or have no changes if they
# aren't unique # aren't unique
ok_list = ['ms_flop.ms_flop', ok_list = ['ms_flop.ms_flop',
'dff.dff',
'dff_buf.dff_buf',
'bitcell.bitcell', 'bitcell.bitcell',
'contact.contact', 'contact.contact',
'ptx.ptx', 'ptx.ptx',

View File

@ -91,6 +91,8 @@ class spice(verilog.verilog):
group of modules are generated.""" group of modules are generated."""
if (check and (len(self.insts[-1].mod.pins) != len(args))): if (check and (len(self.insts[-1].mod.pins) != len(args))):
debug.error("Connections: {}".format(self.insts[-1].mod.pins))
debug.error("Connections: {}".format(args))
debug.error("Number of net connections ({0}) does not match last instance ({1})".format(len(self.insts[-1].mod.pins), debug.error("Number of net connections ({0}) does not match last instance ({1})".format(len(self.insts[-1].mod.pins),
len(args)), 1) len(args)), 1)
self.conns.append(args) self.conns.append(args)

View File

@ -161,17 +161,15 @@ class bank(design.design):
# The central bus is the column address (one hot) and row address (binary) # The central bus is the column address (one hot) and row address (binary)
if self.col_addr_size>0: if self.col_addr_size>0:
self.num_col_addr_lines = 2**self.col_addr_size self.num_col_addr_lines = 2**self.col_addr_size
self.num_addr_lines = self.num_col_addr_lines + self.row_addr_size
else: else:
self.num_col_addr_lines = 0 self.num_col_addr_lines = 0
self.num_addr_lines = self.row_addr_size
# M1/M2 routing pitch is based on contacted pitch # M1/M2 routing pitch is based on contacted pitch
self.m1_pitch = contact.m1m2.height + max(self.m1_space,self.m2_space) self.m1_pitch = contact.m1m2.height + max(self.m1_space,self.m2_space)
self.m2_pitch = contact.m2m3.height + max(self.m2_space,self.m3_space) self.m2_pitch = contact.m2m3.height + max(self.m2_space,self.m3_space)
# The width of this bus is needed to place other modules (e.g. decoder) # The width of this bus is needed to place other modules (e.g. decoder)
self.central_bus_width = self.m2_pitch * (self.num_control_lines + self.num_addr_lines + 1) self.central_bus_width = self.m2_pitch * self.num_control_lines
@ -362,12 +360,10 @@ class bank(design.design):
# The predecoder is below the x-axis and the main decoder is above the x-axis # The predecoder is below the x-axis and the main decoder is above the x-axis
# The address flop and decoder are aligned in the x coord. # The address flop and decoder are aligned in the x coord.
decoder_x_offset = self.row_decoder.width + self.central_bus_width x_offset = -(self.row_decoder.width + self.central_bus_width + self.wordline_driver.width)
offset = vector(decoder_x_offset,
self.row_decoder.predecoder_height)
self.row_decoder_inst=self.add_inst(name="row_decoder", self.row_decoder_inst=self.add_inst(name="row_decoder",
mod=self.row_decoder, mod=self.row_decoder,
offset=offset.scale(-1,-1)) offset=vector(x_offset,0))
temp = [] temp = []
for i in range(self.row_addr_size): for i in range(self.row_addr_size):
@ -381,12 +377,10 @@ class bank(design.design):
""" Wordline Driver """ """ Wordline Driver """
# The wordline driver is placed to the right of the main decoder width. # The wordline driver is placed to the right of the main decoder width.
# This means that it slightly overlaps with the hierarchical decoder, x_offset = -(self.central_bus_width + self.wordline_driver.width) + self.m2_pitch
# but it shares power rails. This may differ for other decoders later...
x_offset = self.row_decoder.width + self.central_bus_width - self.row_decoder.row_decoder_width
self.wordline_driver_inst=self.add_inst(name="wordline_driver", self.wordline_driver_inst=self.add_inst(name="wordline_driver",
mod=self.wordline_driver, mod=self.wordline_driver,
offset=vector(x_offset,0).scale(-1,-1)) offset=vector(x_offset,0))
temp = [] temp = []
for i in range(self.num_rows): for i in range(self.num_rows):
@ -404,8 +398,8 @@ class bank(design.design):
Create a 2:4 or 3:8 column address decoder. Create a 2:4 or 3:8 column address decoder.
""" """
# Place the col decoder aligned left to row decoder # Place the col decoder aligned left to row decoder
x_off = -(self.central_bus_width + self.row_decoder.width) x_off = -(self.row_decoder.width + self.central_bus_width + self.wordline_driver.width)
y_off = -(self.row_decoder.predecoder_height + self.col_decoder.height + 2*drc["well_to_well"]) y_off = -(self.col_decoder.height + 2*drc["well_to_well"])
self.col_decoder_inst=self.add_inst(name="col_address_decoder", self.col_decoder_inst=self.add_inst(name="col_address_decoder",
mod=self.col_decoder, mod=self.col_decoder,
offset=vector(x_off,y_off)) offset=vector(x_off,y_off))
@ -445,10 +439,10 @@ class bank(design.design):
if not self.num_banks > 1: if not self.num_banks > 1:
return return
xoffset = -(self.central_bus_width + self.bank_select.width) x_off = -(self.row_decoder.width + self.central_bus_width + self.wordline_driver.width)
# extra space to allow vias # extra space to allow vias
yoffset = self.min_point + 2*self.supply_rail_pitch + self.m1_space y_off = self.min_point + 2*self.supply_rail_pitch + self.m1_space
self.bank_select_pos = vector(xoffset,yoffset) self.bank_select_pos = vector(x_off,y_off)
self.bank_select_inst = self.add_inst(name="bank_select", self.bank_select_inst = self.add_inst(name="bank_select",
mod=self.bank_select, mod=self.bank_select,
offset=self.bank_select_pos) offset=self.bank_select_pos)
@ -536,12 +530,11 @@ class bank(design.design):
""" Create the address, supply, and control signal central bus lines. """ """ Create the address, supply, and control signal central bus lines. """
# Overall central bus width. It includes all the column mux lines, # Overall central bus width. It includes all the column mux lines,
# control lines, and address flop to decoder lines. # and control lines.
# The bank is at (0,0), so this is to the left of the y-axis. # The bank is at (0,0), so this is to the left of the y-axis.
# 2 pitches on the right for vias/jogs to access the inputs # 2 pitches on the right for vias/jogs to access the inputs
control_bus_x_offset = -self.m2_pitch * (self.num_control_lines) control_bus_x_offset = -self.m2_pitch * self.num_control_lines
address_bus_x_offset = control_bus_x_offset - self.m2_pitch*(self.num_addr_lines)
# Track the bus offsets for other modules to access # Track the bus offsets for other modules to access
self.bus_xoffset = {} self.bus_xoffset = {}
@ -556,35 +549,6 @@ class bank(design.design):
width=self.m2_width, width=self.m2_width,
height=self.height) height=self.height)
# Row address lines (to left of col address lines)
# goes from bottom of bitcell array down to the bottom of the column decoder/addresses
for i in range(self.row_addr_size):
addr_idx = i + self.col_addr_size
x_offset = address_bus_x_offset + i*self.m2_pitch
name = "A[{}]".format(addr_idx)
# Make the xoffset map the center of the rail
self.bus_xoffset[name]=x_offset + 0.5*self.m2_width
# Add a label pin for LVS correspondence and visual help inspecting the rail.
self.add_layout_pin(text=name,
layer="metal2",
offset=vector(x_offset, self.min_point),
width=self.m2_width,
height=-self.min_point)
# Column mux lines if there is column mux
# goes from bottom of bitcell array down to the bottom of the column decoder/addresses
if self.col_addr_size>0:
for i in range(self.num_col_addr_lines):
x_offset = address_bus_x_offset + (i+self.row_addr_size)*self.m2_pitch
name = "sel[{}]".format(i) # One hot select signals
# Make the xoffset map the center of the rail
self.bus_xoffset[name]=x_offset + 0.5*self.m2_width
# Add a label pin for LVS correspondence
self.add_label_pin(text=name,
layer="metal2",
offset=vector(x_offset, self.col_decoder_inst.by()),
width=self.m2_width,
height=-self.col_decoder_inst.by())
def route_precharge_to_bitcell_array(self): def route_precharge_to_bitcell_array(self):
@ -654,33 +618,14 @@ class bank(design.design):
def route_row_decoder(self): def route_row_decoder(self):
""" Routes the row decoder inputs and supplies """ """ Routes the row decoder inputs and supplies """
for i in range(self.row_addr_size): # # Create inputs for the row address lines
addr_idx = i + self.col_addr_size # for i in range(self.row_addr_size):
# before this index, we are using 2x4 decoders # addr_idx = i + self.col_addr_size
switchover_index = 2*self.row_decoder.no_of_pre2x4 # decoder_name = "A[{}]".format(i)
# so decide what modulus to perform the height spacing # addr_name = "A[{}]".format(addr_idx)
if i < switchover_index: # self.copy_layout_pin(self.row_decoder_inst, decoder_name, addr_name)
position_heights = i % 2
else:
position_heights = (i-switchover_index) % 3
# Connect the address rails to the decoder
# Note that the decoder inputs are long vertical rails so spread out the connections vertically.
decoder_in_position = self.row_decoder_inst.get_pin("A[{}]".format(i)).lr() \
+ vector(0,position_heights*self.bitcell.height+self.m2_pitch)
rail_position = vector(self.bus_xoffset["A[{}]".format(addr_idx)],
decoder_in_position.y)
self.add_path("metal1",[decoder_in_position,rail_position])
decoder_in_via = decoder_in_position - vector(0,0.5*self.m2_width)
self.add_via(layers=("metal1", "via1", "metal2"),
offset=decoder_in_via,
rotate=90)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=rail_position,
rotate=90)
# 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. # These must be on M3 to not interfere with column mux address pins.
@ -730,70 +675,51 @@ class bank(design.design):
def route_column_address_lines(self): def route_column_address_lines(self):
""" Connecting the select lines of column mux to the address bus """ """ Connecting the select lines of column mux to the address bus """
if not self.col_addr_size>0: if not self.col_addr_size>0:
return return
# 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(self.num_col_addr_lines):
name = "sel[{}]".format(i)
mux_addr_pos = self.col_mux_array_inst.get_pin(name).lc()
wire_pos = vector(self.bus_xoffset[name], mux_addr_pos.y)
self.add_path("metal1", [wire_pos,mux_addr_pos])
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=wire_pos,
rotate=90)
if self.col_addr_size == 1: if self.col_addr_size == 1:
decode_out_pos = self.col_decoder_inst.get_pin("Zb").rc() # Connect to sel[0] and sel[1]
selx_pos = vector(self.bus_xoffset["sel[0]"],decode_out_pos.y) decode_names = ["Zb", "Z"]
self.add_path("metal1",[decode_out_pos, selx_pos])
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=selx_pos,
rotate=90)
decode_out_pos = self.col_decoder_inst.get_pin("Z").rc()
selx_pos = vector(self.bus_xoffset["sel[1]"],decode_out_pos.y)
self.add_path("metal1",[decode_out_pos, selx_pos])
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=selx_pos,
rotate=90)
# The Address LSB # The Address LSB
decode_in_pin = self.col_decoder_inst.get_pin("A") self.copy_layout_pin(self.col_decoder_inst, "A", "A[0]")
pin_pos = vector(decode_in_pin.cx(), self.min_point)
self.add_layout_pin_center_segment(text="A[0]",
layer="metal2",
start=pin_pos,
end=decode_in_pin.bc())
elif self.col_addr_size > 1: elif self.col_addr_size > 1:
# Route the col decoder outputs to the col select bus decode_names = []
for i in range(self.num_col_addr_lines): for i in range(self.num_col_addr_lines):
name = "sel[{}]".format(i) decode_names.append("out[{}]".format(i))
decode_out_pos = self.col_decoder_inst.get_pin("out[{}]".format(i)).rc()
selx_pos = vector(self.bus_xoffset[name],decode_out_pos.y)
self.add_path("metal1",[decode_out_pos, selx_pos])
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=selx_pos,
rotate=90)
# Route from the col decoder up to the address bus
for i in range(self.col_addr_size): for i in range(self.col_addr_size):
decoder_name = "in[{}]".format(i) decoder_name = "in[{}]".format(i)
addr_name = "A[{}]".format(i) addr_name = "A[{}]".format(i)
decode_in_pin = self.col_decoder_inst.get_pin(decoder_name) self.copy_layout_pin(self.col_decoder_inst, decoder_name, addr_name)
pin_pos = vector(decode_in_pin.cx(), self.min_point)
self.add_layout_pin_center_segment(text=addr_name,
layer="metal2",
start=pin_pos,
end=decode_in_pin.bc())
# This will do a quick "river route" on two layers.
# When above the top select line it will offset "inward" again to prevent conflicts.
# This could be done on a single layer, but we follow preferred direction rules for later routing.
top_y_offset = self.col_mux_array_inst.get_pin("sel[{}]".format(self.num_col_addr_lines-1)).cy()
for (decode_name,i) in zip(decode_names,range(self.num_col_addr_lines)):
mux_name = "sel[{}]".format(i)
mux_addr_pos = self.col_mux_array_inst.get_pin(mux_name).lc()
decode_out_pos = self.col_decoder_inst.get_pin(decode_name).center()
# To get to the edge of the decoder and one track out
delta_offset = self.col_decoder_inst.rx() - decode_out_pos.x + self.m2_pitch
if decode_out_pos.y > top_y_offset:
mid1_pos = vector(decode_out_pos.x + delta_offset + i*self.m2_pitch,decode_out_pos.y)
else:
mid1_pos = vector(decode_out_pos.x + delta_offset + (self.num_col_addr_lines-i)*self.m2_pitch,decode_out_pos.y)
mid2_pos = vector(mid1_pos.x,mux_addr_pos.y)
self.add_wire(("metal1","via1","metal2"),[decode_out_pos, mid1_pos, mid2_pos, mux_addr_pos])
# route the gnd rails, add contact to rail as well # route the gnd rails, add contact to rail as well
for gnd_pin in self.col_decoder_inst.get_pins("gnd"): for gnd_pin in self.col_decoder_inst.get_pins("gnd"):
left_rail_pos = vector(self.left_gnd_x_center, gnd_pin.cy()) left_rail_pos = vector(self.left_gnd_x_center, gnd_pin.cy())

View File

@ -154,12 +154,11 @@ class hierarchical_decoder(design.design):
else: else:
nand_width = self.nand3.width nand_width = self.nand3.width
self.routing_width = self.metal2_pitch*self.total_number_of_predecoder_outputs self.routing_width = self.metal2_pitch*self.total_number_of_predecoder_outputs
self.row_decoder_width = nand_width + self.routing_width + self.inv.width
self.row_decoder_height = self.inv.height * self.rows self.row_decoder_height = self.inv.height * self.rows
# Calculates height and width of hierarchical decoder # Calculates height and width of hierarchical decoder
self.height = self.row_decoder_height self.height = self.row_decoder_height
self.width = self.predecoder_width + self.row_decoder_width self.width = self.predecoder_width + self.routing_width + nand_width + self.inv.width
def create_pre_decoder(self): def create_pre_decoder(self):
""" Creates pre-decoder and places labels input address [A] """ """ Creates pre-decoder and places labels input address [A] """
@ -479,7 +478,7 @@ class hierarchical_decoder(design.design):
def connect_rail_m3(self, rail_index, pin): def connect_rail_m3(self, rail_index, pin):
""" Connect the routing rail to the given metal1 pin """ """ Connect the routing rail to the given metal1 pin """
mid_point = vector(pin.cx(), pin.cy()-self.inv.height/2) mid_point = vector(pin.cx(), pin.cy()+self.inv.height/2)
rail_pos = vector(self.rail_x_offsets[rail_index],mid_point.y) rail_pos = vector(self.rail_x_offsets[rail_index],mid_point.y)
self.add_via_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=pin.center(), offset=pin.center(),

View File

@ -119,7 +119,7 @@ class single_level_column_mux_array(design.design):
def add_horizontal_input_rail(self): def add_horizontal_input_rail(self):
""" Create address input rails on M1 below the mux transistors """ """ Create address input rails on M1 below the mux transistors """
for j in range(self.words_per_row): for j in range(self.words_per_row):
offset = vector(0, self.route_height - (j+1)*self.m1_pitch) offset = vector(0, self.route_height + (j-self.words_per_row)*self.m1_pitch)
self.add_layout_pin(text="sel[{}]".format(j), self.add_layout_pin(text="sel[{}]".format(j),
layer="metal1", layer="metal1",
offset=offset, offset=offset,

View File

@ -22,6 +22,7 @@ class wordline_driver(design.design):
self.rows = rows self.rows = rows
self.add_pins() self.add_pins()
self.design_layout() self.design_layout()
self.offset_all_coordinates()
self.DRC_LVS() self.DRC_LVS()
def add_pins(self): def add_pins(self):

View File

@ -28,7 +28,7 @@ class pinvbuf(design.design):
self.inv2 = pinv(size=inv2_size) self.inv2 = pinv(size=inv2_size)
self.add_mod(self.inv2) self.add_mod(self.inv2)
self.width = self.inv1.width + self.inv2.width self.width = 2*self.inv1.width + self.inv2.width
self.height = 2*self.inv1.height self.height = 2*self.inv1.height
self.create_layout() self.create_layout()

View File

@ -20,9 +20,15 @@ class sram(design.design):
c = reload(__import__(OPTS.control_logic)) c = reload(__import__(OPTS.control_logic))
self.mod_control_logic = getattr(c, OPTS.control_logic) self.mod_control_logic = getattr(c, OPTS.control_logic)
c = reload(__import__(OPTS.dff_array)) if num_banks>1:
self.mod_dff_array = getattr(c, OPTS.dff_array) # Use a buffered array for big arrays
# Also ensures we have Qbar when FF doesn't
c = reload(__import__(OPTS.dff_buf_array))
self.mod_dff_array = getattr(c, OPTS.dff_buf_array)
else:
c = reload(__import__(OPTS.dff_array))
self.mod_dff_array = getattr(c, OPTS.dff_array)
c = reload(__import__(OPTS.bitcell)) c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell) self.mod_bitcell = getattr(c, OPTS.bitcell)
@ -200,6 +206,32 @@ class sram(design.design):
self.width = self.bank_inst[1].ur().x self.width = self.bank_inst[1].ur().x
self.height = self.control_logic_inst.uy() self.height = self.control_logic_inst.uy()
def add_single_bank_modules(self):
"""
This adds the moduels for a single bank SRAM with control
logic.
"""
# No orientation or offset
self.bank_inst = self.add_bank(0, [0, 0], 1, 1)
# 3/5/18 MRG: Cannot reference positions inside submodules because boundaries
# are not recomputed using instance placement. So, place the control logic such that it aligns
# with the top of the SRAM.
control_gap = 2*self.m3_width
control_pos = vector(-self.control_logic.width-control_gap,
self.bank.height-self.control_logic.height-3*self.supply_rail_width)
self.add_control_logic(position=control_pos)
# Leave room for the control routes to the left of the flops
addr_pos = vector(self.control_logic_inst.lx() + 4*self.m2_pitch,
3*self.supply_rail_pitch)
self.add_control_addr_dff(addr_pos)
self.width = self.bank.width + self.control_logic.height + control_gap
self.height = self.bank.height
def route_shared_banks(self): def route_shared_banks(self):
""" Route the shared signals for two and four bank configurations. """ """ Route the shared signals for two and four bank configurations. """
@ -777,9 +809,10 @@ class sram(design.design):
def create_multi_bank_modules(self): def create_multi_bank_modules(self):
""" Create the multibank address flops and bank decoder """ """ Create the multibank address flops and bank decoder """
self.msb_address = self.mod_ms_flop_array(name="msb_address",
columns=self.num_banks/2, self.msb_address = self.mod_dff_array(name="msb_address",
word_size=self.num_banks/2) rows=1,
columns=self.num_banks/2)
self.add_mod(self.msb_address) self.add_mod(self.msb_address)
if self.num_banks>2: if self.num_banks>2:
@ -794,9 +827,9 @@ class sram(design.design):
self.add_mod(self.control_logic) self.add_mod(self.control_logic)
# Create the address and control flops (but not the clk) # Create the address and control flops (but not the clk)
dff_size = self.addr_size + len(self.control_logic.get_inputs())-1 dff_size = self.addr_size
self.addr_ctrl_dff = self.mod_dff_array(name="dff_array", rows=dff_size, columns=1) self.addr_dff = self.mod_dff_array(name="dff_array", rows=dff_size, columns=1)
self.add_mod(self.addr_ctrl_dff) self.add_mod(self.addr_dff)
# 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,
@ -902,9 +935,9 @@ class sram(design.design):
def add_control_addr_dff(self, position): def add_control_addr_dff(self, position):
""" Add and place address and control flops """ """ Add and place address and control flops """
self.addr_ctrl_dff_inst = self.add_inst(name="address", self.addr_dff_inst = self.add_inst(name="address",
mod=self.addr_ctrl_dff, mod=self.addr_dff,
offset=position) offset=position)
# inputs, outputs/output/bar # inputs, outputs/output/bar
inputs = [] inputs = []
outputs = [] outputs = []
@ -912,12 +945,6 @@ class sram(design.design):
inputs.append("ADDR[{}]".format(i)) inputs.append("ADDR[{}]".format(i))
outputs.append("A[{}]".format(i)) outputs.append("A[{}]".format(i))
for i in self.control_logic_inputs:
if i == "clk":
continue
inputs.append(i)
outputs.append(i+"_s")
self.connect_inst(inputs + outputs + ["clk", "vdd", "gnd"]) self.connect_inst(inputs + outputs + ["clk", "vdd", "gnd"])
def add_control_logic(self, position): def add_control_logic(self, position):
@ -951,31 +978,6 @@ class sram(design.design):
layer="metal2", layer="metal2",
offset=self.vert_control_bus_positions[n]) offset=self.vert_control_bus_positions[n])
def add_single_bank_modules(self):
"""
This adds the moduels for a single bank SRAM with control
logic.
"""
# No orientation or offset
self.bank_inst = self.add_bank(0, [0, 0], 1, 1)
# 3/5/18 MRG: Cannot reference positions inside submodules because boundaries
# are not recomputed using instance placement. So, place the control logic such that it aligns
# with the top of the SRAM.
control_gap = 2*self.m3_width
control_pos = vector(-self.control_logic.width-control_gap,
self.bank.height-self.control_logic.height-3*self.supply_rail_width)
self.add_control_logic(position=control_pos)
# Leave room for the control routes to the left of the flops
addr_pos = vector(self.control_logic_inst.lx() + 4*self.m2_pitch,
3*self.supply_rail_pitch)
self.add_control_addr_dff(addr_pos)
self.width = self.bank.width + self.control_logic.height + control_gap
self.height = self.bank.height
def add_single_bank_pins(self): def add_single_bank_pins(self):
""" """
Add the top-level pins for a single bank SRAM with control. Add the top-level pins for a single bank SRAM with control.
@ -985,13 +987,9 @@ class sram(design.design):
self.copy_layout_pin(self.bank_inst, "DATA[{}]".format(i)) self.copy_layout_pin(self.bank_inst, "DATA[{}]".format(i))
for i in range(self.addr_size): for i in range(self.addr_size):
self.copy_layout_pin(self.addr_ctrl_dff_inst, "din[{}]".format(i),"ADDR[{}]".format(i)) self.copy_layout_pin(self.addr_dff_inst, "din[{}]".format(i),"ADDR[{}]".format(i))
ctrl_flops = ["din[{}]".format(i) for i in range(self.addr_size,self.addr_size+3)] self.copy_layout_pin(self.addr_dff_inst, "clk")
for (old,new) in zip(ctrl_flops,["CSb","WEb","OEb"]):
self.copy_layout_pin(self.addr_ctrl_dff_inst, old, new)
self.copy_layout_pin(self.addr_ctrl_dff_inst, "clk")
# Power ring contains the power pins # Power ring contains the power pins
@ -1068,7 +1066,7 @@ class sram(design.design):
for i in range(self.addr_size): for i in range(self.addr_size):
flop_name = "dout[{}]".format(i) flop_name = "dout[{}]".format(i)
bank_name = "A[{}]".format(i) bank_name = "A[{}]".format(i)
flop_pin = self.addr_ctrl_dff_inst.get_pin(flop_name) flop_pin = self.addr_dff_inst.get_pin(flop_name)
bank_pin = self.bank_inst.get_pin(bank_name) bank_pin = self.bank_inst.get_pin(bank_name)
flop_pos = flop_pin.center() flop_pos = flop_pin.center()
bank_pos = vector(bank_pin.cx(),flop_pos.y) bank_pos = vector(bank_pin.cx(),flop_pos.y)
@ -1080,24 +1078,14 @@ class sram(design.design):
offset=bank_pos, offset=bank_pos,
rotate=90) rotate=90)
# Connect the output of the flops to the control pins # Connect the control pins as inputs
for i in range(3): for n in self.control_logic_inputs + ["clk"]:
flop_name = "dout[{}]".format(self.addr_size+i) self.copy_layout_pin(self.control_logic_inst, n.lower(), n)
ctrl_name = ["csb","web","oeb"][i]
flop_pin = self.addr_ctrl_dff_inst.get_pin(flop_name)
ctrl_pin = self.control_logic_inst.get_pin(ctrl_name)
flop_pos = flop_pin.center()
ctrl_pos = ctrl_pin.bc()
mid_pos = vector(ctrl_pos.x, flop_pos.y)
self.add_wire(("metal3","via2","metal2"),[flop_pos, mid_pos, ctrl_pos])
self.add_via_center(layers=("metal2","via2","metal3"),
offset=flop_pos,
rotate=90)
# Connect the clock between the flops and control module # Connect the clock between the flops and control module
# FIXME: Buffered clock should drive the flops, but then # FIXME: Buffered clock should drive the flops, but then
# it would change the setup time... # it would change the setup time...
flop_pin = self.addr_ctrl_dff_inst.get_pin("clk") flop_pin = self.addr_dff_inst.get_pin("clk")
ctrl_pin = self.control_logic_inst.get_pin("clk") ctrl_pin = self.control_logic_inst.get_pin("clk")
flop_pos = flop_pin.uc() flop_pos = flop_pin.uc()
ctrl_pos = ctrl_pin.bc() ctrl_pos = ctrl_pin.bc()
@ -1111,7 +1099,7 @@ class sram(design.design):
""" Route vdd for the control and dff array """ """ Route vdd for the control and dff array """
# Route the vdd rails to the LEFT # Route the vdd rails to the LEFT
modules = [ self.control_logic_inst, self.addr_ctrl_dff_inst] modules = [ self.control_logic_inst, self.addr_dff_inst]
for inst in modules: for inst in modules:
for vdd_pin in inst.get_pins("vdd"): for vdd_pin in inst.get_pins("vdd"):
if vdd_pin.layer != "metal1": if vdd_pin.layer != "metal1":
@ -1140,7 +1128,7 @@ class sram(design.design):
""" Route gnd for the control and dff array """ """ Route gnd for the control and dff array """
# Route the gnd rails to the LEFT # Route the gnd rails to the LEFT
modules = [ self.control_logic_inst, self.addr_ctrl_dff_inst] modules = [ self.control_logic_inst, self.addr_dff_inst]
for inst in modules: for inst in modules:
for gnd_pin in inst.get_pins("gnd"): for gnd_pin in inst.get_pins("gnd"):
if gnd_pin.layer != "metal1": if gnd_pin.layer != "metal1":

View File

@ -33,10 +33,9 @@ class multi_bank_test(openram_test):
a = bank.bank(word_size=4, num_words=64, words_per_row=4, num_banks=2, name="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 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="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
globals.end_openram() globals.end_openram()