├── docs ├── authors.rst ├── readme.rst ├── changelog.rst ├── contributing.rst ├── requirements.txt ├── usage.rst ├── internals.rst ├── installation.rst ├── api.rst ├── index.rst ├── make.bat ├── Makefile └── conf.py ├── requirements.txt ├── MANIFEST.in ├── tests ├── conftest.py ├── test_hw.py ├── test_sim.py └── test_constructors.py ├── .travis.yml ├── tox.ini ├── uhdl ├── hmath.py ├── __init__.py ├── _compat.py ├── structures.py ├── cli.py ├── helpers.py ├── constructors.py ├── utils.py ├── cosim.py └── hw.py ├── .gitignore ├── CHANGELOG.md ├── setup.py ├── LICENSE └── README.md /docs/authors.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../AUTHORS.rst -------------------------------------------------------------------------------- /docs/readme.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../README.rst -------------------------------------------------------------------------------- /docs/changelog.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../CHANGELOG.md 2 | -------------------------------------------------------------------------------- /docs/contributing.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../CONTRIBUTING.rst -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | -r ../requirements.txt 2 | sphinx==1.3.1 3 | sphinx-rtd-theme 4 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | https://github.com/jandecaluwe/myhdl/tarball/master 2 | -e .[testing] 3 | -------------------------------------------------------------------------------- /docs/usage.rst: -------------------------------------------------------------------------------- 1 | ======== 2 | Usage 3 | ======== 4 | 5 | To use Utilities for MyHDL in a project:: 6 | 7 | import uhdl -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include AUTHORS.rst 2 | include CONTRIBUTING.rst 3 | include HISTORY.rst 4 | include LICENSE 5 | include README.md 6 | include requirements.txt 7 | -------------------------------------------------------------------------------- /docs/internals.rst: -------------------------------------------------------------------------------- 1 | Internals 2 | ========= 3 | 4 | .. automodule:: uhdl.structures 5 | :members: 6 | 7 | .. automodule:: uhdl.utils 8 | :members: 9 | -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | 4 | @pytest.yield_fixture 5 | def in_tmpdir(tmpdir): 6 | """Change to pytest-provided temporary directory""" 7 | with tmpdir.as_cwd(): 8 | yield tmpdir 9 | -------------------------------------------------------------------------------- /docs/installation.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | Installation 3 | ============ 4 | 5 | At the command line:: 6 | 7 | $ easy_install uhdl 8 | 9 | Or, if you have virtualenvwrapper installed:: 10 | 11 | $ mkvirtualenv uhdl 12 | $ pip install uhdl -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | language: python 4 | 5 | python: 6 | - "2.7" 7 | - "3.4" 8 | - "3.5" 9 | - "pypy" 10 | 11 | addons: 12 | apt_packages: 13 | - iverilog 14 | 15 | script: py.test 16 | 17 | notifications: 18 | email: false 19 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py27, py34 3 | 4 | [testenv] 5 | deps = -rrequirements.txt 6 | commands = py.test --basetemp={envtmpdir} [] 7 | 8 | [testenv:docs] 9 | whitelist_externals = make 10 | changedir = doc 11 | deps = sphinx-autobuild 12 | commands = make [] 13 | -------------------------------------------------------------------------------- /uhdl/hmath.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | import math as _m 3 | 4 | 5 | def log2(n): 6 | return int(_m.log(n, 2)) 7 | 8 | 9 | def clog2(n): 10 | return int(_m.ceil(_m.log(n, 2))) 11 | 12 | 13 | def roundup(x, y): 14 | """round up x to nearest multiple of y""" 15 | n = x - (x % -y) 16 | return n 17 | -------------------------------------------------------------------------------- /uhdl/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | UHDL 3 | ~~~~ 4 | """ 5 | 6 | from __future__ import absolute_import 7 | 8 | __version__ = __import__('pkg_resources').get_distribution(__name__).version 9 | 10 | from . import hmath 11 | from .constructors import create, randbits, Sig, Sigs 12 | from .helpers import Clock, Reset, run_sim, sim 13 | from .hw import HW 14 | -------------------------------------------------------------------------------- /docs/api.rst: -------------------------------------------------------------------------------- 1 | .. _api: 2 | 3 | Developer Interface 4 | =================== 5 | 6 | .. module:: uhdl 7 | 8 | 9 | Constructors 10 | ------------ 11 | 12 | .. autofunction:: bits 13 | .. autofunction:: randbits 14 | .. autofunction:: Sig 15 | .. autofunction:: create 16 | .. autofunction:: Sigs 17 | 18 | Simulation 19 | ---------- 20 | .. autofunction:: run 21 | .. autoclass:: HW 22 | :members: 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | 3 | # Packages 4 | *.egg 5 | *.egg-info 6 | dist/ 7 | build/ 8 | .eggs/ 9 | parts 10 | bin 11 | var 12 | sdist 13 | develop-eggs 14 | 15 | # Installer logs 16 | pip-log.txt 17 | 18 | # Unit test / coverage reports 19 | .coverage 20 | .tox 21 | .hypothesis 22 | 23 | # Sphinx 24 | docs/_build 25 | 26 | # Generated HDL and related 27 | *.o 28 | *.v 29 | *.vcd* 30 | work* 31 | transcript 32 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | Changelog 2 | ========= 3 | 4 | Unreleased 5 | ---------- 6 | - Python 3 support 7 | - ``run`` has been split into a ``sim`` decorator and a ``run_sim`` function 8 | 9 | 10 | (2013-10-27) 11 | ------------ 12 | - First public version. Not available on PyPI anymore because of various issues. 13 | - Features: 14 | * Constructors: bits, randbits, create, Sig, Sigs, Clock, Reset 15 | * Simulation: HW, run 16 | * math: clog2, roundup 17 | -------------------------------------------------------------------------------- /uhdl/_compat.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | PY2 = sys.version_info[0] == 2 4 | 5 | def with_metaclass(meta, *bases): 6 | class metaclass(meta): 7 | __call__ = type.__call__ 8 | __init__ = type.__init__ 9 | def __new__(cls, name, this_bases, d): 10 | if this_bases is None: 11 | return type.__new__(cls, name, (), d) 12 | return meta(name, bases, d) 13 | return metaclass('temporary_class', None, {}) 14 | 15 | if not PY2: 16 | integer_types = (int,) 17 | else: 18 | integer_types = (int, long) 19 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. complexity documentation master file, created by 2 | sphinx-quickstart on Tue Jul 9 22:26:36 2013. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | UHDL: Python Hardware Description for Humans. 7 | ============================================= 8 | 9 | Contents: 10 | 11 | .. toctree:: 12 | :maxdepth: 2 13 | 14 | readme 15 | installation 16 | usage 17 | api 18 | internals 19 | contributing 20 | authors 21 | changelog 22 | 23 | Indices and tables 24 | ================== 25 | 26 | * :ref:`genindex` 27 | * :ref:`modindex` 28 | * :ref:`search` 29 | -------------------------------------------------------------------------------- /tests/test_hw.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | 3 | from myhdl import always_comb, instance, StopSimulation, Simulation, delay 4 | from uhdl import HW, Sigs, randbits, utils 5 | 6 | 7 | def setup_module(): 8 | utils.VPI.make('icarus') 9 | 10 | 11 | def connect(ip, op): 12 | 13 | @always_comb 14 | def logic(): 15 | op.next = ip 16 | 17 | return logic 18 | 19 | 20 | a, b = Sigs(2, w=32) 21 | dut = HW(connect, a, b) 22 | 23 | 24 | def test_icarus_backend_simple(in_tmpdir): 25 | 26 | @instance 27 | def stim(): 28 | for i in range(5): 29 | rand = randbits(32) 30 | a.next = rand 31 | yield delay(10) 32 | assert b == a 33 | 34 | raise StopSimulation 35 | 36 | gens = dut.sim(backend='icarus'), stim 37 | 38 | Simulation(gens).run() 39 | -------------------------------------------------------------------------------- /tests/test_sim.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from uhdl import sim 4 | 5 | 6 | @pytest.fixture(autouse=True) 7 | def monkey_sim(monkeypatch): 8 | class SimulationMonkey(object): 9 | def __init__(self, *args): 10 | self.args = args 11 | 12 | def run(self, **kwargs): 13 | return self.args, kwargs 14 | 15 | monkeypatch.setattr('uhdl.helpers.Simulation', SimulationMonkey) 16 | 17 | 18 | def test_decorator_without_param(): 19 | g = 1, 2, 3 20 | 21 | @sim 22 | def test(): 23 | return g 24 | 25 | assert test() == ((g,), dict(duration=None, quiet=False)) 26 | 27 | 28 | def test_decorator_with_param(): 29 | g = 1, 2, 3 30 | 31 | @sim(duration=5) 32 | def test(): 33 | return g 34 | 35 | assert test() == ((g,), dict(duration=5, quiet=False)) 36 | -------------------------------------------------------------------------------- /tests/test_constructors.py: -------------------------------------------------------------------------------- 1 | from hypothesis import assume, given 2 | from hypothesis.specifiers import integers_in_range 3 | from myhdl import Signal, intbv 4 | 5 | from uhdl import Sig 6 | 7 | width = integers_in_range(2, 100) 8 | 9 | 10 | def check_sigs(expected, *sigs): 11 | __tracebackhide__ = True 12 | for s in sigs: 13 | assert expected == s 14 | assert len(expected) == len(s) 15 | 16 | 17 | @given(bool) 18 | def test_bool(x): 19 | check_sigs(Signal(x), Sig(x)) 20 | 21 | 22 | @given(width) 23 | def test_only_width(x): 24 | check_sigs(Signal(intbv()[x:]), Sig(w=x)) 25 | 26 | 27 | @given(int, width) 28 | def test_width_and_initial_value(val, width): 29 | check_sigs(Signal(intbv(val)[width:]), 30 | Sig(val, width), 31 | Sig(val, w=width), 32 | Sig(val=val, w=width) 33 | ) 34 | 35 | 36 | @given(int, int) 37 | def test_min_max(min, max): 38 | assume(min < max) 39 | check_sigs(Signal(intbv(val=min, min=min, max=max)), Sig(min=min, max=max)) 40 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | 4 | reqs = [ 5 | 'myhdl>=0.9.0', 6 | 'click', 7 | 'wrapt' 8 | ] 9 | test_reqs = ['pytest', 'hypothesis'] 10 | 11 | requires = { 12 | 'setup_requires': ['setuptools_scm'], 13 | 'install_requires': reqs, 14 | 'tests_require': test_reqs, 15 | 'extras_require': { 16 | 'testing': test_reqs, 17 | } 18 | } 19 | 20 | setup( 21 | name='uhdl', 22 | use_scm_version=True, 23 | description='Python Hardware Description for Humans.', 24 | long_description=open('README.md').read(), 25 | url='https://github.com/jck/uhdl', 26 | author='Keerthan Jaic', 27 | author_email='jckeerthan@gmail.com', 28 | license="BSD", 29 | packages=['uhdl'], 30 | entry_points={ 31 | 'console_scripts': [ 32 | 'uhdl = uhdl.cli:cli' 33 | ] 34 | }, 35 | zip_safe=False, 36 | classifiers=[ 37 | 'Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)' 38 | 'Development Status :: 1 - Planning', 39 | 'Intended Audience :: Developers', 40 | 'License :: OSI Approved :: BSD License', 41 | 'Natural Language :: English', 42 | 'Operating System :: POSIX :: Linux', 43 | 'Programming Language :: Python :: 2.7', 44 | 'Programming Language :: Python :: 3.4', 45 | ], 46 | keywords='myhdl uhdl', 47 | **requires 48 | ) 49 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, Keerthan Jaic 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | * Neither the name of uhdl nor the names of its contributors may be used to 13 | endorse or promote products derived from this software without specific 14 | prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /uhdl/structures.py: -------------------------------------------------------------------------------- 1 | """ 2 | uhdl.structures 3 | ~~~~~~~~~~~~~~~ 4 | 5 | Data structures(unrelated to hardware description) used internally by uhdl. 6 | 7 | """ 8 | import collections 9 | 10 | 11 | def _dictrepr(instance, store): 12 | name = instance.__class__.__name__ 13 | return '{name}({store})'.format(name=name, store=store) 14 | 15 | 16 | class DictRef(object): 17 | def __init__(self, store): 18 | self.__dict__['store'] = store 19 | 20 | def __getattr__(self, key): 21 | return self.__dict__['store'][key] 22 | 23 | def __setattr__(self, key, value): 24 | self.__dict__['store'][key] = value 25 | 26 | def __repr__(self): 27 | return _dictrepr(self, self._store) 28 | 29 | 30 | class CaselessDict(collections.MutableMapping): 31 | """A case-insensitive dictionary. 32 | 33 | All keys are expected to be strings. The structure converts the key to 34 | lower case before storing or retreiving objects. 35 | """ 36 | 37 | def __init__(self, data=None, **kwargs): 38 | self._store = dict() 39 | if data is None: 40 | data = {} 41 | self.update(data, **kwargs) 42 | #self.key = DictRef(self) 43 | 44 | def __setitem__(self, key, value): 45 | self._store[key.lower()] = value 46 | 47 | def __getitem__(self, key): 48 | return self._store[key.lower()] 49 | 50 | def __delitem__(self, key): 51 | del self._store[key.lower()] 52 | 53 | def __iter__(self): 54 | return iter(self._store) 55 | 56 | def __len__(self): 57 | return len(self._store) 58 | 59 | def __repr__(self): 60 | return _dictrepr(self, self._store) 61 | 62 | #@property 63 | #def key(self): 64 | #return self._ref 65 | -------------------------------------------------------------------------------- /uhdl/cli.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import subprocess 3 | import shutil 4 | import os 5 | 6 | from tempfile import mkdtemp 7 | 8 | import click 9 | 10 | from .cosim import CoSimulator 11 | from .utils import cd, VPI 12 | 13 | 14 | @click.group(context_settings={ 15 | 'help_option_names': ['-h', '--help'] 16 | }) 17 | def cli(): 18 | pass 19 | 20 | 21 | @cli.group() 22 | def vpi(): 23 | """Manage cosimulation VPI modules""" 24 | pass 25 | 26 | 27 | supported_sims = CoSimulator.registry.keys() 28 | installed_sims = [s.__name__ for s in CoSimulator.registry.values() if s.exists] 29 | 30 | class SimParamType(click.ParamType): 31 | name = 'simulator' 32 | 33 | def convert(self, value, param, ctx): 34 | if value not in CoSimulator.registry.keys(): 35 | self.fail('%s is not a supported simulator' % value, param, ctx) 36 | if value not in installed_sims: 37 | self.fail('%s is not installed' % value, param, ctx) 38 | return value 39 | 40 | SIM = SimParamType() 41 | 42 | 43 | @vpi.command('init') 44 | @click.option('--force', is_flag=True, 45 | help='Recompile VPIs even if they already exist') 46 | @click.argument('simulators', nargs=-1, type=SIM) 47 | def vpi_init(simulators, force): 48 | """Compile Cosimulation VPI modules""" 49 | if not simulators: 50 | simulators = installed_sims 51 | 52 | if not simulators: 53 | click.secho('No simulators found, exiting.', fg='red') 54 | sys.exit() 55 | 56 | sims = [CoSimulator.registry[k] for k in simulators] 57 | 58 | for s in sims: 59 | name = s.__name__ 60 | if s.vpi_exists and not force: 61 | click.echo('VPI for {0} already exists.'.format(name)) 62 | continue 63 | VPI.make(name) 64 | 65 | 66 | @vpi.command('clean') 67 | def vpi_clean(): 68 | VPI.clean() 69 | -------------------------------------------------------------------------------- /uhdl/helpers.py: -------------------------------------------------------------------------------- 1 | import functools 2 | 3 | import wrapt 4 | from myhdl import SignalType, ResetSignal, delay, always, instance, Simulation 5 | 6 | 7 | class Clock(SignalType): 8 | """Clock class for use in simulations""" 9 | def __init__(self, period=2): 10 | self.period = period 11 | if period % 2 != 0: 12 | raise ValueError("period must be divisible by 2") 13 | super(Clock, self).__init__(False) 14 | 15 | def gen(self): 16 | 17 | @always(delay(self.period/2)) 18 | def _clock(): 19 | self.next = not self 20 | return _clock 21 | 22 | 23 | class Reset(ResetSignal): 24 | """Reset class for use in simulations""" 25 | def __init__(self, val=0, active=0, async=True): 26 | super(Reset, self).__init__(val, active, async) 27 | 28 | def pulse(self, time=5): 29 | 30 | @instance 31 | def _reset(): 32 | self.next = self.active 33 | yield delay(time) 34 | self.next = not self.active 35 | 36 | return _reset 37 | 38 | def run_sim(*args, **kwargs): 39 | return Simulation(*args).run(**kwargs) 40 | 41 | 42 | def sim(wrapped=None, duration=None, quiet=False): 43 | """Decorator which simplifies running a :class:`myhdl.Simulation` 44 | 45 | Usage: 46 | 47 | .. code-block:: python 48 | 49 | @sim 50 | def function_which_returns_generators(...): 51 | ... 52 | 53 | @sim(duration=n, quiet=False) 54 | def function_which_returns_generators(...): 55 | ... 56 | """ 57 | if wrapped is None: 58 | return functools.partial(sim, duration=duration, quiet=quiet) 59 | 60 | @wrapt.decorator 61 | def wrapper(wrapped, instance, args, kwargs): 62 | return run_sim(wrapped(*args, **kwargs), duration=duration, quiet=quiet) 63 | 64 | return wrapper(wrapped) 65 | -------------------------------------------------------------------------------- /uhdl/constructors.py: -------------------------------------------------------------------------------- 1 | """ 2 | uhdl.constructors 3 | ~~~~~~~~~~~~~ 4 | 5 | This module provides the core uhdl constructors. 6 | """ 7 | import random 8 | 9 | from myhdl import intbv, Signal 10 | 11 | from ._compat import integer_types 12 | 13 | def randbits(n): 14 | return intbv(val=random.getrandbits(n))[n:] 15 | 16 | def all_none(*lst): 17 | return all(x is None for x in lst) 18 | 19 | 20 | def is_int(x): 21 | return not isinstance(x, bool) and isinstance(x, integer_types) 22 | 23 | 24 | def Sig(val=None, w=None, min=None, max=None): 25 | if all_none(w, min, max): 26 | if is_int(val): 27 | val = intbv(val) 28 | return Signal(val) 29 | 30 | min_max = not all_none(min, max) 31 | explicit_width = w is not None 32 | if explicit_width and min_max: 33 | raise ValueError("Only one of width or min/max must be provided") 34 | 35 | if not is_int(val) and val is not None: 36 | raise TypeError('Specifying width is supported only for int values') 37 | 38 | if explicit_width: 39 | val = intbv(val or 0)[w:] 40 | elif min_max: 41 | if None in (min, max): 42 | raise ValueError("Both min and max must be provided") 43 | val = intbv(val=val or min, min=min, max=max) 44 | 45 | return Signal(val) 46 | 47 | 48 | def create(n, constructor, *args, **kwargs): 49 | """Helper function for constructing multiple objects with the same 50 | arguments. 51 | 52 | Shorthand for [constructor(\*args, \*\*kwargs) for i in range(n)] 53 | """ 54 | return [constructor(*args, **kwargs) for i in range(n)] 55 | 56 | 57 | def Sigs(n, *args, **kwargs): 58 | """Create multiple Signals cleanly. 59 | 60 | Args: 61 | n: number of signals to create. 62 | *args: passed through to :func:`.Sig` 63 | **kwargs: passed through to :func:`.Sig` 64 | 65 | Returns: 66 | [Sig(\*args, \*\*kwargs) for i in range(n)] 67 | """ 68 | return create(n, Sig, *args, **kwargs) 69 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | UHDL: Python Hardware Description for Humans. 2 | ============================================= 3 | 4 | [![Travis](https://img.shields.io/travis/jck/uhdl/master.svg)][Travis] 5 | [![Docs](https://readthedocs.org/projects/uhdl/badge/?version=latest)][Docs] 6 | [![PyPI](https://img.shields.io/pypi/v/uhdl.svg)][PyPI] 7 | 8 | 9 | 10 | UHDL is a BSD Licensed library which simplifies the process of designing 11 | digital hardware with [MyHDL]. 12 | 13 | UHDL provides utilities to simplify constructing myhdl objects, A uniform 14 | simulation API, and more. 15 | 16 | To compile the cosimulation vpis, simply: 17 | 18 | ```bash 19 | $ uhdl vpi init 20 | ``` 21 | 22 | Usage Example: 23 | 24 | ```python 25 | from myhdl import always_seq, instance, StopSimulation 26 | from uhdl import Clock, Reset, Sig, randbits, HW, run 27 | 28 | def inc(clk, rst, en, count): 29 | @always_seq(clk.posedge, rst) 30 | def logic(): 31 | if en: 32 | count.next = count + 1 33 | return logic 34 | 35 | #Simulation(test_inc()).run() 36 | @run 37 | def test_inc(backend): 38 | clk = Clock() 39 | rst = Reset(async=False) 40 | en = Sig(False) 41 | count = Sig(8) #Signal(intbv()[8:]) 42 | top = HW(inc, clk, rst, en, count) 43 | dut = top.sim(backend=backend) 44 | 45 | @instance 46 | def stim(): 47 | for i in range(20): 48 | en.next = randbits(1) 49 | raise StopSimulation 50 | 51 | @instance 52 | def mon(): 53 | while True: 54 | yield clk.posedge 55 | yield delay(1) 56 | print rst, en, count 57 | 58 | #If the function was not decorated with @run, 59 | #run(clk.gen(), rst.pulse(), dut, stim, mon) would do the trick. 60 | return clk.gen(), rst.pulse(5), dut, stim, mon 61 | 62 | #run with myhdl 63 | test_inc() 64 | #run with icarus 65 | test_inc('icarus') 66 | #run with modelsim 67 | test_inc('modelsim') 68 | ``` 69 | 70 | Features 71 | -------- 72 | - Helper functions to simplify the common cases of Signal creation. 73 | - Consistent simulation and conversion API with sane default arguments. 74 | - Automatic HDL Simulator detection and VPI Compilation(icarus/modelsim). 75 | 76 | 77 | Installation 78 | ------------ 79 | To install UHDL, simply: 80 | 81 | ```bash 82 | $ mkvirtualenv uhdl 83 | $ pip install uhdl 84 | ``` 85 | 86 | Documentation 87 | ------------- 88 | Documentation is avaliable at http://uhdl.readthedocs.org/en/latest/api.html 89 | 90 | [Docs]: https://uhdl.readthedocs.org 91 | [PyPI]: https://pypi.python.org/pypi/uhdl 92 | [Travis]: https://travis-ci.org/jck/uhdl 93 | [MyHDL]: http://myhdl.org/ 94 | -------------------------------------------------------------------------------- /uhdl/utils.py: -------------------------------------------------------------------------------- 1 | """ 2 | uhdl.utils 3 | ~~~~~~~~~~ 4 | 5 | Utility functions(unrelated to hardware desription) used within uhdl. 6 | """ 7 | 8 | import collections 9 | import contextlib 10 | import distutils.spawn 11 | import os 12 | import subprocess 13 | import shutil 14 | import sys 15 | from functools import wraps 16 | from tempfile import mkdtemp 17 | 18 | 19 | def get_data_dir(): 20 | plat = sys.platform 21 | if plat.startswith('linux'): 22 | data_dir = os.getenv('XDG_DATA_HOME', '~/.local/share') 23 | elif plat == 'darwin': 24 | data_dir = '~/Library/Application Support/' 25 | return os.path.join(os.path.expanduser(data_dir), 'uhdl') 26 | 27 | 28 | class _VPI(object): 29 | dir = os.path.join(get_data_dir(), 'vpi') 30 | cosim_src = os.path.join(sys.prefix, 'share/myhdl/cosimulation') 31 | 32 | def __init__(self): 33 | if not os.path.exists(self.dir): 34 | os.makedirs(self.dir) 35 | 36 | def make(self, name, force=False): 37 | dest = os.path.join(self.dir, name+'.vpi') 38 | print(dest) 39 | if not force and os.path.exists(dest): 40 | return 41 | 42 | tmpdir = mkdtemp() 43 | srcdir = os.path.join(tmpdir, 'cosim') 44 | shutil.copytree(os.path.join(self.cosim_src), srcdir) 45 | 46 | vpi_name = { 47 | 'icarus': 'myhdl.vpi', 48 | 'modelsim': 'myhdl_vpi.so' 49 | } 50 | with cd(os.path.join(srcdir, name)): 51 | subprocess.check_call(['make', 'test']) 52 | shutil.copy(vpi_name[name], dest) 53 | 54 | def clean(self): 55 | if os.path.exists(self.dir): 56 | shutil.rmtree(self.dir) 57 | 58 | VPI = _VPI() 59 | 60 | 61 | @contextlib.contextmanager 62 | def cd(path): 63 | """Context manager which changes the current working directory 64 | 65 | Args: 66 | path(str): path to change directory to. 67 | 68 | Usage: 69 | .. code-block:: python 70 | 71 | with cd('path/to/somewhere'): 72 | #do something.. 73 | 74 | """ 75 | curdir = os.getcwd() 76 | os.chdir(path) 77 | try: 78 | yield 79 | finally: 80 | os.chdir(curdir) 81 | 82 | 83 | def which(exe): 84 | return distutils.spawn.find_executable(exe) 85 | 86 | 87 | class classproperty(object): 88 | """Decorator which allows read only class properties""" 89 | 90 | def __init__(self, fget): 91 | self.fget = fget 92 | 93 | def __get__(self, owner_self, owner_cls): 94 | return self.fget(owner_cls) 95 | 96 | 97 | def flatten(*args): 98 | """Flattens arbitrarily nested iterators(Except strings) 99 | 100 | Args: 101 | *args: objects and iterables. 102 | 103 | Returns: 104 | list of all objects. 105 | """ 106 | l = [] 107 | for arg in args: 108 | if isinstance(arg, collections.Iterable) and not isinstance(arg, str): 109 | for item in arg: 110 | l.extend(flatten(item)) 111 | else: 112 | l.append(arg) 113 | return l 114 | 115 | 116 | def memoize(func): 117 | cache = {} 118 | 119 | @wraps(func) 120 | def memoized(*args): 121 | if args in cache: 122 | result = cache[args] 123 | else: 124 | result = func(*args) 125 | cache[args] = result 126 | return result 127 | return memoized 128 | -------------------------------------------------------------------------------- /uhdl/cosim.py: -------------------------------------------------------------------------------- 1 | """ 2 | uhdl.backends.cosim 3 | ~~~~~~~~~~~~~~~~~~~ 4 | """ 5 | 6 | import subprocess 7 | import os 8 | 9 | from myhdl import Cosimulation 10 | 11 | from uhdl._compat import with_metaclass 12 | from uhdl.utils import classproperty, flatten, which, VPI 13 | 14 | 15 | class cosim(object): 16 | """Decorator for specifying how to run the simulation executable. 17 | 18 | For use inside CoSimulator classes. See icarus and modelsim for usage 19 | examples. 20 | """ 21 | def __init__(self, func): 22 | self.func = func 23 | self.cmd = func.__name__ 24 | 25 | def _reg(self, cls): 26 | self.cls = cls 27 | setattr(cls, 'cosim', self) 28 | 29 | def __call__(self, *args, **ports): 30 | cli_args = self.func(self.cls.vpi, *args) 31 | cmd = ' '.join(flatten(self.cmd, cli_args)) 32 | return Cosimulation(exe=cmd, **ports) 33 | 34 | 35 | class compile(object): 36 | """Decorator for specifying how to compile hdl. 37 | 38 | For use inside CoSimulator classes. See icarus and modelsim for usage 39 | examples. 40 | """ 41 | def __init__(self, hdl): 42 | self.hdl = hdl 43 | 44 | def __call__(self, func): 45 | self.func = func 46 | self.cmd = func.__name__ 47 | return self 48 | 49 | def _reg(self, cls): 50 | cls.compilers[self.hdl] = self.run 51 | 52 | def run(self, *args, **kwargs): 53 | cli_args = self.func(*args, **kwargs) 54 | cmd = flatten(self.cmd, cli_args) 55 | subprocess.check_call(cmd) 56 | 57 | 58 | class CoSimulatorBase(type): 59 | """Metaclass for CoSimulator Base class""" 60 | def __init__(cls, name, bases, attrs): 61 | if not hasattr(cls, 'registry'): 62 | #Base class 63 | cls.registry = {} 64 | else: 65 | #Subclasses 66 | cls.registry[name] = cls 67 | cls.compilers = {} 68 | 69 | #set default vpi file path to resources dir 70 | if not hasattr(cls, 'vpi'): 71 | cls.vpi = VPI.dir + '/{0}.vpi'.format(cls.__name__) 72 | 73 | for attr, obj in attrs.items(): 74 | if isinstance(obj, (cosim, compile)): 75 | delattr(cls, attr) 76 | obj._reg(cls) 77 | 78 | 79 | class CoSimulator(with_metaclass(CoSimulatorBase)): 80 | """Base class for all CoSimulators""" 81 | 82 | @classproperty 83 | def exists(cls): 84 | """Check if the cosimulator's executable exists in the PATH""" 85 | return which(cls.cosim.cmd) is not None 86 | 87 | @classproperty 88 | def vpi_exists(cls): 89 | """Check if the vpi for the cosimulator exists.""" 90 | return os.path.exists(cls.vpi) 91 | 92 | @classmethod 93 | def compile(cls, hdl, *args, **kwargs): 94 | return cls.compilers[hdl](*args, **kwargs) 95 | 96 | @classmethod 97 | def cosim_gen(cls, hdl, files, portmap): 98 | op = files[0].split('.')[0] 99 | cls.compile(hdl, files, op) 100 | return cls.cosim(op, **portmap) 101 | 102 | 103 | class icarus(CoSimulator): 104 | 105 | @compile('verilog') 106 | def iverilog(ip, op): 107 | cli_args = '-o', op+'.o', ip 108 | return cli_args 109 | 110 | @cosim 111 | def vvp(vpi, op): 112 | cli_args = '-m', vpi, op+'.o' 113 | return cli_args 114 | 115 | 116 | class modelsim(CoSimulator): 117 | 118 | @compile('vhdl') 119 | def vcom(ip, op): 120 | raise NotImplementedError 121 | 122 | @compile('verilog') 123 | def vlog(ip, op): 124 | subprocess.call(['vlib', 'work_'+op]) 125 | cli_args = '-work', 'work_'+op, ip 126 | return cli_args 127 | 128 | @cosim 129 | def vsim(vpi, op): 130 | top = 'work_{0}.tb_{0}'.format(op) 131 | do = '-do', VPI.dir + '/cosim.do' 132 | cli_args = '-c', '-quiet', '-pli', vpi, top, do 133 | return cli_args 134 | -------------------------------------------------------------------------------- /uhdl/hw.py: -------------------------------------------------------------------------------- 1 | import os 2 | import shutil 3 | 4 | from myhdl import toVerilog, toVHDL, traceSignals 5 | 6 | from uhdl.cosim import CoSimulator 7 | from uhdl.utils import cd 8 | from uhdl.structures import CaselessDict 9 | 10 | 11 | def merge_config(current, new): 12 | if not new: 13 | return current 14 | 15 | merged = CaselessDict(current) 16 | merged.update(new) 17 | 18 | return merged 19 | 20 | 21 | class toMyHDL(object): 22 | """Used to provide a uniform API for simulating with myhdl rather than 23 | a backend. 24 | """ 25 | def __init__(self, top, *args, **kwargs): 26 | self.top = top 27 | self.args = args 28 | self.kwargs = kwargs 29 | 30 | def __call__(self): 31 | if self.trace: 32 | #traceSignals.timescale = toMyHDL.timescale 33 | traceSignals.name = self.name 34 | gen = traceSignals(self.top, *self.args, **self.kwargs) 35 | else: 36 | gen = self.top(*self.args, **self.kwargs) 37 | 38 | return gen 39 | 40 | 41 | _convspec = CaselessDict({ 42 | #hdl: converter, extension 43 | 'myhdl': (toMyHDL, None), 44 | 'verilog': (toVerilog, 'v'), 45 | 'vhdl': (toVHDL, 'vhd'), 46 | }) 47 | 48 | 49 | def get_convspec(conf): 50 | hdl = conf.pop('hdl') 51 | name = conf['name'] 52 | converter, ext = _convspec[hdl] 53 | for k, v in conf.items(): 54 | setattr(converter, k, v) 55 | 56 | files = [] 57 | if ext: 58 | files.append(name) 59 | if not conf['no_testbench']: 60 | files.append('tb_'+name) 61 | 62 | files = [f+'.'+ext for f in files] 63 | 64 | return converter, files 65 | 66 | 67 | class HW(object): 68 | """A Hardware module. 69 | 70 | Provides a uniform API for conversion and simulation of MyHDL Instances. 71 | 72 | Attributes: 73 | config(dict): Dictionary(:class:`~.CaselessDict`) containing 74 | the default config. 75 | 76 | Modifying this attribute will change the default argument values 77 | of the :meth:`.convert` and :meth:`sim()` methods. 78 | """ 79 | 80 | config = { 81 | 'name': None, 82 | 'path': '.', 83 | 'hdl': 'myhdl', 84 | 'backend': 'myhdl', 85 | 'timescale': '1ns/1ps', 86 | 'tb': True, 87 | 'trace': True, 88 | } 89 | 90 | def __init__(self, top, *args, **kwargs): 91 | """ 92 | Args: 93 | top (function): A function which returns MyHDL generators. 94 | *args: Arguments for top. 95 | **kwargs: Keyword arguments for top. 96 | """ 97 | self.top = top 98 | self.args = args 99 | self.kwargs = kwargs 100 | self.config = CaselessDict(self.__class__.config) 101 | self.config['name'] = top.__name__ 102 | 103 | def convert(self, **kwargs): 104 | """Converts the top function to another HDL 105 | 106 | Note: 107 | VHDL conversion has not been implemented yet. 108 | 109 | Args: 110 | hdl(str, optional): The target language. Defaults to 'verilog'. 111 | 112 | path(str, optional): Destination folder. Defaults to current dir. 113 | 114 | name(str, optional): Top level instance name, and output file name. 115 | Defaults to `self.top.__name__` 116 | 117 | tb(bool, optional): Specifies whether a test bench should be 118 | created. Defaults to True. 119 | 120 | trace(bool, optional): Whether the testbench should dump all 121 | signal waveforms. Defaults to True. 122 | 123 | timescale(str, optional): Defaults to '1ns/1ps' 124 | """ 125 | 126 | if 'hdl' not in kwargs: 127 | kwargs['hdl'] = 'verilog' 128 | 129 | conf = merge_config(self.config, kwargs) 130 | self._convert(conf) 131 | 132 | def _convert(self, conf): 133 | if conf['hdl'] == 'vhdl': 134 | raise NotImplementedError('VHDL conversion not implemented yet.') 135 | 136 | converter_conf = { 137 | 'hdl': conf['hdl'], 138 | 'name': conf['name'], 139 | 'timescale': conf['timescale'], 140 | 'no_testbench': not(conf['tb'] or conf['trace']), 141 | 'trace': conf['trace'] 142 | } 143 | 144 | converter, files = get_convspec(converter_conf) 145 | gen = converter(self.top, *self.args, **self.kwargs) 146 | 147 | dest_path = conf['path'] 148 | if dest_path != '.': 149 | for f in files: 150 | shutil.copy(f, dest_path) 151 | os.remove(f) 152 | 153 | return gen, converter, files 154 | 155 | def sim(self, **kwargs): 156 | """Simulate the top function. 157 | 158 | Args: 159 | backend(str, optional): Simulation runner. 160 | Available options are 'myhdl', 'icarus' and 'modelsim'. 161 | Defaults to 'myhdl'. 162 | 163 | hdl(str): Target HDL for conversion before simulation. 164 | **kwargs: Optional arguments that :meth:`.convert` takes. 165 | 166 | Returns: 167 | Generator sequence if the backend is myhdl, 168 | 169 | :class:`myhdl.Cosimulation` object if the backend is a simulator. 170 | """ 171 | #sane defaults for sim 172 | backend_name = kwargs.get('backend', 'myhdl') 173 | if backend_name and backend_name != 'myhdl': 174 | backend = CoSimulator.registry[kwargs['backend']] 175 | if 'hdl' not in kwargs: 176 | if len(backend.compilers) > 1: 177 | raise ValueError('Must specify hdl for backend', backend) 178 | kwargs['hdl'] = list(backend.compilers)[0] 179 | 180 | conf = merge_config(self.config, kwargs) 181 | 182 | gen, converter, files = self._convert(conf) 183 | with cd(conf['path']): 184 | if conf['backend'] == 'myhdl': 185 | r = gen() 186 | else: 187 | backend = CoSimulator.registry[conf['backend']] 188 | r = backend.cosim_gen(conf['hdl'], files, converter.portmap) 189 | 190 | return r 191 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | if "%SPHINXBUILD%" == "" ( 6 | set SPHINXBUILD=sphinx-build 7 | ) 8 | set BUILDDIR=_build 9 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . 10 | set I18NSPHINXOPTS=%SPHINXOPTS% . 11 | if NOT "%PAPER%" == "" ( 12 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 13 | set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% 14 | ) 15 | 16 | if "%1" == "" goto help 17 | 18 | if "%1" == "help" ( 19 | :help 20 | echo.Please use `make ^` where ^ is one of 21 | echo. html to make standalone HTML files 22 | echo. dirhtml to make HTML files named index.html in directories 23 | echo. singlehtml to make a single large HTML file 24 | echo. pickle to make pickle files 25 | echo. json to make JSON files 26 | echo. htmlhelp to make HTML files and a HTML help project 27 | echo. qthelp to make HTML files and a qthelp project 28 | echo. devhelp to make HTML files and a Devhelp project 29 | echo. epub to make an epub 30 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 31 | echo. text to make text files 32 | echo. man to make manual pages 33 | echo. texinfo to make Texinfo files 34 | echo. gettext to make PO message catalogs 35 | echo. changes to make an overview over all changed/added/deprecated items 36 | echo. xml to make Docutils-native XML files 37 | echo. pseudoxml to make pseudoxml-XML files for display purposes 38 | echo. linkcheck to check all external links for integrity 39 | echo. doctest to run all doctests embedded in the documentation if enabled 40 | goto end 41 | ) 42 | 43 | if "%1" == "clean" ( 44 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 45 | del /q /s %BUILDDIR%\* 46 | goto end 47 | ) 48 | 49 | 50 | %SPHINXBUILD% 2> nul 51 | if errorlevel 9009 ( 52 | echo. 53 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 54 | echo.installed, then set the SPHINXBUILD environment variable to point 55 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 56 | echo.may add the Sphinx directory to PATH. 57 | echo. 58 | echo.If you don't have Sphinx installed, grab it from 59 | echo.http://sphinx-doc.org/ 60 | exit /b 1 61 | ) 62 | 63 | if "%1" == "html" ( 64 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 65 | if errorlevel 1 exit /b 1 66 | echo. 67 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 68 | goto end 69 | ) 70 | 71 | if "%1" == "dirhtml" ( 72 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 73 | if errorlevel 1 exit /b 1 74 | echo. 75 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 76 | goto end 77 | ) 78 | 79 | if "%1" == "singlehtml" ( 80 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml 81 | if errorlevel 1 exit /b 1 82 | echo. 83 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. 84 | goto end 85 | ) 86 | 87 | if "%1" == "pickle" ( 88 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 89 | if errorlevel 1 exit /b 1 90 | echo. 91 | echo.Build finished; now you can process the pickle files. 92 | goto end 93 | ) 94 | 95 | if "%1" == "json" ( 96 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 97 | if errorlevel 1 exit /b 1 98 | echo. 99 | echo.Build finished; now you can process the JSON files. 100 | goto end 101 | ) 102 | 103 | if "%1" == "htmlhelp" ( 104 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 105 | if errorlevel 1 exit /b 1 106 | echo. 107 | echo.Build finished; now you can run HTML Help Workshop with the ^ 108 | .hhp project file in %BUILDDIR%/htmlhelp. 109 | goto end 110 | ) 111 | 112 | if "%1" == "qthelp" ( 113 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 114 | if errorlevel 1 exit /b 1 115 | echo. 116 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 117 | .qhcp project file in %BUILDDIR%/qthelp, like this: 118 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\complexity.qhcp 119 | echo.To view the help file: 120 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\complexity.ghc 121 | goto end 122 | ) 123 | 124 | if "%1" == "devhelp" ( 125 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp 126 | if errorlevel 1 exit /b 1 127 | echo. 128 | echo.Build finished. 129 | goto end 130 | ) 131 | 132 | if "%1" == "epub" ( 133 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub 134 | if errorlevel 1 exit /b 1 135 | echo. 136 | echo.Build finished. The epub file is in %BUILDDIR%/epub. 137 | goto end 138 | ) 139 | 140 | if "%1" == "latex" ( 141 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 142 | if errorlevel 1 exit /b 1 143 | echo. 144 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 145 | goto end 146 | ) 147 | 148 | if "%1" == "latexpdf" ( 149 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 150 | cd %BUILDDIR%/latex 151 | make all-pdf 152 | cd %BUILDDIR%/.. 153 | echo. 154 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 155 | goto end 156 | ) 157 | 158 | if "%1" == "latexpdfja" ( 159 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 160 | cd %BUILDDIR%/latex 161 | make all-pdf-ja 162 | cd %BUILDDIR%/.. 163 | echo. 164 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 165 | goto end 166 | ) 167 | 168 | if "%1" == "text" ( 169 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text 170 | if errorlevel 1 exit /b 1 171 | echo. 172 | echo.Build finished. The text files are in %BUILDDIR%/text. 173 | goto end 174 | ) 175 | 176 | if "%1" == "man" ( 177 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man 178 | if errorlevel 1 exit /b 1 179 | echo. 180 | echo.Build finished. The manual pages are in %BUILDDIR%/man. 181 | goto end 182 | ) 183 | 184 | if "%1" == "texinfo" ( 185 | %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo 186 | if errorlevel 1 exit /b 1 187 | echo. 188 | echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. 189 | goto end 190 | ) 191 | 192 | if "%1" == "gettext" ( 193 | %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale 194 | if errorlevel 1 exit /b 1 195 | echo. 196 | echo.Build finished. The message catalogs are in %BUILDDIR%/locale. 197 | goto end 198 | ) 199 | 200 | if "%1" == "changes" ( 201 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 202 | if errorlevel 1 exit /b 1 203 | echo. 204 | echo.The overview file is in %BUILDDIR%/changes. 205 | goto end 206 | ) 207 | 208 | if "%1" == "linkcheck" ( 209 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 210 | if errorlevel 1 exit /b 1 211 | echo. 212 | echo.Link check complete; look for any errors in the above output ^ 213 | or in %BUILDDIR%/linkcheck/output.txt. 214 | goto end 215 | ) 216 | 217 | if "%1" == "doctest" ( 218 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 219 | if errorlevel 1 exit /b 1 220 | echo. 221 | echo.Testing of doctests in the sources finished, look at the ^ 222 | results in %BUILDDIR%/doctest/output.txt. 223 | goto end 224 | ) 225 | 226 | if "%1" == "xml" ( 227 | %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml 228 | if errorlevel 1 exit /b 1 229 | echo. 230 | echo.Build finished. The XML files are in %BUILDDIR%/xml. 231 | goto end 232 | ) 233 | 234 | if "%1" == "pseudoxml" ( 235 | %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml 236 | if errorlevel 1 exit /b 1 237 | echo. 238 | echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. 239 | goto end 240 | ) 241 | 242 | :end -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # User-friendly check for sphinx-build 11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) 12 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) 13 | endif 14 | 15 | # Internal variables. 16 | PAPEROPT_a4 = -D latex_paper_size=a4 17 | PAPEROPT_letter = -D latex_paper_size=letter 18 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 19 | # the i18n builder cannot share the environment and doctrees with the others 20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 21 | 22 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext 23 | 24 | help: 25 | @echo "Please use \`make ' where is one of" 26 | @echo " html to make standalone HTML files" 27 | @echo " dirhtml to make HTML files named index.html in directories" 28 | @echo " singlehtml to make a single large HTML file" 29 | @echo " pickle to make pickle files" 30 | @echo " json to make JSON files" 31 | @echo " htmlhelp to make HTML files and a HTML help project" 32 | @echo " qthelp to make HTML files and a qthelp project" 33 | @echo " devhelp to make HTML files and a Devhelp project" 34 | @echo " epub to make an epub" 35 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 36 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 37 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 38 | @echo " text to make text files" 39 | @echo " man to make manual pages" 40 | @echo " texinfo to make Texinfo files" 41 | @echo " info to make Texinfo files and run them through makeinfo" 42 | @echo " gettext to make PO message catalogs" 43 | @echo " changes to make an overview of all changed/added/deprecated items" 44 | @echo " xml to make Docutils-native XML files" 45 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" 46 | @echo " linkcheck to check all external links for integrity" 47 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 48 | 49 | clean: 50 | rm -rf $(BUILDDIR)/* 51 | 52 | html: 53 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 54 | @echo 55 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 56 | 57 | dirhtml: 58 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 59 | @echo 60 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 61 | 62 | singlehtml: 63 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 64 | @echo 65 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 66 | 67 | pickle: 68 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 69 | @echo 70 | @echo "Build finished; now you can process the pickle files." 71 | 72 | json: 73 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 74 | @echo 75 | @echo "Build finished; now you can process the JSON files." 76 | 77 | htmlhelp: 78 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 79 | @echo 80 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 81 | ".hhp project file in $(BUILDDIR)/htmlhelp." 82 | 83 | qthelp: 84 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 85 | @echo 86 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 87 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 88 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/complexity.qhcp" 89 | @echo "To view the help file:" 90 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/complexity.qhc" 91 | 92 | devhelp: 93 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 94 | @echo 95 | @echo "Build finished." 96 | @echo "To view the help file:" 97 | @echo "# mkdir -p $$HOME/.local/share/devhelp/complexity" 98 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/complexity" 99 | @echo "# devhelp" 100 | 101 | epub: 102 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 103 | @echo 104 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 105 | 106 | latex: 107 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 108 | @echo 109 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 110 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 111 | "(use \`make latexpdf' here to do that automatically)." 112 | 113 | latexpdf: 114 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 115 | @echo "Running LaTeX files through pdflatex..." 116 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 117 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 118 | 119 | latexpdfja: 120 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 121 | @echo "Running LaTeX files through platex and dvipdfmx..." 122 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 123 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 124 | 125 | text: 126 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 127 | @echo 128 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 129 | 130 | man: 131 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 132 | @echo 133 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 134 | 135 | texinfo: 136 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 137 | @echo 138 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 139 | @echo "Run \`make' in that directory to run these through makeinfo" \ 140 | "(use \`make info' here to do that automatically)." 141 | 142 | info: 143 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 144 | @echo "Running Texinfo files through makeinfo..." 145 | make -C $(BUILDDIR)/texinfo info 146 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 147 | 148 | gettext: 149 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 150 | @echo 151 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 152 | 153 | changes: 154 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 155 | @echo 156 | @echo "The overview file is in $(BUILDDIR)/changes." 157 | 158 | linkcheck: 159 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 160 | @echo 161 | @echo "Link check complete; look for any errors in the above output " \ 162 | "or in $(BUILDDIR)/linkcheck/output.txt." 163 | 164 | doctest: 165 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 166 | @echo "Testing of doctests in the sources finished, look at the " \ 167 | "results in $(BUILDDIR)/doctest/output.txt." 168 | 169 | xml: 170 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 171 | @echo 172 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 173 | 174 | pseudoxml: 175 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 176 | @echo 177 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." 178 | 179 | livehtml: 180 | sphinx-autobuild -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 181 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # complexity documentation build configuration file, created by 5 | # sphinx-quickstart on Tue Jul 9 22:26:36 2013. 6 | # 7 | # This file is execfile()d with the current directory set to its containing dir. 8 | # 9 | # Note that not all possible configuration values are present in this 10 | # autogenerated file. 11 | # 12 | # All configuration values have a default; values that are commented out 13 | # serve to show the default. 14 | 15 | import importlib 16 | import inspect 17 | import sys, os 18 | 19 | # If extensions (or modules to document with autodoc) are in another directory, 20 | # add these directories to sys.path here. If the directory is relative to the 21 | # documentation root, use os.path.abspath to make it absolute, like shown here. 22 | #sys.path.insert(0, os.path.abspath('.')) 23 | 24 | # Get the project root dir, which is the parent dir of this 25 | cwd = os.getcwd() 26 | project_root = os.path.dirname(cwd) 27 | 28 | # Insert the project root dir as the first element in the PYTHONPATH. 29 | # This lets us ensure that the source package is imported, and that its 30 | # version is used. 31 | sys.path.insert(0, project_root) 32 | 33 | import uhdl 34 | 35 | # -- General configuration ----------------------------------------------------- 36 | 37 | # If your documentation needs a minimal Sphinx version, state it here. 38 | #needs_sphinx = '1.0' 39 | 40 | # Add any Sphinx extension module names here, as strings. They can be extensions 41 | # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. 42 | extensions = ['sphinx.ext.autodoc', 'sphinx.ext.linkcode', 43 | 'sphinx.ext.intersphinx', 'sphinx.ext.napoleon'] 44 | 45 | intersphinx_mapping = { 46 | 'myhdl': ('http://docs.myhdl.org/en/latest', None), 47 | } 48 | 49 | 50 | # Add any paths that contain templates here, relative to this directory. 51 | templates_path = ['_templates'] 52 | 53 | # The suffix of source filenames. 54 | source_suffix = '.rst' 55 | 56 | # The encoding of source files. 57 | #source_encoding = 'utf-8-sig' 58 | 59 | # The master toctree document. 60 | master_doc = 'index' 61 | 62 | # General information about the project. 63 | project = u'UHDL' 64 | copyright = u'2013, Keerthan Jaic' 65 | 66 | # The version info for the project you're documenting, acts as replacement for 67 | # |version| and |release|, also used in various other places throughout the 68 | # built documents. 69 | # 70 | # The short X.Y version. 71 | version = uhdl.__version__ 72 | # The full version, including alpha/beta/rc tags. 73 | release = uhdl.__version__ 74 | 75 | # The language for content autogenerated by Sphinx. Refer to documentation 76 | # for a list of supported languages. 77 | #language = None 78 | 79 | # There are two options for replacing |today|: either, you set today to some 80 | # non-false value, then it is used: 81 | #today = '' 82 | # Else, today_fmt is used as the format for a strftime call. 83 | #today_fmt = '%B %d, %Y' 84 | 85 | # List of patterns, relative to source directory, that match files and 86 | # directories to ignore when looking for source files. 87 | exclude_patterns = ['_build'] 88 | 89 | # The reST default role (used for this markup: `text`) to use for all documents. 90 | default_role = None 91 | #default_role = 'py:obj' 92 | 93 | # If true, '()' will be appended to :func: etc. cross-reference text. 94 | #add_function_parentheses = True 95 | 96 | # If true, the current module name will be prepended to all description 97 | # unit titles (such as .. function::). 98 | #add_module_names = True 99 | 100 | # If true, sectionauthor and moduleauthor directives will be shown in the 101 | # output. They are ignored by default. 102 | #show_authors = False 103 | 104 | # The name of the Pygments (syntax highlighting) style to use. 105 | pygments_style = 'sphinx' 106 | 107 | # A list of ignored prefixes for module index sorting. 108 | #modindex_common_prefix = [] 109 | 110 | # If true, keep warnings as "system message" paragraphs in the built documents. 111 | #keep_warnings = False 112 | 113 | 114 | # -- Options for HTML output --------------------------------------------------- 115 | 116 | # The theme to use for HTML and HTML Help pages. See the documentation for 117 | # a list of builtin themes. 118 | html_theme = 'default' 119 | on_rtd = os.environ.get('READTHEDOCS', None) == 'True' 120 | 121 | if not on_rtd: # only import and set the theme if we're building docs locally 122 | import sphinx_rtd_theme 123 | html_theme = 'sphinx_rtd_theme' 124 | html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] 125 | 126 | # Theme options are theme-specific and customize the look and feel of a theme 127 | # further. For a list of options available for each theme, see the 128 | # documentation. 129 | #html_theme_options = {} 130 | 131 | # Add any paths that contain custom themes here, relative to this directory. 132 | #html_theme_path = [] 133 | 134 | # The name for this set of Sphinx documents. If None, it defaults to 135 | # " v documentation". 136 | #html_title = None 137 | 138 | # A shorter title for the navigation bar. Default is the same as html_title. 139 | #html_short_title = None 140 | 141 | # The name of an image file (relative to this directory) to place at the top 142 | # of the sidebar. 143 | #html_logo = None 144 | 145 | # The name of an image file (within the static path) to use as favicon of the 146 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 147 | # pixels large. 148 | #html_favicon = None 149 | 150 | # Add any paths that contain custom static files (such as style sheets) here, 151 | # relative to this directory. They are copied after the builtin static files, 152 | # so a file named "default.css" will overwrite the builtin "default.css". 153 | html_static_path = ['_static'] 154 | 155 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 156 | # using the given strftime format. 157 | #html_last_updated_fmt = '%b %d, %Y' 158 | 159 | # If true, SmartyPants will be used to convert quotes and dashes to 160 | # typographically correct entities. 161 | #html_use_smartypants = True 162 | 163 | # Custom sidebar templates, maps document names to template names. 164 | #html_sidebars = {} 165 | 166 | # Additional templates that should be rendered to pages, maps page names to 167 | # template names. 168 | #html_additional_pages = {} 169 | 170 | # If false, no module index is generated. 171 | #html_domain_indices = True 172 | 173 | # If false, no index is generated. 174 | #html_use_index = True 175 | 176 | # If true, the index is split into individual pages for each letter. 177 | #html_split_index = False 178 | 179 | # If true, links to the reST sources are added to the pages. 180 | #html_show_sourcelink = True 181 | 182 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 183 | #html_show_sphinx = True 184 | 185 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 186 | #html_show_copyright = True 187 | 188 | # If true, an OpenSearch description file will be output, and all pages will 189 | # contain a tag referring to it. The value of this option must be the 190 | # base URL from which the finished HTML is served. 191 | #html_use_opensearch = '' 192 | 193 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 194 | #html_file_suffix = None 195 | 196 | # Output file base name for HTML help builder. 197 | htmlhelp_basename = 'uhdldoc' 198 | 199 | 200 | # -- Options for LaTeX output -------------------------------------------------- 201 | 202 | latex_elements = { 203 | # The paper size ('letterpaper' or 'a4paper'). 204 | #'papersize': 'letterpaper', 205 | 206 | # The font size ('10pt', '11pt' or '12pt'). 207 | #'pointsize': '10pt', 208 | 209 | # Additional stuff for the LaTeX preamble. 210 | #'preamble': '', 211 | } 212 | 213 | # Grouping the document tree into LaTeX files. List of tuples 214 | # (source start file, target name, title, author, documentclass [howto/manual]). 215 | latex_documents = [ 216 | ('index', 'uhdl.tex', u'UHDL Documentation', 217 | u'Keerthan Jaic', 'manual'), 218 | ] 219 | 220 | # The name of an image file (relative to this directory) to place at the top of 221 | # the title page. 222 | #latex_logo = None 223 | 224 | # For "manual" documents, if this is true, then toplevel headings are parts, 225 | # not chapters. 226 | #latex_use_parts = False 227 | 228 | # If true, show page references after internal links. 229 | #latex_show_pagerefs = False 230 | 231 | # If true, show URL addresses after external links. 232 | #latex_show_urls = False 233 | 234 | # Documents to append as an appendix to all manuals. 235 | #latex_appendices = [] 236 | 237 | # If false, no module index is generated. 238 | #latex_domain_indices = True 239 | 240 | 241 | # -- Options for manual page output -------------------------------------------- 242 | 243 | # One entry per manual page. List of tuples 244 | # (source start file, name, description, authors, manual section). 245 | man_pages = [ 246 | ('index', 'uhdl', u'UHDL Documentation', 247 | [u'Keerthan Jaic'], 1) 248 | ] 249 | 250 | # If true, show URL addresses after external links. 251 | #man_show_urls = False 252 | 253 | 254 | # -- Options for Texinfo output ------------------------------------------------ 255 | 256 | # Grouping the document tree into Texinfo files. List of tuples 257 | # (source start file, target name, title, author, 258 | # dir menu entry, description, category) 259 | texinfo_documents = [ 260 | ('index', 'uhdl', u'UHDL Documentation', 261 | u'Keerthan Jaic', 'uhdl', 'One line description of project.', 262 | 'Miscellaneous'), 263 | ] 264 | 265 | # Documents to append as an appendix to all manuals. 266 | #texinfo_appendices = [] 267 | 268 | # If false, no module index is generated. 269 | #texinfo_domain_indices = True 270 | 271 | # How to display URL addresses: 'footnote', 'no', or 'inline'. 272 | #texinfo_show_urls = 'footnote' 273 | 274 | # If true, do not generate a @detailmenu in the "Top" node's menu. 275 | #texinfo_no_detailmenu = False 276 | 277 | gh_repo = 'jck/uhdl' 278 | 279 | def linkcode_resolve(domain, info): 280 | """ Link source code to github. """ 281 | if domain != 'py' or not info['module']: 282 | return None 283 | 284 | rel = release 285 | if rel.split('.')[-1].startswith('dev'): 286 | rel = 'master' 287 | 288 | mod = importlib.import_module(info['module']) 289 | item = mod 290 | for piece in info['fullname'].split('.'): 291 | item = getattr(item, piece) 292 | 293 | # filename = os.path.splitext(mod.__file___)[0] 294 | try: 295 | filename = os.path.relpath(inspect.getsourcefile(item), project_root) 296 | lineno = '#L%d' % inspect.getsourcelines(item)[1] 297 | except: 298 | return None 299 | 300 | return ("https://github.com/%s/blob/%s/%s%s" % 301 | (gh_repo, rel, filename, lineno)) 302 | --------------------------------------------------------------------------------