Skip to content

Commit 74bf4ab

Browse files
authored
fix typo and add custom primitives loading in najaeda (#239)
* fix typo * typo * test load primitives from file * fix licenses * clean file * Update najaeda-test.yml * fix issues
1 parent 3374cb4 commit 74bf4ab

File tree

9 files changed

+245
-121
lines changed

9 files changed

+245
-121
lines changed

.github/workflows/najaeda-test.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ jobs:
5050
LIBERTY_BENCHMARKS_PATH: ${{github.workspace}}/test/nl/formats/liberty/benchmarks
5151
VERILOG_BENCHMARKS_PATH: ${{github.workspace}}/test/nl/formats/verilog/benchmarks
5252
NAJAEDA_TEST_PATH: ${{github.workspace}}/build/test/najaeda
53+
NAJAEDA_SOURCE_TEST_PATH: ${{github.workspace}}/test/najaeda
5354
run: |
5455
python -m coverage run -m unittest && python -m coverage xml --rcfile=./.coveragerc
5556
- name: Upload coverage to Codecov

.reuse/dep5

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
22
Upstream-Name: naja
3-
Upstream-Contact: Christophe Alexandre <christophe.alex@gmail.com>
3+
Upstream-Contact: Christophe Alexandre <christophe.alexandre@keplertech.io>
44
Source: https://github.com/najaeda/naja
55

66
Files: .github/workflows/* .gitmodules

primitives/nangate45.py

Lines changed: 111 additions & 111 deletions
Large diffs are not rendered by default.

src/apps/naja_edit/examples/adder/src/adder.v

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@ input [7:0] a;
33
input [7:0] b;
44
output s;
55

6-
assign s = a || b;
6+
assign s = a + b;
77

88
endmodule

src/najaeda/najaeda/netlist.py

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import hashlib
1010
import struct
1111
import sys
12+
import os
1213
from enum import Enum
1314

1415
from najaeda import naja
@@ -1360,7 +1361,7 @@ def get_truth_table(self):
13601361
return self.__get_snl_model().getTruthTable()
13611362

13621363

1363-
def get_top_db() -> naja.NLDB:
1364+
def __get_top_db() -> naja.NLDB:
13641365
if naja.NLUniverse.get() is None:
13651366
naja.NLUniverse.create()
13661367
if naja.NLUniverse.get().getTopDB() is None:
@@ -1385,7 +1386,7 @@ def create_top(name: str) -> Instance:
13851386
:rtype: Instance
13861387
"""
13871388
# init
1388-
db = get_top_db()
1389+
db = __get_top_db()
13891390
# create top design
13901391
lib = naja.NLLibrary.create(db)
13911392
top = naja.SNLDesign.create(lib, name)
@@ -1405,15 +1406,15 @@ def load_verilog(files: list, config: VerilogConfig = None) -> Instance:
14051406
config = VerilogConfig() # Use default settings
14061407
start_time = time.time()
14071408
logging.info(f"Loading verilog: {', '.join(files)}")
1408-
get_top_db().loadVerilog(files, keep_assigns=config.keep_assigns)
1409+
__get_top_db().loadVerilog(files, keep_assigns=config.keep_assigns)
14091410
execution_time = time.time() - start_time
14101411
logging.info(f"Loading done in {execution_time:.2f} seconds")
14111412
return get_top()
14121413

14131414

14141415
def load_liberty(files: list):
14151416
logging.info(f"Loading liberty files: {', '.join(files)}")
1416-
get_top_db().loadLibertyPrimitives(files)
1417+
__get_top_db().loadLibertyPrimitives(files)
14171418

14181419

14191420
def load_primitives(name: str):
@@ -1426,15 +1427,37 @@ def load_primitives(name: str):
14261427
if name == "xilinx":
14271428
from najaeda.primitives import xilinx
14281429

1429-
xilinx.load(get_top_db())
1430+
xilinx.load(__get_top_db())
14301431
else:
14311432
raise ValueError(f"Unknown primitives library: {name}")
14321433

14331434

1435+
def load_primitives_from_file(file: str):
1436+
"""Loads a primitives library from a file.
1437+
1438+
:param str file: the path to the primitives library file.
1439+
The file must define a function `load(db)`.
1440+
"""
1441+
logging.info(f"Loading primitives from file: {file}")
1442+
if not os.path.isfile(file):
1443+
raise FileNotFoundError(f"Cannot load primitives from non existing file: {file}")
1444+
import importlib.util
1445+
spec = importlib.util.spec_from_file_location("user_module", file)
1446+
module = importlib.util.module_from_spec(spec)
1447+
sys.modules["user_module"] = module
1448+
spec.loader.exec_module(module)
1449+
1450+
if not hasattr(module, "load"):
1451+
raise RuntimeError(f"The file {file} must define a function named `load(db)`")
1452+
1453+
db = __get_top_db()
1454+
module.load(db)
1455+
1456+
14341457
def get_primitives_library() -> naja.NLLibrary:
1435-
lib = get_top_db().getLibrary("PRIMS")
1458+
lib = __get_top_db().getLibrary("PRIMS")
14361459
if lib is None:
1437-
lib = naja.NLLibrary.createPrimitives(get_top_db(), "PRIMS")
1460+
lib = naja.NLLibrary.createPrimitives(__get_top_db(), "PRIMS")
14381461
return lib
14391462

14401463

test/najaeda/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,5 @@ add_test(NAME najaeda-python-tests
2323
#add_dependencies(naja-python-tests simulate_package_structure)
2424

2525
set_tests_properties(najaeda-python-tests PROPERTIES
26-
ENVIRONMENT "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR};VERILOG_BENCHMARKS_PATH=${CMAKE_SOURCE_DIR}/test/nl/formats/verilog/benchmarks;LIBERTY_BENCHMARKS_PATH=${CMAKE_SOURCE_DIR}/test/nl/formats/liberty/benchmarks;NAJAEDA_TEST_PATH=${CMAKE_CURRENT_BINARY_DIR}"
26+
ENVIRONMENT "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR};VERILOG_BENCHMARKS_PATH=${CMAKE_SOURCE_DIR}/test/nl/formats/verilog/benchmarks;LIBERTY_BENCHMARKS_PATH=${CMAKE_SOURCE_DIR}/test/nl/formats/liberty/benchmarks;NAJAEDA_TEST_PATH=${CMAKE_CURRENT_BINARY_DIR};NAJAEDA_SOURCE_TEST_PATH=${CMAKE_CURRENT_SOURCE_DIR}"
2727
)
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# SPDX-FileCopyrightText: 2025 The Naja authors <https://github.com/najaeda/naja/blob/main/AUTHORS>
2+
#
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
import os
6+
import unittest
7+
8+
from najaeda import netlist
9+
from najaeda import naja
10+
import logging
11+
12+
najaeda_source_test_path = os.environ.get('NAJAEDA_SOURCE_TEST_PATH')
13+
14+
class NajaNetlistCustomPrimitivesTest(unittest.TestCase):
15+
def setUp(self):
16+
logging.basicConfig(level=logging.DEBUG)
17+
universe = naja.NLUniverse.create()
18+
db = naja.NLDB.create(universe)
19+
universe.setTopDB(db)
20+
21+
def tearDown(self):
22+
if naja.NLUniverse.get():
23+
naja.NLUniverse.get().destroy()
24+
25+
def test_loading(self):
26+
universe = naja.NLUniverse.get()
27+
self.assertIsNotNone(universe)
28+
db = universe.getTopDB()
29+
self.assertIsNotNone(db)
30+
primitives_path = os.path.join(najaeda_source_test_path, 'test_najaeda_custom_primitives', 'primitives.py')
31+
netlist.load_primitives_from_file(primitives_path)
32+
33+
primitives = db.getLibrary("custom_lib")
34+
self.assertIsNotNone(primitives)
35+
nb_primitives = sum(1 for _ in primitives.getSNLDesigns())
36+
self.assertEqual(nb_primitives, 2)
37+
self.assertIsNotNone(primitives.getSNLDesign("AND2"))
38+
self.assertIsNotNone(primitives.getSNLDesign("OR2"))
39+
self.assertIsNotNone(primitives.getSNLDesign("AND2").getScalarTerm("I0"))
40+
self.assertIsNotNone(primitives.getSNLDesign("AND2").getScalarTerm("I1"))
41+
self.assertIsNotNone(primitives.getSNLDesign("AND2").getScalarTerm("O"))
42+
self.assertIsNotNone(primitives.getSNLDesign("OR2").getScalarTerm("I0"))
43+
self.assertIsNotNone(primitives.getSNLDesign("OR2").getScalarTerm("I1"))
44+
self.assertIsNotNone(primitives.getSNLDesign("OR2").getScalarTerm("O"))
45+
46+
#now instantiate in najaeda
47+
top = netlist.create_top('Top')
48+
self.assertIsNotNone(top)
49+
and2_ins0 = top.create_child_instance('AND2', 'and2_ins0')
50+
self.assertIsNotNone(and2_ins0)
51+
or2_ins0 = top.create_child_instance('OR2', 'or2_ins0')
52+
self.assertIsNotNone(or2_ins0)
53+
net = top.create_net('net')
54+
self.assertIsNotNone(net)
55+
and2_ins0.get_term("O").connect(net)
56+
or2_ins0.get_term("I0").connect(net)
57+
nb_connections = sum(1 for _ in net.get_inst_terms())
58+
self.assertEqual(nb_connections, 2)
59+
60+
def test_errors(self):
61+
universe = naja.NLUniverse.get()
62+
self.assertIsNotNone(universe)
63+
db = universe.getTopDB()
64+
self.assertIsNotNone(db)
65+
self.assertRaises(Exception, netlist.load_primitives_from_file, "non_existent_file.py")
66+
primitives_path = os.path.join(najaeda_source_test_path, 'test_najaeda_custom_primitives', 'error_primitives.py')
67+
self.assertRaises(Exception, netlist.load_primitives_from_file, primitives_path)
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# SPDX-FileCopyrightText: 2023 The Naja authors <https://github.com/najaeda/naja/blob/main/AUTHORS>
2+
#
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
from najaeda import naja
6+
7+
def dummy(db):
8+
"""Dummy function to ensure the module is loaded."""
9+
pass
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# SPDX-FileCopyrightText: 2023 The Naja authors <https://github.com/najaeda/naja/blob/main/AUTHORS>
2+
#
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
import logging
6+
from najaeda import naja
7+
8+
def constructAND2(lib):
9+
and2 = naja.SNLDesign.createPrimitive(lib, "AND2")
10+
i0 = naja.SNLScalarTerm.create(and2, naja.SNLTerm.Direction.Input, "I0")
11+
i1 = naja.SNLScalarTerm.create(and2, naja.SNLTerm.Direction.Input, "I1")
12+
o = naja.SNLScalarTerm.create(and2, naja.SNLTerm.Direction.Output, "O")
13+
14+
def constructOR2(lib):
15+
or2 = naja.SNLDesign.createPrimitive(lib, "OR2")
16+
i0 = naja.SNLScalarTerm.create(or2, naja.SNLTerm.Direction.Input, "I0")
17+
i1 = naja.SNLScalarTerm.create(or2, naja.SNLTerm.Direction.Input, "I1")
18+
o = naja.SNLScalarTerm.create(or2, naja.SNLTerm.Direction.Output, "O")
19+
20+
def load(db):
21+
logging.info("Loading Custom primitives")
22+
lib = naja.NLLibrary.createPrimitives(db, "custom_lib")
23+
constructAND2(lib)
24+
constructOR2(lib)

0 commit comments

Comments
 (0)