Commiting working version of multi-port that can generate a netlist on the sram level. Changes that will clean up the code are forthcoming.

This commit is contained in:
Michael Timothy Grimes 2018-09-09 14:00:51 -07:00
parent c91735b23b
commit 1429b9ab1a
5 changed files with 172 additions and 43 deletions

View File

@ -67,13 +67,27 @@ class bank(design.design):
self.DRC_LVS()
def add_pins(self):
self.din_list = []
self.dout_list = []
port_number = 0
for port in range(OPTS.num_rw_ports):
self.din_list.append("din{}".format(port_number))
self.dout_list.append("dout{}".format(port_number))
port_number += 1
for port in range(OPTS.num_w_ports):
self.din_list.append("din{}".format(port_number))
port_number += 1
for port in range(OPTS.num_r_ports):
self.dout_list.append("dout{}".format(port_number))
port_number += 1
""" Adding pins for Bank module"""
for port in range(self.total_read):
for bit in range(self.word_size):
self.add_pin("dout{0}[{1}]".format(port,bit),"OUT")
self.add_pin(self.dout_list[port]+"[{0}]".format(bit),"OUT")
for port in range(self.total_write):
for bit in range(self.word_size):
self.add_pin("din{0}[{1}]".format(port,bit),"IN")
self.add_pin(self.din_list[port]+"[{0}]".format(bit),"IN")
for port in range(self.total_ports):
for bit in range(self.addr_size):
self.add_pin("addr{0}[{1}]".format(port,bit),"INPUT")
@ -350,7 +364,7 @@ class bank(design.design):
temp = []
for bit in range(self.word_size):
temp.append("dout{0}[{1}]".format(port,bit))
temp.append(self.dout_list[port]+"[{0}]".format(bit))
if self.words_per_row == 1:
temp.append(self.read_bl_list[port]+"[{0}]".format(bit))
temp.append(self.read_br_list[port]+"[{0}]".format(bit))
@ -379,7 +393,7 @@ class bank(design.design):
temp = []
for bit in range(self.word_size):
temp.append("din{0}[{1}]".format(port,bit))
temp.append(self.din_list[port]+"[{0}]".format(bit))
for bit in range(self.word_size):
if (self.words_per_row == 1):
temp.append(self.write_bl_list[port]+"[{0}]".format(bit))
@ -547,29 +561,35 @@ class bank(design.design):
# These are the instances that every bank has
top_instances = [self.bitcell_array_inst]
for port in range(self.total_read):
#top_instances.append(self.precharge_array_inst[port])
top_instances.append(self.sense_amp_array_inst[port])
for port in range(self.total_write):
top_instances.append(self.write_driver_array_inst[port])
for port in range(self.total_ports):
top_instances.extend([self.precharge_array_inst[port],
self.sense_amp_array_inst[port],
self.write_driver_array_inst[port],
self.row_decoder_inst[port],
top_instances.extend([self.row_decoder_inst[port],
self.wordline_driver_inst[port]])
# Add these if we use the part...
if self.col_addr_size > 0:
top_instances.append(self.col_decoder_inst[port])
top_instances.append(self.col_mux_array_inst[port])
#top_instances.append(self.col_mux_array_inst[port])
if self.num_banks > 1:
top_instances.append(self.bank_select_inst[port])
if self.col_addr_size > 0:
for port in range(self.total_ports):
self.copy_layout_pin(self.col_mux_array_inst[port], "gnd")
for port in range(self.total_read):
self.copy_layout_pin(self.precharge_array_inst[port], "vdd")
for inst in top_instances:
# Column mux has no vdd
if self.col_addr_size==0 or (self.col_addr_size>0 and inst != self.col_mux_array_inst[0]):
self.copy_layout_pin(inst, "vdd")
#if self.col_addr_size==0 or (self.col_addr_size>0 and inst != self.col_mux_array_inst[0]):
self.copy_layout_pin(inst, "vdd")
# Precharge has no gnd
if inst != self.precharge_array_inst[0]:
self.copy_layout_pin(inst, "gnd")
#if inst != self.precharge_array_inst[port]:
self.copy_layout_pin(inst, "gnd")
def route_bank_select(self):
""" Route the bank select logic. """

View File

@ -128,7 +128,21 @@ class replica_bitline(design.design):
self.rbl_inst=self.add_inst(name="load",
mod=self.rbl)
self.connect_inst(["bl[0]", "br[0]"] + ["gnd"]*self.bitcell_loads + ["vdd", "gnd"])
total_ports = OPTS.num_rw_ports + OPTS.num_w_ports + OPTS.num_r_ports
temp = []
temp.append("bl[0]")
temp.append("br[0]")
for port in range(total_ports - 1):
temp.append("gnd")
temp.append("gnd")
for wl in range(self.bitcell_loads):
for port in range(total_ports):
temp.append("gnd")
temp.append("vdd")
temp.append("gnd")
self.connect_inst(temp)
#self.connect_inst(["bl[0]", "br[0]"] + ["gnd"]*self.bitcell_loads + ["vdd", "gnd"])
def place_modules(self):
""" Add all of the module instances in the logical netlist """

View File

@ -34,7 +34,9 @@ class sram_1bank(sram_base):
self.bank_inst=self.create_bank(0)
self.control_logic_inst = self.create_control_logic()
self.control_logic_inst = [None] * self.total_ports
for port in range(self.total_ports):
self.control_logic_inst[port] = self.create_control_logic(port)
self.row_addr_dff_inst = self.create_row_addr_dff()
@ -59,11 +61,11 @@ class sram_1bank(sram_base):
# 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)
self.control_logic_inst[0].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())
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.place(row_addr_pos)
# This is M2 pitch even though it is on M1 to help stem via spacings on the trunk
@ -95,7 +97,7 @@ class sram_1bank(sram_base):
"""
# Connect the control pins as inputs
for n in self.control_logic_inputs + ["clk"]:
self.copy_layout_pin(self.control_logic_inst, n)
self.copy_layout_pin(self.control_logic_inst[0], n)
for i in range(self.word_size):
dout_name = "dout0[{}]".format(i)
@ -134,7 +136,7 @@ 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")
self.copy_layout_pin(self.control_logic_inst[0], "clk")
# Connect all of these clock pins to the clock in the central bus
# This is something like a "spine" clock distribution. The two spines
@ -158,7 +160,7 @@ class sram_1bank(sram_base):
# 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_pin = self.control_logic_inst[0].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()
@ -177,7 +179,7 @@ class sram_1bank(sram_base):
top_instances = [self.bank_inst,
self.row_addr_dff_inst,
self.data_dff_inst,
self.control_logic_inst]
self.control_logic_inst[0]]
if self.col_addr_dff:
top_instances.append(self.col_addr_dff_inst)
@ -193,7 +195,7 @@ class sram_1bank(sram_base):
top_instances = [self.bank_inst,
self.row_addr_dff_inst,
self.data_dff_inst,
self.control_logic_inst]
self.control_logic_inst[0]]
if self.col_addr_dff:
top_instances.append(self.col_addr_dff_inst)
@ -267,7 +269,7 @@ 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)
src_pin = self.control_logic_inst[0].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"),
@ -332,7 +334,7 @@ class sram_1bank(sram_base):
"""
for n in self.control_logic_outputs:
pin = self.control_logic_inst.get_pin(n)
pin = self.control_logic_inst[0].get_pin(n)
self.add_label(text=n,
layer=pin.layer,
offset=pin.center())

View File

@ -19,6 +19,7 @@ class sram_base(design):
self.sram_config = sram_config
sram_config.set_local_config(self)
print("PORTS: {} - {} - {}".format(OPTS.num_rw_ports, OPTS.num_w_ports, OPTS.num_r_ports))
self.total_write = OPTS.num_rw_ports + OPTS.num_w_ports
self.total_read = OPTS.num_rw_ports + OPTS.num_r_ports
self.total_ports = OPTS.num_rw_ports + OPTS.num_w_ports + OPTS.num_r_ports
@ -28,10 +29,29 @@ class sram_base(design):
def add_pins(self):
""" Add pins for entire SRAM. """
self.din_list = []
self.DIN_list = []
self.dout_list = []
self.DOUT_list = []
port_number = 0
for port in range(OPTS.num_rw_ports):
self.din_list.append("din{}".format(port_number))
self.dout_list.append("dout{}".format(port_number))
self.DIN_list.append("DIN{}".format(port_number))
self.DOUT_list.append("DOUT{}".format(port_number))
port_number += 1
for port in range(OPTS.num_w_ports):
self.din_list.append("din{}".format(port_number))
self.DIN_list.append("DIN{}".format(port_number))
port_number += 1
for port in range(OPTS.num_r_ports):
self.dout_list.append("dout{}".format(port_number))
self.DOUT_list.append("DOUT{}".format(port_number))
port_number += 1
for port in range(self.total_write):
for bit in range(self.word_size):
self.add_pin("DIN{0}[{1}]".format(port,bit),"INPUT")
self.add_pin(self.DIN_list[port]+"[{0}]".format(bit),"INPUT")
for port in range(self.total_ports):
for bit in range(self.addr_size):
@ -41,11 +61,15 @@ class sram_base(design):
self.control_logic_inputs=self.control_logic.get_inputs()
self.control_logic_outputs=self.control_logic.get_outputs()
self.add_pin_list(self.control_logic_inputs,"INPUT")
#self.add_pin_list(self.control_logic_inputs,"INPUT")
self.add_pin("csb","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_read):
for bit in range(self.word_size):
self.add_pin("DOUT{0}[{1}]".format(port,bit),"OUTPUT")
self.add_pin(self.DOUT_list[port]+"[{0}]".format(bit),"OUTPUT")
self.add_pin("vdd","POWER")
self.add_pin("gnd","GROUND")
@ -234,9 +258,11 @@ class sram_base(design):
else:
self.col_addr_dff = None
self.data_dff = dff_array(name="data_dff", rows=1, columns=self.word_size*self.total_ports)
self.data_dff = dff_array(name="data_dff", rows=1, columns=self.word_size*self.total_write)
self.add_mod(self.data_dff)
print("PORTS: {} - {} - {}".format(OPTS.num_rw_ports, OPTS.num_w_ports, OPTS.num_r_ports))
# Create the bank module (up to four are instantiated)
from bank import bank
self.bank = bank(self.sram_config,
@ -262,7 +288,7 @@ class sram_base(design):
temp = []
for port in range(self.total_read):
for bit in range(self.word_size):
temp.append("DOUT{0}[{1}]".format(port,bit))
temp.append(self.DOUT_list[port]+"[{0}]".format(bit))
for port in range(self.total_write):
for bit in range(self.word_size):
temp.append("BANK_DIN{0}[{1}]".format(port,bit))
@ -321,10 +347,10 @@ class sram_base(design):
# inputs, outputs/output/bar
inputs = []
outputs = []
for k in range(self.total_ports):
for port in range(self.total_ports):
for i in range(self.row_addr_size):
inputs.append("ADDR{}[{}]".format(k,i+self.col_addr_size))
outputs.append("A{}[{}]".format(k,i+self.col_addr_size))
inputs.append("ADDR{}[{}]".format(port,i+self.col_addr_size))
outputs.append("A{}[{}]".format(port,i+self.col_addr_size))
self.connect_inst(inputs + outputs + ["clk_buf", "vdd", "gnd"])
return inst
@ -337,10 +363,10 @@ class sram_base(design):
# inputs, outputs/output/bar
inputs = []
outputs = []
for k in range(self.total_ports):
for port in range(self.total_ports):
for i in range(self.col_addr_size):
inputs.append("ADDR{}[{}]".format(k,i))
outputs.append("A{}[{}]".format(k,i))
inputs.append("ADDR{}[{}]".format(port,i))
outputs.append("A{}[{}]".format(port,i))
self.connect_inst(inputs + outputs + ["clk_buf", "vdd", "gnd"])
return inst
@ -353,20 +379,24 @@ class sram_base(design):
# inputs, outputs/output/bar
inputs = []
outputs = []
for k in range(self.total_write):
for port in range(self.total_write):
for i in range(self.word_size):
inputs.append("DIN{}[{}]".format(k,i))
outputs.append("BANK_DIN{}[{}]".format(k,i))
inputs.append("DIN{}[{}]".format(port,i))
outputs.append("BANK_DIN{}[{}]".format(port,i))
self.connect_inst(inputs + outputs + ["clk_buf", "vdd", "gnd"])
return inst
def create_control_logic(self):
def create_control_logic(self, port):
""" Add and place control logic """
inst = self.add_inst(name="control",
mod=self.control_logic)
self.connect_inst(self.control_logic_inputs + self.control_logic_outputs + ["vdd", "gnd"])
self.connect_inst(["csb", "web{}".format(port), "clk",
"s_en{}".format(port), "w_en{}".format(port), "clk_buf_bar", "clk_buf",
"vdd", "gnd"])
#self.connect_inst(self.control_logic_inputs + self.control_logic_outputs + ["vdd", "gnd"])
return inst

View File

@ -0,0 +1,63 @@
#!/usr/bin/env python3
"""
Run a regression test on a 1 bank SRAM
"""
import unittest
from testutils import header,openram_test
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
from globals import OPTS
import debug
class sram_1bank_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
from sram import sram
from sram_config import sram_config
c = sram_config(word_size=4,
num_words=16,
num_banks=1)
c.words_per_row=1
OPTS.bitcell = "pbitcell"
OPTS.num_rw_ports = 1
OPTS.num_w_ports = 1
OPTS.num_r_ports = 1
OPTS.netlist_only = True
debug.info(1, "Single bank, no column mux with control logic")
a = sram(c, "sram1")
self.local_check(a, final_verification=True)
"""
c.num_words=32
c.words_per_row=2
debug.info(1, "Single bank two way column mux with control logic")
a = sram(c, "sram2")
self.local_check(a, final_verification=True)
c.num_words=64
c.words_per_row=4
debug.info(1, "Single bank, four way column mux with control logic")
a = sram(c, "sram3")
self.local_check(a, final_verification=True)
c.word_size=2
c.num_words=128
c.words_per_row=8
debug.info(1, "Single bank, eight way column mux with control logic")
a = sram(c, "sram4")
self.local_check(a, final_verification=True)
"""
#globals.end_openram()
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main()