Skip to content

Commit

Permalink
Merge pull request #69 from dan-fritchman/dev
Browse files Browse the repository at this point in the history
* Revitalize & test examples/ (#66)
* Bug-fix - copying Signals failures when connected
* Move from Vlsir.Param.string to Vlsir.Param.literal when exporting
* Improve error messages for several Bundle-related failures
  • Loading branch information
dan-fritchman authored Nov 29, 2022
2 parents d569079 + c055009 commit 945aa6e
Show file tree
Hide file tree
Showing 20 changed files with 498 additions and 1,040 deletions.
2 changes: 1 addition & 1 deletion SampleSitePdks/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
# Get the long description from the README file
long_description = (here / "readme.md").read_text(encoding="utf-8")

_VLSIR_VERSION = "3.0.dev0"
_VLSIR_VERSION = "3.0.dev1"

setup(
name="sitepdks",
Expand Down
17 changes: 17 additions & 0 deletions examples/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
"""
# Examples "Package"
## `__init__.py`, the file that makes it a package (and does nothing else).
This `examples/` folder isn't really designed to be used as a package,
but we derive plenty of benefit from `pytest`ing it, and moreover
from its test module being able to make relative imports like
```python
from .ro import main # Only works in a package
```
Each `example` is *written* to be run as a script.
This shouldn't stop them from being run as such,
although it's always worth worrying about Python's demands for differences
between scripts and library modules, especially inasmuch as `import`s are concerned.
"""
170 changes: 170 additions & 0 deletions examples/encoder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
"""
# Logical Encoder Example
A demonstration of:
* Using `ExternalModule`s of externally-defined logic cells
* Creating a *recursive* `Module` generator, for a parameteric-width one-hot encoder
"""

import sys
import hdl21 as h

"""
## Generic Logic Cells
In a more fully featured use-case, these would map to a target library.
"""

Inv = h.ExternalModule(
name="Inv",
port_list=[
h.Input(name="i"),
h.Output(name="z"),
],
desc="Generic Inverter",
)
And2 = h.ExternalModule(
name="And2",
port_list=[
h.Input(name="a"),
h.Input(name="b"),
h.Output(name="z"),
],
desc="Generic 3-Input And Gate",
)
And3 = h.ExternalModule(
name="And3",
port_list=[
h.Input(name="a"),
h.Input(name="b"),
h.Input(name="c"),
h.Output(name="z"),
],
desc="Generic 3-Input And Gate",
)
TriInv = h.ExternalModule(
name="TriInv",
port_list=[
h.Input(name="i"),
h.Input(name="en"),
h.Output(name="z"),
],
desc="Generic Tri-State Inverter",
)
Flop = h.ExternalModule(
name="Flop",
port_list=[
h.Input(name="d"),
h.Input(name="clk"),
h.Output(name="q"),
],
desc="Generic Rising-Edge D Flip Flop",
)
FlopResetLow = h.ExternalModule(
name="FlopResetLow",
port_list=[
h.Input(name="d"),
h.Input(name="clk"),
h.Input(name="rstn"),
h.Output(name="q"),
],
desc="Rising-Edge D Flip Flop. Output low with reset asserted.",
)
FlopResetHigh = h.ExternalModule(
name="FlopResetHigh",
port_list=[
h.Input(name="d"),
h.Input(name="clk"),
h.Input(name="rstn"),
h.Output(name="q"),
],
desc="Rising-Edge D Flip Flop. Output high with reset asserted.",
)
Latch = h.ExternalModule(
name="Latch",
port_list=[
h.Input(name="d"),
h.Input(name="clk"),
h.Output(name="q"),
],
desc="Generic Active High Level-Sensitive Latch",
)


@h.paramclass
class Width:
"""Parameter class for Generators with a single integer-valued `width` parameter."""

width = h.Param(dtype=int, desc="Parametric Width", default=1)


@h.module
class OneHotEncoder2to4:
"""
# One-Hot Encoder
2b to 4b with enable.
Also serves as the base-case for the recursive `OneHotEncoder` generator.
All outputs are low if enable-input `en` is low.
"""

# IO Interface
en = h.Input(width=1, desc="Enable input. Active high.")
bin = h.Input(width=2, desc="Binary valued input")
th = h.Output(width=4, desc="Thermometer encoded output")

# Internal Contents
# Input inverters
binb = h.Signal(width=2, desc="Inverted binary input")
invs = 2 * Inv()(i=bin, z=binb)

# The primary logic: a set of four And3's
ands = 4 * And3()(
a=h.Concat(binb[0], bin[0], binb[0], bin[0]),
b=h.Concat(binb[1], binb[1], bin[1], bin[1]),
c=en,
z=th,
)


@h.generator
def OneHotEncoder(p: Width) -> h.Module:
"""
# One-Hot Encoder Generator
Recursively creates a `p.width`-bit one-hot encoder Module comprised of `OneHotEncoder2to4`s.
Also generates `OneHotEncoder` Modules for `p.width-2`, `p.width-4`, et al, down to
the base case two to four bit Module.
"""

if p.width < 2:
raise ValueError(f"OneHotEncoder {p} width must be > 1")
if p.width % 2:
raise ValueError(f"OneHotEncoder {p} width must be even")
if p.width == 2: # Base case: the 2 to 4b encoder
return OneHotEncoder2to4

# Recursive case.
m = h.Module()
m.en = h.Input(width=1, desc="Enable input. Active high.")
m.bin = h.Input(width=p.width, desc="Binary valued input")
m.th = h.Output(width=2**p.width, desc="Thermometer encoded output")

# Thermo-encode the two MSBs, creating select signals for the LSBs
m.lsb_sel = h.Signal(width=4)
m.msb_encoder = OneHotEncoder2to4(en=m.en, bin=m.bin[-2:], th=m.lsb_sel)

# Peel off two bits and recursively generate our child encoder Module
child = OneHotEncoder(width=p.width - 2)
# And create four instances of it, enabled by the thermo-decoded MSBs
m.children = 4 * child(en=m.lsb_sel, bin=m.bin[:-2], th=m.th)

return m


def main():
# "Main" Script Action
h.netlist(h.to_proto(OneHotEncoder(width=10)), dest=sys.stdout)
h.netlist(h.to_proto(OneHotEncoder(width=8)), dest=sys.stdout)


if __name__ == "__main__":
main()
Loading

0 comments on commit 945aa6e

Please sign in to comment.