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):
|
||||
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)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in New Issue