mirror of
https://github.com/VLSIDA/OpenRAM.git
synced 2026-08-29 01:24:39 +02:00
rba done w/o wordline
This commit is contained in:
@@ -158,9 +158,10 @@ class bitcell_base_array(design):
|
||||
height=wl_pin.height())
|
||||
|
||||
def route_supplies(self):
|
||||
for inst in self.cell_inst.values():
|
||||
for inst in self.insts:
|
||||
for pin_name in ["vdd", "gnd"]:
|
||||
self.copy_layout_pin(inst, pin_name)
|
||||
if pin_name in inst.mod.get_pin_names():
|
||||
self.copy_layout_pin(inst, pin_name)
|
||||
|
||||
def add_layout_pins(self):
|
||||
""" Add the layout pins """
|
||||
|
||||
@@ -64,10 +64,9 @@ class dummy_array(bitcell_base_array):
|
||||
core_block[(1+self.mirror) %2][0] = geometry.instance("core_1_0", mod=self.dummy_cell, is_bitcell=True, mirror='MX')
|
||||
|
||||
|
||||
self.pattern = pattern(self, "dummy_array", core_block, num_rows=self.row_size, num_cols=self.column_size, name_template="bit_r{0}_c{1}")
|
||||
self.pattern = pattern(self, "dummy_array", core_block, num_rows=self.row_size, num_cols=self.column_size * 2, name_template="bit_r{0}_c{1}")
|
||||
self.pattern.connect_array()
|
||||
|
||||
|
||||
def add_pins(self):
|
||||
# bitline pins are not added because they are floating
|
||||
for bl_name in self.get_bitline_names():
|
||||
@@ -78,47 +77,6 @@ class dummy_array(bitcell_base_array):
|
||||
self.add_pin("vdd", "POWER")
|
||||
self.add_pin("gnd", "GROUND")
|
||||
|
||||
def add_layout_pins(self):
|
||||
""" Add the layout pins """
|
||||
|
||||
# Add the bitline metal, but not as pins since they are going to just be floating
|
||||
# For some reason, LVS has an issue if we don't add this metal
|
||||
bitline_names = self.cell.get_all_bitline_names()
|
||||
for col in range(self.column_size):
|
||||
for port in self.all_ports:
|
||||
bl_pin = self.cell_inst[0, col].get_pin(bitline_names[2 * port])
|
||||
self.add_layout_pin(text="bl_{0}_{1}".format(port, col),
|
||||
layer=bl_pin.layer,
|
||||
offset=bl_pin.ll().scale(1, 0),
|
||||
width=bl_pin.width(),
|
||||
height=self.height)
|
||||
br_pin = self.cell_inst[0, col].get_pin(bitline_names[2 * port + 1])
|
||||
self.add_layout_pin(text="br_{0}_{1}".format(port, col),
|
||||
layer=br_pin.layer,
|
||||
offset=br_pin.ll().scale(1, 0),
|
||||
width=br_pin.width(),
|
||||
height=self.height)
|
||||
|
||||
wl_names = self.cell.get_all_wl_names()
|
||||
for row in range(self.row_size):
|
||||
for port in self.all_ports:
|
||||
wl_pins = self.cell_inst[row, 0].get_pins(wl_names[port])
|
||||
for wl_pin in wl_pins:
|
||||
self.add_layout_pin(text="wl_{0}_{1}".format(port, row),
|
||||
layer=wl_pin.layer,
|
||||
offset=wl_pin.ll().scale(0, 1),
|
||||
width=self.width,
|
||||
height=wl_pin.height())
|
||||
|
||||
def route_supplies(self):
|
||||
|
||||
# Copy a vdd/gnd layout pin from every cell
|
||||
for row in range(self.row_size):
|
||||
for col in range(self.column_size):
|
||||
inst = self.cell_inst[row, col]
|
||||
for pin_name in ["vdd", "gnd"]:
|
||||
self.copy_layout_pin(inst, pin_name)
|
||||
|
||||
def input_load(self):
|
||||
# FIXME: This appears to be old code from previous characterization. Needs to be updated.
|
||||
wl_wire = self.gen_wl_wire()
|
||||
|
||||
@@ -122,7 +122,7 @@ class pattern():
|
||||
for dr in range(len(block)):
|
||||
row_done = False
|
||||
for dc in range(len(block[0])):
|
||||
if(self.bit_rows.count(self.num_rows) <= self.num_cols and self.bit_cols.count(self.bit_cols) <= self.num_rows):
|
||||
if(self.bit_rows.count(self.num_rows) <= self.num_cols and self.bit_cols.count(self.num_cols) <= self.num_rows):
|
||||
inst = block[dr][dc]
|
||||
if(len(self.bit_rows) <= col + dc):
|
||||
self.bit_rows.append(0)
|
||||
@@ -211,3 +211,11 @@ class pattern():
|
||||
def append_block_right_block(base_block, right_block):
|
||||
for row in base_block:
|
||||
row = row + right_block
|
||||
|
||||
def rotate_list(lst, n):
|
||||
# Loop through the range of n positions to rotate
|
||||
for i in range(n):
|
||||
# Remove the last element of the list and insert it at the beginning
|
||||
lst.insert(0, lst.pop())
|
||||
# Return the rotated list
|
||||
return lst
|
||||
|
||||
@@ -74,7 +74,7 @@ class replica_bitcell_array(bitcell_base_array):
|
||||
""" Array and dummy/replica columns """
|
||||
# Bitcell array
|
||||
self.bitcell_array = factory.create(module_type="bitcell_array",
|
||||
column_offset=1 + len(self.left_rbl),
|
||||
column_offset=len(self.left_rbl),
|
||||
cols=self.column_size,
|
||||
rows=self.row_size)
|
||||
|
||||
@@ -91,7 +91,7 @@ class replica_bitcell_array(bitcell_base_array):
|
||||
elif port in self.right_rbl:
|
||||
# These go bottom up starting from the top of the bitcell array.
|
||||
replica_bit = self.rbl[0] + self.row_size + port - 1
|
||||
column_offset = len(self.left_rbl) + self.column_size + 1
|
||||
column_offset = len(self.left_rbl) + self.column_size
|
||||
else:
|
||||
continue
|
||||
|
||||
@@ -102,14 +102,21 @@ class replica_bitcell_array(bitcell_base_array):
|
||||
replica_bit=replica_bit)
|
||||
|
||||
# Dummy row (for replica wordlines)
|
||||
self.dummy_row = factory.create(module_type="dummy_array",
|
||||
self.dummy_rows = {}
|
||||
|
||||
for port in self.all_ports:
|
||||
if port in self.left_rbl:
|
||||
row_offset = self.row_size
|
||||
elif port in self.right_rbl:
|
||||
row_offset = 0
|
||||
else:
|
||||
continue
|
||||
self.dummy_rows[port] = factory.create(module_type="dummy_array",
|
||||
cols=self.column_size,
|
||||
rows=1,
|
||||
# cap column + left replica column
|
||||
# FIXME: these col offsets should really start at 0 because
|
||||
# this is the left edge of the array... but changing them all is work
|
||||
column_offset=1 + len(self.left_rbl),
|
||||
mirror=0)
|
||||
row_offset=row_offset,
|
||||
column_offset=len(self.left_rbl),
|
||||
mirror='R0')
|
||||
|
||||
def add_pins(self):
|
||||
|
||||
@@ -213,7 +220,7 @@ class replica_bitcell_array(bitcell_base_array):
|
||||
for port in self.all_ports: # TODO: tie to self.rbl or whatever
|
||||
if self.rbl[port] != 0:
|
||||
self.dummy_row_replica_insts.append(self.add_inst(name="dummy_row_{}".format(port),
|
||||
mod=self.dummy_row))
|
||||
mod=self.dummy_rows[port]))
|
||||
self.connect_inst(self.all_bitline_names + self.rbl_wordline_names[port] + self.supplies)
|
||||
else:
|
||||
self.dummy_row_replica_insts.append(None)
|
||||
@@ -244,11 +251,13 @@ class replica_bitcell_array(bitcell_base_array):
|
||||
self.add_layout_pins()
|
||||
|
||||
self.route_supplies()
|
||||
|
||||
ll=vector(min([x.lx() for x in self.insts]),min([y.by() for y in self.insts]))
|
||||
|
||||
self.height = (sum(self.rbl) + self.row_size) * self.cell.height
|
||||
self.width = (len(self.rbls) + self.column_size) * self.cell.width
|
||||
self.width = max([x.rx() for x in self.insts]) - min([x.lx() for x in self.insts])
|
||||
self.height = max([x.uy() for x in self.insts]) - min([y.by() for y in self.insts])
|
||||
|
||||
self.add_boundary()
|
||||
self.add_boundary(ll)
|
||||
|
||||
self.DRC_LVS()
|
||||
|
||||
@@ -280,25 +289,24 @@ class replica_bitcell_array(bitcell_base_array):
|
||||
|
||||
# Grow from left to right, toward the array
|
||||
for bit, port in enumerate(self.left_rbl):
|
||||
offset = self.bitcell_offset.scale(-len(self.left_rbl) + bit, -self.rbl[0])
|
||||
rbc_dimension = vector(self.replica_col_insts[port].width, self.cell.height)
|
||||
offset = rbc_dimension.scale(-len(self.left_rbl) + bit, -self.rbl[0])
|
||||
self.replica_col_insts[bit].place(offset)
|
||||
# Grow to the right of the bitcell array, array outward
|
||||
for bit, port in enumerate(self.right_rbl):
|
||||
offset = self.bitcell_array_inst.lr() + self.bitcell_offset.scale(bit, -self.rbl[0])
|
||||
offset = self.bitcell_array_inst.lr() + rbc_dimension.scale(bit, -self.rbl[0])
|
||||
self.replica_col_insts[self.rbl[0] + bit].place(offset)
|
||||
|
||||
# Replica dummy rows
|
||||
# Add the dummy rows even if we aren't adding the replica column to this bitcell array
|
||||
# These grow up, toward the array
|
||||
for bit in range(self.rbl[0]):
|
||||
dummy_offset = self.bitcell_offset.scale(0, -self.rbl[0] + bit + (-self.rbl[0] + bit) % 2)
|
||||
self.dummy_row_replica_insts[bit].place(offset=dummy_offset,
|
||||
mirror="MX" if (-self.rbl[0] + bit) % 2 else "R0")
|
||||
dummy_offset = self.bitcell_array_inst.ll() - vector(0, self.dummy_row_replica_insts[bit].height)
|
||||
self.dummy_row_replica_insts[bit].place(offset=dummy_offset)
|
||||
# These grow up, away from the array
|
||||
for bit in range(self.rbl[1]):
|
||||
dummy_offset = self.bitcell_offset.scale(0, bit + bit % 2) + self.bitcell_array_inst.ul()
|
||||
self.dummy_row_replica_insts[self.rbl[0] + bit].place(offset=dummy_offset,
|
||||
mirror="MX" if (self.row_size + bit) % 2 else "R0")
|
||||
dummy_offset = self.bitcell_array_inst.ul()
|
||||
self.dummy_row_replica_insts[self.rbl[0] + bit].place(offset=dummy_offset)
|
||||
|
||||
def add_layout_pins(self):
|
||||
""" Add the layout pins """
|
||||
@@ -317,7 +325,7 @@ class replica_bitcell_array(bitcell_base_array):
|
||||
# Replica wordlines (go by the row instead of replica column because we may have to add a pin
|
||||
# even though the column is in another local bitcell array)
|
||||
for (names, inst) in zip(self.rbl_wordline_names, self.dummy_row_replica_insts):
|
||||
for (wl_name, pin_name) in zip(names, self.dummy_row.get_wordline_names()):
|
||||
for (wl_name, pin_name) in zip(names, self.dummy_rows[0].get_wordline_names()):
|
||||
pin = inst.get_pin(pin_name)
|
||||
self.add_layout_pin(text=wl_name,
|
||||
layer=pin.layer,
|
||||
@@ -347,12 +355,6 @@ class replica_bitcell_array(bitcell_base_array):
|
||||
width=pin.width(),
|
||||
height=self.height)
|
||||
|
||||
def route_supplies(self):
|
||||
""" just copy supply pins from all instances """
|
||||
for inst in self.insts:
|
||||
for pin_name in ["vdd", "gnd"]:
|
||||
self.copy_layout_pin(inst, pin_name)
|
||||
|
||||
def analytical_power(self, corner, load):
|
||||
"""Power of Bitcell array and bitline in nW."""
|
||||
# Dynamic Power from Bitline
|
||||
|
||||
@@ -45,10 +45,10 @@ class replica_column(bitcell_base_array):
|
||||
debug.check(replica_bit < self.row_start or replica_bit >= self.row_end,
|
||||
"Replica bit cannot be in the regular array.")
|
||||
|
||||
if layer_props.replica_column.even_rows:
|
||||
debug.check(rows % 2 == 0 and (self.left_rbl + 1) % 2 == 0,
|
||||
"sky130 currently requires rows to be even and to start with X mirroring"
|
||||
+ " (left_rbl must be odd) for LVS.")
|
||||
#if layer_props.replica_column.even_rows:
|
||||
# debug.check(rows % 2 == 0 and (self.left_rbl + 1) % 2 == 0,
|
||||
# "sky130 currently requires rows to be even and to start with X mirroring"
|
||||
# + " (left_rbl must be odd) for LVS.")
|
||||
|
||||
self.create_netlist()
|
||||
if not OPTS.netlist_only:
|
||||
@@ -95,63 +95,19 @@ class replica_column(bitcell_base_array):
|
||||
# Replic bit specifies which other bit (in the full range (0,total_size) to make a replica cell.
|
||||
# All other cells are dummies
|
||||
if (row == self.replica_bit) or (row >= self.row_start and row < self.row_end):
|
||||
if current_row % 2:
|
||||
core_block[row][0] = geometry.instance("rbc_{}".format(row), mod=self.replica_cell, is_bitcell=True, mirror='MX')
|
||||
else:
|
||||
if current_row % 2 == 0:
|
||||
core_block[row][0] = geometry.instance("rbc_{}".format(row), mod=self.replica_cell, is_bitcell=True)
|
||||
else:
|
||||
if current_row %2:
|
||||
core_block[row][0] = geometry.instance("rbc_{}".format(row), mod=self.dummy_cell, is_bitcell=True, mirror='MX')
|
||||
else:
|
||||
core_block[row][0] = geometry.instance("rbc_{}".format(row), mod=self.replica_cell, is_bitcell=True, mirror='MX')
|
||||
else:
|
||||
if current_row %2 == 0:
|
||||
core_block[row][0] = geometry.instance("rbc_{}".format(row), mod=self.dummy_cell, is_bitcell=True)
|
||||
else:
|
||||
core_block[row][0] = geometry.instance("rbc_{}".format(row), mod=self.dummy_cell, is_bitcell=True, mirror='MX')
|
||||
current_row += 1
|
||||
self.pattern = pattern(self, "bitcell_array", core_block, num_rows=self.total_size, num_cols=self.column_size, name_template="rbc_r{0}_c{1}")
|
||||
self.pattern.connect_array()
|
||||
|
||||
def add_layout_pins(self):
|
||||
for port in self.all_ports:
|
||||
bl_pin = self.cell_inst[0,0].get_pin(self.cell.get_bl_name(port))
|
||||
self.add_layout_pin(text="bl_{0}_{1}".format(port, 0),
|
||||
layer=bl_pin.layer,
|
||||
offset=bl_pin.ll().scale(1, 0),
|
||||
width=bl_pin.width(),
|
||||
height=self.height)
|
||||
bl_pin = self.cell_inst[0,0].get_pin(self.cell.get_br_name(port))
|
||||
self.add_layout_pin(text="br_{0}_{1}".format(port, 0),
|
||||
layer=bl_pin.layer,
|
||||
offset=bl_pin.ll().scale(1, 0),
|
||||
width=bl_pin.width(),
|
||||
height=self.height)
|
||||
|
||||
for port in self.all_ports:
|
||||
for row in range(self.total_size):
|
||||
wl_pin = self.cell_inst[row,0].get_pin(self.cell.get_wl_name(port))
|
||||
self.add_layout_pin(text="wl_{0}_{1}".format(port, row),
|
||||
layer=wl_pin.layer,
|
||||
offset=wl_pin.ll().scale(0, 1),
|
||||
width=self.width,
|
||||
height=wl_pin.height())
|
||||
|
||||
def get_bitline_names(self, port=None):
|
||||
if port == None:
|
||||
return self.all_bitline_names
|
||||
else:
|
||||
return self.bitline_names[port]
|
||||
|
||||
def get_bitcell_pins(self, row, col):
|
||||
"""
|
||||
Creates a list of connections in the bitcell,
|
||||
indexed by column and row, for instance use in bitcell_array
|
||||
"""
|
||||
bitcell_pins = []
|
||||
for port in self.all_ports:
|
||||
bitcell_pins.extend([x for x in self.get_bitline_names(port) if x.endswith("_{0}".format(col))])
|
||||
bitcell_pins.extend([x for x in self.all_wordline_names if x.endswith("_{0}".format(row))])
|
||||
bitcell_pins.append("vdd")
|
||||
bitcell_pins.append("gnd")
|
||||
|
||||
return bitcell_pins
|
||||
|
||||
def get_bitcell_pins_col_cap(self, row, col):
|
||||
"""
|
||||
Creates a list of connections in the bitcell,
|
||||
|
||||
Reference in New Issue
Block a user