Skip to content

fixed SV bbox bus msb; black formatting #9

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion __init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
# To get relative imports to work
import os, sys; sys.path.append(os.path.dirname(os.path.realpath(__file__)))
import os, sys

sys.path.append(os.path.dirname(os.path.realpath(__file__)))
2 changes: 1 addition & 1 deletion test/au/spsram_256x256.au
Original file line number Diff line number Diff line change
Expand Up @@ -5039,7 +5039,7 @@ module spsram_256x256
endmodule
(* blackbox *)
module spsram_256x256 (
output reg [31:0] rd_out,
output reg [255:0] rd_out,
input [7:0] addr_in,
input we_in,
input [255:0] wd_in,
Expand Down
9 changes: 4 additions & 5 deletions test/physical_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ class PhysicalDataTest(unittest.TestCase):
def setUp(self):
"""Sets up base_data with example config data"""


def test_empty_physical(self):
"""Tests physical field defaults"""

Expand All @@ -39,7 +38,7 @@ def test_set_extents_and_snapping(self):
# Can't snap before setting extents
with self.assertRaises(Exception):
physical.snap_to_grid(1000, 1000)

# Set extents and verify values
physical.set_extents(width, height)
self.assertEqual(physical.get_width(False), width)
Expand Down Expand Up @@ -73,13 +72,13 @@ def test_pin_pitches_exception(self):
# Can't set pin pitches before setting height
with self.assertRaises(Exception):
physical.set_pin_pitches("bogus", num_pins, min_pin_pitch, y_offset)

# Try again after setting height
physical.set_extents(height, height)
physical.snap_to_grid(1, 1)
with self.assertRaises(Exception):
physical.set_pin_pitches("bogus", num_pins, min_pin_pitch, y_offset)


if __name__ == "__main__":
unittest.main()
23 changes: 23 additions & 0 deletions test/process_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,29 @@ def test_bitcell_override(self):
self.assertEqual(bitcell_width, process_data["bitcell_width_um"])
self.assertEqual(bitcell_height, process_data["bitcell_height_um"])

def test_y_step_calc(self):
"""
Tests y_step calculation

y_step = pin_pitch (snapped to grid) + pin_width / 2
"""

process = Process(self._base_data)
process._calc_y_step()
# 0.048 + (0.024 / 2) = 0.06
self.assertEqual(process.get_y_step(), 0.06)

# change to different pitch that previously didn't get snapped right
# and try again
base_data = self._base_data.copy()
base_data["metal_track_pitch_nm"] = 23
base_data["pin_pitch_nm"] = 2 * base_data["metal_track_pitch_nm"]
base_data["pin_width_nm"] = 12
process = Process(base_data)
# 0.046 + (0.024 / 2) = 0.06
process._calc_y_step()
self.assertEqual(process.get_y_step(), 0.052)


if __name__ == "__main__":
unittest.main()
76 changes: 76 additions & 0 deletions test/sv_bbox_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#!/usr/bin/env python3

import os
import re
import io
import sys
import unittest

sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "utils")))
from single_port_ram_verilog_exporter import SinglePortRAMVerilogExporter
from memory_factory import MemoryFactory
from class_process import Process
from timing_data import TimingData
from test_utils import TestUtils


class SVBBoxDataTest(unittest.TestCase):
"""Unit test for SystemVerilog blackbox class"""

def setUp(self):
"""Sets up base_data with example config data"""
self._process = Process(TestUtils.get_base_process_data())
self._timing_data = TimingData()
self._bus_re = re.compile(
"^\s*\S+\s+(?:reg)?\s*\[\s*(\d+)\:(\d+)\\s*]\s*(\S+)\s*\,"
)

def _extract_bus_msb(self, content):
msb_map = {}
in_strm = io.StringIO(content)

for line in in_strm:
result = self._bus_re.match(line)
if result:
msb = int(result.group(1))
bus_name = result.group(3)
msb_map[bus_name] = msb
return msb_map

