mirror of https://github.com/VLSIDA/OpenRAM.git
Replica bitcell array with arbitrary RBLs working
This commit is contained in:
parent
9dab0be737
commit
b841fd7ce3
|
|
@ -0,0 +1,91 @@
|
|||
# See LICENSE for licensing information.
|
||||
#
|
||||
# Copyright (c) 2016-2019 Regents of the University of California and The Board
|
||||
# of Regents for the Oklahoma Agricultural and Mechanical College
|
||||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
import debug
|
||||
import design
|
||||
from tech import drc, spice,parameter
|
||||
from vector import vector
|
||||
from globals import OPTS
|
||||
from sram_factory import factory
|
||||
|
||||
class dummy_pbitcell(design.design):
|
||||
"""
|
||||
Creates a replica bitcell using pbitcell
|
||||
"""
|
||||
|
||||
def __init__(self, name):
|
||||
self.num_rw_ports = OPTS.num_rw_ports
|
||||
self.num_w_ports = OPTS.num_w_ports
|
||||
self.num_r_ports = OPTS.num_r_ports
|
||||
self.total_ports = self.num_rw_ports + self.num_w_ports + self.num_r_ports
|
||||
|
||||
design.design.__init__(self, name)
|
||||
debug.info(1, "create a dummy bitcell using pbitcell with {0} rw ports, {1} w ports and {2} r ports".format(self.num_rw_ports,
|
||||
self.num_w_ports,
|
||||
self.num_r_ports))
|
||||
|
||||
self.create_netlist()
|
||||
self.create_layout()
|
||||
|
||||
def create_netlist(self):
|
||||
self.add_pins()
|
||||
self.add_modules()
|
||||
self.create_modules()
|
||||
|
||||
def create_layout(self):
|
||||
self.place_pbitcell()
|
||||
self.route_rbc_connections()
|
||||
self.DRC_LVS()
|
||||
|
||||
def add_pins(self):
|
||||
for port in range(self.total_ports):
|
||||
self.add_pin("bl{}".format(port))
|
||||
self.add_pin("br{}".format(port))
|
||||
|
||||
for port in range(self.total_ports):
|
||||
self.add_pin("wl{}".format(port))
|
||||
|
||||
self.add_pin("vdd")
|
||||
self.add_pin("gnd")
|
||||
|
||||
def add_modules(self):
|
||||
self.prbc = factory.create(module_type="pbitcell",dummy_bitcell=True)
|
||||
self.add_mod(self.prbc)
|
||||
|
||||
self.height = self.prbc.height
|
||||
self.width = self.prbc.width
|
||||
|
||||
def create_modules(self):
|
||||
self.prbc_inst = self.add_inst(name="pbitcell",
|
||||
mod=self.prbc)
|
||||
|
||||
temp = []
|
||||
for port in range(self.total_ports):
|
||||
temp.append("bl{}".format(port))
|
||||
temp.append("br{}".format(port))
|
||||
for port in range(self.total_ports):
|
||||
temp.append("wl{}".format(port))
|
||||
temp.append("vdd")
|
||||
temp.append("gnd")
|
||||
self.connect_inst(temp)
|
||||
|
||||
def place_pbitcell(self):
|
||||
self.prbc_inst.place(offset=vector(0,0))
|
||||
|
||||
def route_rbc_connections(self):
|
||||
for port in range(self.total_ports):
|
||||
self.copy_layout_pin(self.prbc_inst, "bl{}".format(port))
|
||||
self.copy_layout_pin(self.prbc_inst, "br{}".format(port))
|
||||
for port in range(self.total_ports):
|
||||
self.copy_layout_pin(self.prbc_inst, "wl{}".format(port))
|
||||
self.copy_layout_pin(self.prbc_inst, "vdd")
|
||||
self.copy_layout_pin(self.prbc_inst, "gnd")
|
||||
|
||||
def get_wl_cin(self):
|
||||
"""Return the relative capacitance of the access transistor gates"""
|
||||
#This module is made using a pbitcell. Get the cin from that module
|
||||
return self.prbc.get_wl_cin()
|
||||
|
|
@ -20,13 +20,14 @@ class pbitcell(design.design):
|
|||
with a variable number of read/write, write, and read ports
|
||||
"""
|
||||
|
||||
def __init__(self, name, replica_bitcell=False):
|
||||
def __init__(self, name, replica_bitcell=False, dummy_bitcell=False):
|
||||
self.num_rw_ports = OPTS.num_rw_ports
|
||||
self.num_w_ports = OPTS.num_w_ports
|
||||
self.num_r_ports = OPTS.num_r_ports
|
||||
self.total_ports = self.num_rw_ports + self.num_w_ports + self.num_r_ports
|
||||
|
||||
self.replica_bitcell = replica_bitcell
|
||||
self.dummy_bitcell = dummy_bitcell
|
||||
|
||||
design.design.__init__(self, name)
|
||||
debug.info(2, "create a multi-port bitcell with {0} rw ports, {1} w ports and {2} r ports".format(self.num_rw_ports,
|
||||
|
|
@ -686,8 +687,10 @@ class pbitcell(design.design):
|
|||
port_contact_offest = left_port_transistors[k].get_pin("S").center()
|
||||
bl_offset = vector(bl_positions[k].x, port_contact_offest.y)
|
||||
|
||||
self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||
offset=port_contact_offest)
|
||||
# Leave bitline disconnected if a dummy cell
|
||||
if not self.dummy_bitcell:
|
||||
self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||
offset=port_contact_offest)
|
||||
|
||||
self.add_path("metal2", [port_contact_offest, bl_offset], width=contact.m1m2.height)
|
||||
|
||||
|
|
@ -695,8 +698,10 @@ class pbitcell(design.design):
|
|||
port_contact_offest = right_port_transistors[k].get_pin("D").center()
|
||||
br_offset = vector(br_positions[k].x, port_contact_offest.y)
|
||||
|
||||
self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||
offset=port_contact_offest)
|
||||
# Leave bitline disconnected if a dummy cell
|
||||
if not self.dummy_bitcell:
|
||||
self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||
offset=port_contact_offest)
|
||||
|
||||
self.add_path("metal2", [port_contact_offest, br_offset], width=contact.m1m2.height)
|
||||
|
||||
|
|
|
|||
|
|
@ -156,7 +156,9 @@ class bank(design.design):
|
|||
|
||||
# These are the offsets of the main array (excluding dummy and replica rows/cols)
|
||||
self.main_bitcell_array_top = self.bitcell_array_top - (self.num_ports*self.bitcell.height)
|
||||
self.main_bitcell_array_left = 2*self.bitcell.width
|
||||
# Just past the dummy column
|
||||
self.main_bitcell_array_left = self.bitcell.width
|
||||
# Just past the dummy row and replica row
|
||||
self.main_bitcell_array_bottom = 2*self.bitcell.height
|
||||
|
||||
self.compute_instance_port0_offsets()
|
||||
|
|
@ -362,9 +364,8 @@ class bank(design.design):
|
|||
for row in range(self.num_rows):
|
||||
for wordline in self.wl_names:
|
||||
temp.append(wordline+"_{0}".format(row))
|
||||
for row in range(self.num_ports):
|
||||
for wordline in self.wl_names:
|
||||
temp.append(wordline+"_{0}".format(row))
|
||||
for wordline in self.wl_names:
|
||||
temp.append("replica_"+wordline)
|
||||
temp.append("vdd")
|
||||
temp.append("gnd")
|
||||
self.connect_inst(temp)
|
||||
|
|
@ -384,6 +385,9 @@ class bank(design.design):
|
|||
mod=self.port_data[port])
|
||||
|
||||
temp = []
|
||||
if port in self.read_ports:
|
||||
temp.append("rbl_{0}".format(self.bl_names[port]))
|
||||
temp.append("rbl_{0}".format(self.br_names[port]))
|
||||
for col in range(self.num_cols):
|
||||
temp.append("{0}_{1}".format(self.bl_names[port],col))
|
||||
temp.append("{0}_{1}".format(self.br_names[port],col))
|
||||
|
|
|
|||
|
|
@ -15,13 +15,14 @@ class dummy_array(design.design):
|
|||
"""
|
||||
Generate a dummy row/column for the replica array.
|
||||
"""
|
||||
def __init__(self, cols, rows, name):
|
||||
def __init__(self, cols, rows, mirror, name):
|
||||
design.design.__init__(self, name)
|
||||
debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols))
|
||||
self.add_comment("rows: {0} cols: {1}".format(rows, cols))
|
||||
|
||||
self.column_size = cols
|
||||
self.row_size = rows
|
||||
self.mirror = mirror
|
||||
|
||||
self.create_netlist()
|
||||
if not OPTS.netlist_only:
|
||||
|
|
@ -46,7 +47,7 @@ class dummy_array(design.design):
|
|||
for row in range(self.row_size):
|
||||
name = "dummy_r{0}_c{1}".format(row, col)
|
||||
|
||||
if row % 2:
|
||||
if (row+self.mirror) % 2:
|
||||
tempy = yoffset + self.dummy_cell.height
|
||||
dir_key = "MX"
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -71,6 +71,9 @@ class port_data(design.design):
|
|||
|
||||
def add_pins(self):
|
||||
""" Adding pins for port address module"""
|
||||
if self.port in self.read_ports or self.col_addr_size>0:
|
||||
self.add_pin("rbl_"+self.bl_names[self.port],"INOUT")
|
||||
self.add_pin("rbl_"+self.br_names[self.port],"INOUT")
|
||||
for bit in range(self.num_cols):
|
||||
self.add_pin(self.bl_names[self.port]+"_{0}".format(bit),"INOUT")
|
||||
self.add_pin(self.br_names[self.port]+"_{0}".format(bit),"INOUT")
|
||||
|
|
@ -134,8 +137,9 @@ class port_data(design.design):
|
|||
def add_modules(self):
|
||||
|
||||
if self.port in self.read_ports:
|
||||
# Extra column for RBL
|
||||
self.precharge_array = factory.create(module_type="precharge_array",
|
||||
columns=self.num_cols,
|
||||
columns=self.num_cols + 1,
|
||||
bitcell_bl=self.bl_names[self.port],
|
||||
bitcell_br=self.br_names[self.port])
|
||||
self.add_mod(self.precharge_array)
|
||||
|
|
@ -144,9 +148,19 @@ class port_data(design.design):
|
|||
word_size=self.word_size,
|
||||
words_per_row=self.words_per_row)
|
||||
self.add_mod(self.sense_amp_array)
|
||||
elif self.col_addr_size>0:
|
||||
# Precharge is needed when we have a column mux
|
||||
self.precharge_array = factory.create(module_type="precharge_array",
|
||||
columns=self.num_cols,
|
||||
bitcell_bl=self.bl_names[self.port],
|
||||
bitcell_br=self.br_names[self.port])
|
||||
self.add_mod(self.precharge_array)
|
||||
self.sense_amp_array = None
|
||||
|
||||
else:
|
||||
self.precharge_array = None
|
||||
self.sense_amp_array = None
|
||||
|
||||
|
||||
if self.col_addr_size > 0:
|
||||
self.column_mux_array = factory.create(module_type="column_mux_array",
|
||||
|
|
@ -197,7 +211,10 @@ class port_data(design.design):
|
|||
|
||||
self.precharge_array_inst = self.add_inst(name="precharge_array{}".format(self.port),
|
||||
mod=self.precharge_array)
|
||||
|
||||
temp = []
|
||||
temp.append("rbl_"+self.bl_names[self.port])
|
||||
temp.append("rbl_"+self.br_names[self.port])
|
||||
for bit in range(self.num_cols):
|
||||
temp.append(self.bl_names[self.port]+"_{0}".format(bit))
|
||||
temp.append(self.br_names[self.port]+"_{0}".format(bit))
|
||||
|
|
@ -296,21 +313,30 @@ class port_data(design.design):
|
|||
vertical_port_order.append(self.sense_amp_array_inst)
|
||||
vertical_port_order.append(self.write_driver_array_inst)
|
||||
|
||||
# Add one column for the the RBL
|
||||
if self.port in self.read_ports:
|
||||
x_offset = self.bitcell.width
|
||||
else:
|
||||
x_offset = 0
|
||||
|
||||
vertical_port_offsets = 4*[None]
|
||||
self.width = 0
|
||||
self.width = x_offset
|
||||
self.height = 0
|
||||
for i,p in enumerate(vertical_port_order):
|
||||
if p==None:
|
||||
continue
|
||||
self.height += (p.height + self.m2_gap)
|
||||
self.width = max(self.width, p.width)
|
||||
vertical_port_offsets[i]=vector(0,self.height)
|
||||
vertical_port_offsets[i]=vector(x_offset,self.height)
|
||||
|
||||
# Reversed order
|
||||
self.write_driver_offset = vertical_port_offsets[3]
|
||||
self.sense_amp_offset = vertical_port_offsets[2]
|
||||
self.column_mux_offset = vertical_port_offsets[1]
|
||||
self.precharge_offset = vertical_port_offsets[0]
|
||||
if self.precharge_offset:
|
||||
self.precharge_offset -= vector(x_offset,0)
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -356,14 +382,15 @@ class port_data(design.design):
|
|||
|
||||
inst1 = self.column_mux_array_inst
|
||||
inst2 = self.precharge_array_inst
|
||||
self.connect_bitlines(inst1, inst2, self.num_cols)
|
||||
|
||||
self.connect_bitlines(inst1, inst2, self.num_cols, inst2_start_bit=1)
|
||||
|
||||
|
||||
|
||||
def route_sense_amp_to_column_mux_or_precharge_array(self, port):
|
||||
""" Routing of BL and BR between sense_amp and column mux or precharge array """
|
||||
inst2 = self.sense_amp_array_inst
|
||||
|
||||
|
||||
start_bit = 0
|
||||
if self.col_addr_size>0:
|
||||
# Sense amp is connected to the col mux
|
||||
inst1 = self.column_mux_array_inst
|
||||
|
|
@ -374,9 +401,11 @@ class port_data(design.design):
|
|||
inst1 = self.precharge_array_inst
|
||||
inst1_bl_name = "bl_{}"
|
||||
inst1_br_name = "br_{}"
|
||||
|
||||
start_bit=1
|
||||
|
||||
|
||||
self.channel_route_bitlines(inst1=inst1, inst2=inst2, num_bits=self.word_size,
|
||||
inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name)
|
||||
inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name, inst1_start_bit=start_bit)
|
||||
|
||||
def route_write_driver_to_column_mux_or_bitcell_array(self, port):
|
||||
""" Routing of BL and BR between sense_amp and column mux or bitcell array """
|
||||
|
|
@ -408,10 +437,14 @@ class port_data(design.design):
|
|||
def route_bitline_pins(self):
|
||||
""" Add the bitline pins for the given port """
|
||||
|
||||
if self.port in self.read_ports:
|
||||
self.copy_layout_pin(self.precharge_array_inst, "bl_0", "rbl_bl")
|
||||
self.copy_layout_pin(self.precharge_array_inst, "br_0", "rbl_br")
|
||||
|
||||
for bit in range(self.num_cols):
|
||||
if self.port in self.read_ports:
|
||||
self.copy_layout_pin(self.precharge_array_inst, "bl_{}".format(bit))
|
||||
self.copy_layout_pin(self.precharge_array_inst, "br_{}".format(bit))
|
||||
self.copy_layout_pin(self.precharge_array_inst, "bl_{}".format(bit+1), "bl_{}".format(bit))
|
||||
self.copy_layout_pin(self.precharge_array_inst, "br_{}".format(bit+1), "br_{}".format(bit))
|
||||
elif self.column_mux_array_inst:
|
||||
self.copy_layout_pin(self.column_mux_array_inst, "bl_{}".format(bit))
|
||||
self.copy_layout_pin(self.column_mux_array_inst, "br_{}".format(bit))
|
||||
|
|
@ -434,8 +467,8 @@ class port_data(design.design):
|
|||
|
||||
|
||||
def channel_route_bitlines(self, inst1, inst2, num_bits,
|
||||
inst1_bl_name="bl_{}", inst1_br_name="br_{}",
|
||||
inst2_bl_name="bl_{}", inst2_br_name="br_{}"):
|
||||
inst1_bl_name="bl_{}", inst1_br_name="br_{}", inst1_start_bit=0,
|
||||
inst2_bl_name="bl_{}", inst2_br_name="br_{}", inst2_start_bit=0):
|
||||
"""
|
||||
Route the bl and br of two modules using the channel router.
|
||||
"""
|
||||
|
|
@ -443,26 +476,27 @@ class port_data(design.design):
|
|||
# determine top and bottom automatically.
|
||||
# since they don't overlap, we can just check the bottom y coordinate.
|
||||
if inst1.by() < inst2.by():
|
||||
(bottom_inst, bottom_bl_name, bottom_br_name) = (inst1, inst1_bl_name, inst1_br_name)
|
||||
(top_inst, top_bl_name, top_br_name) = (inst2, inst2_bl_name, inst2_br_name)
|
||||
(bottom_inst, bottom_bl_name, bottom_br_name, bottom_start_bit) = (inst1, inst1_bl_name, inst1_br_name, inst1_start_bit)
|
||||
(top_inst, top_bl_name, top_br_name, top_start_bit) = (inst2, inst2_bl_name, inst2_br_name, inst2_start_bit)
|
||||
else:
|
||||
(bottom_inst, bottom_bl_name, bottom_br_name) = (inst2, inst2_bl_name, inst2_br_name)
|
||||
(top_inst, top_bl_name, top_br_name) = (inst1, inst1_bl_name, inst1_br_name)
|
||||
(bottom_inst, bottom_bl_name, bottom_br_name, bottom_start_bit) = (inst2, inst2_bl_name, inst2_br_name, inst2_start_bit)
|
||||
(top_inst, top_bl_name, top_br_name, top_start_bit) = (inst1, inst1_bl_name, inst1_br_name, inst1_start_bit)
|
||||
|
||||
|
||||
# Channel route each mux separately since we don't minimize the number
|
||||
# of tracks in teh channel router yet. If we did, we could route all the bits at once!
|
||||
offset = bottom_inst.ul() + vector(0,self.m1_pitch)
|
||||
for bit in range(num_bits):
|
||||
bottom_names = [bottom_inst.get_pin(bottom_bl_name.format(bit)), bottom_inst.get_pin(bottom_br_name.format(bit))]
|
||||
top_names = [top_inst.get_pin(top_bl_name.format(bit)), top_inst.get_pin(top_br_name.format(bit))]
|
||||
bottom_names = [bottom_inst.get_pin(bottom_bl_name.format(bit+bottom_start_bit)), bottom_inst.get_pin(bottom_br_name.format(bit+bottom_start_bit))]
|
||||
top_names = [top_inst.get_pin(top_bl_name.format(bit+top_start_bit)), top_inst.get_pin(top_br_name.format(bit+top_start_bit))]
|
||||
route_map = list(zip(bottom_names, top_names))
|
||||
self.create_horizontal_channel_route(route_map, offset)
|
||||
|
||||
|
||||
def connect_bitlines(self, inst1, inst2, num_bits,
|
||||
inst1_bl_name="bl_{}", inst1_br_name="br_{}",
|
||||
inst2_bl_name="bl_{}", inst2_br_name="br_{}"):
|
||||
inst1_bl_name="bl_{}", inst1_br_name="br_{}", inst1_start_bit=0,
|
||||
inst2_bl_name="bl_{}", inst2_br_name="br_{}", inst2_start_bit=0):
|
||||
|
||||
"""
|
||||
Connect the bl and br of two modules.
|
||||
This assumes that they have sufficient space to create a jog
|
||||
|
|
@ -472,17 +506,17 @@ class port_data(design.design):
|
|||
# determine top and bottom automatically.
|
||||
# since they don't overlap, we can just check the bottom y coordinate.
|
||||
if inst1.by() < inst2.by():
|
||||
(bottom_inst, bottom_bl_name, bottom_br_name) = (inst1, inst1_bl_name, inst1_br_name)
|
||||
(top_inst, top_bl_name, top_br_name) = (inst2, inst2_bl_name, inst2_br_name)
|
||||
(bottom_inst, bottom_bl_name, bottom_br_name, bottom_start_bit) = (inst1, inst1_bl_name, inst1_br_name, inst1_start_bit)
|
||||
(top_inst, top_bl_name, top_br_name, top_start_bit) = (inst2, inst2_bl_name, inst2_br_name, inst2_start_bit)
|
||||
else:
|
||||
(bottom_inst, bottom_bl_name, bottom_br_name) = (inst2, inst2_bl_name, inst2_br_name)
|
||||
(top_inst, top_bl_name, top_br_name) = (inst1, inst1_bl_name, inst1_br_name)
|
||||
(bottom_inst, bottom_bl_name, bottom_br_name, bottom_start_bit) = (inst2, inst2_bl_name, inst2_br_name, inst2_start_bit)
|
||||
(top_inst, top_bl_name, top_br_name, top_start_bit) = (inst1, inst1_bl_name, inst1_br_name, inst1_start_bit)
|
||||
|
||||
for col in range(num_bits):
|
||||
bottom_bl = bottom_inst.get_pin(bottom_bl_name.format(col)).uc()
|
||||
bottom_br = bottom_inst.get_pin(bottom_br_name.format(col)).uc()
|
||||
top_bl = top_inst.get_pin(top_bl_name.format(col)).bc()
|
||||
top_br = top_inst.get_pin(top_br_name.format(col)).bc()
|
||||
bottom_bl = bottom_inst.get_pin(bottom_bl_name.format(col+bottom_start_bit)).uc()
|
||||
bottom_br = bottom_inst.get_pin(bottom_br_name.format(col+bottom_start_bit)).uc()
|
||||
top_bl = top_inst.get_pin(top_bl_name.format(col+top_start_bit)).bc()
|
||||
top_br = top_inst.get_pin(top_br_name.format(col+top_start_bit)).bc()
|
||||
|
||||
yoffset = 0.5*(top_bl.y+bottom_bl.y)
|
||||
self.add_path("metal2",[bottom_bl, vector(bottom_bl.x,yoffset),
|
||||
|
|
|
|||
|
|
@ -22,18 +22,25 @@ class replica_bitcell_array(design.design):
|
|||
Dummy are the outside columns/rows with WL and BL tied to gnd.
|
||||
Requires a regular bitcell array, replica bitcell, and dummy bitcell (Bl/BR disconnected).
|
||||
"""
|
||||
def __init__(self, cols, rows, num_ports, name):
|
||||
def __init__(self, cols, rows, left_rbl, right_rbl, name):
|
||||
design.design.__init__(self, name)
|
||||
debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols))
|
||||
self.add_comment("rows: {0} cols: {1}".format(rows, cols))
|
||||
|
||||
self.column_size = cols
|
||||
self.row_size = rows
|
||||
self.num_ports = num_ports
|
||||
self.left_rbl = left_rbl
|
||||
self.right_rbl = right_rbl
|
||||
|
||||
# FIXME: If we want more than 2 ports of RBL, we also need to modify
|
||||
# replica_column to support this. Right now, it only supports a single
|
||||
# RBL and is used for both the left and right column (right is flipped).
|
||||
#debug.check(self.left_rbl<=1,"Only one RBL supported now.")
|
||||
#debug.check(self.right_rbl<=1,"Only one RBL supported now.")
|
||||
|
||||
# Two dummy rows/cols plus replica for each port
|
||||
self.extra_rows = 2 + self.num_ports
|
||||
self.extra_cols = 2 + self.num_ports
|
||||
self.extra_rows = 2 + left_rbl + right_rbl
|
||||
self.extra_cols = 2 + left_rbl + right_rbl
|
||||
|
||||
self.create_netlist()
|
||||
if not OPTS.netlist_only:
|
||||
|
|
@ -83,22 +90,32 @@ class replica_bitcell_array(design.design):
|
|||
rows=self.row_size)
|
||||
self.add_mod(self.bitcell_array)
|
||||
|
||||
# Replica bitline
|
||||
self.replica_column = factory.create(module_type="replica_column",
|
||||
rows=self.row_size + self.extra_rows,
|
||||
num_ports = self.num_ports)
|
||||
self.add_mod(self.replica_column)
|
||||
# Replica bitlines
|
||||
self.replica_columns = {}
|
||||
for bit in range(self.left_rbl+self.right_rbl):
|
||||
if bit<self.left_rbl:
|
||||
replica_bit = bit+1
|
||||
else:
|
||||
replica_bit = bit+self.row_size+1
|
||||
self.replica_columns[bit] = factory.create(module_type="replica_column",
|
||||
rows=self.row_size,
|
||||
left_rbl=self.left_rbl,
|
||||
right_rbl=self.right_rbl,
|
||||
replica_bit=replica_bit)
|
||||
self.add_mod(self.replica_columns[bit])
|
||||
|
||||
# Dummy row
|
||||
self.dummy_row = factory.create(module_type="dummy_array",
|
||||
cols=self.column_size,
|
||||
rows=1)
|
||||
rows=1,
|
||||
mirror=0)
|
||||
self.add_mod(self.dummy_row)
|
||||
|
||||
# Dummy col
|
||||
# Dummy col (mirror starting at first if odd replica+dummy rows)
|
||||
self.dummy_col = factory.create(module_type="dummy_array",
|
||||
cols=1,
|
||||
rows=self.row_size + self.extra_rows)
|
||||
rows=self.row_size + self.extra_rows,
|
||||
mirror=(self.left_rbl+1)%2)
|
||||
self.add_mod(self.dummy_col)
|
||||
|
||||
|
||||
|
|
@ -108,115 +125,146 @@ class replica_bitcell_array(design.design):
|
|||
self.wl_names = [x for x in self.bitcell_array.pins if x.startswith("w")]
|
||||
self.bl_names = [x for x in self.bitcell_array.pins if x.startswith("b")]
|
||||
|
||||
# top/bottom rows (in the middle)
|
||||
self.replica_wl_names = ["replica_"+x for x in self.cell.list_all_wl_names()]
|
||||
self.dummy_wl_names = ["dummy_"+x for x in self.cell.list_all_wl_names()]
|
||||
self.dummy_bl_names = ["dummy_"+x for x in self.cell.list_all_bitline_names()]
|
||||
# These are the non-indexed names
|
||||
self.replica_cell_wl_names = ["replica_"+x for x in self.cell.list_all_wl_names()]
|
||||
self.dummy_cell_wl_names = ["dummy_"+x for x in self.cell.list_all_wl_names()]
|
||||
self.dummy_cell_bl_names = ["dummy_"+x for x in self.cell.list_all_bitline_names()]
|
||||
self.dummy_row_bl_names = self.bl_names
|
||||
|
||||
# dummy row and replica on each side of the bitcell rows
|
||||
self.replica_col_wl_names = [x+"_0" for x in self.dummy_wl_names] \
|
||||
+ ["replica_"+x+"_0" for x in self.cell.list_all_wl_names()] \
|
||||
+ self.wl_names
|
||||
if self.num_ports==2:
|
||||
self.replica_col_wl_names.extend(["replica_"+x+"_1" for x in self.cell.list_all_wl_names()])
|
||||
self.replica_col_wl_names.extend([x+"_1" for x in self.dummy_wl_names])
|
||||
self.replica_bl_names = ["replica_"+x for x in self.cell.list_all_bitline_names()]
|
||||
self.replica_bl0_names = [x+"_0" for x in self.replica_bl_names]
|
||||
self.replica_bl1_names = [x+"_1" for x in self.replica_bl_names]
|
||||
|
||||
# left/right rows
|
||||
# Create the full WL names include dummy, replica, and regular bit cells
|
||||
self.replica_col_wl_names = []
|
||||
self.replica_col_wl_names.extend(["{0}_bot".format(x) for x in self.dummy_cell_wl_names])
|
||||
# Left port WLs (one dummy for each port when we allow >1 port)
|
||||
for bit in range(self.left_rbl):
|
||||
self.replica_col_wl_names.extend(["replica_{0}_{1}".format(x,bit) for x in self.cell.list_all_wl_names()])
|
||||
# Regular WLs
|
||||
self.replica_col_wl_names.extend(self.wl_names)
|
||||
# Right port WLs (one dummy for each port when we allow >1 port)
|
||||
for bit in range(self.left_rbl,self.left_rbl+self.right_rbl):
|
||||
self.replica_col_wl_names.extend(["replica_{0}_{1}".format(x,bit) for x in self.cell.list_all_wl_names()])
|
||||
self.replica_col_wl_names.extend(["{0}_top".format(x) for x in self.dummy_cell_wl_names])
|
||||
|
||||
# Left/right dummy columns are connected identically to the replica column
|
||||
self.dummy_col_wl_names = self.replica_col_wl_names
|
||||
|
||||
|
||||
|
||||
|
||||
# Per bit bitline names
|
||||
self.replica_bl_names_list = {}
|
||||
self.replica_wl_names_list = {}
|
||||
# Array of all bitline names
|
||||
self.replica_bl_names = []
|
||||
self.replica_wl_names = []
|
||||
for bit in range(self.left_rbl+self.right_rbl):
|
||||
self.replica_bl_names_list[bit] = ["replica_{0}_{1}".format(x,bit) for x in self.cell.list_all_bitline_names()]
|
||||
self.replica_bl_names.extend(self.replica_bl_names_list[bit])
|
||||
|
||||
self.replica_wl_names_list[bit] = ["{0}_{1}".format(x,bit) for x in self.replica_cell_wl_names]
|
||||
self.replica_wl_names.extend(self.replica_wl_names_list[bit])
|
||||
|
||||
|
||||
self.add_pin_list(self.bl_names)
|
||||
self.add_pin_list(self.replica_bl0_names)
|
||||
if self.num_ports==2:
|
||||
self.add_pin_list(self.replica_bl1_names)
|
||||
self.add_pin_list(self.replica_bl_names)
|
||||
self.add_pin_list(self.wl_names)
|
||||
self.add_pin_list(self.replica_wl_names)
|
||||
#self.add_pin_list([x for x in self.replica_col_wl_names if not x.startswith("dummy")])
|
||||
|
||||
self.add_pin("vdd")
|
||||
self.add_pin("gnd")
|
||||
self.add_pin("vdd", "POWER")
|
||||
self.add_pin("gnd", "GROUND")
|
||||
|
||||
|
||||
def create_instances(self):
|
||||
""" Create the module instances used in this design """
|
||||
|
||||
supplies = ["vdd", "gnd"]
|
||||
|
||||
# Used for names/dimensions only
|
||||
self.cell = factory.create(module_type="bitcell")
|
||||
|
||||
# Main array
|
||||
self.bitcell_array_inst=self.add_inst(name="bitcell_array",
|
||||
mod=self.bitcell_array)
|
||||
self.connect_inst(self.bitcell_array.pins)
|
||||
|
||||
# Replica columns (two even if one port for now)
|
||||
self.replica_col_left_inst=self.add_inst(name="replica_col_left",
|
||||
mod=self.replica_column)
|
||||
self.connect_inst(self.replica_bl0_names + self.replica_col_wl_names + supplies)
|
||||
# Replica columns
|
||||
self.replica_col_inst = {}
|
||||
for bit in range(self.left_rbl):
|
||||
self.replica_col_inst[bit]=self.add_inst(name="replica_col_left_{}".format(bit),
|
||||
mod=self.replica_columns[bit])
|
||||
self.connect_inst(self.replica_bl_names_list[bit] + self.replica_col_wl_names + supplies)
|
||||
|
||||
if self.num_ports==2:
|
||||
self.replica_col_right_inst=self.add_inst(name="replica_col_right",
|
||||
mod=self.replica_column)
|
||||
self.connect_inst(self.replica_bl1_names + self.replica_col_wl_names[::-1] + supplies)
|
||||
for bit in range(self.left_rbl,self.left_rbl+self.right_rbl):
|
||||
self.replica_col_inst[bit]=self.add_inst(name="replica_col_right_{}".format(bit),
|
||||
mod=self.replica_columns[bit])
|
||||
self.connect_inst(self.replica_bl_names_list[bit] + self.replica_col_wl_names + supplies)
|
||||
|
||||
|
||||
# Replica rows with replica bitcell
|
||||
self.dummy_row_bottop_inst=self.add_inst(name="dummy_row_bottop",
|
||||
mod=self.dummy_row)
|
||||
self.connect_inst(self.dummy_row_bl_names + [x+"_0" for x in self.replica_wl_names] + supplies)
|
||||
self.dummy_row_topbot_inst=self.add_inst(name="dummy_row_topbot",
|
||||
mod=self.dummy_row)
|
||||
self.connect_inst(self.dummy_row_bl_names + [x+"_1" for x in self.replica_wl_names] + supplies)
|
||||
self.dummy_row_replica_inst = {}
|
||||
for bit in range(self.left_rbl+self.right_rbl):
|
||||
self.dummy_row_replica_inst[bit]=self.add_inst(name="dummy_row_{}".format(bit),
|
||||
mod=self.dummy_row)
|
||||
self.connect_inst(self.dummy_row_bl_names + self.replica_wl_names_list[bit] + supplies)
|
||||
|
||||
|
||||
# Dummy rows without replica bitcell
|
||||
self.dummy_row_botbot_inst=self.add_inst(name="dummy_row_botbot",
|
||||
# Top/bottom dummy rows
|
||||
self.dummy_row_bot_inst=self.add_inst(name="dummy_row_bot",
|
||||
mod=self.dummy_row)
|
||||
self.connect_inst(self.dummy_row_bl_names + [x+"_0" for x in self.dummy_wl_names] + supplies)
|
||||
self.dummy_row_toptop_inst=self.add_inst(name="dummy_row_toptop",
|
||||
self.connect_inst(self.dummy_row_bl_names + [x+"_bot" for x in self.dummy_cell_wl_names] + supplies)
|
||||
self.dummy_row_top_inst=self.add_inst(name="dummy_row_top",
|
||||
mod=self.dummy_row)
|
||||
self.connect_inst(self.dummy_row_bl_names + [x+"_1" for x in self.dummy_wl_names] + supplies)
|
||||
self.connect_inst(self.dummy_row_bl_names + [x+"_top" for x in self.dummy_cell_wl_names] + supplies)
|
||||
|
||||
|
||||
# Dummy columns
|
||||
# Left/right Dummy columns
|
||||
self.dummy_col_left_inst=self.add_inst(name="dummy_col_left",
|
||||
mod=self.dummy_col)
|
||||
self.connect_inst([x+"_0" for x in self.dummy_bl_names] + self.dummy_col_wl_names + supplies)
|
||||
self.connect_inst([x+"_left" for x in self.dummy_cell_bl_names] + self.dummy_col_wl_names + supplies)
|
||||
self.dummy_col_right_inst=self.add_inst(name="dummy_col_right",
|
||||
mod=self.dummy_col)
|
||||
self.connect_inst([x+"_1" for x in self.dummy_bl_names] + self.dummy_col_wl_names + supplies)
|
||||
self.connect_inst([x+"_right" for x in self.dummy_cell_bl_names] + self.dummy_col_wl_names + supplies)
|
||||
|
||||
|
||||
|
||||
def create_layout(self):
|
||||
|
||||
self.height = (self.row_size+self.extra_rows)*self.dummy_row.height
|
||||
self.width = (self.column_size+self.extra_cols)*self.replica_column.width
|
||||
self.width = (self.column_size+self.extra_cols)*self.cell.width
|
||||
|
||||
# This is a bitcell x bitcell offset to scale
|
||||
offset = vector(self.replica_column.width, self.dummy_row.height)
|
||||
offset = vector(self.cell.width, self.cell.height)
|
||||
|
||||
self.bitcell_array_inst.place(offset=[0,0])
|
||||
self.replica_col_left_inst.place(offset=offset.scale(-1,-2))
|
||||
if self.num_ports==2:
|
||||
self.replica_col_right_inst.place(offset=offset.scale(0,2)+self.bitcell_array_inst.ur(),
|
||||
mirror="MX")
|
||||
|
||||
self.dummy_row_toptop_inst.place(offset=offset.scale(0,2)+self.bitcell_array_inst.ul(),
|
||||
mirror="MX")
|
||||
self.dummy_row_topbot_inst.place(offset=offset.scale(0,0)+self.bitcell_array_inst.ul())
|
||||
self.dummy_row_bottop_inst.place(offset=offset.scale(0,0),
|
||||
mirror="MX")
|
||||
self.dummy_row_botbot_inst.place(offset=offset.scale(0,-2))
|
||||
|
||||
self.dummy_col_left_inst.place(offset=offset.scale(-2,-2))
|
||||
if self.num_ports==2:
|
||||
self.dummy_col_right_inst.place(offset=offset.scale(1,-2)+self.bitcell_array_inst.lr())
|
||||
else:
|
||||
self.dummy_col_right_inst.place(offset=offset.scale(0,-2)+self.bitcell_array_inst.lr())
|
||||
# To the left of the bitcell array
|
||||
for bit in range(self.left_rbl):
|
||||
self.replica_col_inst[bit].place(offset=offset.scale(-bit-1,-self.left_rbl-1))
|
||||
# To the right of the bitcell array
|
||||
for bit in range(self.right_rbl):
|
||||
self.replica_col_inst[self.left_rbl+bit].place(offset=offset.scale(bit,-self.left_rbl-1)+self.bitcell_array_inst.lr())
|
||||
|
||||
|
||||
# Far top dummy row (first row above array is NOT flipped)
|
||||
flip_dummy = self.right_rbl%2
|
||||
self.dummy_row_top_inst.place(offset=offset.scale(0,self.right_rbl+flip_dummy)+self.bitcell_array_inst.ul(),
|
||||
mirror="MX" if flip_dummy else "R0")
|
||||
# Far bottom dummy row (first row below array IS flipped)
|
||||
flip_dummy = (self.left_rbl+1)%2
|
||||
self.dummy_row_bot_inst.place(offset=offset.scale(0,-self.left_rbl-1+flip_dummy),
|
||||
mirror="MX" if flip_dummy else "R0")
|
||||
# Far left dummy col
|
||||
self.dummy_col_left_inst.place(offset=offset.scale(-self.left_rbl-1,-self.left_rbl-1))
|
||||
# Far right dummy col
|
||||
self.dummy_col_right_inst.place(offset=offset.scale(self.right_rbl,-self.left_rbl-1)+self.bitcell_array_inst.lr())
|
||||
|
||||
# Replica dummy rows
|
||||
for bit in range(self.left_rbl):
|
||||
self.dummy_row_replica_inst[bit].place(offset=offset.scale(0,-bit-bit%2),
|
||||
mirror="R0" if bit%2 else "MX")
|
||||
for bit in range(self.right_rbl):
|
||||
self.dummy_row_replica_inst[self.left_rbl+bit].place(offset=offset.scale(0,bit+bit%2)+self.bitcell_array_inst.ul(),
|
||||
mirror="MX" if bit%2 else "R0")
|
||||
|
||||
|
||||
self.translate_all(offset.scale(-2,-2))
|
||||
self.translate_all(offset.scale(-1-self.left_rbl,-1-self.left_rbl))
|
||||
|
||||
self.add_layout_pins()
|
||||
|
||||
|
|
@ -234,52 +282,50 @@ class replica_bitcell_array(design.design):
|
|||
if pin_name.startswith("wl"):
|
||||
pin_list = self.bitcell_array_inst.get_pins(pin_name)
|
||||
for pin in pin_list:
|
||||
self.add_layout_pin_rect_center(text=pin_name,
|
||||
layer=pin.layer,
|
||||
offset=pin.center(),
|
||||
width=self.width,
|
||||
height=pin.height())
|
||||
self.add_layout_pin(text=pin_name,
|
||||
layer=pin.layer,
|
||||
offset=pin.ll().scale(0,1),
|
||||
width=self.width,
|
||||
height=pin.height())
|
||||
elif pin_name.startswith("bl") or pin_name.startswith("br"):
|
||||
pin_list = self.bitcell_array_inst.get_pins(pin_name)
|
||||
for pin in pin_list:
|
||||
self.add_layout_pin_rect_center(text=pin_name,
|
||||
layer=pin.layer,
|
||||
offset=pin.center(),
|
||||
width=pin.width(),
|
||||
height=self.height)
|
||||
self.add_layout_pin(text=pin_name,
|
||||
layer=pin.layer,
|
||||
offset=pin.ll().scale(1,0),
|
||||
width=pin.width(),
|
||||
height=self.height)
|
||||
|
||||
|
||||
for index,(side1,side2) in enumerate([("bottop","left"),("topbot","right")]):
|
||||
inst = getattr(self, "dummy_row_{}_inst".format(side1))
|
||||
pin_names = inst.mod.get_pin_names()
|
||||
for pin_name in pin_names:
|
||||
if pin_name.startswith("wl"):
|
||||
pin_list = inst.get_pins(pin_name)
|
||||
for pin in pin_list:
|
||||
name = "replica_{0}_{1}".format(pin_name,index)
|
||||
self.add_layout_pin_rect_center(text=name,
|
||||
layer=pin.layer,
|
||||
offset=pin.center(),
|
||||
width=self.width,
|
||||
height=pin.height())
|
||||
# Replica wordlines
|
||||
for bit in range(self.left_rbl+self.right_rbl):
|
||||
inst = self.replica_col_inst[bit]
|
||||
for (pin_name,wl_name) in zip(self.cell.list_all_wl_names(),self.replica_wl_names_list[bit]):
|
||||
# +1 for dummy row
|
||||
pin_bit = bit+1
|
||||
# +row_size if above the array
|
||||
if bit>=self.left_rbl:
|
||||
pin_bit += self.row_size
|
||||
|
||||
pin_name += "_{}".format(pin_bit)
|
||||
pin = inst.get_pin(pin_name)
|
||||
self.add_layout_pin(text=wl_name,
|
||||
layer=pin.layer,
|
||||
offset=pin.ll().scale(0,1),
|
||||
width=self.width,
|
||||
height=pin.height())
|
||||
|
||||
# Replica columns
|
||||
replica_sides = ["left"]
|
||||
if self.num_ports==2:
|
||||
replica_sides.append("right")
|
||||
for index,side in enumerate(replica_sides):
|
||||
inst = getattr(self, "replica_col_{}_inst".format(side))
|
||||
pin_names = inst.mod.get_pin_names()
|
||||
for pin_name in pin_names:
|
||||
if pin_name.startswith("bl") or pin_name.startswith("br"):
|
||||
pin_list = inst.get_pins(pin_name)
|
||||
for pin in pin_list:
|
||||
name = "replica_{0}_{1}".format(pin_name,index)
|
||||
self.add_layout_pin(text=name,
|
||||
layer=pin.layer,
|
||||
offset=pin.ll().scale(1,0),
|
||||
width=pin.width(),
|
||||
height=self.height)
|
||||
# Replica bitlines
|
||||
for bit in range(self.left_rbl+self.right_rbl):
|
||||
inst = self.replica_col_inst[bit]
|
||||
for (pin_name, bl_name) in zip(self.cell.list_all_bitline_names(),self.replica_bl_names_list[bit]):
|
||||
pin = inst.get_pin(pin_name)
|
||||
name = "replica_{0}_{1}".format(pin_name,bit)
|
||||
self.add_layout_pin(text=name,
|
||||
layer=pin.layer,
|
||||
offset=pin.ll().scale(1,0),
|
||||
width=pin.width(),
|
||||
height=self.height)
|
||||
|
||||
|
||||
for pin_name in ["vdd","gnd"]:
|
||||
|
|
@ -291,17 +337,17 @@ class replica_bitcell_array(design.design):
|
|||
|
||||
# Non-pins
|
||||
|
||||
for side in ["botbot", "toptop"]:
|
||||
for side in ["bot", "top"]:
|
||||
inst = getattr(self, "dummy_row_{}_inst".format(side))
|
||||
pin_names = inst.mod.get_pin_names()
|
||||
for pin_name in pin_names:
|
||||
if pin_name.startswith("wl"):
|
||||
pin_list = inst.get_pins(pin_name)
|
||||
for pin in pin_list:
|
||||
self.add_rect_center(layer=pin.layer,
|
||||
offset=pin.center(),
|
||||
width=self.width,
|
||||
height=pin.height())
|
||||
self.add_rect(layer=pin.layer,
|
||||
offset=pin.ll().scale(0,1),
|
||||
width=self.width,
|
||||
height=pin.height())
|
||||
|
||||
|
||||
for side in ["left", "right"]:
|
||||
|
|
@ -311,10 +357,10 @@ class replica_bitcell_array(design.design):
|
|||
if pin_name.startswith("b"):
|
||||
pin_list = inst.get_pins(pin_name)
|
||||
for pin in pin_list:
|
||||
self.add_rect_center(layer=pin.layer,
|
||||
offset=pin.center(),
|
||||
width=pin.width(),
|
||||
height=self.height)
|
||||
self.add_rect(layer=pin.layer,
|
||||
offset=pin.ll().scale(1,0),
|
||||
width=pin.width(),
|
||||
height=self.height)
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -48,53 +48,34 @@ class replica_bitline(design.design):
|
|||
#self.add_lvs_correspondence_points()
|
||||
|
||||
# Extra pitch on top and right
|
||||
self.width = self.replica_column_inst.rx() - self.delay_chain_inst.lx() + self.m2_pitch
|
||||
self.height = max(self.replica_column_inst.uy(), self.delay_chain_inst.uy()) + self.m3_pitch
|
||||
self.width = self.delay_chain_inst.rx() + self.m2_pitch
|
||||
self.height = self.delay_chain_inst.uy() + self.m3_pitch
|
||||
|
||||
self.add_boundary()
|
||||
self.DRC_LVS()
|
||||
|
||||
def add_pins(self):
|
||||
for pin in ["en", "out", "vdd", "gnd"]:
|
||||
self.add_pin(pin)
|
||||
|
||||
pin_list = ["en", "bl", "wl", "out", "vdd", "gnd"]
|
||||
pin_dir = ["INPUT", "INPUT", "OUTPUT", "OUTPUT", "POWER", "GROUND"]
|
||||
self.add_pin_list(pin_list, pin_dir)
|
||||
|
||||
def calculate_module_offsets(self):
|
||||
""" Calculate all the module offsets """
|
||||
|
||||
# These aren't for instantiating, but we use them to get the dimensions
|
||||
self.poly_contact_offset = vector(0.5*contact.poly.width,0.5*contact.poly.height)
|
||||
|
||||
# Quadrant 1: Replica bitline and such are not rotated, but they must be placed far enough
|
||||
# away from the delay chain/inverter with space for three M2 tracks
|
||||
self.bitcell_offset = vector(0,self.replica_bitcell.height)
|
||||
self.rbl_offset = self.bitcell_offset
|
||||
|
||||
# Gap between the delay chain and RBL
|
||||
gap_width = 2*self.m2_pitch
|
||||
|
||||
# Quadrant 4: with some space below it and tracks on the right for vdd/gnd
|
||||
self.delay_chain_offset = vector(-self.delay_chain.width-gap_width,self.replica_bitcell.height)
|
||||
self.delay_chain_offset = vector(0, self.inv.height)
|
||||
|
||||
# Will be flipped vertically below the delay chain
|
||||
# Align it with the inverters in the delay chain to simplify supply connections
|
||||
self.rbl_inv_offset = self.delay_chain_offset + vector(2*self.inv.width, 0)
|
||||
|
||||
# Placed next to the replica bitcell
|
||||
self.access_tx_offset = vector(-gap_width-self.access_tx.width-self.inv.width, 0.5*self.inv.height)
|
||||
self.access_tx_offset = vector(self.rbl_inv_offset.x + self.inv.width, 0.5*self.inv.height)
|
||||
|
||||
|
||||
def add_modules(self):
|
||||
""" Add the modules for later usage """
|
||||
|
||||
self.replica_bitcell = factory.create(module_type="replica_bitcell")
|
||||
self.add_mod(self.replica_bitcell)
|
||||
|
||||
# This is the replica bitline load column that is the height of our array
|
||||
self.rbl = factory.create(module_type="bitcell_array",
|
||||
cols=1,
|
||||
rows=self.bitcell_loads)
|
||||
self.add_mod(self.rbl)
|
||||
|
||||
# FIXME: The FO and depth of this should be tuned
|
||||
self.delay_chain = factory.create(module_type="delay_chain",
|
||||
fanout_list=self.delay_fanout_list)
|
||||
|
|
@ -125,35 +106,6 @@ class replica_bitline(design.design):
|
|||
mod=self.delay_chain)
|
||||
self.connect_inst(["en", "delayed_en", "vdd", "gnd"])
|
||||
|
||||
self.replica_cell_inst=self.add_inst(name="bitcell",
|
||||
mod=self.replica_bitcell)
|
||||
temp = []
|
||||
for port in self.all_ports:
|
||||
temp.append("bl{}_0".format(port))
|
||||
temp.append("br{}_0".format(port))
|
||||
for port in self.all_ports:
|
||||
temp.append("delayed_en")
|
||||
temp.append("vdd")
|
||||
temp.append("gnd")
|
||||
self.connect_inst(temp)
|
||||
|
||||
self.replica_column_inst=self.add_inst(name="load",
|
||||
mod=self.rbl)
|
||||
|
||||
temp = []
|
||||
for port in self.all_ports:
|
||||
temp.append("bl{}_0".format(port))
|
||||
temp.append("br{}_0".format(port))
|
||||
for wl in range(self.bitcell_loads):
|
||||
for port in self.all_ports:
|
||||
temp.append("gnd")
|
||||
temp.append("vdd")
|
||||
temp.append("gnd")
|
||||
self.connect_inst(temp)
|
||||
|
||||
self.wl_list = self.rbl.cell.list_all_wl_names()
|
||||
self.bl_list = self.rbl.cell.list_all_bl_names()
|
||||
|
||||
def place_instances(self):
|
||||
""" Add all of the module instances in the logical netlist """
|
||||
|
||||
|
|
@ -165,113 +117,23 @@ class replica_bitline(design.design):
|
|||
|
||||
self.delay_chain_inst.place(self.delay_chain_offset)
|
||||
|
||||
self.replica_cell_inst.place(offset=self.bitcell_offset,
|
||||
mirror="MX")
|
||||
|
||||
self.replica_column_inst.place(self.rbl_offset)
|
||||
|
||||
|
||||
def route(self):
|
||||
""" Connect all the signals together """
|
||||
self.route_supplies()
|
||||
self.route_wl()
|
||||
self.route_access_tx()
|
||||
|
||||
def route_wl(self):
|
||||
""" Connect the RBL word lines to gnd """
|
||||
# Connect the WL and gnd pins directly to the center and right gnd rails
|
||||
for row in range(self.bitcell_loads):
|
||||
wl = self.wl_list[0]+"_{}".format(row)
|
||||
pin = self.replica_column_inst.get_pin(wl)
|
||||
|
||||
# Route the connection to the right so that it doesn't interfere with the cells
|
||||
# Wordlines may be close to each other when tiled, so gnd connections are routed in opposite directions
|
||||
pin_right = pin.rc()
|
||||
pin_extension = pin_right + vector(self.m3_pitch,0)
|
||||
|
||||
if pin.layer != "metal1":
|
||||
continue
|
||||
pin_width_ydir = pin.uy()-pin.by()
|
||||
#Width is set to pin y width to avoid DRC issues with m1 gaps
|
||||
self.add_path("metal1", [pin_right, pin_extension], pin_width_ydir)
|
||||
self.add_power_pin("gnd", pin_extension)
|
||||
|
||||
# for multiport, need to short wordlines to each other so they all connect to gnd.
|
||||
wl_last = self.wl_list[-1]+"_{}".format(row)
|
||||
pin_last = self.replica_column_inst.get_pin(wl_last)
|
||||
self.short_wordlines(pin, pin_last, "right", False, row, vector(self.m3_pitch,0))
|
||||
|
||||
def short_wordlines(self, wl_pin_a, wl_pin_b, pin_side, is_replica_cell, cell_row=0, offset_x_vec=None):
|
||||
"""Connects the word lines together for a single bitcell. Also requires which side of the bitcell to short the pins."""
|
||||
#Assumes input pins are wordlines. Also assumes the word lines are horizontal in metal1. Also assumes pins have same x coord.
|
||||
#This is my (Hunter) first time editing layout in openram so this function is likely not optimal.
|
||||
if len(self.all_ports) > 1:
|
||||
#1. Create vertical metal for all the bitlines to connect to
|
||||
#m1 needs to be extended in the y directions, direction needs to be determined as every other cell is flipped
|
||||
correct_y = vector(0, 0.5*drc("minwidth_metal1"))
|
||||
#x spacing depends on the side being drawn. Unknown to me (Hunter) why the size of the space differs by the side.
|
||||
#I assume this is related to how a wire is draw, but I have not investigated the issue.
|
||||
if pin_side == "right":
|
||||
correct_x = vector(0.5*drc("minwidth_metal1"), 0)
|
||||
if offset_x_vec != None:
|
||||
correct_x = offset_x_vec
|
||||
else:
|
||||
correct_x = vector(1.5*drc("minwidth_metal1"), 0)
|
||||
|
||||
if wl_pin_a.uy() > wl_pin_b.uy():
|
||||
self.add_path("metal1", [wl_pin_a.rc()+correct_x+correct_y, wl_pin_b.rc()+correct_x-correct_y])
|
||||
else:
|
||||
self.add_path("metal1", [wl_pin_a.rc()+correct_x-correct_y, wl_pin_b.rc()+correct_x+correct_y])
|
||||
elif pin_side == "left":
|
||||
if offset_x_vec != None:
|
||||
correct_x = offset_x_vec
|
||||
else:
|
||||
correct_x = vector(1.5*drc("minwidth_metal1"), 0)
|
||||
|
||||
if wl_pin_a.uy() > wl_pin_b.uy():
|
||||
self.add_path("metal1", [wl_pin_a.lc()-correct_x+correct_y, wl_pin_b.lc()-correct_x-correct_y])
|
||||
else:
|
||||
self.add_path("metal1", [wl_pin_a.lc()-correct_x-correct_y, wl_pin_b.lc()-correct_x+correct_y])
|
||||
else:
|
||||
debug.error("Could not connect wordlines on specified input side={}".format(pin_side),1)
|
||||
|
||||
#2. Connect word lines horizontally. Only replica cell needs. Bitline loads currently already do this.
|
||||
for port in self.all_ports:
|
||||
if is_replica_cell:
|
||||
wl = self.wl_list[port]
|
||||
pin = self.replica_cell_inst.get_pin(wl)
|
||||
else:
|
||||
wl = self.wl_list[port]+"_{}".format(cell_row)
|
||||
pin = self.replica_column_inst.get_pin(wl)
|
||||
|
||||
if pin_side == "left":
|
||||
self.add_path("metal1", [pin.lc()-correct_x, pin.lc()])
|
||||
elif pin_side == "right":
|
||||
self.add_path("metal1", [pin.rc()+correct_x, pin.rc()])
|
||||
|
||||
|
||||
|
||||
def route_supplies(self):
|
||||
""" Propagate all vdd/gnd pins up to this level for all modules """
|
||||
|
||||
# These are the instances that every bank has
|
||||
top_instances = [self.replica_column_inst,
|
||||
self.delay_chain_inst]
|
||||
for inst in top_instances:
|
||||
self.copy_layout_pin(inst, "vdd")
|
||||
self.copy_layout_pin(inst, "gnd")
|
||||
|
||||
self.copy_layout_pin(self.delay_chain_inst, "vdd")
|
||||
self.copy_layout_pin(self.delay_chain_inst, "gnd")
|
||||
|
||||
# Route the inverter supply pin from M1
|
||||
# Only vdd is needed because gnd shares a rail with the delay chain
|
||||
pin = self.rbl_inv_inst.get_pin("vdd")
|
||||
self.add_power_pin("vdd", pin.lc())
|
||||
|
||||
for pin in self.replica_cell_inst.get_pins("vdd"):
|
||||
self.add_power_pin(name="vdd", loc=pin.center(), vertical=True, start_layer=pin.layer)
|
||||
|
||||
for pin in self.replica_cell_inst.get_pins("gnd"):
|
||||
self.add_power_pin("gnd", pin.center(), vertical=True, start_layer=pin.layer)
|
||||
|
||||
|
||||
|
||||
|
|
@ -304,24 +166,10 @@ class replica_bitline(design.design):
|
|||
|
||||
# 3. Route the contact of previous route to the bitcell WL
|
||||
# route bend of previous net to bitcell WL
|
||||
wl_offset = self.replica_cell_inst.get_pin(self.wl_list[0]).lc()
|
||||
wl_mid1 = wl_offset - vector(1.5*drc("minwidth_metal1"), 0)
|
||||
wl_mid2 = vector(wl_mid1.x, contact_offset.y)
|
||||
#xmid_point= 0.5*(wl_offset.x+contact_offset.x)
|
||||
#wl_mid1 = vector(xmid_point,contact_offset.y)
|
||||
#wl_mid2 = vector(xmid_point,wl_offset.y)
|
||||
self.add_path("metal1", [wl_offset, wl_mid1, wl_mid2, contact_offset])
|
||||
self.add_layout_pin_rect_center(text="wl",
|
||||
layer="metal1",
|
||||
offset=contact_offset)
|
||||
|
||||
# 4. Short wodlines if multiport
|
||||
wl = self.wl_list[0]
|
||||
wl_last = self.wl_list[-1]
|
||||
pin = self.replica_cell_inst.get_pin(wl)
|
||||
pin_last = self.replica_cell_inst.get_pin(wl_last)
|
||||
x_offset = self.short_wordlines(pin, pin_last, "left", True)
|
||||
|
||||
#correct = vector(0.5*drc("minwidth_metal1"), 0)
|
||||
#self.add_path("metal1", [pin.lc()+correct, pin_last.lc()+correct])
|
||||
|
||||
# DRAIN ROUTE
|
||||
# Route the drain to the vdd rail
|
||||
drain_offset = self.tx_inst.get_pin("D").center()
|
||||
|
|
@ -334,13 +182,13 @@ class replica_bitline(design.design):
|
|||
self.add_path("metal1",[source_offset, inv_A_offset])
|
||||
|
||||
# Route the connection of the source route to the RBL bitline (left)
|
||||
# Via will go halfway down from the bitcell
|
||||
bl_offset = self.replica_cell_inst.get_pin(self.bl_list[0]).bc()
|
||||
# Route down a pitch so we can use M2 routing
|
||||
bl_down_offset = bl_offset - vector(0, self.m2_pitch)
|
||||
self.add_path("metal2",[source_offset, bl_down_offset, bl_offset])
|
||||
source_down_offset = source_offset - vector(0,3*self.m2_pitch)
|
||||
self.add_path("metal1",[source_offset, source_down_offset])
|
||||
self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||
offset=source_offset)
|
||||
self.add_layout_pin_rect_center(text="bl",
|
||||
layer="metal1",
|
||||
offset=source_down_offset)
|
||||
|
||||
# BODY ROUTE
|
||||
# Connect it to the inverter well
|
||||
|
|
@ -351,205 +199,6 @@ class replica_bitline(design.design):
|
|||
width=ur_offset.x-nwell_offset.x,
|
||||
height=ur_offset.y-nwell_offset.y)
|
||||
|
||||
def route_vdd(self):
|
||||
""" Route all signals connected to vdd """
|
||||
|
||||
self.copy_layout_pin(self.delay_chain_inst,"vdd")
|
||||
self.copy_layout_pin(self.replica_cell_inst,"vdd")
|
||||
|
||||
# Connect the WL and vdd pins directly to the center and right vdd rails
|
||||
# Connect RBL vdd pins to center and right rails
|
||||
rbl_vdd_pins = self.replica_column_inst.get_pins("vdd")
|
||||
for pin in rbl_vdd_pins:
|
||||
if pin.layer != "metal1":
|
||||
continue
|
||||
start = vector(self.center_vdd_pin.cx(),pin.cy())
|
||||
end = vector(self.right_vdd_pin.cx(),pin.cy())
|
||||
self.add_layout_pin_segment_center(text="vdd",
|
||||
layer="metal1",
|
||||
start=start,
|
||||
end=end)
|
||||
self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||
offset=start)
|
||||
self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||
offset=end)
|
||||
|
||||
# Add via for the inverter
|
||||
pin = self.rbl_inv_inst.get_pin("vdd")
|
||||
start = vector(self.left_vdd_pin.cx(),pin.cy())
|
||||
end = vector(self.center_vdd_pin.cx(),pin.cy())
|
||||
self.add_segment_center(layer="metal1",
|
||||
start=start,
|
||||
end=end)
|
||||
self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||
offset=start)
|
||||
|
||||
self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||
offset=end)
|
||||
|
||||
|
||||
# Add via for the RBC
|
||||
pin = self.replica_cell_inst.get_pin("vdd")
|
||||
start = pin.lc()
|
||||
end = vector(self.right_vdd_pin.cx(),pin.cy())
|
||||
self.add_segment_center(layer="metal1",
|
||||
start=start,
|
||||
end=end)
|
||||
self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||
offset=end)
|
||||
|
||||
# Create the RBL rails too
|
||||
rbl_pins = self.replica_column_inst.get_pins("vdd")
|
||||
for pin in rbl_pins:
|
||||
if pin.layer != "metal1":
|
||||
continue
|
||||
# If above the delay line, route the full width
|
||||
left = vector(self.left_vdd_pin.cx(),pin.cy())
|
||||
center = vector(self.center_vdd_pin.cx(),pin.cy())
|
||||
if pin.cy() > self.delay_chain_inst.uy() + self.m1_pitch:
|
||||
start = left
|
||||
self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||
offset=left)
|
||||
else:
|
||||
start = center
|
||||
end = vector(self.right_vdd_pin.cx()+0.5*self.m1_width,pin.cy())
|
||||
self.add_layout_pin_segment_center(text="vdd",
|
||||
layer="metal1",
|
||||
start=start,
|
||||
end=end)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def route_gnd(self):
|
||||
""" Route all signals connected to gnd """
|
||||
|
||||
# Route the gnd lines from left to right
|
||||
|
||||
# Add via for the delay chain
|
||||
left_gnd_start = self.delay_chain_inst.ll().scale(1,0) - vector(2*self.m2_pitch,0)
|
||||
left_gnd_end = vector(left_gnd_start.x, self.replica_column_inst.uy()+self.m2_pitch)
|
||||
self.left_gnd_pin=self.add_segment_center(layer="metal2",
|
||||
start=left_gnd_start,
|
||||
end=left_gnd_end)
|
||||
|
||||
# Gnd line to the left of the replica bitline
|
||||
center_gnd_start = self.replica_cell_inst.ll().scale(1,0) - vector(2*self.m2_pitch,0)
|
||||
center_gnd_end = vector(center_gnd_start.x, self.replica_column_inst.uy()+self.m2_pitch)
|
||||
self.center_gnd_pin=self.add_segment_center(layer="metal2",
|
||||
start=center_gnd_start,
|
||||
end=center_gnd_end)
|
||||
|
||||
# Gnd line to the right of the replica bitline
|
||||
right_gnd_start = self.replica_cell_inst.lr().scale(1,0) + vector(self.m2_pitch,0)
|
||||
right_gnd_end = vector(right_gnd_start.x, self.replica_column_inst.uy()+self.m2_pitch)
|
||||
self.right_gnd_pin=self.add_segment_center(layer="metal2",
|
||||
start=right_gnd_start,
|
||||
end=right_gnd_end)
|
||||
|
||||
|
||||
|
||||
# Connect the WL and gnd pins directly to the center and right gnd rails
|
||||
for row in range(self.bitcell_loads):
|
||||
wl = self.wl_list[0]+"_{}".format(row)
|
||||
pin = self.replica_column_inst.get_pin(wl)
|
||||
if pin.layer != "metal1":
|
||||
continue
|
||||
# If above the delay line, route the full width
|
||||
left = vector(self.left_gnd_pin.cx(),pin.cy())
|
||||
center = vector(self.center_gnd_pin.cx(),pin.cy())
|
||||
if pin.cy() > self.delay_chain_inst.uy() + self.m1_pitch:
|
||||
start = left
|
||||
else:
|
||||
start = center
|
||||
end = vector(self.right_gnd_pin.cx(),pin.cy())
|
||||
self.add_layout_pin_segment_center(text="gnd",
|
||||
layer="metal1",
|
||||
start=start,
|
||||
end=end)
|
||||
if start == left:
|
||||
self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||
offset=left)
|
||||
self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||
offset=center)
|
||||
self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||
offset=end)
|
||||
|
||||
|
||||
# rbl_gnd_pins = self.replica_column_inst.get_pins("gnd")
|
||||
# # Add L shapes to each vertical gnd rail
|
||||
# for pin in rbl_gnd_pins:
|
||||
# if pin.layer != "metal1":
|
||||
# continue
|
||||
# # If above the delay line, route the full width
|
||||
# left = vector(self.left_gnd_pin.cx(),pin.cy())
|
||||
# center = vector(self.center_gnd_pin.cx(),pin.cy())
|
||||
# if pin.cy() > self.delay_chain_inst.uy() + self.m1_pitch:
|
||||
# start = left
|
||||
# else:
|
||||
# start = center
|
||||
# end = vector(self.right_gnd_pin.cx(),pin.cy())
|
||||
# self.add_segment_center(layer="metal1",
|
||||
# start=start,
|
||||
# end=end)
|
||||
# if start == left:
|
||||
# self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||
# offset=left)
|
||||
# self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||
# offset=center)
|
||||
# self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||
# offset=end)
|
||||
|
||||
|
||||
|
||||
# Connect the gnd pins of the delay chain to the left rails
|
||||
dc_gnd_pins = self.delay_chain_inst.get_pins("gnd")
|
||||
for pin in dc_gnd_pins:
|
||||
if pin.layer != "metal1":
|
||||
continue
|
||||
start = vector(self.left_gnd_pin.cx(),pin.cy())
|
||||
# Note, we don't connect to the center rails because of
|
||||
# via conflicts with the RBL
|
||||
#end = vector(self.center_gnd_pin.cx(),pin.cy())
|
||||
end = pin.rc()
|
||||
self.add_segment_center(layer="metal1",
|
||||
start=start,
|
||||
end=end)
|
||||
self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||
offset=start)
|
||||
|
||||
# self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||
# offset=end)
|
||||
|
||||
|
||||
# Add via for the inverter
|
||||
# pin = self.rbl_inv_inst.get_pin("gnd")
|
||||
# start = vector(self.left_gnd_pin.cx(),pin.cy())
|
||||
# end = vector(self.center_gnd_pin.cx(),pin.cy())
|
||||
# self.add_segment_center(layer="metal1",
|
||||
# start=start,
|
||||
# end=end)
|
||||
# self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||
# offset=start)
|
||||
# self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||
# offset=end)
|
||||
|
||||
|
||||
|
||||
# Create RBL rails too
|
||||
rbl_pins = self.replica_column_inst.get_pins("gnd")
|
||||
for pin in rbl_pins:
|
||||
if pin.layer != "metal2":
|
||||
continue
|
||||
start = vector(pin.cx(),self.right_gnd_pin.by())
|
||||
end = vector(pin.cx(),self.right_gnd_pin.uy())
|
||||
self.add_layout_pin_segment_center(text="gnd",
|
||||
layer="metal2",
|
||||
start=start,
|
||||
end=end)
|
||||
|
||||
|
||||
|
||||
def add_layout_pins(self):
|
||||
|
|
|
|||
|
|
@ -14,13 +14,25 @@ from globals import OPTS
|
|||
class replica_column(design.design):
|
||||
"""
|
||||
Generate a replica bitline column for the replica array.
|
||||
Rows is the total number of rows i the main array.
|
||||
Left_rbl and right_rbl are the number of left and right replica bitlines.
|
||||
Replica bit specifies which replica column this is (to determine where to put the
|
||||
replica cell.
|
||||
"""
|
||||
|
||||
def __init__(self, name, rows, num_ports):
|
||||
def __init__(self, name, rows, left_rbl, right_rbl, replica_bit):
|
||||
design.design.__init__(self, name)
|
||||
|
||||
self.row_size = rows
|
||||
self.num_ports = num_ports
|
||||
self.rows = rows
|
||||
self.left_rbl = left_rbl
|
||||
self.right_rbl = right_rbl
|
||||
self.replica_bit = replica_bit
|
||||
# left, right, regular rows plus top/bottom dummy cells
|
||||
self.total_size = self.left_rbl+rows+self.right_rbl+2
|
||||
|
||||
debug.check(replica_bit!=0 and replica_bit!=rows,"Replica bit cannot be the dummy row.")
|
||||
debug.check(replica_bit<=left_rbl or replica_bit>=self.total_size-right_rbl-1,
|
||||
"Replica bit cannot be in the regular array.")
|
||||
|
||||
self.create_netlist()
|
||||
if not OPTS.netlist_only:
|
||||
|
|
@ -32,12 +44,11 @@ class replica_column(design.design):
|
|||
self.create_instances()
|
||||
|
||||
def create_layout(self):
|
||||
self.place_instances()
|
||||
self.add_layout_pins()
|
||||
|
||||
self.height = self.row_size*self.cell.height
|
||||
self.height = self.total_size*self.cell.height
|
||||
self.width = self.cell.width
|
||||
|
||||
self.place_instances()
|
||||
self.add_layout_pins()
|
||||
self.add_boundary()
|
||||
self.DRC_LVS()
|
||||
|
||||
|
|
@ -46,7 +57,7 @@ class replica_column(design.design):
|
|||
for cell_column in column_list:
|
||||
self.add_pin("{0}_{1}".format(cell_column,0))
|
||||
row_list = self.cell.list_all_wl_names()
|
||||
for row in range(self.row_size):
|
||||
for row in range(self.total_size):
|
||||
for cell_row in row_list:
|
||||
self.add_pin("{0}_{1}".format(cell_row,row))
|
||||
|
||||
|
|
@ -63,9 +74,15 @@ class replica_column(design.design):
|
|||
|
||||
def create_instances(self):
|
||||
self.cell_inst = {}
|
||||
for row in range(self.row_size):
|
||||
for row in range(self.total_size):
|
||||
name="rbc_{0}".format(row)
|
||||
if row>0 and row<self.row_size - self.num_ports:
|
||||
# Top/bottom cell are always dummy cells.
|
||||
# Regular array cells are replica cells (>left_rbl and <rows-right_rbl)
|
||||
# Replic bit specifies which other bit (in the full range (0,rows) to make a replica cell.
|
||||
if (row>self.left_rbl and row<self.total_size-self.right_rbl-1):
|
||||
self.cell_inst[row]=self.add_inst(name=name,
|
||||
mod=self.replica_cell)
|
||||
elif row==self.replica_bit:
|
||||
self.cell_inst[row]=self.add_inst(name=name,
|
||||
mod=self.replica_cell)
|
||||
else:
|
||||
|
|
@ -75,21 +92,20 @@ class replica_column(design.design):
|
|||
|
||||
def place_instances(self):
|
||||
|
||||
yoffset = 0
|
||||
for row in range(self.row_size):
|
||||
# Flip the mirrors if we have an odd number of replica+dummy rows at the bottom
|
||||
# so that we will start with mirroring rather than not mirroring
|
||||
rbl_offset = (self.left_rbl+1)%2
|
||||
|
||||
for row in range(self.total_size):
|
||||
name = "bit_r{0}_{1}".format(row,"rbl")
|
||||
|
||||
# This is opposite of a bitcell array since we will be 1 row off
|
||||
if not row % 2:
|
||||
tempy = yoffset
|
||||
dir_key = ""
|
||||
else:
|
||||
tempy = yoffset + self.cell.height
|
||||
offset = vector(0,self.cell.height*(row+(row+rbl_offset)%2))
|
||||
if (row+rbl_offset)%2:
|
||||
dir_key = "MX"
|
||||
else:
|
||||
dir_key = "R0"
|
||||
|
||||
self.cell_inst[row].place(offset=[0.0, tempy],
|
||||
mirror=dir_key)
|
||||
yoffset += self.cell.height
|
||||
self.cell_inst[row].place(offset=offset,
|
||||
mirror=dir_key)
|
||||
|
||||
|
||||
|
||||
|
|
@ -99,26 +115,25 @@ class replica_column(design.design):
|
|||
row_list = self.cell.list_all_wl_names()
|
||||
column_list = self.cell.list_all_bitline_names()
|
||||
|
||||
col = "0"
|
||||
for cell_column in column_list:
|
||||
bl_pin = self.cell_inst[0].get_pin(cell_column)
|
||||
self.add_layout_pin(text=cell_column+"_{0}".format(col),
|
||||
self.add_layout_pin(text=cell_column,
|
||||
layer="metal2",
|
||||
offset=bl_pin.ll(),
|
||||
width=bl_pin.width(),
|
||||
height=self.height)
|
||||
|
||||
for row in range(self.row_size):
|
||||
for row in range(self.total_size):
|
||||
for cell_row in row_list:
|
||||
wl_pin = self.cell_inst[row].get_pin(cell_row)
|
||||
self.add_layout_pin(text=cell_row+"_{0}".format(row),
|
||||
layer="metal1",
|
||||
offset=wl_pin.ll(),
|
||||
offset=wl_pin.ll().scale(0,1),
|
||||
width=self.width,
|
||||
height=wl_pin.height())
|
||||
|
||||
# For every second row and column, add a via for gnd and vdd
|
||||
for row in range(self.row_size):
|
||||
for row in range(self.total_size):
|
||||
inst = self.cell_inst[row]
|
||||
for pin_name in ["vdd", "gnd"]:
|
||||
self.copy_layout_pin(inst, pin_name)
|
||||
|
|
|
|||
|
|
@ -283,7 +283,8 @@ class sram_base(design, verilog, lef):
|
|||
# Create the bank module (up to four are instantiated)
|
||||
from bank import bank
|
||||
self.bank = bank(self.sram_config,
|
||||
name="bank")
|
||||
name="bank",
|
||||
num_ports=len(self.all_ports))
|
||||
self.add_mod(self.bank)
|
||||
|
||||
# Create bank decoder
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
#!/usr/bin/env python3
|
||||
# See LICENSE for licensing information.
|
||||
#
|
||||
# Copyright (c) 2016-2019 Regents of the University of California and The Board
|
||||
# of Regents for the Oklahoma Agricultural and Mechanical College
|
||||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
import unittest
|
||||
from testutils import *
|
||||
import sys,os
|
||||
sys.path.append(os.getenv("OPENRAM_HOME"))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
from sram_factory import factory
|
||||
import debug
|
||||
|
||||
class replica_pbitcell_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
||||
import dummy_pbitcell
|
||||
|
||||
OPTS.bitcell = "pbitcell"
|
||||
OPTS.num_rw_ports = 1
|
||||
OPTS.num_r_ports = 0
|
||||
OPTS.num_w_ports = 0
|
||||
|
||||
factory.reset()
|
||||
debug.info(2, "Checking dummy bitcell using pbitcell (small cell)")
|
||||
tx = dummy_pbitcell.dummy_pbitcell(name="rpbc")
|
||||
self.local_check(tx)
|
||||
|
||||
OPTS.num_rw_ports = 1
|
||||
OPTS.num_r_ports = 1
|
||||
OPTS.num_w_ports = 1
|
||||
|
||||
factory.reset()
|
||||
debug.info(2, "Checking dummy bitcell using pbitcell (large cell)")
|
||||
tx = dummy_pbitcell.dummy_pbitcell(name="rpbc")
|
||||
self.local_check(tx)
|
||||
|
||||
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(testRunner=debugTestRunner())
|
||||
|
|
@ -20,12 +20,14 @@ import debug
|
|||
class bitcell_1rw_1r_array_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
||||
|
||||
debug.info(2, "Testing 4x4 array for cell_1rw_1r")
|
||||
OPTS.num_rw_ports = 1
|
||||
OPTS.num_r_ports = 1
|
||||
OPTS.num_w_ports = 0
|
||||
|
||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
||||
|
||||
a = factory.create(module_type="bitcell_array", cols=4, rows=4)
|
||||
self.local_check(a)
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
#!/usr/bin/env python3
|
||||
# See LICENSE for licensing information.
|
||||
#
|
||||
# Copyright (c) 2016-2019 Regents of the University of California
|
||||
# All rights reserved.
|
||||
#
|
||||
import unittest
|
||||
from testutils import *
|
||||
import sys,os
|
||||
sys.path.append(os.getenv("OPENRAM_HOME"))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
from sram_factory import factory
|
||||
import debug
|
||||
|
||||
class replica_bitcell_array_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
OPTS.num_rw_ports = 1
|
||||
OPTS.num_r_ports = 1
|
||||
OPTS.num_w_ports = 0
|
||||
|
||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
||||
|
||||
debug.info(2, "Testing 4x4 array for cell_1rw_1r")
|
||||
a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, left_rbl=1, right_rbl=1)
|
||||
self.local_check(a)
|
||||
|
||||
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(testRunner=debugTestRunner())
|
||||
|
|
@ -19,16 +19,11 @@ class replica_bitcell_array_test(openram_test):
|
|||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
||||
|
||||
debug.info(2, "Testing 4x4 array for 6t_cell")
|
||||
a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, num_ports=1)
|
||||
a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, left_rbl=1, right_rbl=0)
|
||||
self.local_check(a)
|
||||
|
||||
OPTS.num_rw_ports = 1
|
||||
OPTS.num_r_ports = 1
|
||||
OPTS.num_w_ports = 0
|
||||
|
||||
factory.reset()
|
||||
debug.info(2, "Testing 4x4 array for 6t_cell")
|
||||
a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, num_ports=2)
|
||||
a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, left_rbl=0, right_rbl=1)
|
||||
self.local_check(a)
|
||||
|
||||
globals.end_openram()
|
||||
|
|
|
|||
|
|
@ -19,11 +19,15 @@ class replica_column_test(openram_test):
|
|||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
||||
|
||||
debug.info(2, "Testing replica column for 6t_cell")
|
||||
a = factory.create(module_type="replica_column", rows=4, num_ports=1)
|
||||
a = factory.create(module_type="replica_column", rows=4, left_rbl=1, right_rbl=0, replica_bit=1)
|
||||
self.local_check(a)
|
||||
|
||||
debug.info(2, "Testing replica column for 6t_cell")
|
||||
a = factory.create(module_type="replica_column", rows=4, num_ports=2)
|
||||
a = factory.create(module_type="replica_column", rows=4, left_rbl=1, right_rbl=1, replica_bit=6)
|
||||
self.local_check(a)
|
||||
|
||||
debug.info(2, "Testing replica column for 6t_cell")
|
||||
a = factory.create(module_type="replica_column", rows=4, left_rbl=2, right_rbl=0, replica_bit=2)
|
||||
self.local_check(a)
|
||||
|
||||
globals.end_openram()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
#!/usr/bin/env python3
|
||||
# See LICENSE for licensing information.
|
||||
#
|
||||
# Copyright (c) 2016-2019 Regents of the University of California
|
||||
# All rights reserved.
|
||||
#
|
||||
import unittest
|
||||
from testutils import *
|
||||
import sys,os
|
||||
sys.path.append(os.getenv("OPENRAM_HOME"))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
from sram_factory import factory
|
||||
import debug
|
||||
|
||||
class replica_bitcell_array_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
||||
|
||||
debug.info(2, "Testing 4x4 array for multiport bitcell, with read ports at the edge of the bit cell")
|
||||
OPTS.bitcell = "pbitcell"
|
||||
OPTS.replica_bitcell = "replica_pbitcell"
|
||||
OPTS.dummy_bitcell = "dummy_pbitcell"
|
||||
OPTS.num_rw_ports = 1
|
||||
OPTS.num_r_ports = 1
|
||||
OPTS.num_w_ports = 0
|
||||
|
||||
debug.info(2, "Testing 4x4 array for pbitcell")
|
||||
a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, left_rbl=1, right_rbl=1)
|
||||
self.local_check(a)
|
||||
|
||||
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(testRunner=debugTestRunner())
|
||||
|
|
@ -18,13 +18,12 @@ import debug
|
|||
class single_bank_1rw_1r_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
||||
|
||||
OPTS.bitcell = "bitcell_1rw_1r"
|
||||
OPTS.num_rw_ports = 1
|
||||
OPTS.num_r_ports = 1
|
||||
OPTS.num_w_ports = 0
|
||||
|
||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
||||
|
||||
from sram_config import sram_config
|
||||
c = sram_config(word_size=4,
|
||||
num_words=16)
|
||||
|
|
@ -33,7 +32,7 @@ class single_bank_1rw_1r_test(openram_test):
|
|||
factory.reset()
|
||||
c.recompute_sizes()
|
||||
debug.info(1, "No column mux")
|
||||
a = factory.create(module_type="bank", sram_config=c)
|
||||
a = factory.create(module_type="bank", sram_config=c, num_ports=2)
|
||||
self.local_check(a)
|
||||
|
||||
c.num_words=32
|
||||
|
|
@ -41,7 +40,7 @@ class single_bank_1rw_1r_test(openram_test):
|
|||
factory.reset()
|
||||
c.recompute_sizes()
|
||||
debug.info(1, "Two way column mux")
|
||||
a = factory.create(module_type="bank", sram_config=c)
|
||||
a = factory.create(module_type="bank", sram_config=c, num_ports=2)
|
||||
self.local_check(a)
|
||||
|
||||
c.num_words=64
|
||||
|
|
@ -49,7 +48,7 @@ class single_bank_1rw_1r_test(openram_test):
|
|||
factory.reset()
|
||||
c.recompute_sizes()
|
||||
debug.info(1, "Four way column mux")
|
||||
a = factory.create(module_type="bank", sram_config=c)
|
||||
a = factory.create(module_type="bank", sram_config=c, num_ports=2)
|
||||
self.local_check(a)
|
||||
|
||||
c.word_size=2
|
||||
|
|
@ -58,7 +57,7 @@ class single_bank_1rw_1r_test(openram_test):
|
|||
factory.reset()
|
||||
c.recompute_sizes()
|
||||
debug.info(1, "Eight way column mux")
|
||||
a = factory.create(module_type="bank", sram_config=c)
|
||||
a = factory.create(module_type="bank", sram_config=c, num_ports=2)
|
||||
self.local_check(a)
|
||||
|
||||
globals.end_openram()
|
||||
|
|
|
|||
|
|
@ -18,13 +18,12 @@ import debug
|
|||
class single_bank_1w_1r_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
OPTS.num_rw_ports = 0
|
||||
OPTS.num_r_ports = 1
|
||||
OPTS.num_w_ports = 1
|
||||
|
||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
||||
|
||||
OPTS.bitcell = "bitcell_1w_1r"
|
||||
OPTS.num_rw_ports = 1
|
||||
OPTS.num_r_ports = 1
|
||||
OPTS.num_w_ports = 0
|
||||
|
||||
from sram_config import sram_config
|
||||
c = sram_config(word_size=4,
|
||||
num_words=16)
|
||||
|
|
@ -33,7 +32,7 @@ class single_bank_1w_1r_test(openram_test):
|
|||
factory.reset()
|
||||
c.recompute_sizes()
|
||||
debug.info(1, "No column mux")
|
||||
a = factory.create(module_type="bank", sram_config=c)
|
||||
a = factory.create(module_type="bank", sram_config=c, num_ports=2)
|
||||
self.local_check(a)
|
||||
|
||||
c.num_words=32
|
||||
|
|
@ -41,7 +40,7 @@ class single_bank_1w_1r_test(openram_test):
|
|||
factory.reset()
|
||||
c.recompute_sizes()
|
||||
debug.info(1, "Two way column mux")
|
||||
a = factory.create(module_type="bank", sram_config=c)
|
||||
a = factory.create(module_type="bank", sram_config=c, num_ports=2)
|
||||
self.local_check(a)
|
||||
|
||||
c.num_words=64
|
||||
|
|
@ -49,7 +48,7 @@ class single_bank_1w_1r_test(openram_test):
|
|||
factory.reset()
|
||||
c.recompute_sizes()
|
||||
debug.info(1, "Four way column mux")
|
||||
a = factory.create(module_type="bank", sram_config=c)
|
||||
a = factory.create(module_type="bank", sram_config=c, num_ports=2)
|
||||
self.local_check(a)
|
||||
|
||||
c.word_size=2
|
||||
|
|
@ -58,7 +57,7 @@ class single_bank_1w_1r_test(openram_test):
|
|||
factory.reset()
|
||||
c.recompute_sizes()
|
||||
debug.info(1, "Eight way column mux")
|
||||
a = factory.create(module_type="bank", sram_config=c)
|
||||
a = factory.create(module_type="bank", sram_config=c, num_ports=2)
|
||||
self.local_check(a)
|
||||
|
||||
globals.end_openram()
|
||||
|
|
|
|||
|
|
@ -60,6 +60,8 @@ class openram_test(unittest.TestCase):
|
|||
#shutil.make_archive(zip_file, 'zip', OPTS.openram_temp)
|
||||
self.fail("LVS mismatch: {}".format(a.name))
|
||||
|
||||
# For debug...
|
||||
#import pdb; pdb.set_trace()
|
||||
if OPTS.purge_temp:
|
||||
self.cleanup()
|
||||
|
||||
|
|
|
|||
|
|
@ -2,15 +2,11 @@
|
|||
ignore class c
|
||||
equate class {-circuit1 nfet} {-circuit2 n}
|
||||
equate class {-circuit1 pfet} {-circuit2 p}
|
||||
# This circuit has symmetries and needs to be flattened to resolve them
|
||||
# or the banks won't pass
|
||||
# We must flatten these because the ports are disconnected
|
||||
flatten class {-circuit1 dummy_cell_6t}
|
||||
flatten class {-circuit1 bitcell_array_0}
|
||||
flatten class {-circuit1 bitcell_array_1}
|
||||
#flatten class {-circuit1 precharge_array_0}
|
||||
#flatten class {-circuit1 precharge_array_1}
|
||||
#flatten class {-circuit1 precharge_array_2}
|
||||
#flatten class {-circuit1 precharge_array_3}
|
||||
flatten class {-circuit1 dummy_cell_1rw_1r}
|
||||
flatten class {-circuit1 dummy_cell_1w_1r}
|
||||
flatten class {-circuit1 dummy_pbitcell}
|
||||
property {-circuit1 nfet} remove as ad ps pd
|
||||
property {-circuit1 pfet} remove as ad ps pd
|
||||
property {-circuit2 n} remove as ad ps pd
|
||||
|
|
|
|||
Loading…
Reference in New Issue