Add initial support and unit tests for 2 port SRAM

This commit is contained in:
Matt Guthaus 2018-11-14 17:05:23 -08:00
parent 6ac5adaeca
commit 3221d3e744
5 changed files with 171 additions and 47 deletions

View File

@ -61,7 +61,8 @@ class bank(design.design):
#self.add_lvs_correspondence_points() #self.add_lvs_correspondence_points()
# Remember the bank center for further placement # Remember the bank center for further placement
self.bank_center=self.offset_all_coordinates().scale(-1,-1) self.bank_array_ll = self.offset_all_coordinates().scale(-1,-1)
self.bank_array_ur = self.bitcell_array_inst.ur()
self.DRC_LVS() self.DRC_LVS()

View File

@ -43,10 +43,10 @@ class sram_1bank(sram_base):
self.data_dff_insts = self.create_data_dff() self.data_dff_insts = self.create_data_dff()
def place_modules(self): def place_instances(self):
""" """
This places the modules for a single bank SRAM with control This places the instances for a single bank SRAM with control
logic. logic and up to 2 ports.
""" """
# No orientation or offset # No orientation or offset
@ -57,38 +57,69 @@ 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 self.all_ports: control_pos = [None]*len(self.all_ports)
control_pos = vector(-self.control_logic_rw.width - 2*self.m2_pitch, row_addr_pos = [None]*len(self.all_ports)
self.bank.bank_center.y - self.control_logic_rw.control_logic_center.y) col_addr_pos = [None]*len(self.all_ports)
self.control_logic_insts[port].place(control_pos) data_pos = [None]*len(self.all_ports)
# The row address bits are placed above the control logic aligned on the right. # This is M2 pitch even though it is on M1 to help stem via spacings on the trunk
row_addr_pos = vector(self.control_logic_insts[0].rx() - self.row_addr_dff.width, data_gap = self.m2_pitch*(self.word_size+1)
self.control_logic_insts[0].uy())
self.row_addr_dff_insts[port].place(row_addr_pos)
# This is M2 pitch even though it is on M1 to help stem via spacings on the trunk # Port 0
data_gap = -self.m2_pitch*(self.word_size+1) port = 0
control_pos[port] = vector(-self.control_logic_insts[port].width - 2*self.m2_pitch,
self.bank.bank_array_ll.y - self.control_logic_insts[port].mod.control_logic_center.y)
self.control_logic_insts[port].place(control_pos[port])
# Add the column address below the bank under the control # The row address bits are placed above the control logic aligned on the right.
# The column address flops are aligned with the data flops row_addr_pos[port] = vector(self.control_logic_insts[port].rx() - self.row_addr_dff_insts[port].width,
if self.col_addr_dff: self.control_logic_insts[port].uy())
col_addr_pos = vector(self.bank.bank_center.x - self.col_addr_dff.width - self.bank.central_bus_width, self.row_addr_dff_insts[port].place(row_addr_pos[port])
data_gap - self.col_addr_dff.height)
self.col_addr_dff_insts[port].place(col_addr_pos)
# Add the data flops below the bank to the right of the center of bank: # Add the col address flops below the bank to the left of the lower-left of bank array
# This relies on the center point of the bank: if self.col_addr_dff:
# decoder in upper left, bank in upper right, sensing in lower right. col_addr_pos[port] = vector(self.bank.bank_array_ll.x - self.col_addr_dff_insts[port].width - self.bank.central_bus_width,
# These flops go below the sensing and leave a gap to channel route to the -data_gap - self.col_addr_dff_insts[port].height)
# sense amps. self.col_addr_dff_insts[port].place(col_addr_pos[port])
data_pos = vector(self.bank.bank_center.x,
data_gap - self.data_dff.height) # Add the data flops below the bank to the right of the lower-left of bank array
self.data_dff_insts[port].place(data_pos) # This relies on the lower-left of the array 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.
if port in self.write_ports:
data_pos[port] = vector(self.bank.bank_array_ll.x,
-data_gap - self.data_dff_insts[port].height)
self.data_dff_insts[port].place(data_pos[port])
# Port 1
port = 1
control_pos[port] = vector(self.bank_inst.rx() + self.control_logic_insts[port].width + 2*self.m2_pitch,
self.bank.bank_array_ll.y - self.control_logic_insts[port].mod.control_logic_center.y)
self.control_logic_insts[port].place(control_pos[port], mirror="MY")
# The row address bits are placed above the control logic aligned on the left.
row_addr_pos[port] = vector(self.bank_inst.rx() + self.row_addr_dff_insts[port].width,
self.control_logic_insts[port].uy())
self.row_addr_dff_insts[port].place(row_addr_pos[port], mirror="MY")
# Add the col address flops above the bank to the right of the upper-right of bank array
if self.col_addr_dff:
col_addr_pos[port] = vector(self.bank.bank_array_ur.x + self.bank.central_bus_width,
self.bank_inst.uy() + data_gap + self.col_addr_dff_insts[port].height)
self.col_addr_dff_insts[port].place(col_addr_pos[port], mirror="MX")
# Add the data flops above the bank to the left of the upper-right of bank array
# This relies on the upper-right of the array 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.
if port in self.write_ports:
data_pos[port] = vector(self.bank.bank_array_ur.x - self.data_dff_insts[port].width,
self.bank.uy() + data_gap + self.data_dff_insts[port].height)
self.data_dff_insts[port].place(data_pos[port], mirror="MX")
# 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): def add_layout_pins(self):
""" """
@ -114,7 +145,7 @@ class sram_1bank(sram_base):
for bit in range(self.word_size): for bit in range(self.word_size):
self.copy_layout_pin(self.data_dff_insts[port], "din_{}".format(bit), "DIN{0}[{1}]".format(port,bit)) self.copy_layout_pin(self.data_dff_insts[port], "din_{}".format(bit), "DIN{0}[{1}]".format(port,bit))
def route(self): def route_layout(self):
""" Route a single bank SRAM """ """ Route a single bank SRAM """
self.add_layout_pins() self.add_layout_pins()
@ -152,10 +183,11 @@ class sram_1bank(sram_base):
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_insts[port].get_pin("clk") if port in self.write_ports:
data_dff_clk_pos = data_dff_clk_pin.center() data_dff_clk_pin = self.data_dff_insts[port].get_pin("clk")
mid_pos = vector(bank_clk_buf_pos.x, data_dff_clk_pos.y) data_dff_clk_pos = data_dff_clk_pin.center()
self.add_wire(("metal3","via2","metal2"),[data_dff_clk_pos, mid_pos, bank_clk_buf_pos]) 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 # This uses a metal2 track to the right of the control/row addr DFF
# to route vertically. # to route vertically.

