mirror of https://github.com/VLSIDA/OpenRAM.git
Merge remote-tracking branch 'private/dev' into control-logic-pull
This commit is contained in:
commit
13bdae2e30
|
|
@ -4,52 +4,54 @@ jobs:
|
||||||
scn4me_subm:
|
scn4me_subm:
|
||||||
runs-on: self-hosted
|
runs-on: self-hosted
|
||||||
steps:
|
steps:
|
||||||
- name: Check out repository
|
- name: Checkout code
|
||||||
uses: actions/checkout@v1
|
uses: actions/checkout@v1
|
||||||
- name: SCMOS test
|
- name: SCMOS test
|
||||||
run: |
|
run: |
|
||||||
. /home/github-runner/setup-paths.sh
|
. /home/github-runner/setup-paths.sh
|
||||||
export OPENRAM_HOME="`pwd`/compiler"
|
export OPENRAM_HOME="`pwd`/compiler"
|
||||||
export OPENRAM_TECH="`pwd`/technology:/software/PDKs/skywater-tech"
|
export OPENRAM_TECH="`pwd`/technology:/software/PDKs/skywater-tech"
|
||||||
export OPENRAM_TMP="`pwd`/scn4me_subm"
|
export OPENRAM_TMP="${{ github.workspace }}/scn4me_subm_temp"
|
||||||
python3-coverage run -p $OPENRAM_HOME/tests/regress.py -j 48 -t scn4m_subm
|
#python3-coverage run -p $OPENRAM_HOME/tests/regress.py -j 12 -t scn4m_subm
|
||||||
|
$OPENRAM_HOME/tests/regress.py -j 12 -t scn4m_subm
|
||||||
- name: Archive
|
- name: Archive
|
||||||
if: ${{ failure() }}
|
if: ${{ failure() }}
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: scn4me_subm Archives
|
name: scn4me_subm Archives
|
||||||
path: $OPENRAM_TMP/
|
path: ${{ github.workspace }}/scn4me_subm_temp/*/
|
||||||
freepdk45:
|
freepdk45:
|
||||||
runs-on: self-hosted
|
runs-on: self-hosted
|
||||||
steps:
|
steps:
|
||||||
- name: Check out repository
|
- name: Checkout code
|
||||||
uses: actions/checkout@v1
|
uses: actions/checkout@v1
|
||||||
- name: FreePDK45 test
|
- name: FreePDK45 test
|
||||||
run: |
|
run: |
|
||||||
. /home/github-runner/setup-paths.sh
|
. /home/github-runner/setup-paths.sh
|
||||||
export OPENRAM_HOME="`pwd`/compiler"
|
export OPENRAM_HOME="`pwd`/compiler"
|
||||||
export OPENRAM_TECH="`pwd`/technology:/software/PDKs/skywater-tech"
|
export OPENRAM_TECH="`pwd`/technology:/software/PDKs/skywater-tech"
|
||||||
export OPENRAM_TMP="`pwd`/freepdk45"
|
export OPENRAM_TMP="${{ github.workspace }}/freepdk45_temp"
|
||||||
python3-coverage run -p $OPENRAM_HOME/tests/regress.py -j 48 -t freepdk45
|
#python3-coverage run -p $OPENRAM_HOME/tests/regress.py -j 12 -t freepdk45
|
||||||
|
$OPENRAM_HOME/tests/regress.py -j 12 -t freepdk45
|
||||||
- name: Archive
|
- name: Archive
|
||||||
if: ${{ failure() }}
|
if: ${{ failure() }}
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: FreePDK45 Archives
|
name: FreePDK45 Archives
|
||||||
path: $OPENRAM_TMP/
|
path: ${{ github.workspace }}/freepdk45_temp/*/
|
||||||
coverage:
|
# coverage_stats:
|
||||||
if: ${{ always() }}
|
# if: ${{ always() }}
|
||||||
needs: [scn4me_subm, freepdk45]
|
# needs: [scn4me_subm, freepdk45]
|
||||||
runs-on: self-hosted
|
# runs-on: self-hosted
|
||||||
steps:
|
# steps:
|
||||||
- name: Coverage stats
|
# - name: Coverage stats
|
||||||
run: |
|
# run: |
|
||||||
python3-coverage combine
|
# python3-coverage combine
|
||||||
python3-coverage report
|
# python3-coverage report
|
||||||
python3-coverage html -d coverage_html
|
# python3-coverage html -d ${{ github.workspace }}/coverage_html
|
||||||
- name: Archive coverage
|
# - name: Archive coverage
|
||||||
uses: actions/upload-artifact@v2
|
# uses: actions/upload-artifact@v2
|
||||||
with:
|
# with:
|
||||||
name: code-coverage-report
|
# name: code-coverage-report
|
||||||
path: coverage_html/
|
# path: ${{ github.workspace }}/coverage_html/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -146,10 +146,10 @@ class sense_amp_array(design.design):
|
||||||
inst = self.local_insts[i]
|
inst = self.local_insts[i]
|
||||||
|
|
||||||
for gnd_pin in inst.get_pins("gnd"):
|
for gnd_pin in inst.get_pins("gnd"):
|
||||||
self.copy_power_pin(gnd_pin, directions=("V", "V"))
|
self.copy_power_pin(gnd_pin)
|
||||||
|
|
||||||
for vdd_pin in inst.get_pins("vdd"):
|
for vdd_pin in inst.get_pins("vdd"):
|
||||||
self.copy_power_pin(vdd_pin, directions=("V", "V"))
|
self.copy_power_pin(vdd_pin)
|
||||||
|
|
||||||
bl_pin = inst.get_pin(inst.mod.get_bl_names())
|
bl_pin = inst.get_pin(inst.mod.get_bl_names())
|
||||||
br_pin = inst.get_pin(inst.mod.get_br_names())
|
br_pin = inst.get_pin(inst.mod.get_br_names())
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@
|
||||||
#
|
#
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from vector3d import vector3d
|
from vector3d import vector3d
|
||||||
|
import debug
|
||||||
|
|
||||||
|
|
||||||
class direction(Enum):
|
class direction(Enum):
|
||||||
NORTH = 1
|
NORTH = 1
|
||||||
|
|
@ -20,31 +22,30 @@ class direction(Enum):
|
||||||
SOUTHEAST = 9
|
SOUTHEAST = 9
|
||||||
SOUTHWEST = 10
|
SOUTHWEST = 10
|
||||||
|
|
||||||
|
|
||||||
def get_offset(direct):
|
def get_offset(direct):
|
||||||
"""
|
"""
|
||||||
Returns the vector offset for a given direction.
|
Returns the vector offset for a given direction.
|
||||||
"""
|
"""
|
||||||
if direct==direction.NORTH:
|
if direct==direction.NORTH:
|
||||||
offset = vector3d(0,1,0)
|
offset = vector3d(0, 1, 0)
|
||||||
elif direct==direction.SOUTH:
|
elif direct==direction.SOUTH:
|
||||||
offset = vector3d(0,-1,0)
|
offset = vector3d(0, -1 ,0)
|
||||||
elif direct==direction.EAST:
|
elif direct==direction.EAST:
|
||||||
offset = vector3d(1,0,0)
|
offset = vector3d(1, 0, 0)
|
||||||
elif direct==direction.WEST:
|
elif direct==direction.WEST:
|
||||||
offset = vector3d(-1,0,0)
|
offset = vector3d(-1, 0, 0)
|
||||||
elif direct==direction.UP:
|
elif direct==direction.UP:
|
||||||
offset = vector3d(0,0,1)
|
offset = vector3d(0, 0, 1)
|
||||||
elif direct==direction.DOWN:
|
elif direct==direction.DOWN:
|
||||||
offset = vector3d(0,0,-1)
|
offset = vector3d(0, 0, -1)
|
||||||
elif direct==direction.NORTHEAST:
|
elif direct==direction.NORTHEAST:
|
||||||
offset = vector3d(1,1,0)
|
offset = vector3d(1, 1, 0)
|
||||||
elif direct==direction.NORTHWEST:
|
elif direct==direction.NORTHWEST:
|
||||||
offset = vector3d(-1,1,0)
|
offset = vector3d(-1, 1, 0)
|
||||||
elif direct==direction.SOUTHEAST:
|
elif direct==direction.SOUTHEAST:
|
||||||
offset = vector3d(1,-1,0)
|
offset = vector3d(1, -1, 0)
|
||||||
elif direct==direction.SOUTHWEST:
|
elif direct==direction.SOUTHWEST:
|
||||||
offset = vector3d(-1,-1,0)
|
offset = vector3d(-1, -1, 0)
|
||||||
else:
|
else:
|
||||||
debug.error("Invalid direction {}".format(direct))
|
debug.error("Invalid direction {}".format(direct))
|
||||||
|
|
||||||
|
|
@ -67,8 +68,8 @@ class direction(Enum):
|
||||||
return [direction.get_offset(d) for d in direction.all_directions()]
|
return [direction.get_offset(d) for d in direction.all_directions()]
|
||||||
|
|
||||||
def all_neighbors(cell):
|
def all_neighbors(cell):
|
||||||
return [cell+x for x in direction.all_offsets()]
|
return [cell + x for x in direction.all_offsets()]
|
||||||
|
|
||||||
def cardinal_neighbors(cell):
|
def cardinal_neighbors(cell):
|
||||||
return [cell+x for x in direction.cardinal_offsets()]
|
return [cell + x for x in direction.cardinal_offsets()]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,6 @@ class pin_group:
|
||||||
# Remove any redundant pins (i.e. contained in other pins)
|
# Remove any redundant pins (i.e. contained in other pins)
|
||||||
self.remove_redundant_pins()
|
self.remove_redundant_pins()
|
||||||
|
|
||||||
|
|
||||||
self.router = router
|
self.router = router
|
||||||
# These are the corresponding pin grids for each pin group.
|
# These are the corresponding pin grids for each pin group.
|
||||||
self.grids = set()
|
self.grids = set()
|
||||||
|
|
@ -101,13 +100,11 @@ class pin_group:
|
||||||
if local_debug:
|
if local_debug:
|
||||||
debug.info(0, "INITIAL: {}".format(pin_list))
|
debug.info(0, "INITIAL: {}".format(pin_list))
|
||||||
|
|
||||||
new_pin_list = pin_list.copy()
|
add_indices = set(range(len(pin_list)))
|
||||||
|
|
||||||
remove_indices = set()
|
|
||||||
# This is n^2, but the number is small
|
# This is n^2, but the number is small
|
||||||
for index1, pin1 in enumerate(pin_list):
|
for index1, pin1 in enumerate(pin_list):
|
||||||
# If we remove this pin, it can't contain other pins
|
# If we remove this pin, it can't contain other pins
|
||||||
if index1 in remove_indices:
|
if index1 not in add_indices:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
for index2, pin2 in enumerate(pin_list):
|
for index2, pin2 in enumerate(pin_list):
|
||||||
|
|
@ -117,17 +114,15 @@ class pin_group:
|
||||||
if index1 == index2:
|
if index1 == index2:
|
||||||
continue
|
continue
|
||||||
# If we already removed it, can't remove it again...
|
# If we already removed it, can't remove it again...
|
||||||
if index2 in remove_indices:
|
if index2 not in add_indices:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if pin1.contains(pin2):
|
if pin1.contains(pin2):
|
||||||
if local_debug:
|
if local_debug:
|
||||||
debug.info(0, "{0} contains {1}".format(pin1, pin2))
|
debug.info(0, "{0} contains {1}".format(pin1, pin2))
|
||||||
remove_indices.add(index2)
|
add_indices.remove(index2)
|
||||||
|
|
||||||
# Remove them in decreasing order to not invalidate the indices
|
new_pin_list = [pin_list[x] for x in add_indices]
|
||||||
for i in sorted(remove_indices, reverse=True):
|
|
||||||
del new_pin_list[i]
|
|
||||||
|
|
||||||
if local_debug:
|
if local_debug:
|
||||||
debug.info(0, "FINAL : {}".format(new_pin_list))
|
debug.info(0, "FINAL : {}".format(new_pin_list))
|
||||||
|
|
@ -423,13 +418,15 @@ class pin_group:
|
||||||
# We may have started with an empty set
|
# We may have started with an empty set
|
||||||
debug.check(len(self.grids) > 0, "Cannot seed an grid empty set.")
|
debug.check(len(self.grids) > 0, "Cannot seed an grid empty set.")
|
||||||
|
|
||||||
|
common_blockages = self.router.get_blocked_grids() & self.grids
|
||||||
|
|
||||||
# Start with the ll and make the widest row
|
# Start with the ll and make the widest row
|
||||||
row = [ll]
|
row = [ll]
|
||||||
# Move in dir1 while we can
|
# Move in dir1 while we can
|
||||||
while True:
|
while True:
|
||||||
next_cell = row[-1] + offset1
|
next_cell = row[-1] + offset1
|
||||||
# Can't move if not in the pin shape
|
# Can't move if not in the pin shape
|
||||||
if next_cell in self.grids and next_cell not in self.router.get_blocked_grids():
|
if next_cell in self.grids and next_cell not in common_blockages:
|
||||||
row.append(next_cell)
|
row.append(next_cell)
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
|
|
@ -438,7 +435,7 @@ class pin_group:
|
||||||
next_row = [x + offset2 for x in row]
|
next_row = [x + offset2 for x in row]
|
||||||
for cell in next_row:
|
for cell in next_row:
|
||||||
# Can't move if any cell is not in the pin shape
|
# Can't move if any cell is not in the pin shape
|
||||||
if cell not in self.grids or cell in self.router.get_blocked_grids():
|
if cell not in self.grids or cell in common_blockages:
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
row = next_row
|
row = next_row
|
||||||
|
|
@ -619,6 +616,11 @@ class pin_group:
|
||||||
# Set of track adjacent to or paritally overlap a pin (not full DRC connection)
|
# Set of track adjacent to or paritally overlap a pin (not full DRC connection)
|
||||||
partial_set = set()
|
partial_set = set()
|
||||||
|
|
||||||
|
# for pin in self.pins:
|
||||||
|
# lx = pin.lx()
|
||||||
|
# ly = pin.by()
|
||||||
|
# if lx > 87.9 and lx < 87.99 and ly > 18.56 and ly < 18.6:
|
||||||
|
# breakpoint()
|
||||||
for pin in self.pins:
|
for pin in self.pins:
|
||||||
debug.info(4, " Converting {0}".format(pin))
|
debug.info(4, " Converting {0}".format(pin))
|
||||||
# Determine which tracks the pin overlaps
|
# Determine which tracks the pin overlaps
|
||||||
|
|
@ -632,7 +634,8 @@ class pin_group:
|
||||||
blockage_in_tracks = self.router.convert_blockage(pin)
|
blockage_in_tracks = self.router.convert_blockage(pin)
|
||||||
# Must include the pins here too because these are computed in a different
|
# Must include the pins here too because these are computed in a different
|
||||||
# way than blockages.
|
# way than blockages.
|
||||||
self.blockages.update(sufficient | insufficient | blockage_in_tracks)
|
blockages = sufficient | insufficient | blockage_in_tracks
|
||||||
|
self.blockages.update(blockages)
|
||||||
|
|
||||||
# If we have a blockage, we must remove the grids
|
# If we have a blockage, we must remove the grids
|
||||||
# Remember, this excludes the pin blockages already
|
# Remember, this excludes the pin blockages already
|
||||||
|
|
|
||||||
|
|
@ -504,14 +504,21 @@ class router(router_tech):
|
||||||
ll = vector(boundary[0], boundary[1])
|
ll = vector(boundary[0], boundary[1])
|
||||||
ur = vector(boundary[2], boundary[3])
|
ur = vector(boundary[2], boundary[3])
|
||||||
rect = [ll, ur]
|
rect = [ll, ur]
|
||||||
new_pin = pin_layout("blockage{}".format(len(self.blockages)),
|
new_shape = pin_layout("blockage{}".format(len(self.blockages)),
|
||||||
rect,
|
rect,
|
||||||
lpp)
|
lpp)
|
||||||
|
|
||||||
# If there is a rectangle that is the same in the pins,
|
# If there is a rectangle that is the same in the pins,
|
||||||
# it isn't a blockage!
|
# it isn't a blockage!
|
||||||
if new_pin not in self.all_pins:
|
if new_shape not in self.all_pins and not self.pin_contains(new_shape):
|
||||||
self.blockages.append(new_pin)
|
self.blockages.append(new_shape)
|
||||||
|
|
||||||
|
def pin_contains(self, shape):
|
||||||
|
for pin in self.all_pins:
|
||||||
|
if pin.contains(shape):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
def convert_point_to_units(self, p):
|
def convert_point_to_units(self, p):
|
||||||
"""
|
"""
|
||||||
Convert a path set of tracks to center line path.
|
Convert a path set of tracks to center line path.
|
||||||
|
|
@ -1048,6 +1055,7 @@ class router(router_tech):
|
||||||
# Double check source and taget are not same node, if so, we are done!
|
# Double check source and taget are not same node, if so, we are done!
|
||||||
for k, v in self.rg.map.items():
|
for k, v in self.rg.map.items():
|
||||||
if v.source and v.target:
|
if v.source and v.target:
|
||||||
|
self.paths.append([k])
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# returns the path in tracks
|
# returns the path in tracks
|
||||||
|
|
|
||||||
|
|
@ -37,12 +37,12 @@ class supply_tree_router(router):
|
||||||
"""
|
"""
|
||||||
Route the two nets in a single layer)
|
Route the two nets in a single layer)
|
||||||
"""
|
"""
|
||||||
debug.info(1,"Running supply router on {0} and {1}...".format(vdd_name, gnd_name))
|
debug.info(1, "Running supply router on {0} and {1}...".format(vdd_name, gnd_name))
|
||||||
self.vdd_name = vdd_name
|
self.vdd_name = vdd_name
|
||||||
self.gnd_name = gnd_name
|
self.gnd_name = gnd_name
|
||||||
|
|
||||||
# Clear the pins if we have previously routed
|
# Clear the pins if we have previously routed
|
||||||
if (hasattr(self,'rg')):
|
if (hasattr(self, 'rg')):
|
||||||
self.clear_pins()
|
self.clear_pins()
|
||||||
else:
|
else:
|
||||||
# Creat a routing grid over the entire area
|
# Creat a routing grid over the entire area
|
||||||
|
|
@ -53,14 +53,14 @@ class supply_tree_router(router):
|
||||||
# Get the pin shapes
|
# Get the pin shapes
|
||||||
start_time = datetime.now()
|
start_time = datetime.now()
|
||||||
self.find_pins_and_blockages([self.vdd_name, self.gnd_name])
|
self.find_pins_and_blockages([self.vdd_name, self.gnd_name])
|
||||||
print_time("Finding pins and blockages",datetime.now(), start_time, 3)
|
print_time("Finding pins and blockages", datetime.now(), start_time, 3)
|
||||||
|
|
||||||
# Route the supply pins to the supply rails
|
# Route the supply pins to the supply rails
|
||||||
# Route vdd first since we want it to be shorter
|
# Route vdd first since we want it to be shorter
|
||||||
start_time = datetime.now()
|
start_time = datetime.now()
|
||||||
self.route_pins(vdd_name)
|
self.route_pins(vdd_name)
|
||||||
self.route_pins(gnd_name)
|
self.route_pins(gnd_name)
|
||||||
print_time("Maze routing supplies",datetime.now(), start_time, 3)
|
print_time("Maze routing supplies", datetime.now(), start_time, 3)
|
||||||
|
|
||||||
# self.write_debug_gds("final_tree_router.gds",False)
|
# self.write_debug_gds("final_tree_router.gds",False)
|
||||||
|
|
||||||
|
|
@ -79,11 +79,11 @@ class supply_tree_router(router):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
remaining_components = sum(not x.is_routed() for x in self.pin_groups[pin_name])
|
remaining_components = sum(not x.is_routed() for x in self.pin_groups[pin_name])
|
||||||
debug.info(1,"Routing {0} with {1} pin components to connect.".format(pin_name,
|
debug.info(1, "Routing {0} with {1} pin components to connect.".format(pin_name,
|
||||||
remaining_components))
|
remaining_components))
|
||||||
|
|
||||||
# Create full graph
|
# Create full graph
|
||||||
debug.info(2,"Creating adjacency matrix")
|
debug.info(2, "Creating adjacency matrix")
|
||||||
pin_size = len(self.pin_groups[pin_name])
|
pin_size = len(self.pin_groups[pin_name])
|
||||||
adj_matrix = [[0] * pin_size for i in range(pin_size)]
|
adj_matrix = [[0] * pin_size for i in range(pin_size)]
|
||||||
|
|
||||||
|
|
@ -95,7 +95,7 @@ class supply_tree_router(router):
|
||||||
adj_matrix[index1][index2] = dist
|
adj_matrix[index1][index2] = dist
|
||||||
|
|
||||||
# Find MST
|
# Find MST
|
||||||
debug.info(2,"Finding MinimumSpanning Tree")
|
debug.info(2, "Finding MinimumSpanning Tree")
|
||||||
X = csr_matrix(adj_matrix)
|
X = csr_matrix(adj_matrix)
|
||||||
Tcsr = minimum_spanning_tree(X)
|
Tcsr = minimum_spanning_tree(X)
|
||||||
mst = Tcsr.toarray().astype(int)
|
mst = Tcsr.toarray().astype(int)
|
||||||
|
|
@ -144,6 +144,7 @@ class supply_tree_router(router):
|
||||||
self.add_pin_component_source(pin_name, src_idx)
|
self.add_pin_component_source(pin_name, src_idx)
|
||||||
|
|
||||||
# Marks all pin components except index as target
|
# Marks all pin components except index as target
|
||||||
|
# which unmarks it as a blockage too
|
||||||
self.add_pin_component_target(pin_name, dest_idx)
|
self.add_pin_component_target(pin_name, dest_idx)
|
||||||
|
|
||||||
# Actually run the A* router
|
# Actually run the A* router
|
||||||
|
|
|
||||||
|
|
@ -325,13 +325,13 @@ class sram_1bank(sram_base):
|
||||||
# they might create some blockages
|
# they might create some blockages
|
||||||
self.add_layout_pins()
|
self.add_layout_pins()
|
||||||
|
|
||||||
# Route the supplies first since the MST is not blockage aware
|
|
||||||
# and signals can route to anywhere on sides (it is flexible)
|
|
||||||
self.route_supplies()
|
|
||||||
|
|
||||||
# Route the pins to the perimeter
|
# Route the pins to the perimeter
|
||||||
if OPTS.perimeter_pins:
|
if OPTS.perimeter_pins:
|
||||||
self.route_escape_pins()
|
self.route_escape_pins()
|
||||||
|
|
||||||
|
# Route the supplies first since the MST is not blockage aware
|
||||||
|
# and signals can route to anywhere on sides (it is flexible)
|
||||||
|
self.route_supplies()
|
||||||
|
|
||||||
def route_dffs(self, add_routes=True):
|
def route_dffs(self, add_routes=True):
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue