mirror of https://github.com/VLSIDA/OpenRAM.git
136 lines
5.9 KiB
Python
136 lines
5.9 KiB
Python
from openram import debug
|
|
from openram.base.geometry import instance,geometry
|
|
from typing import List
|
|
from typing import Optional
|
|
from openram.base import design
|
|
from openram.globals import OPTS
|
|
class pattern():
|
|
"""
|
|
This class is used to desribe the internals of a bitcell array. It describes
|
|
instance modules, rotation, and ordering
|
|
|
|
"""
|
|
block = List[List[instance]]
|
|
def __init__(self,
|
|
parent_design: design,
|
|
name:str,
|
|
core_block:block,
|
|
num_core_x:int,
|
|
num_core_y:int,
|
|
cores_per_x_block: int = 1,
|
|
cores_per_y_block: int = 1,
|
|
x_block: Optional[block] = None,
|
|
y_block: Optional[block] = None,
|
|
xy_block: Optional[block] = None,
|
|
initial_x_block:bool = False,
|
|
initial_y_block:bool = False,
|
|
final_x_block:bool = False,
|
|
final_y_block:bool = False
|
|
):
|
|
"""
|
|
a "block" is a 2d list of instances
|
|
core_block defines the main block that is tiled
|
|
num_core defines the number of times the core block is to be tiled
|
|
(i.e. bitcells in dimension / bitcells in core_block)
|
|
x_block defines a block that is inserted to the right of the core_block
|
|
y_block defines a block that is inserted below the core block
|
|
xy_block defines a block that is a inserted where the x_block and y_block intercept
|
|
the initial and final booleans determine whether the pattern begins and/or ends with x/y blocks
|
|
"""
|
|
self.parent_design = parent_design
|
|
self.name = name
|
|
self.core_block = core_block
|
|
self.num_core_x = num_core_x
|
|
self.num_core_y = num_core_y
|
|
self.cores_per_x_block = cores_per_x_block
|
|
self.cores_per_y_block = cores_per_y_block
|
|
self.x_block = x_block
|
|
self.y_block = y_block
|
|
self.xy_block = xy_block
|
|
self.initial_x_block = initial_x_block
|
|
self.initial_y_block = initial_y_block
|
|
self.final_x_block = final_x_block
|
|
self.final_y_block = final_y_block
|
|
if not OPTS.netlist_only:
|
|
self.verify_interblock_dimensions()
|
|
|
|
def compute_and_verify_intrablock_dimensions(self, block: block) -> List[int]:
|
|
for row in block:
|
|
row_height = row[0].height
|
|
for inst in row:
|
|
debug.check(row_height == inst.height, "intrablock instances within the same row are different heights")
|
|
|
|
for y in range(len(block[0])):
|
|
debug.check(all([row[y].width for row in block]), "intrablock instances within the same column are different widths")
|
|
|
|
block_width = sum([instance.width for instance in block[0]])
|
|
block_height = sum([row[0].height for row in block])
|
|
|
|
return [block_width, block_height]
|
|
|
|
def verify_interblock_dimensions(self) -> None:
|
|
"""
|
|
Ensure the individual blocks are valid and interblock dimensions are valid
|
|
"""
|
|
debug.check(len(self.core_block) >= 1, "invalid core_block dimension: core_block rows must be >=1")
|
|
debug.check(len(self.core_block[0]) >= 1, "invalid core_block dimension: core_block cols must be >=1")
|
|
if self.x_block and self.y_block:
|
|
debug.check(self.xy_block is not None, "must have xy_block if both x_block and y_block are provided")
|
|
|
|
|
|
(self.core_block_width, self.core_block_height) = self.compute_and_verify_intrablock_dimensions(self.core_block)
|
|
if self.x_block:
|
|
(self.x_block_width, self.x_block_height) = self.compute_and_verify_intrablock_dimensions(self.x_block)
|
|
if self.y_block:
|
|
(self.y_block_width, self.y_block_height) = self.compute_and_verify_intrablock_dimensions(self.y_block)
|
|
if self.xy_block:
|
|
(self.xy_block_width, self.xy_block_height) = self.compute_and_verify_intrablock_dimensions(self.xy_block)
|
|
if(self.x_block):
|
|
debug.check(self.core_block_width * self.cores_per_x_block == self.x_block_width, "core_block does not align with x_block")
|
|
if(self.y_block):
|
|
debug.check(self.core_block_height * self.cores_per_y_block == self.y_block_height, "core_block does not aligns with y_block")
|
|
if(self.xy_block):
|
|
debug.check(self.xy_block_height == self.x_block_height, "xy_block does not align with x_block")
|
|
debug.check(self.xy_block_width == self.y_block_width, "xy_block does not align with y_block")
|
|
|
|
def place_block(self, block: block, x: float, y: float, x_count: int, y_count: int) -> None:
|
|
return
|
|
|
|
|
|
def connect_block(self, block: block, x: int, y: int) -> None:
|
|
for dy in range(len(block)):
|
|
for dx in range(len(block[0])):
|
|
inst = block[dy][dx]
|
|
self.parent_design.cell_inst[x + dx, y + dy] = self.parent_design.add_existing_inst(inst)
|
|
self.parent_design.connect_inst(self.parent_design.get_bitcell_pins(x+dx, y+dy))
|
|
|
|
|
|
def connect_array(self) -> None:
|
|
x = 0
|
|
y = 0
|
|
for i in range(self.num_core_y):
|
|
for j in range (self.num_core_x):
|
|
print("connecting {} {}".format(x,y))
|
|
self.connect_block(self.core_block, x,y)
|
|
x += len(self.core_block[0])
|
|
x = 0
|
|
y += len(self.core_block)
|
|
|
|
def place_array(self) -> None:
|
|
|
|
array_x = 0
|
|
array_y = 0
|
|
# if(self.initial_x_block and self.initial_y_block):
|
|
# self.place_block(array, self.xy_block, array_x, array_y)
|
|
# array_x += self.xy_block_width
|
|
# if(self.initial_x_block):
|
|
# self.place_block(array, self.xy_block, array_x, array_y)
|
|
# array_x += self.x_block_width
|
|
self.connect_array()
|
|
self.place_block(self.core_block, array_x, array_y, 0, 0)
|
|
|
|
|
|
def connect_pins(self, array: design) -> None:
|
|
array.connect_isnt()
|
|
|