Skip to content

Commit

Permalink
B0.1.6 (#175)
Browse files Browse the repository at this point in the history
* start 0.1.6

* change README

* fix README

* update instance visitor

* add documentation generation

* update example

* reuse setting

* Update najaeda-test.yml

* remove hash for the instance. update READMEs

* typo
  • Loading branch information
xtofalex authored Dec 17, 2024
1 parent 7688657 commit e2961ab
Show file tree
Hide file tree
Showing 14 changed files with 258 additions and 23 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/najaeda-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ jobs:
pip install coverage
- name: Lint with flake8
working-directory: ${{github.workspace}}/src/najaeda
run: flake8 --max-line-length=100 --ignore=E128
run: flake8 --max-line-length=100 --ignore=E128 --exclude docs
- name: Run najaeda testing with pytest
working-directory: ${{github.workspace}}/test/najaeda
env:
Expand Down
4 changes: 4 additions & 0 deletions .reuse/dep5
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ FILES: thirdparty/yosys-liberty/test/benchmarks/test1.lib test/snl/formats/liber
Copyright: Copyright 2020 Lawrence T. Clark, Vinay Vashishtha, or Arizona State University
License: BSD-3-Clause

FILES: src/najaeda/najaeda/docs/*
Copyright: 2022 The Naja Authors.
License: Apache-2.0

FILES: najaeda_examples/benchmarks/liberty/*
Copyright: 2022 The Naja Authors.
License: Apache-2.0
Expand Down
36 changes: 34 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,41 @@

## Introduction

Naja is an Electronic Design Automation (EDA) project that provides open source data structures and APIs for the development of post logic synthesis EDA algorithms such as: netlist simplification (constant and dead logic propagation), logic replication, netlist partitioning, ASIC and FPGA place and route,
Naja is an Electronic Design Automation (EDA) project that provides open source data structures and APIs for the development of post logic synthesis EDA algorithms such as: netlist simplification (constant and dead logic propagation), logic replication, netlist partitioning, ASIC and FPGA place and route, ...

Naja best starting point is netlist optimization and ECO (Engineering Change Order) tool: [naja-edit](#naja_edit) with Python scripts [gallery](README_pages/naja-edit-python-examples.md).
### Quick Start with `najaeda`

The easiest way to get started with **Naja** is through the
[najaeda](https://pypi.org/project/najaeda/) Python package.

`najaeda` provides a powerful yet simple framework designed to help software
`AND` hardware developers efficiently navigate and manipulate electronic design
automation (EDA) workflows.

With `najaeda`, you can:

- **Explore Netlists with Ease**:
- Navigate netlist hierarchy and connectivity effortlessly.
- Browse at multiple levels of detail:
- Bit-level or bus-level granularity.
- Instance-by-instance exploration or flattened views at the primitives level.
- Localized per-instance connections or comprehensive equipotential views.

- **Perform ECO (Engineering Change Order) Transformations**:
- Seamlessly apply and manage changes to your designs.

- **Prototype EDA Ideas Quickly**:
- Use an intuitive API to experiment with new EDA concepts and workflows.

- **Develop Custom EDA Tools**:
- Build fast, tailored tools for solving specific challenges without relying on costly, proprietary EDA software.

`najaeda` empowers developers to innovate, adapt, and accelerate their EDA processes with minimal overhead.

Another entry point for **Naja** is [`naja-edit`](#naja_edit), a tool focused on netlist optimization with Dead Logic Elimination (DLE) or constant propagation.

For advanced use cases, EDA developers can build custom tools on top of naja C++ APIs.
See some simple examples [here](#snippets).

### Acknowledgement

Expand Down
52 changes: 47 additions & 5 deletions najaeda_README/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,38 @@ Naja EDA Python Package
=======================

Naja EDA is a Python package that provides data structures and APIs for developing post-synthesis Electronic Design Automation (EDA) algorithms.
It serves as the Python counterpart to the `Naja C++ project <https://github.com/najaeda/naja>`_.

Naja EDA provides a powerful yet simple framework designed to help software
and hardware developers efficiently navigate and manipulate electronic
design automation (EDA) workflows.

With Naja EDA, you can:

* Explore Netlists with Ease:

* Navigate netlist hierarchy and connectivity effortlessly.
* Browse at multiple levels of detail:

* Bit-level or bus-level granularity.
* Instance-by-instance exploration or flattened views at the primitives level.
* Localized per-instance connections or comprehensive equipotential views.

* Perform ECO (Engineering Change Order) Transformations:

* Seamlessly apply and manage changes to your designs.

* Prototype EDA Ideas Quickly:

* Use an intuitive API to experiment with new EDA concepts and workflows.

* Develop Custom EDA Tools:

* Build fast, tailored tools for solving specific challenges without relying on costly, proprietary EDA software.

Naja EDA empowers developers to innovate, adapt, and accelerate their EDA
processes with minimal overhead.

Naja EDA is the Python counterpart of the `Naja C++ project <https://github.com/najaeda/naja>`_.

Installation
------------
Expand All @@ -25,10 +56,11 @@ a netlist from a Verilog file.
Load a design with pre-existing libraries
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In FPGA design environments, Liberty files are often unavailable.

To address this, the following example demonstrates how to load primitives
without relying on Liberty files.

najaeda comes with pre-configured libraries to simplify this process.
Naja EDA comes with pre-configured libraries to simplify this process.
Currently, it includes support for partial Xilinx primitives, but this can be
easily extended in the future. Don't hesitate to reach out if you need help.
.. snippet:: load_xilinx_design
Expand All @@ -43,19 +75,29 @@ This approach allows you to perform operations on each instance while
also defining conditions for stopping or continuing exploration.
.. snippet:: print_design_visitor

Counting the Number of Leaves in a Netlist
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The instance visitor provides a tool for collecting various types of information
about a netlist.

The following example demonstrates how to use the visitor’s callback
function to transmit user-defined arguments, allowing for flexible data processing.

This specific use case shows how to count the number of leaf instances in a netlist.
.. snippet:: count_leaves

Documentation
-------------
najaeda is a work in progress, and the documentation is still under development.
Naja EDA is a work in progress, and the documentation is still under development.

Naja documentation is available on the `Naja GitHub repository <https://github.com/najaeda/naja>`_.

Support
-------
Please put up issues on the Delocate issue tracker.
If you encounter any issues or have questions, please report them on the
`Naja issue tracker <https://github.com/najaeda/naja/issues>`_.

License
-------
This project is licensed under the Apache License 2.0.
This project is licensed under the Apache License 2.0. \
See the `LICENSE <https://github.com/najaeda/naja/blob/main/LICENSE>`_ file for details.
36 changes: 36 additions & 0 deletions najaeda_examples/count_leaves/najaeda_count_leaves.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# SPDX-FileCopyrightText: 2024 The Naja authors
# <https://github.com/najaeda/naja/blob/main/AUTHORS>
#
# SPDX-License-Identifier: Apache-2.0

# snippet-start: load_design

from os import path
import sys

from najaeda import netlist
from najaeda import instance_visitor

netlist.load_primitives('xilinx')
benchmarks = path.join('..','benchmarks')
top = netlist.load_verilog([path.join(benchmarks, 'verilog', 'arm_core_netlist.v')])

# snippet-start: count_leaves
leaves = {"count": 0, "assigns": 0, "constants": 0}
def count_leaves(instance, leaves):
if instance.is_leaf():
if instance.is_assign():
leaves["assigns"] += 1
elif instance.is_const():
leaves["constants"] += 1
else:
leaves["count"] += 1
visitor_config = instance_visitor.VisitorConfig(callback=count_leaves, args=(leaves,))
instance_visitor.Visitor(top).visit(top, visitor_config)
print(f"{top} leaves count")
print(f"nb_assigns={leaves['assigns']}")
print(f"nb constants={leaves['constants']}")
print(f"nb other leaves={leaves['count']}")
# snippet-end: count_leaves

sys.exit(0)
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ build-backend = "scikit_build_core.build"

[project]
name = "najaeda"
version = "0.1.5"
version = "0.1.6"
description = "Naja EDA Python package"
authors = [{name = "Naja Authors", email = "[email protected]"}]
readme = "README.rst"
Expand Down
20 changes: 20 additions & 0 deletions src/najaeda/najaeda/docs/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Minimal makefile for Sphinx documentation
#

# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = source
BUILDDIR = build

# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

.PHONY: help Makefile

# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
35 changes: 35 additions & 0 deletions src/najaeda/najaeda/docs/make.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
@ECHO OFF

pushd %~dp0

REM Command file for Sphinx documentation

if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=source
set BUILDDIR=build

%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.https://www.sphinx-doc.org/
exit /b 1
)

if "%1" == "" goto help

%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
goto end

:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%

:end
popd
7 changes: 7 additions & 0 deletions src/najaeda/najaeda/docs/source/api.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
najaeda API Documentation
=========================

.. automodule:: najaeda.netlist
:members:
:undoc-members:
:show-inheritance:
40 changes: 40 additions & 0 deletions src/najaeda/najaeda/docs/source/conf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Configuration file for the Sphinx documentation builder.
#
# For the full list of built-in configuration values, see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html

# -- Project information -----------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information

import sys
import os

# Add the src directory to sys.path
sys.path.insert(0, os.path.abspath('../../../'))

project = 'najaeda'
copyright = '2024, Naja authors'
author = 'Naja authors'
release = '0.1.6'

# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration

extensions = [
'sphinx.ext.autodoc', # Enables the automodule directive
'sphinx.ext.napoleon', # (Optional) Supports Google and NumPy-style docstrings
'sphinx.ext.viewcode', # (Optional) Links to source code in docs
'sphinx.ext.todo', # (Optional) For TODOs in the documentation
]

autodoc_mock_imports = ["najaeda.snl"]
templates_path = ['_templates']
exclude_patterns = []



# -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output

html_theme = 'sphinx_rtd_theme'
html_static_path = ['_static']
13 changes: 13 additions & 0 deletions src/najaeda/najaeda/docs/source/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.. najaeda documentation master file, created by
sphinx-quickstart on Mon Dec 16 16:39:26 2024.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
najaeda documentation
=====================

.. toctree::
:maxdepth: 2
:caption: Contents:

api
18 changes: 12 additions & 6 deletions src/najaeda/najaeda/instance_visitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,21 @@ class VisitorConfig:
def __init__(
self,
enter_condition: Callable[[netlist.Instance], bool] = lambda node: True,
callback: Callable[[netlist.Instance], None] = lambda node: None,
callback: Callable[..., None] = lambda node, *args, **kwargs: None,
args: tuple = (),
kwargs: dict = None,
):
"""
:param enter_condition: A function that determines whether to visit
the children of an instance.
:param callback: The callback to be executed when an instance is visited.
:param enter_condition: A callable that takes a node (dict)
and returns True if the visitor should enter.
:param callback: A callable that takes a node (dict) and performs an operation on it.
:param args: Positional arguments to pass to the callback.
:param kwargs: Keyword arguments to pass to the callback.
"""
self.callback = callback
self.enter_condition = enter_condition
self.callback = callback
self.args = args
self.kwargs = kwargs or {}


class Visitor:
Expand All @@ -37,7 +43,7 @@ def visit(self, instance: netlist.Instance, config: VisitorConfig):
:param config: VisitorConfig object defining conditions and callbacks.
"""
# Execute the callback
config.callback(instance)
config.callback(instance, *config.args, **config.kwargs)

# Check if we should proceed to children
if config.enter_condition(instance):
Expand Down
4 changes: 2 additions & 2 deletions src/najaeda/najaeda/netlist.py
Original file line number Diff line number Diff line change
Expand Up @@ -438,8 +438,8 @@ def __str__(self):
def __repr__(self) -> str:
return f"Instance({self.path})"

def __hash__(self):
return hash(self.path)
# def __hash__(self):
# return hash(self.path)

def is_top(self) -> bool:
"""Return True if this is the top design."""
Expand Down
12 changes: 6 additions & 6 deletions test/najaeda/test_najaeda_netlist1.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,12 +218,12 @@ def testInstanceHash(self):
top = netlist.get_top()
instances = list(top.get_child_instances())
self.assertEqual(3, len(instances))
instancesDict = {}
for index, instance in enumerate(instances):
instancesDict[instance] = index
instancesDict[top] = 4
self.assertEqual(4, len(instancesDict))
self.assertEqual(4, instancesDict[top])
#instancesDict = {}
#for index, instance in enumerate(instances):
# instancesDict[instance] = index
#instancesDict[top] = 4
#self.assertEqual(4, len(instancesDict))
#self.assertEqual(4, instancesDict[top])
#FIXME xtof can we find back in a dict
#different but == instances ?
#self.assertIn(top.get_child_instance('Ins0'), instancesDict)
Expand Down

0 comments on commit e2961ab

Please sign in to comment.