mirror of https://github.com/VLSIDA/OpenRAM.git
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:
parent
648e57d195
commit
1ca0154027
|
|
@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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())
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue