mirror of https://github.com/VLSIDA/OpenRAM.git
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:
parent
f1560375fc
commit
648e57d195
|
|
@ -53,6 +53,7 @@ class bank(design.design):
|
|||
self.add_modules()
|
||||
self.create_modules()
|
||||
|
||||
|
||||
def create_layout(self):
|
||||
self.place_modules()
|
||||
self.setup_routing_constraints()
|
||||
|
|
@ -65,17 +66,22 @@ class bank(design.design):
|
|||
self.bank_center=self.offset_all_coordinates().scale(-1,-1)
|
||||
|
||||
self.DRC_LVS()
|
||||
|
||||
|
||||
|
||||
def add_pins(self):
|
||||
self.read_index = []
|
||||
self.port_id = []
|
||||
port_number = 0
|
||||
for port in range(OPTS.num_rw_ports):
|
||||
self.read_index.append("{}".format(port_number))
|
||||
self.port_id.append("rw")
|
||||
port_number += 1
|
||||
for port in range(OPTS.num_w_ports):
|
||||
self.port_id.append("w")
|
||||
port_number += 1
|
||||
for port in range(OPTS.num_r_ports):
|
||||
self.read_index.append("{}".format(port_number))
|
||||
self.port_id.append("r")
|
||||
port_number += 1
|
||||
|
||||
""" Adding pins for Bank module"""
|
||||
|
|
@ -94,14 +100,17 @@ class bank(design.design):
|
|||
if self.num_banks > 1:
|
||||
for port in range(self.total_ports):
|
||||
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):
|
||||
self.add_pin("w_en{0}".format(port), "INPUT")
|
||||
for pin in ["clk_buf_bar","clk_buf"]:
|
||||
self.add_pin(pin,"INPUT")
|
||||
for port in range(self.total_ports):
|
||||
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("gnd","GROUND")
|
||||
|
||||
|
||||
def route_layout(self):
|
||||
""" Create routing amoung the modules """
|
||||
self.route_central_bus()
|
||||
|
|
@ -118,6 +127,7 @@ class bank(design.design):
|
|||
self.route_bank_select()
|
||||
|
||||
self.route_vdd_gnd()
|
||||
|
||||
|
||||
def create_modules(self):
|
||||
""" Add modules. The order should not matter! """
|
||||
|
|
@ -155,10 +165,10 @@ class bank(design.design):
|
|||
self.place_row_decoder()
|
||||
self.place_wordline_driver()
|
||||
self.place_column_decoder()
|
||||
|
||||
|
||||
self.place_bank_select()
|
||||
|
||||
|
||||
|
||||
def compute_sizes(self):
|
||||
""" Computes the required sizes to create the bank """
|
||||
|
||||
|
|
@ -180,13 +190,25 @@ class bank(design.design):
|
|||
# Number of control lines in the bus
|
||||
self.num_control_lines = 4
|
||||
# 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.
|
||||
if self.num_banks > 1:
|
||||
self.control_signals = ["gated_"+str for str in self.input_control_signals]
|
||||
else:
|
||||
self.control_signals = self.input_control_signals
|
||||
self.control_signals = []
|
||||
for port in range(self.total_ports):
|
||||
if self.num_banks > 1:
|
||||
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)
|
||||
if self.col_addr_size>0:
|
||||
self.num_col_addr_lines = 2**self.col_addr_size
|
||||
|
|
@ -291,6 +313,7 @@ class bank(design.design):
|
|||
temp.append("gnd")
|
||||
self.connect_inst(temp)
|
||||
|
||||
|
||||
def place_bitcell_array(self):
|
||||
""" Placing Bitcell Array """
|
||||
self.bitcell_array_inst.place(vector(0,0))
|
||||
|
|
@ -307,9 +330,10 @@ class bank(design.design):
|
|||
for i in range(self.num_cols):
|
||||
temp.append(self.read_bl_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)
|
||||
|
||||
|
||||
def place_precharge_array(self):
|
||||
""" Placing Precharge """
|
||||
|
||||
|
|
@ -319,6 +343,7 @@ class bank(design.design):
|
|||
# The enclosure is for the well and the spacing is to the bitcell wells
|
||||
y_offset = self.bitcell_array.height + self.m2_gap
|
||||
self.precharge_array_inst[port].place(vector(0,y_offset))
|
||||
|
||||
|
||||
def create_column_mux_array(self):
|
||||
""" Creating Column Mux when words_per_row > 1 . """
|
||||
|
|
@ -342,6 +367,7 @@ class bank(design.design):
|
|||
temp.append("gnd")
|
||||
self.connect_inst(temp)
|
||||
|
||||
|
||||
def place_column_mux_array(self):
|
||||
""" Placing Column Mux when words_per_row > 1 . """
|
||||
if self.col_addr_size > 0:
|
||||
|
|
@ -353,6 +379,7 @@ class bank(design.design):
|
|||
for port in range(self.total_ports):
|
||||
y_offset = self.column_mux_height
|
||||
self.col_mux_array_inst[port].place(vector(0,y_offset).scale(-1,-1))
|
||||
|
||||
|
||||
def create_sense_amp_array(self):
|
||||
""" 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_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)
|
||||
|
||||
|
||||
def place_sense_amp_array(self):
|
||||
""" Placing Sense amp """
|
||||
|
||||
|
|
@ -382,6 +410,7 @@ class bank(design.design):
|
|||
for port in range(self.total_read):
|
||||
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))
|
||||
|
||||
|
||||
def create_write_driver_array(self):
|
||||
""" Creating Write Driver """
|
||||
|
|
@ -404,6 +433,7 @@ class bank(design.design):
|
|||
temp.extend([self.prefix+"w_en{0}".format(port), "vdd", "gnd"])
|
||||
self.connect_inst(temp)
|
||||
|
||||
|
||||
def place_write_driver_array(self):
|
||||
""" Placing Write Driver """
|
||||
|
||||
|
|
@ -412,7 +442,6 @@ class bank(design.design):
|
|||
y_offset = self.sense_amp_array.height + self.column_mux_height \
|
||||
+ self.m2_gap + self.write_driver_array.height
|
||||
self.write_driver_array_inst[port].place(vector(0,y_offset).scale(-1,-1))
|
||||
|
||||
|
||||
|
||||
def create_row_decoder(self):
|
||||
|
|
@ -431,6 +460,7 @@ class bank(design.design):
|
|||
temp.extend(["vdd", "gnd"])
|
||||
self.connect_inst(temp)
|
||||
|
||||
|
||||
def place_row_decoder(self):
|
||||
""" Place the hierarchical row decoder """
|
||||
|
||||
|
|
@ -459,11 +489,12 @@ class bank(design.design):
|
|||
temp.append("dec_out{0}[{1}]".format(port,row))
|
||||
for row in range(self.num_rows):
|
||||
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("gnd")
|
||||
self.connect_inst(temp)
|
||||
|
||||
|
||||
def place_wordline_driver(self):
|
||||
""" Place the Wordline Driver """
|
||||
|
||||
|
|
@ -505,6 +536,7 @@ class bank(design.design):
|
|||
temp.extend(["vdd", "gnd"])
|
||||
self.connect_inst(temp)
|
||||
|
||||
|
||||
def place_column_decoder(self):
|
||||
"""
|
||||
Place a 2:4 or 3:8 column address decoder.
|
||||
|
|
@ -532,12 +564,13 @@ class bank(design.design):
|
|||
mod=self.bank_select))
|
||||
|
||||
temp = []
|
||||
temp.extend(self.input_control_signals)
|
||||
temp.extend(self.input_control_signals[port])
|
||||
temp.append("bank_sel{}".format(port))
|
||||
temp.extend(self.control_signals)
|
||||
temp.extend(self.control_signals[port])
|
||||
temp.extend(["vdd", "gnd"])
|
||||
self.connect_inst(temp)
|
||||
|
||||
|
||||
def place_bank_select(self):
|
||||
""" Place the bank select logic. """
|
||||
|
||||
|
|
@ -548,9 +581,9 @@ class bank(design.design):
|
|||
for port in range(self.total_ports):
|
||||
x_off = -(self.row_decoder.width + self.central_bus_width + self.wordline_driver.width)
|
||||
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:
|
||||
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"])
|
||||
self.bank_select_pos = vector(x_off,y_off)
|
||||
self.bank_select_inst[port].place(self.bank_select_pos)
|
||||
|
|
@ -590,18 +623,31 @@ class bank(design.design):
|
|||
# Precharge has no gnd
|
||||
#if inst != self.precharge_array_inst[port]:
|
||||
self.copy_layout_pin(inst, "gnd")
|
||||
|
||||
|
||||
|
||||
def route_bank_select(self):
|
||||
""" Route the bank select logic. """
|
||||
|
||||
for port in range(self.total_ports):
|
||||
for input_name in self.input_control_signals+["bank_sel"]:
|
||||
self.copy_layout_pin(self.bank_select_inst[port], input_name)
|
||||
|
||||
for gated_name in self.control_signals:
|
||||
if self.port_id[port] == "rw":
|
||||
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"]
|
||||
|
||||
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
|
||||
out_pos = self.bank_select_inst[port].get_pin(gated_name).rc()
|
||||
bus_pos = vector(self.bus_xoffset[gated_name].x, out_pos.y)
|
||||
out_pos = self.bank_select_inst[port].get_pin(gated_bank_sel_signals[signal]).rc()
|
||||
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_via_center(layers=("metal2", "via2", "metal3"),
|
||||
offset=bus_pos,
|
||||
|
|
@ -619,7 +665,8 @@ class bank(design.design):
|
|||
After the modules are instantiated, find the dimensions for the
|
||||
control bus, power ring, etc.
|
||||
"""
|
||||
|
||||
# FIXME: calculate for multiport
|
||||
|
||||
#The minimum point is either the bottom of the address flops,
|
||||
#the column decoder (if there is one).
|
||||
write_driver_min_y_offset = self.write_driver_array_inst[0].by() - 3*self.m2_pitch
|
||||
|
|
@ -653,7 +700,6 @@ class bank(design.design):
|
|||
self.height = ur.y - ll.y
|
||||
self.width = ur.x - ll.x
|
||||
|
||||
|
||||
|
||||
def route_central_bus(self):
|
||||
""" Create the address, supply, and control signal central bus lines. """
|
||||
|
|
@ -662,16 +708,16 @@ class bank(design.design):
|
|||
# and control lines.
|
||||
# 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
|
||||
control_bus_offset = vector(-self.m2_pitch * self.num_control_lines - self.m2_width, self.min_y_offset)
|
||||
control_bus_length = self.max_y_offset - self.min_y_offset
|
||||
self.bus_xoffset = self.create_bus(layer="metal2",
|
||||
pitch=self.m2_pitch,
|
||||
offset=control_bus_offset,
|
||||
names=self.control_signals,
|
||||
length=control_bus_length,
|
||||
vertical=True,
|
||||
make_pins=(self.num_banks==1))
|
||||
|
||||
for port in range(self.total_ports):
|
||||
control_bus_offset = vector(-self.m2_pitch * self.num_control_lines - self.m2_width, self.min_y_offset)
|
||||
control_bus_length = self.max_y_offset - self.min_y_offset
|
||||
self.bus_xoffset = self.create_bus(layer="metal2",
|
||||
pitch=self.m2_pitch,
|
||||
offset=control_bus_offset,
|
||||
names=self.control_signals[port],
|
||||
length=control_bus_length,
|
||||
vertical=True,
|
||||
make_pins=(self.num_banks==1))
|
||||
|
||||
|
||||
def route_precharge_to_bitcell_array(self):
|
||||
|
|
@ -712,7 +758,8 @@ class bank(design.design):
|
|||
vector(bitcell_bl.x,yoffset), bitcell_bl])
|
||||
self.add_path("metal2",[col_mux_br, vector(col_mux_br.x,yoffset),
|
||||
vector(bitcell_br.x,yoffset), bitcell_br])
|
||||
|
||||
|
||||
|
||||
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 """
|
||||
|
||||
|
|
@ -736,61 +783,61 @@ class bank(design.design):
|
|||
vector(connect_bl.x,yoffset), connect_bl])
|
||||
self.add_path("metal2",[sense_amp_br, vector(sense_amp_br.x,yoffset),
|
||||
vector(connect_br.x,yoffset), connect_br])
|
||||
|
||||
|
||||
|
||||
|
||||
def route_sense_amp_out(self):
|
||||
""" Add pins for the sense amp output """
|
||||
|
||||
# FIXME: Update for multiport
|
||||
for bit in range(self.word_size):
|
||||
data_pin = self.sense_amp_array_inst[0].get_pin("data[{}]".format(bit))
|
||||
self.add_layout_pin_rect_center(text="dout0[{}]".format(bit),
|
||||
layer=data_pin.layer,
|
||||
offset=data_pin.center(),
|
||||
height=data_pin.height(),
|
||||
width=data_pin.width())
|
||||
|
||||
for port in range(self.total_read):
|
||||
for bit in range(self.word_size):
|
||||
data_pin = self.sense_amp_array_inst[port].get_pin("data[{}]".format(bit))
|
||||
self.add_layout_pin_rect_center(text="dout{0}[{1}]".format(self.read_index[port],bit),
|
||||
layer=data_pin.layer,
|
||||
offset=data_pin.center(),
|
||||
height=data_pin.height(),
|
||||
width=data_pin.width())
|
||||
|
||||
|
||||
def route_row_decoder(self):
|
||||
""" Routes the row decoder inputs and supplies """
|
||||
|
||||
# FIXME: Update for multiport
|
||||
# Create inputs for the row address lines
|
||||
for row in range(self.row_addr_size):
|
||||
addr_idx = row + self.col_addr_size
|
||||
decoder_name = "addr[{}]".format(row)
|
||||
addr_name = "addr0[{}]".format(addr_idx)
|
||||
self.copy_layout_pin(self.row_decoder_inst[0], decoder_name, addr_name)
|
||||
for port in range(self.total_ports):
|
||||
for row in range(self.row_addr_size):
|
||||
addr_idx = row + self.col_addr_size
|
||||
decoder_name = "addr[{}]".format(row)
|
||||
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):
|
||||
""" Connecting write driver """
|
||||
|
||||
for row in range(self.word_size):
|
||||
data_name = "data[{}]".format(row)
|
||||
din_name = "din0[{}]".format(row)
|
||||
self.copy_layout_pin(self.write_driver_array_inst[0], data_name, din_name)
|
||||
|
||||
for port in range(self.total_ports):
|
||||
for row in range(self.word_size):
|
||||
data_name = "data[{}]".format(row)
|
||||
din_name = "din{0}[{1}]".format(port,row)
|
||||
self.copy_layout_pin(self.write_driver_array_inst[port], data_name, din_name)
|
||||
|
||||
|
||||
def route_wordline_driver(self):
|
||||
""" 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 pre/post is to access the pin from "outside" the cell to avoid DRCs
|
||||
decoder_out_pos = self.row_decoder_inst[0].get_pin("decode[{}]".format(row)).rc()
|
||||
driver_in_pos = self.wordline_driver_inst[0].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])
|
||||
|
||||
# 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])
|
||||
|
||||
# The mid guarantees we exit the input cell to the right.
|
||||
driver_wl_pos = self.wordline_driver_inst[port].get_pin("wl[{}]".format(row)).rc()
|
||||
bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.total_wl_list[port]+"[{}]".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):
|
||||
|
|
@ -798,49 +845,45 @@ class bank(design.design):
|
|||
if not self.col_addr_size>0:
|
||||
return
|
||||
|
||||
|
||||
|
||||
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[0], "A", "addr0[0]")
|
||||
|
||||
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)
|
||||
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))
|
||||
|
||||
# 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()
|
||||
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)
|
||||
|
||||
|
||||
# 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])
|
||||
|
||||
# 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[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)):
|
||||
mux_name = "sel[{}]".format(i)
|
||||
mux_addr_pos = self.col_mux_array_inst[port].get_pin(mux_name).lc()
|
||||
|
||||
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):
|
||||
|
|
@ -894,30 +937,39 @@ class bank(design.design):
|
|||
# From control signal to the module pin
|
||||
# Connection from the central bus to the main control block crosses
|
||||
# pre-decoder and this connection is in metal3
|
||||
connection = []
|
||||
connection.append((self.prefix+"clk_buf_bar", self.precharge_array_inst[0].get_pin("en").lc()))
|
||||
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_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"
|
||||
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)
|
||||
write_inst = 0
|
||||
read_inst = 0
|
||||
|
||||
# Control lines for RW ports
|
||||
for port in range(self.total_ports):
|
||||
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"),
|
||||
offset=control_via_pos,
|
||||
rotate=90)
|
||||
|
||||
|
||||
def analytical_delay(self, slew, load):
|
||||
|
|
|
|||
|
|
@ -15,9 +15,11 @@ class bank_select(design.design):
|
|||
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)
|
||||
|
||||
self.port = port
|
||||
|
||||
self.create_netlist()
|
||||
if not OPTS.netlist_only:
|
||||
self.create_layout()
|
||||
|
|
@ -38,10 +40,17 @@ class bank_select(design.design):
|
|||
def add_pins(self):
|
||||
|
||||
# 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:
|
||||
# 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
|
||||
self.control_signals = ["gated_"+str for str in self.input_control_signals]
|
||||
|
||||
|
|
|
|||
|
|
@ -17,8 +17,16 @@ class bank_select_test(openram_test):
|
|||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
import bank_select
|
||||
|
||||
debug.info(1, "No column mux")
|
||||
a = bank_select.bank_select()
|
||||
debug.info(1, "No column mux, rw control logic")
|
||||
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)
|
||||
|
||||
globals.end_openram()
|
||||
|
|
|
|||
Loading…
Reference in New Issue