Editting top level netlist for multiport. Now there are multiple control logic modules, one per port. Since diffent ports are driven by different clocks, also separating dff modules, one per port.

This commit is contained in:
Michael Timothy Grimes 2018-09-26 19:10:24 -07:00
parent 648e57d195
commit 1ca0154027
6 changed files with 320 additions and 262 deletions

View File

@ -101,7 +101,7 @@ class bank(design.design):
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")
for port in range(self.total_read): for port in range(self.total_read):
self.add_pin("s_en{0}".format(port), "INPUT") self.add_pin("s_en{0}".format(self.read_index[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 port in range(self.total_ports): for port in range(self.total_ports):
@ -399,7 +399,7 @@ 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{}".format(port), "vdd", "gnd"]) temp.extend([self.prefix+"s_en{}".format(self.read_index[port]), "vdd", "gnd"])
self.connect_inst(temp) self.connect_inst(temp)

View File

@ -20,8 +20,9 @@ class control_logic(design.design):
def __init__(self, num_rows, port="rw"): def __init__(self, num_rows, port="rw"):
""" Constructor """ """ Constructor """
design.design.__init__(self, "control_logic") name = "control_logic_" + port
debug.info(1, "Creating {}".format(self.name)) design.design.__init__(self, name)
debug.info(1, "Creating {}".format(name))
self.num_rows = num_rows self.num_rows = num_rows
self.port = port self.port = port
@ -95,7 +96,7 @@ class control_logic(design.design):
delay_stages = 4 # Must be non-inverting delay_stages = 4 # Must be non-inverting
delay_fanout = 3 # This can be anything >=2 delay_fanout = 3 # This can be anything >=2
bitcell_loads = int(math.ceil(self.num_rows / 5.0)) bitcell_loads = int(math.ceil(self.num_rows / 5.0))
self.replica_bitline = replica_bitline(delay_stages, delay_fanout, bitcell_loads) self.replica_bitline = replica_bitline(delay_stages, delay_fanout, bitcell_loads, name="replica_bitline_"+self.port)
self.add_mod(self.replica_bitline) self.add_mod(self.replica_bitline)

View File

@ -13,8 +13,12 @@ class delay_chain(design.design):
Usually, this will be constant, but it could have varied fanout. Usually, this will be constant, but it could have varied fanout.
""" """
unique_id = 1
def __init__(self, fanout_list, name="delay_chain"): def __init__(self, fanout_list, name="delay_chain"):
"""init function""" """init function"""
name = name+"_{}".format(delay_chain.unique_id)
delay_chain.unique_id += 1
design.design.__init__(self, name) design.design.__init__(self, name)
# Two fanouts are needed so that we can route the vdd/gnd connections # Two fanouts are needed so that we can route the vdd/gnd connections

View File

@ -81,8 +81,8 @@ class replica_bitline(design.design):
""" Add the modules for later usage """ """ Add the modules for later usage """
from importlib import reload from importlib import reload
g = reload(__import__(OPTS.delay_chain)) #g = reload(__import__(OPTS.delay_chain))
self.mod_delay_chain = getattr(g, OPTS.delay_chain) #self.mod_delay_chain = getattr(g, OPTS.delay_chain)
g = reload(__import__(OPTS.replica_bitcell)) g = reload(__import__(OPTS.replica_bitcell))
self.mod_replica_bitcell = getattr(g, OPTS.replica_bitcell) self.mod_replica_bitcell = getattr(g, OPTS.replica_bitcell)
@ -95,7 +95,8 @@ class replica_bitline(design.design):
self.add_mod(self.rbl) self.add_mod(self.rbl)
# FIXME: The FO and depth of this should be tuned # FIXME: The FO and depth of this should be tuned
self.delay_chain = self.mod_delay_chain([self.delay_fanout]*self.delay_stages) from delay_chain import delay_chain
self.delay_chain = delay_chain([self.delay_fanout]*self.delay_stages)
self.add_mod(self.delay_chain) self.add_mod(self.delay_chain)
self.inv = pinv() self.inv = pinv()

View File

@ -57,14 +57,15 @@ class sram_1bank(sram_base):
# the sense amps/column mux and cell array) # the sense amps/column mux and cell array)
# The x-coordinate is placed to allow a single clock wire (plus an extra pitch) # The x-coordinate is placed to allow a single clock wire (plus an extra pitch)
# up to the row address DFFs. # up to the row address DFFs.
for port in range(self.total_ports):
control_pos = vector(-self.control_logic.width - 2*self.m2_pitch, control_pos = vector(-self.control_logic.width - 2*self.m2_pitch,
self.bank.bank_center.y - self.control_logic.control_logic_center.y) self.bank.bank_center.y - self.control_logic.control_logic_center.y)
self.control_logic_inst.place(control_pos) self.control_logic_inst[port].place(control_pos)
# The row address bits are placed above the control logic aligned on the right. # The row address bits are placed above the control logic aligned on the right.
row_addr_pos = vector(self.control_logic_inst.rx() - self.row_addr_dff.width, row_addr_pos = vector(self.control_logic_inst[0].rx() - self.row_addr_dff.width,
self.control_logic_inst.uy()) self.control_logic_inst[0].uy())
self.row_addr_dff_inst.place(row_addr_pos) self.row_addr_dff_inst[port].place(row_addr_pos)
# This is M2 pitch even though it is on M1 to help stem via spacings on the trunk # This is M2 pitch even though it is on M1 to help stem via spacings on the trunk
data_gap = -self.m2_pitch*(self.word_size+1) data_gap = -self.m2_pitch*(self.word_size+1)
@ -74,7 +75,7 @@ class sram_1bank(sram_base):
if self.col_addr_dff: if self.col_addr_dff:
col_addr_pos = vector(self.bank.bank_center.x - self.col_addr_dff.width - self.bank.central_bus_width, col_addr_pos = vector(self.bank.bank_center.x - self.col_addr_dff.width - self.bank.central_bus_width,
data_gap - self.col_addr_dff.height) data_gap - self.col_addr_dff.height)
self.col_addr_dff_inst.place(col_addr_pos) self.col_addr_dff_inst[port].place(col_addr_pos)
# Add the data flops below the bank to the right of the center of bank: # Add the data flops below the bank to the right of the center of bank:
# This relies on the center point of the bank: # This relies on the center point of the bank:
@ -83,7 +84,7 @@ class sram_1bank(sram_base):
# sense amps. # sense amps.
data_pos = vector(self.bank.bank_center.x, data_pos = vector(self.bank.bank_center.x,
data_gap - self.data_dff.height) data_gap - self.data_dff.height)
self.data_dff_inst.place(data_pos) self.data_dff_inst[port].place(data_pos)
# two supply rails are already included in the bank, so just 2 here. # two supply rails are already included in the bank, so just 2 here.
# self.width = self.bank.width + self.control_logic.width + 2*self.supply_rail_pitch # self.width = self.bank.width + self.control_logic.width + 2*self.supply_rail_pitch
@ -93,24 +94,23 @@ class sram_1bank(sram_base):
""" """
Add the top-level pins for a single bank SRAM with control. Add the top-level pins for a single bank SRAM with control.
""" """
for port in range(self.total_ports):
# Connect the control pins as inputs # Connect the control pins as inputs
for n in self.control_logic_inputs + ["clk"]: for signal in self.control_logic_inputs[port] + ["clk"]:
self.copy_layout_pin(self.control_logic_inst, n) self.copy_layout_pin(self.control_logic_inst[port], signal, signal+"{}".format(port))
for i in range(self.word_size): for bit in range(self.word_size):
dout_name = "dout0[{}]".format(i) self.copy_layout_pin(self.bank_inst, "dout{0}[{1}]".format(port,bit), "DOUT{0}[{1}]".format(port,bit))
self.copy_layout_pin(self.bank_inst, dout_name, "DOUT0[{}]".format(i))
# Lower address bits # Lower address bits
for i in range(self.col_addr_size): for bit in range(self.col_addr_size):
self.copy_layout_pin(self.col_addr_dff_inst, "din[{}]".format(i),"ADDR0[{}]".format(i)) self.copy_layout_pin(self.col_addr_dff_inst[port], "din[{}]".format(bit),"ADDR{0}[{1}]".format(port,bit))
# Upper address bits # Upper address bits
for i in range(self.row_addr_size): for bit in range(self.row_addr_size):
self.copy_layout_pin(self.row_addr_dff_inst, "din[{}]".format(i),"ADDR0[{}]".format(i+self.col_addr_size)) self.copy_layout_pin(self.row_addr_dff_inst[port], "din[{}]".format(bit),"ADDR{0}[{1}]".format(port,bit+self.col_addr_size))
for i in range(self.word_size): for bit in range(self.word_size):
din_name = "din[{}]".format(i) self.copy_layout_pin(self.data_dff_inst[port], "din[{}]".format(bit), "DIN{0}[{1}]".format(port,bit))
self.copy_layout_pin(self.data_dff_inst, din_name, "DIN0[{}]".format(i))
def route(self): def route(self):
""" Route a single bank SRAM """ """ Route a single bank SRAM """
@ -134,35 +134,36 @@ class sram_1bank(sram_base):
""" Route the clock network """ """ Route the clock network """
# This is the actual input to the SRAM # This is the actual input to the SRAM
self.copy_layout_pin(self.control_logic_inst, "clk") for port in range(self.total_ports):
self.copy_layout_pin(self.control_logic_inst[port], "clk", "clk{}".format(port))
# Connect all of these clock pins to the clock in the central bus # Connect all of these clock pins to the clock in the central bus
# This is something like a "spine" clock distribution. The two spines # This is something like a "spine" clock distribution. The two spines
# are clk_buf and clk_buf_bar # are clk_buf and clk_buf_bar
bank_clk_buf_pin = self.bank_inst.get_pin("clk_buf") bank_clk_buf_pin = self.bank_inst.get_pin("clk_buf{}".format(port))
bank_clk_buf_pos = bank_clk_buf_pin.center() bank_clk_buf_pos = bank_clk_buf_pin.center()
bank_clk_buf_bar_pin = self.bank_inst.get_pin("clk_buf_bar") bank_clk_buf_bar_pin = self.bank_inst.get_pin("clk_buf_bar{}".format(port))
bank_clk_buf_bar_pos = bank_clk_buf_bar_pin.center() bank_clk_buf_bar_pos = bank_clk_buf_bar_pin.center()
if self.col_addr_dff: if self.col_addr_dff:
dff_clk_pin = self.col_addr_dff_inst.get_pin("clk") dff_clk_pin = self.col_addr_dff_inst[port].get_pin("clk")
dff_clk_pos = dff_clk_pin.center() dff_clk_pos = dff_clk_pin.center()
mid_pos = vector(bank_clk_buf_pos.x, dff_clk_pos.y) mid_pos = vector(bank_clk_buf_pos.x, dff_clk_pos.y)
self.add_wire(("metal3","via2","metal2"),[dff_clk_pos, mid_pos, bank_clk_buf_pos]) self.add_wire(("metal3","via2","metal2"),[dff_clk_pos, mid_pos, bank_clk_buf_pos])
data_dff_clk_pin = self.data_dff_inst.get_pin("clk") data_dff_clk_pin = self.data_dff_inst[port].get_pin("clk")
data_dff_clk_pos = data_dff_clk_pin.center() data_dff_clk_pos = data_dff_clk_pin.center()
mid_pos = vector(bank_clk_buf_pos.x, data_dff_clk_pos.y) mid_pos = vector(bank_clk_buf_pos.x, data_dff_clk_pos.y)
self.add_wire(("metal3","via2","metal2"),[data_dff_clk_pos, mid_pos, bank_clk_buf_pos]) self.add_wire(("metal3","via2","metal2"),[data_dff_clk_pos, mid_pos, bank_clk_buf_pos])
# This uses a metal2 track to the right of the control/row addr DFF # This uses a metal2 track to the right of the control/row addr DFF
# to route vertically. # to route vertically.
control_clk_buf_pin = self.control_logic_inst.get_pin("clk_buf") control_clk_buf_pin = self.control_logic_inst[port].get_pin("clk_buf")
control_clk_buf_pos = control_clk_buf_pin.rc() control_clk_buf_pos = control_clk_buf_pin.rc()
row_addr_clk_pin = self.row_addr_dff_inst.get_pin("clk") row_addr_clk_pin = self.row_addr_dff_inst[port].get_pin("clk")
row_addr_clk_pos = row_addr_clk_pin.rc() row_addr_clk_pos = row_addr_clk_pin.rc()
mid1_pos = vector(self.row_addr_dff_inst.rx() + self.m2_pitch, mid1_pos = vector(self.row_addr_dff_inst[port].rx() + self.m2_pitch,
row_addr_clk_pos.y) row_addr_clk_pos.y)
mid2_pos = vector(mid1_pos.x, mid2_pos = vector(mid1_pos.x,
control_clk_buf_pos.y) control_clk_buf_pos.y)
@ -174,12 +175,14 @@ class sram_1bank(sram_base):
""" Propagate all vdd/gnd pins up to this level for all modules """ """ Propagate all vdd/gnd pins up to this level for all modules """
# These are the instances that every bank has # These are the instances that every bank has
top_instances = [self.bank_inst, top_instances = [self.bank_inst]
self.row_addr_dff_inst, for port in range(self.total_write):
self.data_dff_inst, top_instances.append(self.data_dff_inst[port])
self.control_logic_inst] for port in range(self.total_ports):
top_instances.append(self.row_addr_dff_inst[port])
top_instances.append(self.control_logic_inst[port])
if self.col_addr_dff: if self.col_addr_dff:
top_instances.append(self.col_addr_dff_inst) top_instances.append(self.col_addr_dff_inst[port])
for inst in top_instances: for inst in top_instances:
@ -190,12 +193,14 @@ class sram_1bank(sram_base):
""" Propagate all vdd/gnd pins up to this level for all modules """ """ Propagate all vdd/gnd pins up to this level for all modules """
# These are the instances that every bank has # These are the instances that every bank has
top_instances = [self.bank_inst, top_instances = [self.bank_inst]
self.row_addr_dff_inst, for port in range(self.total_write):
self.data_dff_inst, top_instances.append(self.data_dff_inst[port])
self.control_logic_inst] for port in range(self.total_ports):
top_instances.append(self.row_addr_dff_inst[port])
top_instances.append(self.control_logic_inst[port])
if self.col_addr_dff: if self.col_addr_dff:
top_instances.append(self.col_addr_dff_inst) top_instances.append(self.col_addr_dff_inst[port])
# for inst in top_instances: # for inst in top_instances:
@ -266,9 +271,10 @@ class sram_1bank(sram_base):
def route_control_logic(self): def route_control_logic(self):
""" Route the outputs from the control logic module """ """ Route the outputs from the control logic module """
for n in self.control_logic_outputs: for port in range(self.total_ports):
src_pin = self.control_logic_inst.get_pin(n) for signal in self.control_logic_outputs[port]:
dest_pin = self.bank_inst.get_pin(n) src_pin = self.control_logic_inst[port].get_pin(signal)
dest_pin = self.bank_inst.get_pin(signal+"{}".format(port))
self.connect_rail_from_left_m2m3(src_pin, dest_pin) self.connect_rail_from_left_m2m3(src_pin, dest_pin)
self.add_via_center(layers=("metal1","via1","metal2"), self.add_via_center(layers=("metal1","via1","metal2"),
offset=src_pin.rc(), offset=src_pin.rc(),
@ -277,10 +283,11 @@ class sram_1bank(sram_base):
def route_row_addr_dff(self): def route_row_addr_dff(self):
""" Connect the output of the row flops to the bank pins """ """ Connect the output of the row flops to the bank pins """
for i in range(self.row_addr_size): for port in range(self.total_ports):
flop_name = "dout[{}]".format(i) for bit in range(self.row_addr_size):
bank_name = "addr0[{}]".format(i+self.col_addr_size) flop_name = "dout[{}]".format(bit)
flop_pin = self.row_addr_dff_inst.get_pin(flop_name) bank_name = "addr{0}[{1}]".format(port,bit+self.col_addr_size)
flop_pin = self.row_addr_dff_inst[port].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 = bank_pin.center() bank_pos = bank_pin.center()
@ -292,19 +299,19 @@ class sram_1bank(sram_base):
def route_col_addr_dff(self): def route_col_addr_dff(self):
""" Connect the output of the row flops to the bank pins """ """ Connect the output of the row flops to the bank pins """
for port in range(self.total_ports):
bus_names = ["addr[{}]".format(x) for x in range(self.col_addr_size)] bus_names = ["addr[{}]".format(x) for x in range(self.col_addr_size)]
col_addr_bus_offsets = self.create_horizontal_bus(layer="metal1", col_addr_bus_offsets = self.create_horizontal_bus(layer="metal1",
pitch=self.m1_pitch, pitch=self.m1_pitch,
offset=self.col_addr_dff_inst.ul() + vector(0, self.m1_pitch), offset=self.col_addr_dff_inst[port].ul() + vector(0, self.m1_pitch),
names=bus_names, names=bus_names,
length=self.col_addr_dff_inst.width) length=self.col_addr_dff_inst[port].width)
dff_names = ["dout[{}]".format(x) for x in range(self.col_addr_size)] dff_names = ["dout[{}]".format(x) for x in range(self.col_addr_size)]
data_dff_map = zip(dff_names, bus_names) data_dff_map = zip(dff_names, bus_names)
self.connect_horizontal_bus(data_dff_map, self.col_addr_dff_inst, col_addr_bus_offsets) self.connect_horizontal_bus(data_dff_map, self.col_addr_dff_inst[port], col_addr_bus_offsets)
bank_names = ["addr0[{}]".format(x) for x in range(self.col_addr_size)] bank_names = ["addr{0}[{1}]".format(port,x) for x in range(self.col_addr_size)]
data_bank_map = zip(bank_names, bus_names) data_bank_map = zip(bank_names, bus_names)
self.connect_horizontal_bus(data_bank_map, self.bank_inst, col_addr_bus_offsets) self.connect_horizontal_bus(data_bank_map, self.bank_inst, col_addr_bus_offsets)
@ -312,13 +319,14 @@ class sram_1bank(sram_base):
def route_data_dff(self): def route_data_dff(self):
""" Connect the output of the data flops to the write driver """ """ Connect the output of the data flops to the write driver """
# This is where the channel will start (y-dimension at least) # This is where the channel will start (y-dimension at least)
offset = self.data_dff_inst.ul() + vector(0, self.m1_pitch) for port in range(self.total_write):
offset = self.data_dff_inst[port].ul() + vector(0, self.m1_pitch)
dff_names = ["dout[{}]".format(x) for x in range(self.word_size)] dff_names = ["dout[{}]".format(x) for x in range(self.word_size)]
bank_names = ["din0[{}]".format(x) for x in range(self.word_size)] bank_names = ["din{0}[{1}]".format(port,x) for x in range(self.word_size)]
route_map = list(zip(bank_names, dff_names)) route_map = list(zip(bank_names, dff_names))
dff_pins = {key: self.data_dff_inst.get_pin(key) for key in dff_names } dff_pins = {key: self.data_dff_inst[port].get_pin(key) for key in dff_names }
bank_pins = {key: self.bank_inst.get_pin(key) for key in bank_names } bank_pins = {key: self.bank_inst.get_pin(key) for key in bank_names }
# Combine the dff and bank pins into a single dictionary of pin name to pin. # Combine the dff and bank pins into a single dictionary of pin name to pin.
all_pins = {**dff_pins, **bank_pins} all_pins = {**dff_pins, **bank_pins}
@ -333,8 +341,8 @@ class sram_1bank(sram_base):
will show these as ports in the extracted netlist. will show these as ports in the extracted netlist.
""" """
for n in self.control_logic_outputs: for n in self.control_logic_outputs[0]:
pin = self.control_logic_inst.get_pin(n) pin = self.control_logic_inst[0].get_pin(n)
self.add_label(text=n, self.add_label(text=n,
layer=pin.layer, layer=pin.layer,
offset=pin.center()) offset=pin.center())

View File

@ -29,14 +29,18 @@ class sram_base(design):
def add_pins(self): def add_pins(self):
""" Add pins for entire SRAM. """ """ Add pins for entire SRAM. """
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
for port in range(self.total_write): for port in range(self.total_write):
@ -47,15 +51,26 @@ class sram_base(design):
for bit in range(self.addr_size): for bit in range(self.addr_size):
self.add_pin("ADDR{0}[{1}]".format(port,bit),"INPUT") self.add_pin("ADDR{0}[{1}]".format(port,bit),"INPUT")
# These are used to create the physical pins too # These are used to create the physical pins
self.control_logic_inputs=self.control_logic.get_inputs() self.control_logic_inputs = []
self.control_logic_outputs=self.control_logic.get_outputs() self.control_logic_outputs = []
for port in range(self.total_ports):
if self.port_id[port] == "rw":
self.control_logic_inputs.append(self.control_logic_rw.get_inputs())
self.control_logic_outputs.append(self.control_logic_rw.get_outputs())
elif self.port_id[port] == "w":
self.control_logic_inputs.append(self.control_logic_w.get_inputs())
self.control_logic_outputs.append(self.control_logic_w.get_outputs())
else:
self.control_logic_inputs.append(self.control_logic_r.get_inputs())
self.control_logic_outputs.append(self.control_logic_r.get_outputs())
#self.add_pin_list(self.control_logic_inputs,"INPUT") for port in range(self.total_ports):
self.add_pin("csb","INPUT") self.add_pin("csb{}".format(port),"INPUT")
for port in range(self.total_write): for port in range(self.total_write):
self.add_pin("web{}".format(port),"INPUT") self.add_pin("web{}".format(port),"INPUT")
self.add_pin("clk","INPUT") for port in range(self.total_ports):
self.add_pin("clk{}".format(port),"INPUT")
for port in range(self.total_read): for port in range(self.total_read):
for bit in range(self.word_size): for bit in range(self.word_size):
@ -76,6 +91,7 @@ class sram_base(design):
self.width=0 self.width=0
self.height=0 self.height=0
def create_layout(self): def create_layout(self):
""" Layout creation """ """ Layout creation """
self.place_modules() self.place_modules()
@ -116,19 +132,24 @@ class sram_base(design):
"Bank is too small compared to control logic.") "Bank is too small compared to control logic.")
def add_busses(self): def add_busses(self):
""" Add the horizontal and vertical busses """ """ Add the horizontal and vertical busses """
# Vertical bus # Vertical bus
# The order of the control signals on the control bus: # The order of the control signals on the control bus:
self.control_bus_names = ["clk_buf", "clk_buf_bar", "w_en0", "s_en"] self.control_bus_names = []
for port in range(self.total_ports):
self.control_bus_names[port] = ["clk_buf{}".format(port), "clk_buf_bar{}".format(port)]
if (self.port_id[port] == "rw") or (self.port_id[port] == "w"):
self.control_bus_names[port].append("w_en{}".format(port))
if (self.port_id[port] == "rw") or (self.port_id[port] == "r"):
self.control_bus_names[port].append("s_en{}".format(port))
self.vert_control_bus_positions = self.create_vertical_bus(layer="metal2", self.vert_control_bus_positions = self.create_vertical_bus(layer="metal2",
pitch=self.m2_pitch, pitch=self.m2_pitch,
offset=self.vertical_bus_offset, offset=self.vertical_bus_offset,
names=self.control_bus_names, names=self.control_bus_names[port],
length=self.vertical_bus_height) length=self.vertical_bus_height)
self.addr_bus_names=["A[{}]".format(i) for i in range(self.addr_size)] self.addr_bus_names=["A{0}[{1}]".format(port,i) for i in range(self.addr_size)]
self.vert_control_bus_positions.update(self.create_vertical_pin_bus(layer="metal2", self.vert_control_bus_positions.update(self.create_vertical_pin_bus(layer="metal2",
pitch=self.m2_pitch, pitch=self.m2_pitch,
offset=self.addr_bus_offset, offset=self.addr_bus_offset,
@ -136,7 +157,7 @@ class sram_base(design):
length=self.addr_bus_height)) length=self.addr_bus_height))
self.bank_sel_bus_names = ["bank_sel[{}]".format(i) for i in range(self.num_banks)] self.bank_sel_bus_names = ["bank_sel{0}[{1}]".format(port,i) for i in range(self.num_banks)]
self.vert_control_bus_positions.update(self.create_vertical_pin_bus(layer="metal2", self.vert_control_bus_positions.update(self.create_vertical_pin_bus(layer="metal2",
pitch=self.m2_pitch, pitch=self.m2_pitch,
offset=self.bank_sel_bus_offset, offset=self.bank_sel_bus_offset,
@ -145,7 +166,7 @@ class sram_base(design):
# Horizontal data bus # Horizontal data bus
self.data_bus_names = ["DATA[{}]".format(i) for i in range(self.word_size)] self.data_bus_names = ["DATA{0}[{1}]".format(port,i) for i in range(self.word_size)]
self.data_bus_positions = self.create_horizontal_pin_bus(layer="metal3", self.data_bus_positions = self.create_horizontal_pin_bus(layer="metal3",
pitch=self.m3_pitch, pitch=self.m3_pitch,
offset=self.data_bus_offset, offset=self.data_bus_offset,
@ -170,13 +191,10 @@ class sram_base(design):
self.horz_control_bus_positions.update(self.create_horizontal_bus(layer="metal1", self.horz_control_bus_positions.update(self.create_horizontal_bus(layer="metal1",
pitch=self.m1_pitch, pitch=self.m1_pitch,
offset=self.control_bus_offset, offset=self.control_bus_offset,
names=self.control_bus_names, names=self.control_bus_names[port],
length=self.control_bus_width)) length=self.control_bus_width))
def route_vdd_gnd(self): def route_vdd_gnd(self):
""" Propagate all vdd/gnd pins up to this level for all modules """ """ Propagate all vdd/gnd pins up to this level for all modules """
@ -218,33 +236,41 @@ class sram_base(design):
self.msb_decoder = self.bank.decoder.pre2_4 self.msb_decoder = self.bank.decoder.pre2_4
self.add_mod(self.msb_decoder) self.add_mod(self.msb_decoder)
def add_modules(self): def add_modules(self):
""" Create all the modules that will be used """ """ Create all the modules that will be used """
c = reload(__import__(OPTS.bitcell)) c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell) self.mod_bitcell = getattr(c, OPTS.bitcell)
self.bitcell = self.mod_bitcell() self.bitcell = self.mod_bitcell()
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)
from control_logic import control_logic from control_logic import control_logic
# Create the control logic module # Create the control logic module for each port type
self.control_logic = self.mod_control_logic(num_rows=self.num_rows) if OPTS.num_rw_ports>0:
self.add_mod(self.control_logic) self.control_logic = self.control_logic_rw = control_logic(num_rows=self.num_rows, port="rw")
self.add_mod(self.control_logic_rw)
if OPTS.num_w_ports>0:
self.control_logic_w = control_logic(num_rows=self.num_rows, port="w")
self.add_mod(self.control_logic_w)
if OPTS.num_r_ports>0:
self.control_logic_r = control_logic(num_rows=self.num_rows, port="r")
self.add_mod(self.control_logic_r)
# Create the address and control flops (but not the clk) # Create the address and control flops (but not the clk)
from dff_array import dff_array from dff_array import dff_array
self.row_addr_dff = dff_array(name="row_addr_dff", rows=self.row_addr_size*self.total_ports, columns=1) self.row_addr_dff = dff_array(name="row_addr_dff", rows=self.row_addr_size, columns=1)
self.add_mod(self.row_addr_dff) self.add_mod(self.row_addr_dff)
if self.col_addr_size > 0: if self.col_addr_size > 0:
self.col_addr_dff = dff_array(name="col_addr_dff", rows=1, columns=self.col_addr_size*self.total_ports) self.col_addr_dff = dff_array(name="col_addr_dff", rows=1, columns=self.col_addr_size)
self.add_mod(self.col_addr_dff) self.add_mod(self.col_addr_dff)
else: else:
self.col_addr_dff = None self.col_addr_dff = None
self.data_dff = dff_array(name="data_dff", rows=1, columns=self.word_size*self.total_write) self.data_dff = dff_array(name="data_dff", rows=1, columns=self.word_size)
self.add_mod(self.data_dff) self.add_mod(self.data_dff)
# Create the bank module (up to four are instantiated) # Create the bank module (up to four are instantiated)
@ -263,7 +289,6 @@ class sram_base(design):
self.supply_rail_pitch = self.bank.supply_rail_pitch self.supply_rail_pitch = self.bank.supply_rail_pitch
def create_bank(self,bank_num): def create_bank(self,bank_num):
""" Create a bank """ """ Create a bank """
self.bank_insts.append(self.add_inst(name="bank{0}".format(bank_num), self.bank_insts.append(self.add_inst(name="bank{0}".format(bank_num),
@ -282,10 +307,14 @@ class sram_base(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):
temp.append("bank_sel{0}[{1}]".format(port,bank_num)) temp.append("bank_sel{0}[{1}]".format(port,bank_num))
temp.append("s_en") for port in range(self.total_read):
temp.append("s_en{0}".format(self.read_index[port]))
for port in range(self.total_write): for port in range(self.total_write):
temp.append("w_en{0}".format(port)) temp.append("w_en{0}".format(port))
temp.extend(["clk_buf_bar","clk_buf" , "vdd", "gnd"]) for port in range(self.total_ports):
temp.append("clk_buf_bar{0}".format(port))
temp.append("clk_buf{0}".format(port))
temp.extend(["vdd", "gnd"])
self.connect_inst(temp) self.connect_inst(temp)
return self.bank_insts[-1] return self.bank_insts[-1]
@ -324,73 +353,87 @@ class sram_base(design):
def create_row_addr_dff(self): def create_row_addr_dff(self):
""" Add all address flops for the main decoder """ """ Add all address flops for the main decoder """
inst = self.add_inst(name="row_address", insts = []
mod=self.row_addr_dff) for port in range(self.total_ports):
insts.append(self.add_inst(name="row_address{}".format(port),
mod=self.row_addr_dff))
# inputs, outputs/output/bar # inputs, outputs/output/bar
inputs = [] inputs = []
outputs = [] outputs = []
for port in range(self.total_ports): for bit in range(self.row_addr_size):
for i in range(self.row_addr_size): inputs.append("ADDR{}[{}]".format(port,bit+self.col_addr_size))
inputs.append("ADDR{}[{}]".format(port,i+self.col_addr_size)) outputs.append("A{}[{}]".format(port,bit+self.col_addr_size))
outputs.append("A{}[{}]".format(port,i+self.col_addr_size))
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port), "vdd", "gnd"])
return insts
self.connect_inst(inputs + outputs + ["clk_buf", "vdd", "gnd"])
return inst
def create_col_addr_dff(self): def create_col_addr_dff(self):
""" Add and place all address flops for the column decoder """ """ Add and place all address flops for the column decoder """
inst = self.add_inst(name="col_address", insts = []
mod=self.col_addr_dff) for port in range(self.total_ports):
insts.append(self.add_inst(name="col_address{}".format(port),
mod=self.col_addr_dff))
# inputs, outputs/output/bar # inputs, outputs/output/bar
inputs = [] inputs = []
outputs = [] outputs = []
for port in range(self.total_ports): for bit in range(self.col_addr_size):
for i in range(self.col_addr_size): inputs.append("ADDR{}[{}]".format(port,bit))
inputs.append("ADDR{}[{}]".format(port,i)) outputs.append("A{}[{}]".format(port,bit))
outputs.append("A{}[{}]".format(port,i))
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port), "vdd", "gnd"])
return insts
self.connect_inst(inputs + outputs + ["clk_buf", "vdd", "gnd"])
return inst
def create_data_dff(self): def create_data_dff(self):
""" Add and place all data flops """ """ Add and place all data flops """
inst = self.add_inst(name="data_dff", insts = []
mod=self.data_dff) for port in range(self.total_write):
insts.append(self.add_inst(name="data_dff{}".format(port),
mod=self.data_dff))
# inputs, outputs/output/bar # inputs, outputs/output/bar
inputs = [] inputs = []
outputs = [] outputs = []
for port in range(self.total_write): for bit in range(self.word_size):
for i in range(self.word_size): inputs.append("DIN{}[{}]".format(port,bit))
inputs.append("DIN{}[{}]".format(port,i)) outputs.append("BANK_DIN{}[{}]".format(port,bit))
outputs.append("BANK_DIN{}[{}]".format(port,i))
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port), "vdd", "gnd"])
return insts
self.connect_inst(inputs + outputs + ["clk_buf", "vdd", "gnd"])
return inst
def create_control_logic(self): def create_control_logic(self):
""" Add and place control logic """ """ Add and place control logic """
inst = self.add_inst(name="control", insts = []
mod=self.control_logic) for port in range(self.total_ports):
if self.port_id[port] == "rw":
mod = self.control_logic_rw
elif self.port_id[port] == "w":
mod = self.control_logic_w
else:
mod = self.control_logic_r
temp = ["csb"] insts.append(self.add_inst(name="control{}".format(port),
for port in range(self.total_write): mod=mod))
temp = ["csb{}".format(port)]
if (self.port_id[port] == "rw") or (self.port_id[port] == "w"):
temp.append("web{}".format(port)) temp.append("web{}".format(port))
temp.extend(["clk", "s_en"]) temp.append("clk{}".format(port))
for port in range(self.total_write): if (self.port_id[port] == "rw") or (self.port_id[port] == "r"):
temp.append("s_en{}".format(port))
if (self.port_id[port] == "rw") or (self.port_id[port] == "w"):
temp.append("w_en{}".format(port)) temp.append("w_en{}".format(port))
temp.extend(["clk_buf_bar", "clk_buf", "vdd", "gnd"]) temp.extend(["clk_buf_bar{}".format(port), "clk_buf{}".format(port), "vdd", "gnd"])
self.connect_inst(temp) self.connect_inst(temp)
#self.connect_inst(self.control_logic_inputs + self.control_logic_outputs + ["vdd", "gnd"]) return insts
return inst
def connect_rail_from_left_m2m3(self, src_pin, dest_pin): def connect_rail_from_left_m2m3(self, src_pin, dest_pin):
@ -402,6 +445,7 @@ class sram_base(design):
offset=src_pin.rc(), offset=src_pin.rc(),
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):
""" Helper routine to connect an unrotated/mirrored oriented instance to the rails """ """ Helper routine to connect an unrotated/mirrored oriented instance to the rails """
in_pos = src_pin.rc() in_pos = src_pin.rc()
@ -409,7 +453,6 @@ class sram_base(design):
self.add_wire(("metal2","via1","metal1"),[in_pos, out_pos, out_pos - vector(0,self.m2_pitch)]) self.add_wire(("metal2","via1","metal1"),[in_pos, out_pos, out_pos - vector(0,self.m2_pitch)])
def sp_write(self, sp_name): def sp_write(self, sp_name):
# Write the entire spice of the object to the file # Write the entire spice of the object to the file
############################################################ ############################################################
@ -434,6 +477,7 @@ class sram_base(design):
del usedMODS del usedMODS
sp.close() sp.close()
def analytical_delay(self,slew,load): def analytical_delay(self,slew,load):
""" LH and HL are the same in analytical model. """ """ LH and HL are the same in analytical model. """
return self.bank.analytical_delay(slew,load) return self.bank.analytical_delay(slew,load)