View File

@ -75,8 +75,9 @@ class sram_base(design):
def create_layout(self): def create_layout(self):
""" Layout creation """ """ Layout creation """
self.place_modules() self.place_instances()
self.route()
self.route_layout()
self.add_lvs_correspondence_points() self.add_lvs_correspondence_points()
@ -369,9 +370,13 @@ class sram_base(design):
def create_data_dff(self): def create_data_dff(self):
""" Add and place all data flops """ """ Add and place all data flops """
insts = [] insts = []
for port in self.write_ports: for port in self.all_ports:
insts.append(self.add_inst(name="data_dff{}".format(port), if port in self.write_ports:
mod=self.data_dff)) insts.append(self.add_inst(name="data_dff{}".format(port),
mod=self.data_dff))
else:
insts.append(None)
continue
# inputs, outputs/output/bar # inputs, outputs/output/bar
inputs = [] inputs = []

View File

@ -0,0 +1,43 @@
#!/usr/bin/env python3
"""
Run a regression test on a 1 bank, 2 port 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_2mux_1rw_1r_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
OPTS.bitcell = "bitcell_1rw_1r"
OPTS.replica_bitcell = "replica_bitcell_1rw_1r"
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
c = sram_config(word_size=4,
num_words=32,
num_banks=1)
c.words_per_row=2
debug.info(1, "Single bank, two way column mux 1rw, 1r with control logic")
a = sram(c, "sram")
self.local_check(a, final_verification=True)
globals.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main()

View File

@ -0,0 +1,43 @@
#!/usr/bin/env python3
"""
Run a regression test on a 1 bank, 2 port 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_nomux_1rw_1r_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
OPTS.bitcell = "bitcell_1rw_1r"
OPTS.replica_bitcell = "replica_bitcell_1rw_1r"
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
c = sram_config(word_size=4,
num_words=16,
num_banks=1)
c.words_per_row=1
debug.info(1, "Single bank, no column mux 1rw, 1r with control logic")
a = sram(c, "sram")
self.local_check(a, final_verification=True)
globals.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main()