mirror of https://github.com/VLSIDA/OpenRAM.git
Add initial support and unit tests for 2 port SRAM
This commit is contained in:
parent
6ac5adaeca
commit
3221d3e744
|
|
@ -61,7 +61,8 @@ class bank(design.design):
|
|||
#self.add_lvs_correspondence_points()
|
||||
|
||||
# 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()
|
||||
|
||||
|
|
|
|||
|
|
@ -43,10 +43,10 @@ class sram_1bank(sram_base):
|
|||
|
||||
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
|
||||
logic.
|
||||
This places the instances for a single bank SRAM with control
|
||||
logic and up to 2 ports.
|
||||
"""
|
||||
|
||||
# No orientation or offset
|
||||
|
|
@ -57,39 +57,70 @@ 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.
|
||||
for port in self.all_ports:
|
||||
control_pos = vector(-self.control_logic_rw.width - 2*self.m2_pitch,
|
||||
self.bank.bank_center.y - self.control_logic_rw.control_logic_center.y)
|
||||
self.control_logic_insts[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_insts[0].rx() - self.row_addr_dff.width,
|
||||
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
|
||||
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_insts[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_insts[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
|
||||
control_pos = [None]*len(self.all_ports)
|
||||
row_addr_pos = [None]*len(self.all_ports)
|
||||
col_addr_pos = [None]*len(self.all_ports)
|
||||
data_pos = [None]*len(self.all_ports)
|
||||
|
||||
# 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)
|
||||
|
||||
# Port 0
|
||||
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])
|
||||
|
||||
# The row address bits are placed above the control logic aligned on the right.
|
||||
row_addr_pos[port] = vector(self.control_logic_insts[port].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])
|
||||
|
||||
# Add the col address flops below the bank to the left of the lower-left of bank array
|
||||
if self.col_addr_dff:
|
||||
col_addr_pos[port] = vector(self.bank.bank_array_ll.x - self.col_addr_dff_insts[port].width - self.bank.central_bus_width,
|
||||
-data_gap - self.col_addr_dff_insts[port].height)
|
||||
self.col_addr_dff_insts[port].place(col_addr_pos[port])
|
||||
|
||||
# Add the data flops below the bank to the right of the lower-left of bank array
|
||||
# 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")
|
||||
|
||||
|
||||
def add_layout_pins(self):
|
||||
"""
|
||||
Add the top-level pins for a single bank SRAM with control.
|
||||
|
|
@ -114,7 +145,7 @@ class sram_1bank(sram_base):
|
|||
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))
|
||||
|
||||
def route(self):
|
||||
def route_layout(self):
|
||||
""" Route a single bank SRAM """
|
||||
|
||||
self.add_layout_pins()
|
||||
|
|
@ -151,11 +182,12 @@ class sram_1bank(sram_base):
|
|||
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_insts[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])
|
||||
|
||||
if port in self.write_ports:
|
||||
data_dff_clk_pin = self.data_dff_insts[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.
|
||||
|
|
|
|||
|
|
@ -75,8 +75,9 @@ class sram_base(design):
|
|||
|
||||
def create_layout(self):
|
||||
""" Layout creation """
|
||||
self.place_modules()
|
||||
self.route()
|
||||
self.place_instances()
|
||||
|
||||
self.route_layout()
|
||||
|
||||
self.add_lvs_correspondence_points()
|
||||
|
||||
|
|
@ -369,9 +370,13 @@ class sram_base(design):
|
|||
def create_data_dff(self):
|
||||
""" Add and place all data flops """
|
||||
insts = []
|
||||
for port in self.write_ports:
|
||||
insts.append(self.add_inst(name="data_dff{}".format(port),
|
||||
mod=self.data_dff))
|
||||
for port in self.all_ports:
|
||||
if port in self.write_ports:
|
||||
insts.append(self.add_inst(name="data_dff{}".format(port),
|
||||
mod=self.data_dff))
|
||||
else:
|
||||
insts.append(None)
|
||||
continue
|
||||
|
||||
# inputs, outputs/output/bar
|
||||
inputs = []
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
@ -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()
|
||||
Loading…
Reference in New Issue