Skip to content
Permalink
Browse files

Successfully added to pip!

  • Loading branch information...
Verkhovskaya committed Feb 11, 2018
1 parent aa2fac0 commit bf5200e4488017466f730f2bb0c47b22d1872d0f
@@ -0,0 +1,5 @@
# Include the license file
include LICENSE.txt

# Include the data files
recursive-include pywire *
110 README.md
@@ -1,107 +1,31 @@
# Pywire
pywire is an easy-to-use Python library for generating VHDL, designed for use with FPGAs.

An easy-to-use Python 2.7 library for generating VHDL.

### Supports all main FPGA components, including:
- Look-up tables
- Logic slices
Features:
- Simple and complex functions
- BRAM
- Import components
- Generate timing files

### Other features include:
- Generating .ucf files

(Support for import VHDL components coming soon)

### Does not support:
- Using more than one clock

### Sections in this documentation:
[Blink example](https://github.com/Verkhovskaya/Pywire/new/master?readme=1#blink-example) (Look-up tables, logic slices and generating .vhdl and .ucf files)

[BRAM](https://github.com/Verkhovskaya/Pywire/new/master?readme=1#bram)

# Blink example
Pywire is based on a `Signal` class, which contains an integer value between 0 and 2**(size)-1. It is initialized as

```python
Signal(bit_size, io=None, port=None, name=None)
```
Does not support:
- More than one clock

During each clock cycle (~50 million/second), each Signal is set to the result of function. This function is assigned to the signal with
To install:
```python
my_signal.drive(my_func, args=(arg1, arg2, ...))
pip install pywire
```

For example:
Example:
```python
from pywire import *
counter = Signal(26)
def increment(x):
return x+1
counter.drive(increment, args=(counter))
led1 = Signal(1, io="out", port="P134")
def blink(slow_clock):
if slow_clock > 2**25:
return 1
else:
return 0
led1.drive(blink, args=(counter))
print(generate_vhdl(globals()))
```

If you are testing on Xilinx hardware, you will also need to create a .ucf file that tells the FPGA how to connect the outputs to the pins.
My hardware uses an external clock on pin 56 that runs at 50MHz/second, so I use

```python
print(generate_ucf(globals(), 50, 'P56'))
```

Built with ISE and loaded onto a MojoV3, this creates a blinking light: [YouTube link](https://www.youtube.com/watch?v=y5rW_DIoK7Y&feature=youtu.be)

# BRAM
BRAM is initialized with
```python
mem = BRAM(width, depth, a_write=True, a_read=True, b_write=False, b_read=False)`.
x = Signal(1, io=“out”, port=“P7”)
y = Signal(1, io=in”, port=“P42”)
# Pins:
mem.a_address
mem.a_write_en # Only implemented if a_write == True
mem.a_data_in # Only implemented if a_write == True
mem.a_data_out # Only implemented if a_read == True
mem.b_address # Only implemented if b_write == True or b_read == True
mem.b_write_en # Only implemented if b_write == True
mem.b_data_in # Only implemented if b_write == True
mem.b_data_out # Only implemented if b_read == True
def inverter(x):
return 1-x
# Properties:
mem.width
mem.depth
mem.props # {"a_write":a_write, "a_read":a_read, "b_write":b_write, "b_read":b_read}
mem.id
x.drive(inverter, y)
print(vhdl(globals()))
```

So for example, a single port 8x2 BRAM:

```python
from pywire import *
mem = BRAM(8, 2, True, True)
bram_address = Signal(1, io="in", port="P51")
bram_write_data = Signal(8, io="in", port=["P35", "P33", "P30", "P27", "P24", "P22", "P17", "P15"])
bram_write_en = Signal(1, io="in", port="P41")
bram_read = Signal(8, io="out", port=["P134", "P133", "P132", "P131", "P127", "P126", "P124", "P123"])
mem.a_address.drive(bram_address)
mem.a_data_in.drive(bram_write_data)
mem.a_write_en.drive(bram_write_en)
bram_read.drive(mem.a_data_out)
print(generate_vhdl(globals()))
print(generate_ucf(globals(), 50, 'P56'))
```
The full documentation can be found at http://pywire.readthedocs.io/en/latest/
@@ -0,0 +1,7 @@
from recommonmark.parser import CommonMarkParser

source_parsers = {
'.md': CommonMarkParser,
}

source_suffix = ['.rst', '.md']
Binary file not shown.
No changes.
@@ -0,0 +1,41 @@
# BRAM
BRAM is initialized with
```python
mem = BRAM(width, depth, a_write=True, a_read=True, b_write=False, b_read=False)`.
# Pins:
mem.a_address
mem.a_write_en # Only implemented if a_write == True
mem.a_data_in # Only implemented if a_write == True
mem.a_data_out # Only implemented if a_read == True
mem.b_address # Only implemented if b_write == True or b_read == True
mem.b_write_en # Only implemented if b_write == True
mem.b_data_in # Only implemented if b_write == True
mem.b_data_out # Only implemented if b_read == True
# Properties:
mem.width
mem.depth
mem.props # {"a_write":a_write, "a_read":a_read, "b_write":b_write, "b_read":b_read}
mem.id
```

So for example, a single port 8x2 BRAM:

```python
from pywire import *
mem = BRAM(8, 2, True, True)
bram_address = Signal(1, io="in", port="P51")
bram_write_data = Signal(8, io="in", port=["P35", "P33", "P30", "P27", "P24", "P22", "P17", "P15"])
bram_write_en = Signal(1, io="in", port="P41")
bram_read = Signal(8, io="out", port=["P134", "P133", "P132", "P131", "P127", "P126", "P124", "P123"])
mem.a_address.drive(bram_address)
mem.a_data_in.drive(bram_write_data)
mem.a_write_en.drive(bram_write_en)
bram_read.drive(mem.a_data_out)
print(generate_vhdl(globals()))
print(generate_ucf(globals(), 50, 'P56'))
```
No changes.
No changes.
@@ -21,5 +21,5 @@ def blink(slow_clock):

led1.drive(blink, args=(counter))

print(generate_vhdl(globals(), name="blink_example"))
print(generate_ucf(globals(), 50, 'P56'))
print(vhdl(globals(), name="blink_example"))
print(timing(globals(), 50, 'P56', vendor="Xilinx"))
@@ -13,5 +13,5 @@ def logic(counter, led):

build(logic, (counter, led1))

print(generate_vhdl(globals(), name="blink_example"))
print(generate_ucf(globals(), 50, 'P56'))
print(vhdl(globals(), name="blink_example"))
print(timing(globals(), 50, 'P56', vendor="Xilinx"))
@@ -11,5 +11,5 @@
mem.a_write_en.drive(bram_write_en)
bram_read.drive(mem.a_data_out)

print(generate_vhdl(globals(), name="bram_example"))
print(generate_ucf(globals(), 50, 'P56'))
print(vhdl(globals(), name="bram_example"))
print(timing(globals(), 50, 'P56', vendor="Xilinx"))
@@ -57,5 +57,5 @@ def latch(request_x, request_y, camera_x, camera_y, current_data, pixel_clock):

response.drive(latch, args=(request_x, request_y, camera_x, camera_y, new_data, pixel_clock))

print(generate_vhdl(globals(), name="camera_example"))
print(generate_ucf(globals(), 50, 'P56'))
print(vhdl(globals(), name="camera_example"))
print(timing(globals(), 50, 'P56', vendor="Xilinx"))
@@ -27,5 +27,5 @@
inverter = FromText(component_text)
inverter.link({"a": a_out, "b": b_out})

print(generate_vhdl(globals(), name="component_example"))
print(generate_ucf(globals(), 50, 'P56'))
print(vhdl(globals(), name="component_example"))
print(timing(globals(), 50, 'P56', vendor="Xilinx"))
@@ -0,0 +1,50 @@
Metadata-Version: 1.1
Name: pywire
Version: 1.0.0
Summary: A library for generating VHDL, designed for use in FPGAs
Home-page: https://github.com/Verkhovskaya/Pywire
Author: Anna Verkhovskaya
Author-email: verkhovskaya.anna@gmail.com
License: UNKNOWN
Description-Content-Type: UNKNOWN
Description: pywire is an easy-to-use Python library for generating VHDL, designed for use with FPGAs.

Features:
- Simple and complex functions
- BRAM
- Import components
- Generate timing files

Does not support:
- More than one clock

To install:
```python
pip install pywire
```

Example:
```python
from pywire import *

x = Signal(1, io=“out”, port=“P7”)
y = Signal(1, io=“in”, port=“P42”)

def inverter(x):
return 1-x

x.drive(inverter, y)
print(vhdl(globals()))
```

The full documentation can be found at http://pywire.readthedocs.io/en/latest/
Keywords: vhdl fpga
Platform: UNKNOWN
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Topic :: Software Development :: Build Tools
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.6
@@ -0,0 +1,24 @@
LICENSE.txt
MANIFEST.in
README.md
setup.cfg
setup.py
pywire/__init__.py
pywire/__init__.pyc
pywire/bram.py
pywire/bram.pyc
pywire/build.py
pywire/build.pyc
pywire/component.py
pywire/component.pyc
pywire/main.py
pywire/main.pyc
pywire.egg-info/PKG-INFO
pywire.egg-info/SOURCES.txt
pywire.egg-info/dependency_links.txt
pywire.egg-info/top_level.txt
pywire/__pycache__/__init__.cpython-36.pyc
pywire/__pycache__/bram.cpython-36.pyc
pywire/__pycache__/build.cpython-36.pyc
pywire/__pycache__/component.cpython-36.pyc
pywire/__pycache__/main.cpython-36.pyc
@@ -0,0 +1 @@

@@ -0,0 +1 @@
pywire
@@ -1,9 +1,4 @@
import sys

if sys.version_info[0] != 2:
raise Exception("Pywire only works with Python 2.7")

from .main import Signal, generate_vhdl, generate_ucf
from .main import Signal, vhdl, timing
from .bram import BRAM
from .component import Component, FromText
from .build import build
@@ -43,7 +43,7 @@ def __init__(self, text):
else:
signal_size = int(flat_text[x+3])-int(flat_text[x+5])+1
else:
raise Exception("Only std_logic and std_logic_vector are supported by Pywire as IO types")
raise Exception("Only std_logic and std_logic_vector are supported by pywire as IO types")
self.signals[signal_name] = {"size": signal_size, "io": signal_io}
header_text = " ".join(flat_text[flat_text.index("port")+2:flat_text.index("end")]).replace(" ; ", ";\n").replace("is ", "is\n").replace("( ", "(").replace(" )", ")").replace(" ;",";")
self.header_text = "component " + self.name + " is\n" + header_text + "\nend component;"
@@ -23,7 +23,7 @@ def replace_args_with_signals(original, replace_dict):

def as_vhdl_string(val, width=1):
if type(val) is str:
if len(filter(lambda x: x not in ["0", "1"], val)) == 0:
if len(list(filter(lambda x: x not in ["0", "1"], val))) == 0:
return '"' + val + '"'
if type(val) is int:
return '"' + bin(val)[2:].zfill(width) + '"'
@@ -264,12 +264,12 @@ def __indent(in_text):
return "\n".join(out_text)


def generate_vhdl(code_globals, name="generated_top"):
def vhdl(code_globals, name="generated_top"):
all_signals = copy.copy(Signal.all_signals)
for signal in all_signals:
if signal.name is None:
if signal in code_globals.values():
signal.name = filter(lambda x: id(code_globals[x]) == id(signal), code_globals.keys())[0]
signal.name = list(filter(lambda x: id(code_globals[x]) == id(signal), code_globals.keys()))[0]
else:
signal.name = "unnamed_" + str(len(filter(signal.name[:8] == "unnamed_", Signal.all_signals)))
if signal.io == "out":
@@ -287,7 +287,7 @@ def generate_vhdl(code_globals, name="generated_top"):
unseen = list(set([x.name for x in Signal.all_signals]) - set([x.name for x in signals_done]))
if not unseen:
break
signal = filter(lambda x: x.name == unseen[0], Signal.all_signals)[0]
signal = list(filter(lambda x: x.name == unseen[0], Signal.all_signals))[0]
signals_done.append(signal)
new_arch_text, new_body_text, sub_done = generate_signal_vhdl(signal)
arch_signal_text += new_arch_text
@@ -330,7 +330,7 @@ def generate_signal_vhdl(signal):
return arch_text, body_text, sub_generated


def generate_ucf(code_globals, frequency, clock_pin):
def timing(code_globals, frequency, clock_pin, vendor=""):
entity_signals = []
for each in code_globals:
if isinstance(code_globals[each], Signal):
@@ -339,7 +339,7 @@ def generate_ucf(code_globals, frequency, clock_pin):
entity_signals.append(signal)
signal.name = each
text = 'NET "clock" TNM_NET = clock;\n'
text += 'TIMESPEC TS_clk = PERIOD "clock" ' + str(frequency) + ' MHz HIGH 50%;\n'
text += 'TIMESPEC TS_clk = PERIOD "clock" ' + str(frequency/1000000.0) + ' MHz HIGH 50%;\n'
text += 'NET "clock" LOC = ' + clock_pin + ' | IOSTANDARD = LVTTL;\n'
for signal in entity_signals:
if signal.port:
@@ -1,2 +1,6 @@
[metadata]
description-file = README.md
[bdist_wheel]
# This flag says to generate wheels that support both Python 2 and Python
# 3. If your code will not run unchanged on both Python 2 and 3, you will
# need to generate separate wheels for each Python version that you
# support.
universal=1
Oops, something went wrong.

0 comments on commit bf5200e

Please sign in to comment.
You can’t perform that action at this time.