def _check_bus_msb(self, mem_name, bus_name, bus_msb_map, exp_msb):
self.assertIn(bus_name, bus_msb_map)
self.assertEqual(
bus_msb_map[bus_name],
exp_msb,
f"msb's don't match for {bus_name} on {mem_name}: {bus_msb_map[bus_name]} {exp_msb}",
)

def _check_bbox(self, words, depth):
name = f"fakeram_16_{depth}"
mem = MemoryFactory.create(
name, words, depth, 4, "RAM", "SP", self._process, self._timing_data
)
exporter = SinglePortRAMVerilogExporter(mem)
strm = io.StringIO()
exporter.export_blackbox(strm)
content = strm.getvalue()
strm.close()
bus_msb_map = self._extract_bus_msb(content)
self._check_bus_msb(name, "rd_out", bus_msb_map, mem.get_data_bus_msb())
self._check_bus_msb(name, "wd_in", bus_msb_map, mem.get_data_bus_msb())
self._check_bus_msb(name, "addr_in", bus_msb_map, mem.get_addr_bus_msb())

def test_spsram_bbox(self):
"""
Tests that the spsram rd_out and wd_in indices are the same and
correct
"""

words = 16
depths = [32, 64, 256]
for depth in depths:
self._check_bbox(words, depth)


if __name__ == "__main__":
unittest.main()
4 changes: 2 additions & 2 deletions test/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import os


class TestUtils:
@staticmethod
def get_base_process_data():
Expand Down Expand Up @@ -31,7 +32,6 @@ def get_exec_name(exec_name):

if "COVERAGE_RUN" in os.environ:
exec_cmd = "coverage run --parallel-mode " + exec_name
else: #pragma: nocover
else: # pragma: nocover
exec_cmd = exec_name
return exec_cmd

22 changes: 14 additions & 8 deletions utils/class_process.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ def __init__(self, json_data):
self.pin_width_nm = int(json_data["pin_width_nm"])
self.pin_pitch_nm = int(json_data["pin_pitch_nm"])
self.metal_track_pitch_nm = int(json_data["metal_track_pitch_nm"])
self.contacted_poly_pitch_nm = int(json_data["contacted_poly_pitch_nm"])
self.fin_pitch_nm = int(json_data["fin_pitch_nm"])
self.contacted_poly_pitch_nm = json_data.get("contacted_poly_pitch_nm", None)
self.fin_pitch_nm = json_data.get("fin_pitch_nm", None)
self.manufacturing_grid_nm = int(json_data["manufacturing_grid_nm"])
self.column_mux_factor = int(json_data["column_mux_factor"])

Expand Down Expand Up @@ -57,15 +57,21 @@ def __init__(self, json_data):
self.y_offset = 1 * self.pin_pitch_um
# as told by MSK

self.y_step = (
self.y_offset
- (self.y_offset % self.manufacturing_grid_um)
+ (self.pin_width_um / 2.0)
)

self._calc_y_step()
self.bitcell_width_um = json_data.get("bitcell_width_um", None)
self.bitcell_height_um = json_data.get("bitcell_height_um", None)

def _calc_y_step(self):
"""
Calculates y_step, which is really the y location for the center of
the first pin
"""

offset_snap = round(self.y_offset % self.manufacturing_grid_um, 2)
if offset_snap < self.manufacturing_grid_um:
offset_snap = 0
self.y_step = self.y_offset - offset_snap + (self.pin_width_um / 2.0)

def has_defined_bitcell_size(self):
return self.bitcell_width_um and self.bitcell_height_um

Expand Down
2 changes: 1 addition & 1 deletion utils/single_port_ram_verilog_exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ def export_blackbox(self, out_fh):
addr_bus_msb = mem.get_addr_bus_msb()
data_bus_msb = mem.get_data_bus_msb()
self.export_bb_header(out_fh)
out_fh.write(f" output reg [31:0] rd_out,\n")
out_fh.write(f" output reg [{data_bus_msb}:0] rd_out,\n")
out_fh.write(f" input [{addr_bus_msb}:0] addr_in,\n")
out_fh.write(" input we_in,\n")
out_fh.write(f" input [{data_bus_msb}:0] wd_in,\n")
Expand Down
Loading