Altering bank select for port specific use. Altering bank select test to test different port types. Altering bank for control signal changes.

This commit is contained in:
Michael Timothy Grimes 2018-09-26 14:53:55 -07:00
parent f1560375fc
commit 648e57d195
3 changed files with 211 additions and 142 deletions

View File

@ -53,6 +53,7 @@ class bank(design.design):
self.add_modules() self.add_modules()
self.create_modules() self.create_modules()
def create_layout(self): def create_layout(self):
self.place_modules() self.place_modules()
self.setup_routing_constraints() self.setup_routing_constraints()
@ -66,16 +67,21 @@ class bank(design.design):
self.DRC_LVS() self.DRC_LVS()
def add_pins(self): def add_pins(self):
self.read_index = [] self.read_index = []
self.port_id = []
port_number = 0 port_number = 0
for port in range(OPTS.num_rw_ports): for port in range(OPTS.num_rw_ports):
self.read_index.append("{}".format(port_number)) self.read_index.append("{}".format(port_number))
self.port_id.append("rw")
port_number += 1 port_number += 1
for port in range(OPTS.num_w_ports): for port in range(OPTS.num_w_ports):
self.port_id.append("w")
port_number += 1 port_number += 1
for port in range(OPTS.num_r_ports): for port in range(OPTS.num_r_ports):
self.read_index.append("{}".format(port_number)) self.read_index.append("{}".format(port_number))
self.port_id.append("r")
port_number += 1 port_number += 1
""" Adding pins for Bank module""" """ Adding pins for Bank module"""
@ -94,14 +100,17 @@ class bank(design.design):
if self.num_banks > 1: if self.num_banks > 1:
for port in range(self.total_ports): for port in range(self.total_ports):
self.add_pin("bank_sel{}".format(port),"INPUT") self.add_pin("bank_sel{}".format(port),"INPUT")
self.add_pin("s_en", "INPUT") for port in range(self.total_read):
self.add_pin("s_en{0}".format(port), "INPUT")
for port in range(self.total_write): for port in range(self.total_write):
self.add_pin("w_en{0}".format(port), "INPUT") self.add_pin("w_en{0}".format(port), "INPUT")
for pin in ["clk_buf_bar","clk_buf"]: for port in range(self.total_ports):
self.add_pin(pin,"INPUT") self.add_pin("clk_buf_bar{0}".format(port),"INPUT")
self.add_pin("clk_buf{0}".format(port),"INPUT")
self.add_pin("vdd","POWER") self.add_pin("vdd","POWER")
self.add_pin("gnd","GROUND") self.add_pin("gnd","GROUND")
def route_layout(self): def route_layout(self):
""" Create routing amoung the modules """ """ Create routing amoung the modules """
self.route_central_bus() self.route_central_bus()
@ -119,6 +128,7 @@ class bank(design.design):
self.route_vdd_gnd() self.route_vdd_gnd()
def create_modules(self): def create_modules(self):
""" Add modules. The order should not matter! """ """ Add modules. The order should not matter! """
@ -156,9 +166,9 @@ class bank(design.design):
self.place_wordline_driver() self.place_wordline_driver()
self.place_column_decoder() self.place_column_decoder()
self.place_bank_select() self.place_bank_select()
def compute_sizes(self): def compute_sizes(self):
""" Computes the required sizes to create the bank """ """ Computes the required sizes to create the bank """
@ -180,13 +190,25 @@ class bank(design.design):
# Number of control lines in the bus # Number of control lines in the bus
self.num_control_lines = 4 self.num_control_lines = 4
# 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_buf", "clk_buf_bar", "w_en0", "s_en"] self.input_control_signals = []
port_num = 0
for port in range(OPTS.num_rw_ports):
self.input_control_signals.append(["clk_buf{}".format(port_num), "clk_buf_bar{}".format(port_num), "w_en{}".format(port_num), "s_en{}".format(port_num)])
port_num += 1
for port in range(OPTS.num_w_ports):
self.input_control_signals.append(["clk_buf{}".format(port_num), "clk_buf_bar{}".format(port_num), "w_en{}".format(port_num)])
port_num += 1
for port in range(OPTS.num_r_ports):
self.input_control_signals.append(["clk_buf{}".format(port_num), "clk_buf_bar{}".format(port_num), "s_en{}".format(port_num)])
port_num += 1
# These will be outputs of the gaters if this is multibank, if not, normal signals. # These will be outputs of the gaters if this is multibank, if not, normal signals.
if self.num_banks > 1: self.control_signals = []
self.control_signals = ["gated_"+str for str in self.input_control_signals] for port in range(self.total_ports):
else: if self.num_banks > 1:
self.control_signals = self.input_control_signals self.control_signals.append(["gated_"+str for str in self.input_control_signals[port]])
else:
self.control_signals.append(self.input_control_signals[port])
# 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
@ -291,6 +313,7 @@ class bank(design.design):
temp.append("gnd") temp.append("gnd")
self.connect_inst(temp) self.connect_inst(temp)
def place_bitcell_array(self): def place_bitcell_array(self):
""" Placing Bitcell Array """ """ Placing Bitcell Array """
self.bitcell_array_inst.place(vector(0,0)) self.bitcell_array_inst.place(vector(0,0))
@ -307,9 +330,10 @@ class bank(design.design):
for i in range(self.num_cols): for i in range(self.num_cols):
temp.append(self.read_bl_list[port]+"[{0}]".format(i)) temp.append(self.read_bl_list[port]+"[{0}]".format(i))
temp.append(self.read_br_list[port]+"[{0}]".format(i)) temp.append(self.read_br_list[port]+"[{0}]".format(i))
temp.extend([self.prefix+"clk_buf_bar", "vdd"]) temp.extend([self.prefix+"clk_buf_bar{0}".format(self.read_index[port]), "vdd"])
self.connect_inst(temp) self.connect_inst(temp)
def place_precharge_array(self): def place_precharge_array(self):
""" Placing Precharge """ """ Placing Precharge """
@ -320,6 +344,7 @@ class bank(design.design):
y_offset = self.bitcell_array.height + self.m2_gap y_offset = self.bitcell_array.height + self.m2_gap
self.precharge_array_inst[port].place(vector(0,y_offset)) self.precharge_array_inst[port].place(vector(0,y_offset))
def create_column_mux_array(self): def create_column_mux_array(self):
""" Creating Column Mux when words_per_row > 1 . """ """ Creating Column Mux when words_per_row > 1 . """
if self.col_addr_size == 0: if self.col_addr_size == 0:
@ -342,6 +367,7 @@ class bank(design.design):
temp.append("gnd") temp.append("gnd")
self.connect_inst(temp) self.connect_inst(temp)
def place_column_mux_array(self): def place_column_mux_array(self):
""" Placing Column Mux when words_per_row > 1 . """ """ Placing Column Mux when words_per_row > 1 . """
if self.col_addr_size > 0: if self.col_addr_size > 0:
@ -354,6 +380,7 @@ class bank(design.design):
y_offset = self.column_mux_height y_offset = self.column_mux_height
self.col_mux_array_inst[port].place(vector(0,y_offset).scale(-1,-1)) self.col_mux_array_inst[port].place(vector(0,y_offset).scale(-1,-1))
def create_sense_amp_array(self): def create_sense_amp_array(self):
""" Creating Sense amp """ """ Creating Sense amp """
@ -372,9 +399,10 @@ class bank(design.design):
temp.append(self.read_bl_list[port]+"_out[{0}]".format(bit)) temp.append(self.read_bl_list[port]+"_out[{0}]".format(bit))
temp.append(self.read_br_list[port]+"_out[{0}]".format(bit)) temp.append(self.read_br_list[port]+"_out[{0}]".format(bit))
temp.extend([self.prefix+"s_en", "vdd", "gnd"]) temp.extend([self.prefix+"s_en{}".format(port), "vdd", "gnd"])
self.connect_inst(temp) self.connect_inst(temp)
def place_sense_amp_array(self): def place_sense_amp_array(self):
""" Placing Sense amp """ """ Placing Sense amp """
@ -383,6 +411,7 @@ class bank(design.design):
y_offset = self.column_mux_height + self.sense_amp_array.height + self.m2_gap y_offset = self.column_mux_height + self.sense_amp_array.height + self.m2_gap
self.sense_amp_array_inst[port].place(vector(0,y_offset).scale(-1,-1)) self.sense_amp_array_inst[port].place(vector(0,y_offset).scale(-1,-1))
def create_write_driver_array(self): def create_write_driver_array(self):
""" Creating Write Driver """ """ Creating Write Driver """
@ -404,6 +433,7 @@ class bank(design.design):
temp.extend([self.prefix+"w_en{0}".format(port), "vdd", "gnd"]) temp.extend([self.prefix+"w_en{0}".format(port), "vdd", "gnd"])
self.connect_inst(temp) self.connect_inst(temp)
def place_write_driver_array(self): def place_write_driver_array(self):
""" Placing Write Driver """ """ Placing Write Driver """
@ -414,7 +444,6 @@ class bank(design.design):
self.write_driver_array_inst[port].place(vector(0,y_offset).scale(-1,-1)) self.write_driver_array_inst[port].place(vector(0,y_offset).scale(-1,-1))
def create_row_decoder(self): def create_row_decoder(self):
""" Create the hierarchical row decoder """ """ Create the hierarchical row decoder """
@ -431,6 +460,7 @@ class bank(design.design):
temp.extend(["vdd", "gnd"]) temp.extend(["vdd", "gnd"])
self.connect_inst(temp) self.connect_inst(temp)
def place_row_decoder(self): def place_row_decoder(self):
""" Place the hierarchical row decoder """ """ Place the hierarchical row decoder """
@ -459,11 +489,12 @@ class bank(design.design):
temp.append("dec_out{0}[{1}]".format(port,row)) temp.append("dec_out{0}[{1}]".format(port,row))
for row in range(self.num_rows): for row in range(self.num_rows):
temp.append(self.total_wl_list[port]+"[{0}]".format(row)) temp.append(self.total_wl_list[port]+"[{0}]".format(row))
temp.append(self.prefix+"clk_buf") temp.append(self.prefix+"clk_buf{0}".format(port))
temp.append("vdd") temp.append("vdd")
temp.append("gnd") temp.append("gnd")
self.connect_inst(temp) self.connect_inst(temp)
def place_wordline_driver(self): def place_wordline_driver(self):
""" Place the Wordline Driver """ """ Place the Wordline Driver """
@ -505,6 +536,7 @@ class bank(design.design):
temp.extend(["vdd", "gnd"]) temp.extend(["vdd", "gnd"])
self.connect_inst(temp) self.connect_inst(temp)
def place_column_decoder(self): def place_column_decoder(self):
""" """
Place a 2:4 or 3:8 column address decoder. Place a 2:4 or 3:8 column address decoder.
@ -532,12 +564,13 @@ class bank(design.design):
mod=self.bank_select)) mod=self.bank_select))
temp = [] temp = []
temp.extend(self.input_control_signals) temp.extend(self.input_control_signals[port])
temp.append("bank_sel{}".format(port)) temp.append("bank_sel{}".format(port))
temp.extend(self.control_signals) temp.extend(self.control_signals[port])
temp.extend(["vdd", "gnd"]) temp.extend(["vdd", "gnd"])
self.connect_inst(temp) self.connect_inst(temp)
def place_bank_select(self): def place_bank_select(self):
""" Place the bank select logic. """ """ Place the bank select logic. """
@ -548,9 +581,9 @@ class bank(design.design):
for port in range(self.total_ports): for port in range(self.total_ports):
x_off = -(self.row_decoder.width + self.central_bus_width + self.wordline_driver.width) x_off = -(self.row_decoder.width + self.central_bus_width + self.wordline_driver.width)
if self.col_addr_size > 0: if self.col_addr_size > 0:
y_off = min(self.col_decoder_inst[0].by(), self.col_mux_array_inst[0].by()) y_off = min(self.col_decoder_inst[port].by(), self.col_mux_array_inst[port].by())
else: else:
y_off = self.row_decoder_inst[0].by() y_off = self.row_decoder_inst[port].by()
y_off -= (self.bank_select.height + drc["well_to_well"]) y_off -= (self.bank_select.height + drc["well_to_well"])
self.bank_select_pos = vector(x_off,y_off) self.bank_select_pos = vector(x_off,y_off)
self.bank_select_inst[port].place(self.bank_select_pos) self.bank_select_inst[port].place(self.bank_select_pos)
@ -591,17 +624,30 @@ class bank(design.design):
#if inst != self.precharge_array_inst[port]: #if inst != self.precharge_array_inst[port]:
self.copy_layout_pin(inst, "gnd") self.copy_layout_pin(inst, "gnd")
def route_bank_select(self): def route_bank_select(self):
""" Route the bank select logic. """ """ Route the bank select logic. """
for port in range(self.total_ports): for port in range(self.total_ports):
for input_name in self.input_control_signals+["bank_sel"]: if self.port_id[port] == "rw":
self.copy_layout_pin(self.bank_select_inst[port], input_name) bank_sel_signals = ["clk_buf", "clk_buf_bar", "w_en", "s_en", "bank_sel"]
gated_bank_sel_signals = ["gated_clk_buf", "gated_clk_buf_bar", "gated_w_en", "gated_s_en"]
elif self.port_id[port] == "w":
bank_sel_signals = ["clk_buf", "clk_buf_bar", "w_en", "bank_sel"]
gated_bank_sel_signals = ["gated_clk_buf", "gated_clk_buf_bar", "gated_w_en"]
else:
bank_sel_signals = ["clk_buf", "clk_buf_bar", "s_en", "bank_sel"]
gated_bank_sel_signals = ["gated_clk_buf", "gated_clk_buf_bar", "gated_s_en"]
for gated_name in self.control_signals: copy_control_signals = self.input_control_signals[port]+["bank_sel{}".format(port)]
for signal in range(len(copy_control_signals)):
self.copy_layout_pin(self.bank_select_inst[port], bank_sel_signals[signal], copy_control_signals[signal])
for signal in range(len(gated_bank_sel_signals)):
# Connect the inverter output to the central bus # Connect the inverter output to the central bus
out_pos = self.bank_select_inst[port].get_pin(gated_name).rc() out_pos = self.bank_select_inst[port].get_pin(gated_bank_sel_signals[signal]).rc()
bus_pos = vector(self.bus_xoffset[gated_name].x, out_pos.y) name = self.control_signals[port][signal]
bus_pos = vector(self.bus_xoffset[name].x, out_pos.y)
self.add_path("metal3",[out_pos, bus_pos]) self.add_path("metal3",[out_pos, bus_pos])
self.add_via_center(layers=("metal2", "via2", "metal3"), self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=bus_pos, offset=bus_pos,
@ -619,6 +665,7 @@ class bank(design.design):
After the modules are instantiated, find the dimensions for the After the modules are instantiated, find the dimensions for the
control bus, power ring, etc. control bus, power ring, etc.
""" """
# FIXME: calculate for multiport
#The minimum point is either the bottom of the address flops, #The minimum point is either the bottom of the address flops,
#the column decoder (if there is one). #the column decoder (if there is one).
@ -654,7 +701,6 @@ class bank(design.design):
self.width = ur.x - ll.x self.width = ur.x - ll.x
def route_central_bus(self): def route_central_bus(self):
""" Create the address, supply, and control signal central bus lines. """ """ Create the address, supply, and control signal central bus lines. """
@ -662,16 +708,16 @@ class bank(design.design):
# and control 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_offset = vector(-self.m2_pitch * self.num_control_lines - self.m2_width, self.min_y_offset) for port in range(self.total_ports):
control_bus_length = self.max_y_offset - self.min_y_offset control_bus_offset = vector(-self.m2_pitch * self.num_control_lines - self.m2_width, self.min_y_offset)
self.bus_xoffset = self.create_bus(layer="metal2", control_bus_length = self.max_y_offset - self.min_y_offset
pitch=self.m2_pitch, self.bus_xoffset = self.create_bus(layer="metal2",
offset=control_bus_offset, pitch=self.m2_pitch,
names=self.control_signals, offset=control_bus_offset,
length=control_bus_length, names=self.control_signals[port],
vertical=True, length=control_bus_length,
make_pins=(self.num_banks==1)) vertical=True,
make_pins=(self.num_banks==1))
def route_precharge_to_bitcell_array(self): def route_precharge_to_bitcell_array(self):
@ -713,6 +759,7 @@ class bank(design.design):
self.add_path("metal2",[col_mux_br, vector(col_mux_br.x,yoffset), self.add_path("metal2",[col_mux_br, vector(col_mux_br.x,yoffset),
vector(bitcell_br.x,yoffset), bitcell_br]) vector(bitcell_br.x,yoffset), bitcell_br])
def route_sense_amp_to_col_mux_or_bitcell_array(self): def route_sense_amp_to_col_mux_or_bitcell_array(self):
""" Routing of BL and BR between sense_amp and column mux or bitcell array """ """ Routing of BL and BR between sense_amp and column mux or bitcell array """
@ -742,13 +789,14 @@ class bank(design.design):
""" Add pins for the sense amp output """ """ Add pins for the sense amp output """
# FIXME: Update for multiport # FIXME: Update for multiport
for bit in range(self.word_size): for port in range(self.total_read):
data_pin = self.sense_amp_array_inst[0].get_pin("data[{}]".format(bit)) for bit in range(self.word_size):
self.add_layout_pin_rect_center(text="dout0[{}]".format(bit), data_pin = self.sense_amp_array_inst[port].get_pin("data[{}]".format(bit))
layer=data_pin.layer, self.add_layout_pin_rect_center(text="dout{0}[{1}]".format(self.read_index[port],bit),
offset=data_pin.center(), layer=data_pin.layer,
height=data_pin.height(), offset=data_pin.center(),
width=data_pin.width()) height=data_pin.height(),
width=data_pin.width())
def route_row_decoder(self): def route_row_decoder(self):
@ -756,41 +804,40 @@ class bank(design.design):
# FIXME: Update for multiport # FIXME: Update for multiport
# Create inputs for the row address lines # Create inputs for the row address lines
for row in range(self.row_addr_size): for port in range(self.total_ports):
addr_idx = row + self.col_addr_size for row in range(self.row_addr_size):
decoder_name = "addr[{}]".format(row) addr_idx = row + self.col_addr_size
addr_name = "addr0[{}]".format(addr_idx) decoder_name = "addr[{}]".format(row)
self.copy_layout_pin(self.row_decoder_inst[0], decoder_name, addr_name) addr_name = "addr{0}[{1}]".format(port,addr_idx)
self.copy_layout_pin(self.row_decoder_inst[port], decoder_name, addr_name)
def route_write_driver(self): def route_write_driver(self):
""" Connecting write driver """ """ Connecting write driver """
for port in range(self.total_ports):
for row in range(self.word_size): for row in range(self.word_size):
data_name = "data[{}]".format(row) data_name = "data[{}]".format(row)
din_name = "din0[{}]".format(row) din_name = "din{0}[{1}]".format(port,row)
self.copy_layout_pin(self.write_driver_array_inst[0], data_name, din_name) self.copy_layout_pin(self.write_driver_array_inst[port], data_name, din_name)
def route_wordline_driver(self): def route_wordline_driver(self):
""" Connecting Wordline driver output to Bitcell WL connection """ """ Connecting Wordline driver output to Bitcell WL connection """
for port in range(self.total_ports):
for row in range(self.num_rows):
# The pre/post is to access the pin from "outside" the cell to avoid DRCs
decoder_out_pos = self.row_decoder_inst[port].get_pin("decode[{}]".format(row)).rc()
driver_in_pos = self.wordline_driver_inst[port].get_pin("in[{}]".format(row)).lc()
mid1 = decoder_out_pos.scale(0.5,1)+driver_in_pos.scale(0.5,0)
mid2 = decoder_out_pos.scale(0.5,0)+driver_in_pos.scale(0.5,1)
self.add_path("metal1", [decoder_out_pos, mid1, mid2, driver_in_pos])
for row in range(self.num_rows): # The mid guarantees we exit the input cell to the right.
# The pre/post is to access the pin from "outside" the cell to avoid DRCs driver_wl_pos = self.wordline_driver_inst[port].get_pin("wl[{}]".format(row)).rc()
decoder_out_pos = self.row_decoder_inst[0].get_pin("decode[{}]".format(row)).rc() bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.total_wl_list[port]+"[{}]".format(row)).lc()
driver_in_pos = self.wordline_driver_inst[0].get_pin("in[{}]".format(row)).lc() mid1 = driver_wl_pos.scale(0.5,1)+bitcell_wl_pos.scale(0.5,0)
mid1 = decoder_out_pos.scale(0.5,1)+driver_in_pos.scale(0.5,0) mid2 = driver_wl_pos.scale(0.5,0)+bitcell_wl_pos.scale(0.5,1)
mid2 = decoder_out_pos.scale(0.5,0)+driver_in_pos.scale(0.5,1) self.add_path("metal1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos])
self.add_path("metal1", [decoder_out_pos, mid1, mid2, driver_in_pos])
# The mid guarantees we exit the input cell to the right.
driver_wl_pos = self.wordline_driver_inst[0].get_pin("wl[{}]".format(row)).rc()
bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.total_wl_list[0]+"[{}]".format(row)).lc()
mid1 = driver_wl_pos.scale(0.5,1)+bitcell_wl_pos.scale(0.5,0)
mid2 = driver_wl_pos.scale(0.5,0)+bitcell_wl_pos.scale(0.5,1)
self.add_path("metal1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos])
def route_column_address_lines(self): def route_column_address_lines(self):
@ -798,49 +845,45 @@ class bank(design.design):
if not self.col_addr_size>0: if not self.col_addr_size>0:
return return
for port in range(self.total_ports):
if self.col_addr_size == 1:
# Connect to sel[0] and sel[1]
decode_names = ["Zb", "Z"]
# The Address LSB
self.copy_layout_pin(self.col_decoder_inst[port], "A", "addr{}[0]".format(port))
elif self.col_addr_size > 1:
decode_names = []
for i in range(self.num_col_addr_lines):
decode_names.append("out[{}]".format(i))
for i in range(self.col_addr_size):
decoder_name = "in[{}]".format(i)
addr_name = "addr{0}[{1}]".format(port,i)
self.copy_layout_pin(self.col_decoder_inst[port], decoder_name, addr_name)
if self.col_addr_size == 1: # This will do a quick "river route" on two layers.
# When above the top select line it will offset "inward" again to prevent conflicts.
# Connect to sel[0] and sel[1] # This could be done on a single layer, but we follow preferred direction rules for later routing.
decode_names = ["Zb", "Z"] top_y_offset = self.col_mux_array_inst[port].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)):
# The Address LSB mux_name = "sel[{}]".format(i)
self.copy_layout_pin(self.col_decoder_inst[0], "A", "addr0[0]") mux_addr_pos = self.col_mux_array_inst[port].get_pin(mux_name).lc()
elif self.col_addr_size > 1:
decode_names = []
for i in range(self.num_col_addr_lines):
decode_names.append("out[{}]".format(i))
for i in range(self.col_addr_size):
decoder_name = "in[{}]".format(i)
addr_name = "addr0[{}]".format(i)
self.copy_layout_pin(self.col_decoder_inst[0], decoder_name, addr_name)
# 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[0].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[0].get_pin(mux_name).lc()
decode_out_pos = self.col_decoder_inst[0].get_pin(decode_name).center()
# To get to the edge of the decoder and one track out
delta_offset = self.col_decoder_inst[0].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])
self.add_path("metal1",[decode_out_pos, mid1_pos, mid2_pos, mux_addr_pos])
decode_out_pos = self.col_decoder_inst[port].get_pin(decode_name).center()
# To get to the edge of the decoder and one track out
delta_offset = self.col_decoder_inst[port].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])
self.add_path("metal1",[decode_out_pos, mid1_pos, mid2_pos, mux_addr_pos])
def add_lvs_correspondence_points(self): def add_lvs_correspondence_points(self):
@ -894,31 +937,40 @@ class bank(design.design):
# From control signal to the module pin # From control signal to the module pin
# Connection from the central bus to the main control block crosses # Connection from the central bus to the main control block crosses
# pre-decoder and this connection is in metal3 # pre-decoder and this connection is in metal3
connection = [] write_inst = 0
connection.append((self.prefix+"clk_buf_bar", self.precharge_array_inst[0].get_pin("en").lc())) read_inst = 0
connection.append((self.prefix+"w_en0", self.write_driver_array_inst[0].get_pin("en").lc()))
connection.append((self.prefix+"s_en", self.sense_amp_array_inst[0].get_pin("en").lc()))
for (control_signal, pin_pos) in connection: # Control lines for RW ports
control_pos = vector(self.bus_xoffset[control_signal].x ,pin_pos.y) for port in range(self.total_ports):
self.add_path("metal1", [control_pos, pin_pos]) connection = []
if (self.port_id[port] == "rw") or (self.port_id[port] == "r"):
connection.append((self.prefix+"clk_buf_bar{}".format(port), self.precharge_array_inst[read_inst].get_pin("en").lc()))
if (self.port_id[port] == "rw") or (self.port_id[port] == "w"):
connection.append((self.prefix+"w_en{}".format(port), self.write_driver_array_inst[write_inst].get_pin("en").lc()))
write_inst += 1
if (self.port_id[port] == "rw") or (self.port_id[port] == "r"):
connection.append((self.prefix+"s_en{}".format(port), self.sense_amp_array_inst[read_inst].get_pin("en").lc()))
read_inst += 1
for (control_signal, pin_pos) in connection:
control_pos = vector(self.bus_xoffset[control_signal].x ,pin_pos.y)
self.add_path("metal1", [control_pos, pin_pos])
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=control_pos,
rotate=90)
# clk to wordline_driver
control_signal = self.prefix+"clk_buf{}".format(port)
pin_pos = self.wordline_driver_inst[port].get_pin("en").uc()
mid_pos = pin_pos + vector(0,self.m1_pitch)
control_x_offset = self.bus_xoffset[control_signal].x
control_pos = vector(control_x_offset + self.m1_width, mid_pos.y)
self.add_wire(("metal1","via1","metal2"),[pin_pos, mid_pos, control_pos])
control_via_pos = vector(control_x_offset, mid_pos.y)
self.add_via_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=control_pos, offset=control_via_pos,
rotate=90) rotate=90)
# clk to wordline_driver
control_signal = self.prefix+"clk_buf"
pin_pos = self.wordline_driver_inst[0].get_pin("en").uc()
mid_pos = pin_pos + vector(0,self.m1_pitch)
control_x_offset = self.bus_xoffset[control_signal].x
control_pos = vector(control_x_offset + self.m1_width, mid_pos.y)
self.add_wire(("metal1","via1","metal2"),[pin_pos, mid_pos, control_pos])
control_via_pos = vector(control_x_offset, mid_pos.y)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=control_via_pos,
rotate=90)
def analytical_delay(self, slew, load): def analytical_delay(self, slew, load):
""" return analytical delay of the bank""" """ return analytical delay of the bank"""

View File

@ -15,9 +15,11 @@ class bank_select(design.design):
banks are created in upper level SRAM module banks are created in upper level SRAM module
""" """
def __init__(self, name="bank_select"): def __init__(self, name="bank_select", port="rw"):
design.design.__init__(self, name) design.design.__init__(self, name)
self.port = port
self.create_netlist() self.create_netlist()
if not OPTS.netlist_only: if not OPTS.netlist_only:
self.create_layout() self.create_layout()
@ -38,10 +40,17 @@ class bank_select(design.design):
def add_pins(self): def add_pins(self):
# Number of control lines in the bus # Number of control lines in the bus
self.num_control_lines = 4 if self.port == "rw":
self.num_control_lines = 4
else:
self.num_control_lines = 3
# The order of the control signals on the control bus: # The order of the control signals on the control bus:
# FIXME: Update for multiport (these names are not right) # FIXME: Update for multiport (these names are not right)
self.input_control_signals = ["clk_buf", "clk_buf_bar", "w_en0", "s_en"] self.input_control_signals = ["clk_buf", "clk_buf_bar"]
if (self.port == "rw") or (self.port == "w"):
self.input_control_signals.append("w_en")
if (self.port == "rw") or (self.port == "r"):
self.input_control_signals.append("s_en")
# These will be outputs of the gaters if this is multibank # These will be outputs of the gaters if this is multibank
self.control_signals = ["gated_"+str for str in self.input_control_signals] self.control_signals = ["gated_"+str for str in self.input_control_signals]

12
compiler/tests/19_bank_select_test.py Executable file → Normal file
View File

@ -17,8 +17,16 @@ class bank_select_test(openram_test):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
import bank_select import bank_select
debug.info(1, "No column mux") debug.info(1, "No column mux, rw control logic")
a = bank_select.bank_select() a = bank_select.bank_select(port="rw")
self.local_check(a)
debug.info(1, "No column mux, w control logic")
a = bank_select.bank_select(port="w")
self.local_check(a)
debug.info(1, "No column mux, r control logic")
a = bank_select.bank_select(port="r")
self.local_check(a) self.local_check(a)
globals.end_openram() globals.end_openram()