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):
self.add_pin("bank_sel{}".format(port),"INPUT")
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):
self.add_pin("w_en{0}".format(port), "INPUT")
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_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)

View File

@ -20,8 +20,9 @@ class control_logic(design.design):
def __init__(self, num_rows, port="rw"):
""" Constructor """
design.design.__init__(self, "control_logic")
debug.info(1, "Creating {}".format(self.name))
name = "control_logic_" + port
design.design.__init__(self, name)
debug.info(1, "Creating {}".format(name))
self.num_rows = num_rows
self.port = port
@ -95,7 +96,7 @@ class control_logic(design.design):
delay_stages = 4 # Must be non-inverting
delay_fanout = 3 # This can be anything >=2
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)

View File

@ -13,8 +13,12 @@ class delay_chain(design.design):
Usually, this will be constant, but it could have varied fanout.
"""
unique_id = 1
def __init__(self, fanout_list, name="delay_chain"):
"""init function"""
name = name+"_{}".format(delay_chain.unique_id)
delay_chain.unique_id += 1
design.design.__init__(self, name)
# 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 """
from importlib import reload
g = reload(__import__(OPTS.delay_chain))
self.mod_delay_chain = getattr(g, OPTS.delay_chain)
#g = reload(__import__(OPTS.delay_chain))
#self.mod_delay_chain = getattr(g, OPTS.delay_chain)
g = reload(__import__(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)
# 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.inv = pinv()

View File

@ -57,60 +57,60 @@ class sram_1bank(sram_base):
# the sense amps/column mux and cell array)
# The x-coordinate is placed to allow a single clock wire (plus an extra pitch)
# up to the row address DFFs.
control_pos = vector(-self.control_logic.width - 2*self.m2_pitch,
self.bank.bank_center.y - self.control_logic.control_logic_center.y)
self.control_logic_inst.place(control_pos)
for port in range(self.total_ports):
control_pos = vector(-self.control_logic.width - 2*self.m2_pitch,
self.bank.bank_center.y - self.control_logic.control_logic_center.y)
self.control_logic_inst[port].place(control_pos)
# 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,
self.control_logic_inst.uy())
self.row_addr_dff_inst.place(row_addr_pos)
# The row address bits are placed above the control logic aligned on the right.
row_addr_pos = vector(self.control_logic_inst[0].rx() - self.row_addr_dff.width,
self.control_logic_inst[0].uy())
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
data_gap = -self.m2_pitch*(self.word_size+1)
# Add the column address below the bank under the control
# The column address flops are aligned with the data flops
if self.col_addr_dff:
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)
self.col_addr_dff_inst.place(col_addr_pos)
# Add the data flops below the bank to the right of the center of bank:
# This relies on the center point of the bank:
# decoder in upper left, bank in upper right, sensing in lower right.
# These flops go below the sensing and leave a gap to channel route to the
# sense amps.
data_pos = vector(self.bank.bank_center.x,
data_gap - self.data_dff.height)
self.data_dff_inst.place(data_pos)
# 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.height = self.bank.height
# 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)
# Add the column address below the bank under the control
# The column address flops are aligned with the data flops
if self.col_addr_dff:
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)
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:
# This relies on the center point of the bank:
# decoder in upper left, bank in upper right, sensing in lower right.
# These flops go below the sensing and leave a gap to channel route to the
# sense amps.
data_pos = vector(self.bank.bank_center.x,
data_gap - self.data_dff.height)
self.data_dff_inst[port].place(data_pos)
# 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.height = self.bank.height
def add_layout_pins(self):
"""
Add the top-level pins for a single bank SRAM with control.
"""
# Connect the control pins as inputs
for n in self.control_logic_inputs + ["clk"]:
self.copy_layout_pin(self.control_logic_inst, n)
for port in range(self.total_ports):
# Connect the control pins as inputs
for signal in self.control_logic_inputs[port] + ["clk"]:
self.copy_layout_pin(self.control_logic_inst[port], signal, signal+"{}".format(port))
for i in range(self.word_size):
dout_name = "dout0[{}]".format(i)
self.copy_layout_pin(self.bank_inst, dout_name, "DOUT0[{}]".format(i))
for bit in range(self.word_size):
self.copy_layout_pin(self.bank_inst, "dout{0}[{1}]".format(port,bit), "DOUT{0}[{1}]".format(port,bit))
# Lower address bits
for i in range(self.col_addr_size):
self.copy_layout_pin(self.col_addr_dff_inst, "din[{}]".format(i),"ADDR0[{}]".format(i))
# Upper address bits
for i 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))
# Lower address bits
for bit in range(self.col_addr_size):
self.copy_layout_pin(self.col_addr_dff_inst[port], "din[{}]".format(bit),"ADDR{0}[{1}]".format(port,bit))
# Upper address bits
for bit in range(self.row_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):
din_name = "din[{}]".format(i)
self.copy_layout_pin(self.data_dff_inst, din_name, "DIN0[{}]".format(i))
for bit in range(self.word_size):
self.copy_layout_pin(self.data_dff_inst[port], "din[{}]".format(bit), "DIN{0}[{1}]".format(port,bit))
def route(self):
""" Route a single bank SRAM """
@ -134,52 +134,55 @@ class sram_1bank(sram_base):
""" Route the clock network """
# 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
# This is something like a "spine" clock distribution. The two spines
# are clk_buf and clk_buf_bar
bank_clk_buf_pin = self.bank_inst.get_pin("clk_buf")
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_pos = bank_clk_buf_bar_pin.center()
# Connect all of these clock pins to the clock in the central bus
# This is something like a "spine" clock distribution. The two spines
# are clk_buf and clk_buf_bar
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_bar_pin = self.bank_inst.get_pin("clk_buf_bar{}".format(port))
bank_clk_buf_bar_pos = bank_clk_buf_bar_pin.center()
if self.col_addr_dff:
dff_clk_pin = self.col_addr_dff_inst.get_pin("clk")
dff_clk_pos = dff_clk_pin.center()
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])
data_dff_clk_pin = self.data_dff_inst.get_pin("clk")
data_dff_clk_pos = data_dff_clk_pin.center()
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])
if self.col_addr_dff:
dff_clk_pin = self.col_addr_dff_inst[port].get_pin("clk")
dff_clk_pos = dff_clk_pin.center()
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])
data_dff_clk_pin = self.data_dff_inst[port].get_pin("clk")
data_dff_clk_pos = data_dff_clk_pin.center()
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])
# This uses a metal2 track to the right of the control/row addr DFF
# to route vertically.
control_clk_buf_pin = self.control_logic_inst.get_pin("clk_buf")
control_clk_buf_pos = control_clk_buf_pin.rc()
row_addr_clk_pin = self.row_addr_dff_inst.get_pin("clk")
row_addr_clk_pos = row_addr_clk_pin.rc()
mid1_pos = vector(self.row_addr_dff_inst.rx() + self.m2_pitch,
row_addr_clk_pos.y)
mid2_pos = vector(mid1_pos.x,
control_clk_buf_pos.y)
# Note, the via to the control logic is taken care of when we route
# the control logic to the bank
self.add_wire(("metal3","via2","metal2"),[row_addr_clk_pos, mid1_pos, mid2_pos, control_clk_buf_pos])
# This uses a metal2 track to the right of the control/row addr DFF
# to route vertically.
control_clk_buf_pin = self.control_logic_inst[port].get_pin("clk_buf")
control_clk_buf_pos = control_clk_buf_pin.rc()
row_addr_clk_pin = self.row_addr_dff_inst[port].get_pin("clk")
row_addr_clk_pos = row_addr_clk_pin.rc()
mid1_pos = vector(self.row_addr_dff_inst[port].rx() + self.m2_pitch,
row_addr_clk_pos.y)
mid2_pos = vector(mid1_pos.x,
control_clk_buf_pos.y)
# Note, the via to the control logic is taken care of when we route
# the control logic to the bank
self.add_wire(("metal3","via2","metal2"),[row_addr_clk_pos, mid1_pos, mid2_pos, control_clk_buf_pos])
def route_vdd_gnd(self):
""" Propagate all vdd/gnd pins up to this level for all modules """
# These are the instances that every bank has
top_instances = [self.bank_inst,
self.row_addr_dff_inst,
self.data_dff_inst,
self.control_logic_inst]
if self.col_addr_dff:
top_instances.append(self.col_addr_dff_inst)
top_instances = [self.bank_inst]
for port in range(self.total_write):
top_instances.append(self.data_dff_inst[port])
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:
top_instances.append(self.col_addr_dff_inst[port])
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 """
# These are the instances that every bank has
top_instances = [self.bank_inst,
self.row_addr_dff_inst,
self.data_dff_inst,
self.control_logic_inst]
if self.col_addr_dff:
top_instances.append(self.col_addr_dff_inst)
top_instances = [self.bank_inst]
for port in range(self.total_write):
top_instances.append(self.data_dff_inst[port])
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:
top_instances.append(self.col_addr_dff_inst[port])
# for inst in top_instances:
@ -266,63 +271,66 @@ class sram_1bank(sram_base):
def route_control_logic(self):
""" Route the outputs from the control logic module """
for n in self.control_logic_outputs:
src_pin = self.control_logic_inst.get_pin(n)
dest_pin = self.bank_inst.get_pin(n)
self.connect_rail_from_left_m2m3(src_pin, dest_pin)
self.add_via_center(layers=("metal1","via1","metal2"),
offset=src_pin.rc(),
rotate=90)
for port in range(self.total_ports):
for signal in self.control_logic_outputs[port]:
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.add_via_center(layers=("metal1","via1","metal2"),
offset=src_pin.rc(),
rotate=90)
def route_row_addr_dff(self):
""" Connect the output of the row flops to the bank pins """
for i in range(self.row_addr_size):
flop_name = "dout[{}]".format(i)
bank_name = "addr0[{}]".format(i+self.col_addr_size)
flop_pin = self.row_addr_dff_inst.get_pin(flop_name)
bank_pin = self.bank_inst.get_pin(bank_name)
flop_pos = flop_pin.center()
bank_pos = bank_pin.center()
mid_pos = vector(bank_pos.x,flop_pos.y)
self.add_wire(("metal3","via2","metal2"),[flop_pos, mid_pos,bank_pos])
self.add_via_center(layers=("metal2","via2","metal3"),
offset=flop_pos,
rotate=90)
for port in range(self.total_ports):
for bit in range(self.row_addr_size):
flop_name = "dout[{}]".format(bit)
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)
flop_pos = flop_pin.center()
bank_pos = bank_pin.center()
mid_pos = vector(bank_pos.x,flop_pos.y)
self.add_wire(("metal3","via2","metal2"),[flop_pos, mid_pos,bank_pos])
self.add_via_center(layers=("metal2","via2","metal3"),
offset=flop_pos,
rotate=90)
def route_col_addr_dff(self):
""" 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)]
col_addr_bus_offsets = self.create_horizontal_bus(layer="metal1",
pitch=self.m1_pitch,
offset=self.col_addr_dff_inst[port].ul() + vector(0, self.m1_pitch),
names=bus_names,
length=self.col_addr_dff_inst[port].width)
bus_names = ["addr[{}]".format(x) for x in range(self.col_addr_size)]
col_addr_bus_offsets = self.create_horizontal_bus(layer="metal1",
pitch=self.m1_pitch,
offset=self.col_addr_dff_inst.ul() + vector(0, self.m1_pitch),
names=bus_names,
length=self.col_addr_dff_inst.width)
dff_names = ["dout[{}]".format(x) for x in range(self.col_addr_size)]
data_dff_map = zip(dff_names, bus_names)
self.connect_horizontal_bus(data_dff_map, self.col_addr_dff_inst, col_addr_bus_offsets)
bank_names = ["addr0[{}]".format(x) for x in range(self.col_addr_size)]
data_bank_map = zip(bank_names, bus_names)
self.connect_horizontal_bus(data_bank_map, self.bank_inst, col_addr_bus_offsets)
dff_names = ["dout[{}]".format(x) for x in range(self.col_addr_size)]
data_dff_map = zip(dff_names, bus_names)
self.connect_horizontal_bus(data_dff_map, self.col_addr_dff_inst[port], col_addr_bus_offsets)
bank_names = ["addr{0}[{1}]".format(port,x) for x in range(self.col_addr_size)]
data_bank_map = zip(bank_names, bus_names)
self.connect_horizontal_bus(data_bank_map, self.bank_inst, col_addr_bus_offsets)
def route_data_dff(self):
""" Connect the output of the data flops to the write driver """
# 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)]
bank_names = ["din0[{}]".format(x) for x in range(self.word_size)]
dff_names = ["dout[{}]".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))
dff_pins = {key: self.data_dff_inst.get_pin(key) for key in dff_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.
all_pins = {**dff_pins, **bank_pins}
self.create_horizontal_channel_route(route_map, all_pins, offset)
route_map = list(zip(bank_names, 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 }
# Combine the dff and bank pins into a single dictionary of pin name to pin.
all_pins = {**dff_pins, **bank_pins}
self.create_horizontal_channel_route(route_map, all_pins, offset)
@ -333,8 +341,8 @@ class sram_1bank(sram_base):
will show these as ports in the extracted netlist.
"""
for n in self.control_logic_outputs:
pin = self.control_logic_inst.get_pin(n)
for n in self.control_logic_outputs[0]:
pin = self.control_logic_inst[0].get_pin(n)
self.add_label(text=n,
layer=pin.layer,
offset=pin.center())

View File

@ -29,14 +29,18 @@ class sram_base(design):
def add_pins(self):
""" Add pins for entire SRAM. """
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
for port in range(self.total_write):
@ -47,15 +51,26 @@ class sram_base(design):
for bit in range(self.addr_size):
self.add_pin("ADDR{0}[{1}]".format(port,bit),"INPUT")
# These are used to create the physical pins too
self.control_logic_inputs=self.control_logic.get_inputs()
self.control_logic_outputs=self.control_logic.get_outputs()
# These are used to create the physical pins
self.control_logic_inputs = []
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")
self.add_pin("csb","INPUT")
for port in range(self.total_ports):
self.add_pin("csb{}".format(port),"INPUT")
for port in range(self.total_write):
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 bit in range(self.word_size):
@ -75,6 +90,7 @@ class sram_base(design):
# This is for the lib file if we don't create layout
self.width=0
self.height=0
def create_layout(self):
""" Layout creation """
@ -116,65 +132,67 @@ class sram_base(design):
"Bank is too small compared to control logic.")
def add_busses(self):
""" Add the horizontal and vertical busses """
# Vertical 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.vert_control_bus_positions = self.create_vertical_bus(layer="metal2",
pitch=self.m2_pitch,
offset=self.vertical_bus_offset,
names=self.control_bus_names,
length=self.vertical_bus_height)
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",
pitch=self.m2_pitch,
offset=self.vertical_bus_offset,
names=self.control_bus_names[port],
length=self.vertical_bus_height)
self.addr_bus_names=["A[{}]".format(i) for i in range(self.addr_size)]
self.vert_control_bus_positions.update(self.create_vertical_pin_bus(layer="metal2",
pitch=self.m2_pitch,
offset=self.addr_bus_offset,
names=self.addr_bus_names,
length=self.addr_bus_height))
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",
pitch=self.m2_pitch,
offset=self.addr_bus_offset,
names=self.addr_bus_names,
length=self.addr_bus_height))
self.bank_sel_bus_names = ["bank_sel[{}]".format(i) for i in range(self.num_banks)]
self.vert_control_bus_positions.update(self.create_vertical_pin_bus(layer="metal2",
pitch=self.m2_pitch,
offset=self.bank_sel_bus_offset,
names=self.bank_sel_bus_names,
length=self.vertical_bus_height))
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",
pitch=self.m2_pitch,
offset=self.bank_sel_bus_offset,
names=self.bank_sel_bus_names,
length=self.vertical_bus_height))
# Horizontal data bus
self.data_bus_names = ["DATA[{}]".format(i) for i in range(self.word_size)]
self.data_bus_positions = self.create_horizontal_pin_bus(layer="metal3",
pitch=self.m3_pitch,
offset=self.data_bus_offset,
names=self.data_bus_names,
length=self.data_bus_width)
# Horizontal control logic bus
# vdd/gnd in bus go along whole SRAM
# FIXME: Fatten these wires?
self.horz_control_bus_positions = self.create_horizontal_bus(layer="metal1",
pitch=self.m1_pitch,
offset=self.supply_bus_offset,
names=["vdd"],
length=self.supply_bus_width)
# The gnd rail must not be the entire width since we protrude the right-most vdd rail up for
# the decoder in 4-bank SRAMs
self.horz_control_bus_positions.update(self.create_horizontal_bus(layer="metal1",
pitch=self.m1_pitch,
offset=self.supply_bus_offset+vector(0,self.m1_pitch),
names=["gnd"],
length=self.supply_bus_width))
self.horz_control_bus_positions.update(self.create_horizontal_bus(layer="metal1",
pitch=self.m1_pitch,
offset=self.control_bus_offset,
names=self.control_bus_names,
length=self.control_bus_width))
# Horizontal data bus
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",
pitch=self.m3_pitch,
offset=self.data_bus_offset,
names=self.data_bus_names,
length=self.data_bus_width)
# Horizontal control logic bus
# vdd/gnd in bus go along whole SRAM
# FIXME: Fatten these wires?
self.horz_control_bus_positions = self.create_horizontal_bus(layer="metal1",
pitch=self.m1_pitch,
offset=self.supply_bus_offset,
names=["vdd"],
length=self.supply_bus_width)
# The gnd rail must not be the entire width since we protrude the right-most vdd rail up for
# the decoder in 4-bank SRAMs
self.horz_control_bus_positions.update(self.create_horizontal_bus(layer="metal1",
pitch=self.m1_pitch,
offset=self.supply_bus_offset+vector(0,self.m1_pitch),
names=["gnd"],
length=self.supply_bus_width))
self.horz_control_bus_positions.update(self.create_horizontal_bus(layer="metal1",
pitch=self.m1_pitch,
offset=self.control_bus_offset,
names=self.control_bus_names[port],
length=self.control_bus_width))
def route_vdd_gnd(self):
@ -218,33 +236,41 @@ class sram_base(design):
self.msb_decoder = self.bank.decoder.pre2_4
self.add_mod(self.msb_decoder)
def add_modules(self):
""" Create all the modules that will be used """
c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell)
self.bitcell = self.mod_bitcell()
c = reload(__import__(OPTS.control_logic))
self.mod_control_logic = getattr(c, OPTS.control_logic)
#c = reload(__import__(OPTS.control_logic))
#self.mod_control_logic = getattr(c, OPTS.control_logic)
from control_logic import control_logic
# Create the control logic module
self.control_logic = self.mod_control_logic(num_rows=self.num_rows)
self.add_mod(self.control_logic)
# Create the control logic module for each port type
if OPTS.num_rw_ports>0:
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)
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)
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)
else:
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)
# 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
def create_bank(self,bank_num):
""" Create a bank """
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):
for port in range(self.total_ports):
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):
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)
return self.bank_insts[-1]
@ -324,73 +353,87 @@ class sram_base(design):
def create_row_addr_dff(self):
""" Add all address flops for the main decoder """
inst = self.add_inst(name="row_address",
mod=self.row_addr_dff)
# inputs, outputs/output/bar
inputs = []
outputs = []
insts = []
for port in range(self.total_ports):
for i in range(self.row_addr_size):
inputs.append("ADDR{}[{}]".format(port,i+self.col_addr_size))
outputs.append("A{}[{}]".format(port,i+self.col_addr_size))
insts.append(self.add_inst(name="row_address{}".format(port),
mod=self.row_addr_dff))
# inputs, outputs/output/bar
inputs = []
outputs = []
for bit in range(self.row_addr_size):
inputs.append("ADDR{}[{}]".format(port,bit+self.col_addr_size))
outputs.append("A{}[{}]".format(port,bit+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):
""" Add and place all address flops for the column decoder """
inst = self.add_inst(name="col_address",
mod=self.col_addr_dff)
# inputs, outputs/output/bar
inputs = []
outputs = []
insts = []
for port in range(self.total_ports):
for i in range(self.col_addr_size):
inputs.append("ADDR{}[{}]".format(port,i))
outputs.append("A{}[{}]".format(port,i))
insts.append(self.add_inst(name="col_address{}".format(port),
mod=self.col_addr_dff))
# inputs, outputs/output/bar
inputs = []
outputs = []
for bit in range(self.col_addr_size):
inputs.append("ADDR{}[{}]".format(port,bit))
outputs.append("A{}[{}]".format(port,bit))
self.connect_inst(inputs + outputs + ["clk_buf", "vdd", "gnd"])
return inst
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port), "vdd", "gnd"])
return insts
def create_data_dff(self):
""" Add and place all data flops """
inst = self.add_inst(name="data_dff",
mod=self.data_dff)
# inputs, outputs/output/bar
inputs = []
outputs = []
insts = []
for port in range(self.total_write):
for i in range(self.word_size):
inputs.append("DIN{}[{}]".format(port,i))
outputs.append("BANK_DIN{}[{}]".format(port,i))
insts.append(self.add_inst(name="data_dff{}".format(port),
mod=self.data_dff))
# inputs, outputs/output/bar
inputs = []
outputs = []
for bit in range(self.word_size):
inputs.append("DIN{}[{}]".format(port,bit))
outputs.append("BANK_DIN{}[{}]".format(port,bit))
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):
""" Add and place control logic """
inst = self.add_inst(name="control",
mod=self.control_logic)
insts = []
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
insts.append(self.add_inst(name="control{}".format(port),
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("clk{}".format(port))
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.extend(["clk_buf_bar{}".format(port), "clk_buf{}".format(port), "vdd", "gnd"])
self.connect_inst(temp)
temp = ["csb"]
for port in range(self.total_write):
temp.append("web{}".format(port))
temp.extend(["clk", "s_en"])
for port in range(self.total_write):
temp.append("w_en{}".format(port))
temp.extend(["clk_buf_bar", "clk_buf", "vdd", "gnd"])
self.connect_inst(temp)
#self.connect_inst(self.control_logic_inputs + self.control_logic_outputs + ["vdd", "gnd"])
return inst
return insts
def connect_rail_from_left_m2m3(self, src_pin, dest_pin):
@ -401,14 +444,14 @@ class sram_base(design):
self.add_via_center(layers=("metal2","via2","metal3"),
offset=src_pin.rc(),
rotate=90)
def connect_rail_from_left_m2m1(self, src_pin, dest_pin):
""" Helper routine to connect an unrotated/mirrored oriented instance to the rails """
in_pos = src_pin.rc()
out_pos = vector(dest_pin.cx(), in_pos.y)
self.add_wire(("metal2","via1","metal1"),[in_pos, out_pos, out_pos - vector(0,self.m2_pitch)])
def sp_write(self, sp_name):
# Write the entire spice of the object to the file
@ -434,6 +477,7 @@ class sram_base(design):
del usedMODS
sp.close()
def analytical_delay(self,slew,load):
""" LH and HL are the same in analytical model. """
return self.bank.analytical_delay(slew,load)