1
0
mirror of https://github.com/myhdl/myhdl.git synced 2024-12-14 07:44:38 +08:00

Merge branch 'master' of https://github.com/jandecaluwe/myhdl into add_tests

This commit is contained in:
udara28 2018-02-22 11:21:09 -05:00
commit d726752437
463 changed files with 12143 additions and 28701 deletions

9
.gitignore vendored
View File

@ -2,17 +2,22 @@
*~
*.swp
*.out
*.coverage
build/
.cache
.style.yapf
# Python
*.py[cod]
__pycache__/
*egg-info/
dist/
.tox
# Cosim
*.o
*.vpi
*.so
# Simulator generated files
*.vcd
@ -20,6 +25,7 @@ modelsim.ini
transcript
*.log
work/
work_nvc/
work_vlog/
work_vcom/
*.wlf
@ -27,3 +33,6 @@ work_vcom/
# Test artifacts
myhdl/**/*.v
myhdl/**/*.vhd
# Pycharm ide junk
.idea/

View File

@ -1,35 +1,27 @@
# http://docs.travis-ci.com/user/workers/container-based-infrastructure/
sudo: false
sudo: required
dist: trusty
language: python
python:
- "2.6"
- "2.7"
- "pypy"
- "3.4"
addons:
apt:
sources:
- pgavin-ghdl
packages:
- iverilog
- ghdl
- "3.5"
- "3.6"
install:
- pip install .
env:
- CI_TARGET=core
- CI_TARGET=icarus
- CI_TARGET=iverilog
- CI_TARGET=ghdl
- CI_TARGET=bugs
matrix:
allow_failures:
- python: "3.4"
before_script:
- ./scripts/ci_deps.sh
script: ./ci.sh
script: ./scripts/ci.sh
notifications:
email: false

View File

@ -1,3 +1,10 @@
Release 0.9.0 11-Jul-2015
-------------------------
Full details about new features and changes can be found here:
http://docs.myhdl.org/en/latest/whatsnew/0.9.html
Release 0.8.1 26-Aug-2014
-------------------------

View File

@ -4,6 +4,12 @@ install:
localinstall:
python setup.py install --home=$(HOME)
docs:
tox -e docs html
livedocs:
tox -e docs livehtml
release:
- rm MANIFEST
- rm CHANGELOG.txt

View File

@ -1,8 +1,11 @@
MyHDL 0.9
=========
MyHDL 1.0dev
============
[![Documentation Status](https://readthedocs.org/projects/myhdl/badge/?version=master)](http://docs.myhdl.org/en/latest/manual)
[![Build Status](https://travis-ci.org/jandecaluwe/myhdl.svg?branch=master)](https://travis-ci.org/jandecaluwe/myhdl)
[![Join the chat at https://gitter.im/jandecaluwe/myhdl](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/myhdl/myhdl?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Documentation Status](https://readthedocs.org/projects/myhdl/badge/?version=stable)](http://docs.myhdl.org/en/stable/manual)
[![Documentation Status](https://readthedocs.org/projects/myhdl/badge/?version=latest)](http://docs.myhdl.org/en/latest/manual)
[![Build Status](https://travis-ci.org/myhdl/myhdl.svg?branch=master)](https://travis-ci.org/myhdl/myhdl)
What is MyHDL?
--------------
@ -11,11 +14,11 @@ description and verification language.
To find out whether MyHDL can be useful to you, please read:
[http://www.myhdl.org/start/why.html](http://www.myhdl.org/start/why.html)
- http://www.myhdl.org/start/why.html
License
-------
MyHDL is available under the LGPL license. See LICENSE.txt.
MyHDL is available under the LGPL license. See ``LICENSE.txt``.
Website
-------
@ -25,13 +28,13 @@ Documentation
-------------
The manual is available on-line:
http://docs.myhdl.org/en/latest/manual
- http://docs.myhdl.org/en/stable/manual
What's new
----------
To find out what's new in this release, please read:
[http://docs.myhdl.org/en/latest/whatsnew/0.8.html](http://docs.myhdl.org/en/latest/whatsnew/0.8.html)
- http://docs.myhdl.org/en/stable/whatsnew/0.9.html
Installation
------------
@ -52,7 +55,7 @@ python setup.py install --home=$HOME
```
In this case, be sure to add the appropriate install dir to the
$PYTHONPATH.
``$PYTHONPATH``.
If necessary, consult the distutils documentation in the standard
Python library if necessary for more details;
@ -62,11 +65,10 @@ You can test the proper installation as follows:
```
cd myhdl/test/core
python test_all.py
py.test
```
To install co-simulation support:
Go to the directory co-simulation/<platform> for your target platform
and following the instructions in the README.txt file.
Go to the directory ``cosimulation/<platform>`` for your target platform
and following the instructions in the ``README.txt`` file.

View File

@ -5,7 +5,7 @@ myhdl.vpi: myhdl.c myhdl_table.c
.PHONY: test
test: myhdl.vpi
make -C test
cd test && python test_all.py
clean:
-rm *.o *.vpi

View File

@ -1,2 +0,0 @@
all:
python test_all.py

View File

@ -6,7 +6,8 @@ cmd = "iverilog -o bin2gray.o -Dwidth=%s " + \
"../../test/verilog/bin2gray.v " + \
"../../test/verilog/dut_bin2gray.v "
def bin2gray(B, G, width):
def bin2gray(B, G):
width = len(B)
os.system(cmd % width)
return Cosimulation("vvp -m ../myhdl.vpi bin2gray.o", B=B, G=G)

View File

@ -23,11 +23,11 @@
import sys
sys.path.append("../../test")
sys.path.append("../../../example/manual")
import test_bin2gray, test_inc, test_dff
import test_gray_properties, test_gray_original, test_inc, test_dff
modules = (test_inc, )
modules = (test_bin2gray, test_inc, test_dff )
modules = (test_gray_properties, test_gray_original, test_inc, test_dff )
import unittest

View File

@ -17,20 +17,16 @@
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
""" Run all myhdl unit tests. """
from __future__ import absolute_import
""" Run cosimulation unit tests. """
import test_Simulation, test_Signal, test_intbv, test_Cosimulation, test_misc, \
test_always_comb, test_bin, test_traceSignals, test_enum, test_concat, \
test_inferWaiter, test_always, test_instance, test_signed, \
test_modbv
import sys
modules = (test_Simulation, test_Signal, test_intbv, test_misc, test_always_comb,
test_bin, test_traceSignals, test_enum, test_concat,
test_inferWaiter, test_always, test_instance, test_signed,
test_modbv
)
sys.path.append("../../../example/manual")
import test_gray_properties, test_gray_original
modules = (test_gray_properties, test_gray_original)
import unittest

View File

@ -0,0 +1,21 @@
INCS := C:\\modeltech64_10.4\\include
LIB_PATH := C:\\modeltech64_10.4\\win64
ifneq ($(filter cl%,$(CC)),)
CFLAGS := /LD /I$(INCS)
LIBFLAGS := $(LIB_PATH)\\mtipli.lib
else
CFLAGS := -static -g -I$(INCS) -o myhdl_vpi.dll
LIBFLAGS := -L$(LIB_PATH) -lmtipli
endif
all: myhdl_vpi.dll
myhdl_vpi.dll: myhdl_vpi.c
$(CC) $(CFLAGS) $< $(LIBFLAGS)
clean:
@del /q myhdl_vpi.dll || rm -rf myhdl_vpi.dll 2>&1> /dev/null ||:
@del /q myhdl_vpi.lib || rm -rf myhdl_vpi.lib 2>&1> /dev/null ||:
@del /q myhdl_vpi.exp || rm -rf myhdl_vpi.exp 2>&1> /dev/null ||:
@del /q myhdl_vpi.obj || rm -rf myhdl_vpi.obj 2>&1> /dev/null ||:

View File

@ -0,0 +1,532 @@
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <Windows.h>
#include "vpi_user.h"
#include "sv_vpi_user.h"
#define MAXLINE 4096
#define MAXWIDTH 10
#define MAXARGS 64
// #define DEBUG 1
/* Sized variables */
#ifndef PLI_TYPES
#define PLI_TYPES
typedef int PLI_INT32;
typedef unsigned int PLI_UINT32;
typedef short PLI_INT16;
typedef unsigned short PLI_UINT16;
typedef char PLI_BYTE8;
typedef unsigned char PLI_UBYTE8;
#endif
/* 64 bit type for time calculations */
typedef unsigned long long myhdl_time64_t;
static HANDLE rpipe;
static HANDLE wpipe;
static vpiHandle from_myhdl_systf_handle = NULL;
static vpiHandle to_myhdl_systf_handle = NULL;
static char changeFlag[MAXARGS];
static char bufcp[MAXLINE];
static myhdl_time64_t myhdl_time;
static myhdl_time64_t verilog_time;
static myhdl_time64_t pli_time;
static int delta;
/* prototypes */
static PLI_INT32 from_myhdl_calltf(PLI_BYTE8 *user_data);
static PLI_INT32 to_myhdl_calltf(PLI_BYTE8 *user_data);
static PLI_INT32 readonly_callback(p_cb_data cb_data);
static PLI_INT32 delay_callback(p_cb_data cb_data);
static PLI_INT32 delta_callback(p_cb_data cb_data);
static PLI_INT32 change_callback(p_cb_data cb_data);
static int init_pipes();
static myhdl_time64_t timestruct_to_time(const struct t_vpi_time*ts);
/* from Icarus */
static myhdl_time64_t timestruct_to_time(const struct t_vpi_time*ts)
{
myhdl_time64_t ti = ts->high;
ti <<= 32;
ti += ts->low & 0xffffffff;
return ti;
}
static int read_pipe(void *buf, size_t count)
{
DWORD read;
if (!ReadFile(rpipe, buf, (DWORD)count, &read, NULL))
{
return -1;
}
return (int)read;
}
static int write_pipe(const void *buf, size_t count)
{
DWORD written;
if (!WriteFile(wpipe, buf, (DWORD)count, &written, NULL))
{
return -1;
}
return (int)written;
}
static int init_pipes()
{
char *w;
char *r;
static int init_pipes_flag = 0;
if (init_pipes_flag) {
return(0);
}
if ((w = getenv("MYHDL_TO_PIPE")) == NULL) {
vpi_printf("ERROR: no write pipe to myhdl\n");
vpi_control(vpiFinish, 1); /* abort simulation */
return(0);
}
if ((r = getenv("MYHDL_FROM_PIPE")) == NULL) {
vpi_printf("ERROR: no read pipe from myhdl\n");
vpi_control(vpiFinish, 1); /* abort simulation */
return(0);
}
wpipe = (HANDLE)atoi(w);
rpipe = (HANDLE)atoi(r);
init_pipes_flag = 1;
return (0);
}
static PLI_INT32 from_myhdl_calltf(PLI_BYTE8 *user_data)
{
vpiHandle reg_iter, reg_handle;
s_vpi_time verilog_time_s;
char buf[MAXLINE];
char s[MAXWIDTH];
int n;
static int from_myhdl_flag = 0;
if (from_myhdl_flag) {
vpi_printf("ERROR: $from_myhdl called more than once\n");
vpi_control(vpiFinish, 1); /* abort simulation */
return(0);
}
from_myhdl_flag = 1;
init_pipes();
verilog_time_s.type = vpiSimTime;
vpi_get_time(NULL, &verilog_time_s);
verilog_time = timestruct_to_time(&verilog_time_s);
if (verilog_time != 0) {
vpi_printf("ERROR: $from_myhdl should be called at time 0\n");
vpi_control(vpiFinish, 1); /* abort simulation */
return(0);
}
sprintf(buf, "FROM 0 ");
pli_time = 0;
delta = 0;
from_myhdl_systf_handle = vpi_handle(vpiSysTfCall, NULL);
reg_iter = vpi_iterate(vpiArgument, from_myhdl_systf_handle);
while ((reg_handle = vpi_scan(reg_iter)) != NULL) {
if (vpi_get(vpiType, reg_handle) != vpiReg) {
vpi_printf("ERROR: $from_myhdl argument %s should be a reg\n",
vpi_get_str(vpiName, reg_handle));
vpi_control(vpiFinish, 1); /* abort simulation */
return(0);
}
strcat(buf, vpi_get_str(vpiName, reg_handle));
strcat(buf, " ");
sprintf(s, "%d ", vpi_get(vpiSize, reg_handle));
strcat(buf, s);
vpi_free_object(reg_handle);
}
//vpi_free_object(reg_iter);
n = write_pipe(buf, strlen(buf));
if ((n = read_pipe(buf, MAXLINE)) <= 0) {
vpi_printf("Info: MyHDL simulator down\n");
vpi_control(vpiFinish, 1); /* abort simulation */
return(0);
}
assert(n > 0);
buf[n] = '\0';
return(0);
}
static PLI_INT32 to_myhdl_calltf(PLI_BYTE8 *user_data)
{
vpiHandle net_iter, net_handle, cb_h;
char buf[MAXLINE];
char s[MAXWIDTH];
int n;
int i;
int *id;
s_cb_data cb_data_s;
s_vpi_time verilog_time_s;
s_vpi_time time_s;
s_vpi_value value_s;
static int to_myhdl_flag = 0;
if (to_myhdl_flag) {
vpi_printf("ERROR: $to_myhdl called more than once\n");
vpi_control(vpiFinish, 1); /* abort simulation */
return(0);
}
to_myhdl_flag = 1;
init_pipes();
verilog_time_s.type = vpiSimTime;
vpi_get_time(NULL, &verilog_time_s);
verilog_time = timestruct_to_time(&verilog_time_s);
if (verilog_time != 0) {
vpi_printf("ERROR: $to_myhdl should be called at time 0\n");
vpi_control(vpiFinish, 1); /* abort simulation */
return(0);
}
sprintf(buf, "TO 0 ");
pli_time = 0;
delta = 0;
time_s.type = vpiSuppressTime;
value_s.format = vpiSuppressVal;
cb_data_s.reason = cbValueChange;
cb_data_s.cb_rtn = change_callback;
cb_data_s.time = &time_s;
cb_data_s.value = &value_s;
// value_s.format = vpiHexStrVal;
i = 0;
to_myhdl_systf_handle = vpi_handle(vpiSysTfCall, NULL);
net_iter = vpi_iterate(vpiArgument, to_myhdl_systf_handle);
while ((net_handle = vpi_scan(net_iter)) != NULL) {
if (i == MAXARGS) {
vpi_printf("ERROR: $to_myhdl max #args (%d) exceeded\n", MAXARGS);
vpi_control(vpiFinish, 1); /* abort simulation */
}
strcat(buf, vpi_get_str(vpiName, net_handle));
strcat(buf, " ");
sprintf(s, "%d ", vpi_get(vpiSize, net_handle));
strcat(buf, s);
changeFlag[i] = 0;
id = malloc(sizeof(int));
*id = i;
cb_data_s.user_data = (PLI_BYTE8 *)id;
cb_data_s.obj = net_handle;
cb_h = vpi_register_cb(&cb_data_s);
vpi_free_object(cb_h);
i++;
vpi_free_object(net_handle);
}
//vpi_free_object(net_iter);
n = write_pipe(buf, strlen(buf));
if ((n = read_pipe(buf, MAXLINE)) <= 0) {
vpi_printf("ABORT from $to_myhdl\n");
vpi_control(vpiFinish, 1); /* abort simulation */
return(0);
}
buf[n] = '\0';
assert(n > 0);
// register read-only callback //
time_s.type = vpiSimTime;
time_s.high = 0;
time_s.low = 0;
cb_data_s.reason = cbReadOnlySynch;
cb_data_s.user_data = NULL;
cb_data_s.cb_rtn = readonly_callback;
cb_data_s.obj = NULL;
cb_data_s.time = &time_s;
cb_data_s.value = NULL;
cb_h = vpi_register_cb(&cb_data_s);
vpi_free_object(cb_h);
// pre-register delta cycle callback //
delta = 0;
time_s.type = vpiSimTime;
time_s.high = 0;
time_s.low = 1;
cb_data_s.reason = cbAfterDelay;
cb_data_s.user_data = NULL;
cb_data_s.cb_rtn = delta_callback;
cb_data_s.obj = NULL;
cb_data_s.time = &time_s;
cb_data_s.value = NULL;
cb_h = vpi_register_cb(&cb_data_s);
vpi_free_object(cb_h);
return(0);
}
static PLI_INT32 readonly_callback(p_cb_data cb_data)
{
vpiHandle net_iter, net_handle, cb_h;
s_cb_data cb_data_s;
s_vpi_time verilog_time_s;
s_vpi_value value_s;
s_vpi_time time_s;
char buf[MAXLINE];
int n;
int i;
char *myhdl_time_string;
myhdl_time64_t delay;
static int start_flag = 1;
if (start_flag) {
start_flag = 0;
n = write_pipe("START", 5);
// vpi_printf("INFO: RO cb at start-up\n");
if ((n = read_pipe(buf, MAXLINE)) <= 0) {
vpi_printf("ABORT from RO cb at start-up\n");
vpi_control(vpiFinish, 1); /* abort simulation */
}
assert(n > 0);
}
buf[0] = '\0';
verilog_time_s.type = vpiSimTime;
vpi_get_time(NULL, &verilog_time_s);
verilog_time = timestruct_to_time(&verilog_time_s);
if (verilog_time != (pli_time * 1000 + delta)) {
vpi_printf("%u %u\n", verilog_time_s.high, verilog_time_s.low );
vpi_printf("%llu %llu %d\n", verilog_time, pli_time, delta);
}
/* Icarus 0.7 fails on this assertion beyond 32 bits due to a bug */
// assert(verilog_time == pli_time * 1000 + delta);
assert( (verilog_time & 0xFFFFFFFF) == ( (pli_time * 1000 + delta) & 0xFFFFFFFF ) );
sprintf(buf, "%llu ", pli_time);
net_iter = vpi_iterate(vpiArgument, to_myhdl_systf_handle);
value_s.format = vpiHexStrVal;
i = 0;
while ((net_handle = vpi_scan(net_iter)) != NULL) {
if (changeFlag[i]) {
strcat(buf, vpi_get_str(vpiName, net_handle));
strcat(buf, " ");
vpi_get_value(net_handle, &value_s);
strcat(buf, value_s.value.str);
strcat(buf, " ");
changeFlag[i] = 0;
}
i++;
vpi_free_object(net_handle); // done with this one
}
//vpi_free_object(net_iter);
n = write_pipe(buf, strlen(buf));
if ((n = read_pipe(buf, MAXLINE)) <= 0) {
// vpi_printf("ABORT from RO cb\n");
vpi_control(vpiFinish, 1); /* abort simulation */
return(0);
}
assert(n > 0);
buf[n] = '\0';
/* save copy for later callback */
strcpy(bufcp, buf);
myhdl_time_string = strtok(buf, " ");
myhdl_time = (myhdl_time64_t) strtoull(myhdl_time_string, (char **) NULL, 10);
delay = (myhdl_time - pli_time) * 1000;
assert(delay >= 0);
assert(delay <= 0xFFFFFFFF);
if (delay > 0) { // schedule cbAfterDelay callback
assert(delay > delta);
delay -= delta;
/* Icarus 20030518 runs RO callbacks when time has already advanced */
/* Therefore, one had to compensate for the prescheduled delta callback */
/* delay -= 1; */
/* Icarus 20031009 has a different scheduler, more correct I believe */
/* compensation is no longer necessary */
delta = 0;
pli_time = myhdl_time;
// register cbAfterDelay callback //
time_s.type = vpiSimTime;
time_s.high = 0;
time_s.low = (PLI_UINT32) delay;
cb_data_s.reason = cbAfterDelay;
cb_data_s.user_data = NULL;
cb_data_s.cb_rtn = delay_callback;
cb_data_s.obj = NULL;
cb_data_s.time = &time_s;
cb_data_s.value = NULL;
cb_h = vpi_register_cb(&cb_data_s);
vpi_free_object(cb_h);
} else {
delta++;
assert(delta < 1000);
}
return(0);
}
static PLI_INT32 delay_callback(p_cb_data cb_data)
{
s_vpi_time time_s;
s_cb_data cb_data_s;
vpiHandle cb_h;
// register readonly callback //
time_s.type = vpiSimTime;
time_s.high = 0;
time_s.low = 0;
cb_data_s.reason = cbReadOnlySynch;
cb_data_s.user_data = NULL;
cb_data_s.cb_rtn = readonly_callback;
cb_data_s.obj = NULL;
cb_data_s.time = &time_s;
cb_data_s.value = NULL;
cb_h = vpi_register_cb(&cb_data_s);
vpi_free_object(cb_h);
// register delta callback //
time_s.type = vpiSimTime;
time_s.high = 0;
time_s.low = 1;
cb_data_s.reason = cbAfterDelay;
cb_data_s.user_data = NULL;
cb_data_s.cb_rtn = delta_callback;
cb_data_s.obj = NULL;
cb_data_s.time = &time_s;
cb_data_s.value = NULL;
cb_h = vpi_register_cb(&cb_data_s);
vpi_free_object(cb_h);
return(0);
}
static PLI_INT32 delta_callback(p_cb_data cb_data)
{
s_cb_data cb_data_s;
s_vpi_time time_s;
vpiHandle reg_iter, reg_handle, cb_h;
s_vpi_value value_s;
if (delta == 0) {
return(0);
}
/* skip time value */
strtok(bufcp, " ");
reg_iter = vpi_iterate(vpiArgument, from_myhdl_systf_handle);
value_s.format = vpiHexStrVal;
while ((value_s.value.str = strtok(NULL, " ")) != NULL) {
reg_handle = vpi_scan(reg_iter);
vpi_put_value(reg_handle, &value_s, NULL, vpiNoDelay);
vpi_free_object(reg_handle);
}
if (reg_iter != NULL) {
vpi_free_object(reg_iter);
}
// register readonly callback //
time_s.type = vpiSimTime;
time_s.high = 0;
time_s.low = 0;
cb_data_s.reason = cbReadOnlySynch;
cb_data_s.user_data = NULL;
cb_data_s.cb_rtn = readonly_callback;
cb_data_s.obj = NULL;
cb_data_s.time = &time_s;
cb_data_s.value = NULL;
cb_h = vpi_register_cb(&cb_data_s);
vpi_free_object(cb_h);
// register delta callback //
time_s.type = vpiSimTime;
time_s.high = 0;
time_s.low = 1;
cb_data_s.reason = cbAfterDelay;
cb_data_s.user_data = NULL;
cb_data_s.cb_rtn = delta_callback;
cb_data_s.obj = NULL;
cb_data_s.time = &time_s;
cb_data_s.value = NULL;
cb_h = vpi_register_cb(&cb_data_s);
vpi_free_object(cb_h);
return(0);
}
static PLI_INT32 change_callback(p_cb_data cb_data)
{
int *id;
// vpi_printf("change callback");
id = (int *)cb_data->user_data;
changeFlag[*id] = 1;
return(0);
}
__declspec(dllexport)
void myhdl_register()
{
s_vpi_systf_data tf_data;
tf_data.type = vpiSysTask;
tf_data.tfname = "$to_myhdl";
tf_data.calltf = (void *) to_myhdl_calltf;
tf_data.compiletf = NULL;
tf_data.sizetf = NULL;
tf_data.user_data = "$to_myhdl";
vpi_register_systf(&tf_data);
//vpi_free_object(tf_data); // @mod cfelton
tf_data.type = vpiSysTask;
tf_data.tfname = "$from_myhdl";
tf_data.calltf = (void *) from_myhdl_calltf;
tf_data.compiletf = NULL;
tf_data.sizetf = NULL;
tf_data.user_data = "$from_myhdl";
vpi_register_systf(&tf_data);
//vpi_free_object(tf_data); // @mod cfelton
}
__declspec(dllexport)
void (*vlog_startup_routines[])() = {
myhdl_register,
0
};
/* dummy +loadvpi= boostrap routine - mimics old style exec all routines */
/* in standard PLI vlog_startup_routines table */
__declspec(dllexport)
void vpi_compat_bootstrap(void)
{
int i;
for (i = 0;; i++)
{
if (vlog_startup_routines[i] == NULL) break;
vlog_startup_routines[i]();
}
}

View File

@ -0,0 +1,11 @@
import os
from myhdl import Cosimulation
cmd = 'vsim -c -quiet -pli ../myhdl_vpi.dll -do cosim.do dut_bin2gray'
def bin2gray(B, G, width):
os.system('vlog -quiet +define+width=%s ../../test/verilog/bin2gray.v' % (width))
os.system('vlog -quiet +define+width=%s ../../test/verilog/dut_bin2gray.v' % (width))
return Cosimulation(cmd, B=B, G=G)

View File

@ -0,0 +1,2 @@
run -all
quit

View File

@ -0,0 +1,11 @@
import os
from myhdl import Cosimulation
cmd = 'vsim -c -quiet -pli ../myhdl_vpi.dll -do cosim.do dut_dff'
def dff(q, d, clk, reset):
os.system('vlog -quiet ../../test/verilog/dff.v')
os.system('vlog -quiet ../../test/verilog/dut_dff.v')
return Cosimulation(cmd, **locals())

View File

@ -0,0 +1,11 @@
import os
from myhdl import Cosimulation
cmd = 'vsim -c -quiet -pli ../myhdl_vpi.dll -do cosim.do dut_dff_clkout'
def dff_clkout(clkout, q, d, clk, reset):
os.system('vlog -quiet ../../test/verilog/dff_clkout.v')
os.system('vlog -quiet ../../test/verilog/dut_dff_clkout.v')
return Cosimulation(cmd, **locals())

View File

@ -0,0 +1,11 @@
import os
from myhdl import Cosimulation
cmd = 'vsim -c -quiet -pli ../myhdl_vpi.dll -do cosim.do dut_inc'
def inc(count, enable, clock, reset, n):
os.system('vlog -quiet +define+n=%s ../../test/verilog/inc.v' % (n))
os.system('vlog -quiet +define+n=%s ../../test/verilog/dut_inc.v' % (n))
return Cosimulation(cmd, **locals())

View File

@ -0,0 +1,47 @@
# This file is part of the myhdl library, a Python package for using
# Python as a Hardware Description Language.
#
# Copyright (C) 2003-2008 Jan Decaluwe
#
# The myhdl library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation; either version 2.1 of the
# License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
""" Run cosimulation unit tests. """
import sys
sys.path.append("../../test")
import test_bin2gray, test_inc, test_dff
# modules = (test_dff, )
modules = (test_bin2gray, test_inc, test_dff )
import unittest
tl = unittest.defaultTestLoader
def suite():
alltests = unittest.TestSuite()
for m in modules:
alltests.addTest(tl.loadTestsFromModule(m))
return alltests
def main():
unittest.main(defaultTest='suite',
testRunner=unittest.TextTestRunner(verbosity=2))
if __name__ == '__main__':
main()

View File

@ -1,34 +1,27 @@
# could add to CFLAGS to turn on warnings if you are using gcc
WARNS=-Wall
# This makefile assumes that 32bit Modelsim is installed.
# If you have a 64 bit version, run 'ARCH=64 make'
ARCH?=32
CFLAGS_32= -m32
CFLAGS_64= -m64
# change this path to point to the pli include files directory for cver
# Guess include dir based on location of vsim
INCS=-I $(shell dirname `which vsim`)/../include
CFLAGS= -Wall -shared -BSymbolic -fPIC $(CFLAGS_$(ARCH)) $(INCS)
# maybe want -O<something> and/or -g
VSIM_VERSION=$(shell vsim -version 2>/dev/null; echo $$?)
# 32bit for Altera ASE/PE on Ubuntu Natty Narwhal
CFLAGS= -fPIC -Wall -g -m32 $(INCS) -fno-stack-protector
LFLAGS= -G -shared -export-dynamic -melf_i386
# 64bit for SE
#CFLAGS= -fPIC -Wall -c -g $(INCS)
#LFLAGS= -shared -E
# change to your compiler
CC=gcc
all: myhdl_vpi.so
myhdl_vpi.o: myhdl_vpi.c
$(CC) $(CFLAGS) -c myhdl_vpi.c
# make rules for dynamic libaries
myhdl_vpi.so: myhdl_vpi.o
$(LD) $(LFLAGS) myhdl_vpi.o -o myhdl_vpi.so
myhdl_vpi.so: myhdl_vpi.c
$(info Compiling $(ARCH)bit vpi lib for "$(VSIM_VERSION)")
$(info )
$(CC) $(CFLAGS) -o $@ $?
clean:
-rm *.o *.so
@rm -f myhdl_vpi.so
.PHONY: test
test: myhdl_vpi.so
make -C test
rm -rf test/work
cd test && vlib work && python test_all.py

View File

@ -125,7 +125,7 @@ static PLI_INT32 from_myhdl_calltf(PLI_BYTE8 *user_data)
while ((reg_handle = vpi_scan(reg_iter)) != NULL) {
if (vpi_get(vpiType, reg_handle) != vpiReg) {
vpi_printf("ERROR: $from_myhdl argument %s should be a reg\n",
vpi_get_str(vpiName, reg_handle));
vpi_get_str(vpiName, reg_handle));
vpi_control(vpiFinish, 1); /* abort simulation */
return(0);
}
@ -137,7 +137,7 @@ static PLI_INT32 from_myhdl_calltf(PLI_BYTE8 *user_data)
}
//vpi_free_object(reg_iter);
n = write(wpipe, buf, strlen(buf));
n = write(wpipe, buf, strlen(buf));
if ((n = read(rpipe, buf, MAXLINE)) == 0) {
vpi_printf("Info: MyHDL simulator down\n");
@ -274,12 +274,12 @@ static PLI_INT32 readonly_callback(p_cb_data cb_data)
if (start_flag) {
start_flag = 0;
n = write(wpipe, "START", 5);
n = write(wpipe, "START", 5);
// vpi_printf("INFO: RO cb at start-up\n");
if ((n = read(rpipe, buf, MAXLINE)) == 0) {
vpi_printf("ABORT from RO cb at start-up\n");
vpi_control(vpiFinish, 1); /* abort simulation */
}
}
assert(n > 0);
}
@ -311,7 +311,7 @@ static PLI_INT32 readonly_callback(p_cb_data cb_data)
vpi_free_object(net_handle); // done with this one
}
//vpi_free_object(net_iter);
n = write(wpipe, buf, strlen(buf));
if ((n = read(rpipe, buf, MAXLINE)) == 0) {
// vpi_printf("ABORT from RO cb\n");
@ -463,7 +463,6 @@ static PLI_INT32 change_callback(p_cb_data cb_data)
}
void myhdl_register()
{
s_vpi_systf_data tf_data;
@ -498,9 +497,9 @@ void vpi_compat_bootstrap(void)
{
int i;
for (i = 0;; i++)
for (i = 0;; i++)
{
if (vlog_startup_routines[i] == NULL) break;
if (vlog_startup_routines[i] == NULL) break;
vlog_startup_routines[i]();
}
}

View File

@ -1,2 +0,0 @@
all:
python test_all.py

View File

@ -2,7 +2,7 @@ import os
from myhdl import Cosimulation
cmd = 'vsim -c -quiet -pli myhdl_vpi.so -do cosim.do dut_bin2gray'
cmd = 'vsim -c -quiet -pli ../myhdl_vpi.so -do cosim.do dut_bin2gray'
def bin2gray(B, G, width):
os.system('vlog -quiet +define+width=%s ../../test/verilog/bin2gray.v' % (width))

View File

@ -2,7 +2,7 @@ import os
from myhdl import Cosimulation
cmd = 'vsim -c -quiet -pli myhdl_vpi.so -do cosim.do dut_dff'
cmd = 'vsim -c -quiet -pli ../myhdl_vpi.so -do cosim.do dut_dff'
def dff(q, d, clk, reset):
os.system('vlog -quiet ../../test/verilog/dff.v')

View File

@ -3,7 +3,7 @@ import os.path as path
from myhdl import Cosimulation
cmd = 'vsim -c -quiet -pli myhdl_vpi.so -do cosim.do dut_dff_clkout'
cmd = 'vsim -c -quiet -pli ../myhdl_vpi.so -do cosim.do dut_dff_clkout'
def dff_clkout(clkout, q, d, clk, reset):
os.system('vlog -quiet ../../test/verilog/dff_clkout.v')

View File

@ -2,7 +2,7 @@ import os
from myhdl import Cosimulation
cmd = 'vsim -c -quiet -pli myhdl_vpi.so -do cosim.do dut_inc'
cmd = 'vsim -c -quiet -pli ../myhdl_vpi.so -do cosim.do dut_inc'
def inc(count, enable, clock, reset, n):
os.system('vlog -quiet +define+n=%s ../../test/verilog/inc.v' % (n))

View File

@ -1,4 +1,4 @@
from myhdl import *
from myhdl import always_comb
def bin2gray(B, G, width):
""" Gray encoder.
@ -14,5 +14,3 @@ def bin2gray(B, G, width):
G.next[i] = B[i+1] ^ B[i]
return logic

View File

@ -1,3 +1,4 @@
import myhdl
from myhdl import *
ACTIVE_LOW, INACTIVE_HIGH = 0, 1

View File

@ -1,3 +1,4 @@
import myhdl
from myhdl import *
from dff import dff

View File

@ -1,3 +1,4 @@
import myhdl
from myhdl import *
ACTIVE_LOW, INACTIVE_HIGH = 0, 1

View File

@ -3,15 +3,7 @@ module bin2gray(B, G);
parameter width = 8;
input [width-1:0] B;
output [width-1:0] G;
reg [width-1:0] G;
integer i;
wire [width:0] extB;
assign extB = {1'b0, B}; // zero-extend input
always @(extB) begin
for (i=0; i < width; i=i+1)
G[i] <= extB[i+1] ^ extB[i];
end
assign G = (B >> 1) ^ B;
endmodule // bin2gray

View File

@ -19,6 +19,7 @@ I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " livehtml to make continuously updating standalone HTML files"
@echo " web to make files usable by Sphinx.web"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@ -41,6 +42,10 @@ html:
@echo
@echo "Build finished. The HTML pages are in build/html."
livehtml:
mkdir -p build/html build/doctrees
sphinx-autobuild -b html $(ALLSPHINXOPTS) build/html
web:
mkdir -p build/web build/doctrees
$(SPHINXBUILD) -b web $(ALLSPHINXOPTS) build/web

View File

@ -13,10 +13,13 @@
import sys, os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))
sys.path.insert(0, os.path.abspath('../..'))
sys.path.append(os.path.abspath('.'))
import myhdl
# -- General configuration -----------------------------------------------------
@ -26,7 +29,8 @@ import sys, os
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.intersphinx',
'sphinx.ext.doctest']
'sphinx.ext.doctest',
'myhdldoctools']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
@ -42,16 +46,16 @@ master_doc = 'index'
# General information about the project.
project = u'MyHDL'
copyright = u'2014, Jan Decaluwe'
copyright = u'2015, Jan Decaluwe'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '0.8'
# version = myhdl.__version__
# The full version, including alpha/beta/rc tags.
release = '0.8'
release = myhdl.__version__
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
@ -71,7 +75,7 @@ exclude_patterns = []
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
add_function_parentheses = True
add_function_parentheses = False
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).

View File

@ -4,7 +4,7 @@
.. include:: <isonum.txt>
|myhdl-site|_
|myhdl-site|_
.. |myhdl-site| replace:: Back to the main site |raquo|
@ -18,10 +18,22 @@ Welcome to the MyHDL documentation
:maxdepth: 2
manual/index
whatsnew/1.0
python3
Old Whatsnew documents
======================
.. toctree::
:maxdepth: 1
whatsnew/0.9
whatsnew/0.8
whatsnew/0.7
whatsnew/0.6
whatsnew/0.5
whatsnew/0.4
whatsnew/0.3
Index
=====
@ -31,4 +43,3 @@ Index
Search
======
* :ref:`search`

View File

@ -73,15 +73,13 @@ Generator are mapped to Verilog or VHDL constructs
it will map them to ``process`` statements or concurrent signal assignments.
The module ports are inferred from signal usage
In MyHDL, the input or output direction of interface signals is not explicitly
In MyHDL, the input or output direction of ports is not explicitly
declared. The converter investigates signal usage in the design hierarchy to
infer whether a signal is used as input, output, or as an internal signal.
Interfaces are expanded
MyHDL provides a power mechanism to define complex module interfaces.
These interfaces are name extended to individual signals in the target
HDL (Verilog and VHDL). This enables MyHDL to support higher-level
abstractions that are not available in the target HDL.
Interfaces are convertible
An *interface*: an object that has a number of :class:`Signal` objects as its
attributes. The convertor supports this by name expansion and mangling.
Function calls are mapped to Verilog or VHDL subprograms
The converter analyzes function calls and function code. Each function is
@ -434,16 +432,15 @@ description of RAM memories.
Conversion of Interfaces
========================
Interfaces simplify the complicated interconnect between modules.
In MyHDL the interfaces provide an intuitive approach to group
logically related ports. The grouping of ports has many benefits
such as reducing complexity and increasing modularity.
The converter will name extend the interfaces during conversion,
in the converted code each attribute will appear as a individual
signal. Because the hierarchy is flattened the name extension
may need to include information on the where in the hierarchy
the interface occurs to prevent name collisions.
Complex designs often have many signals that are passed to different levels of
hierarchy. Typically, many signals logically belong together. This can be
modelled by an *interface*: an object that has a number of :class:`Signal`
objects as its attributes. Grouping signals into an interface simplifies the
code, improves efficiency, and reduces errors.
The convertor supports interface using hierarchical name expansion and name
mangling.
.. _conv-meth-assign:

View File

@ -21,122 +21,37 @@ read the companion chapter :ref:`conv`.
A small sequential design
=========================
Consider the following MyHDL code for an incrementer module::
Consider the following MyHDL code for an incrementer block:
.. include-example:: inc.py
def Inc(count, enable, clock, reset):
""" Incrementer with enable.
count -- output
enable -- control input, increment when 1
clock -- clock input
reset -- asynchronous reset input
"""
@always_seq(clock.posedge, reset=reset)
def incLogic():
if enable:
count.next = count + 1
This design can be converted to Verilog and VHDL. The first step is to elaborate
it, just as we do for simulation. Then we can use the :func:`convert` method on
the elaborated instance.
return incLogic
.. include-example:: convert_inc.py
For flexibility, we wrap the conversion in a :func:`convert_inc` function.
``inc_1`` is an elaborated design instance that provides the conversion
method.
Normally, to simulate the design, we would elaborate it as follows::
The conversion to Verilog generates an equivalent Verilog module in file
:file:`inc.v`. The Verilog code looks as follows:
m = 8
.. include-example:: inc.v
count = Signal(modbv(0)[m:])
enable = Signal(bool(0))
clock = Signal(bool(0))
reset = ResetSignal(0, active=0, async=True)
The convertor infers a proper Verilog module interface and maps the MyHDL
generator to a Verilog always block.
inc_inst = Inc(count, enable, clock, reset)
``inc_inst`` is an elaborated design instance that can be simulated. To convert
it to Verilog, we change the last line as follows::
inc_inst = toVerilog(Inc, count, enable, clock, reset)
Again, this creates an instance that can be simulated, but as a side effect, it
also generates an equivalent Verilog module in file :file:`Inc.v`. The Verilog
code looks as follows::
module Inc (
count,
enable,
clock,
reset
);
output [7:0] count;
reg [7:0] count;
input enable;
input clock;
input reset;
always @(posedge clock, negedge reset) begin: INC_INCLOGIC
if (reset == 0) begin
count <= 0;
end
else begin
if (enable) begin
count <= (count + 1);
end
end
end
endmodule
The convertor infers a proper Verilog module interface and maps
the MyHDL generator to a Verilog always block.
Similarly, we can convert to VHDL as follows::
inc_inst = toVHDL(Inc, count, enable, clock, reset, n=n)
This creates an equivalent VHDL module in file :file:`Inc.vhd`::
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
use std.textio.all;
use work.pck_myhdl_08.all;
entity Inc is
port (
count: inout unsigned(7 downto 0);
enable: in std_logic;
clock: in std_logic;
reset: in std_logic
);
end entity Inc;
architecture MyHDL of Inc is
begin
INC_INCLOGIC: process (clock, reset) is
begin
if (reset = '0') then
count <= (others => '0');
elsif rising_edge(clock) then
if bool(enable) then
count <= (count + 1);
end if;
end if;
end process INC_INCLOGIC;
end architecture MyHDL;
Similarly, the conversion to VHDL generates a file :file:`inc.vhd` with the
following content:
.. include-example:: inc.vhd
The MyHDL generator is mapped to a VHDL process in this case.
Note that the VHDL file refers to a VHDL package called
``pck_myhdl_08``. This package contains a number of convenience
``pck_myhdl_<version>``. This package contains a number of convenience
functions that make the conversion easier.
Note also the use of an ``inout`` in the interface. This is not
@ -153,93 +68,23 @@ A small combinatorial design
============================
The second example is a small combinatorial design, more specifically the binary
to Gray code converter from previous chapters::
to Gray code converter from previous chapters:
def bin2gray(B, G, width):
.. include-example:: bin2gray.py
""" Gray encoder.
As before, you can create an instance and convert to Verilog and VHDL as
follows:
B -- input intbv signal, binary encoded
G -- output intbv signal, gray encoded
width -- bit width
"""
@always_comb
def logic():
Bext = intbv(0)[width+1:]
Bext[:] = B
for i in range(width):
G.next[i] = Bext[i+1] ^ Bext[i]
return logic
As before, you can create an instance and convert to Verilog and VHDL as follows::
width = 8
B = Signal(intbv(0)[width:])
G = Signal(intbv(0)[width:])
bin2gray_inst = toVerilog(bin2gray, B, G, width)
bin2gray_inst = toVHDL(bin2gray, B, G, width)
The generated Verilog code looks as follows::
module bin2gray (
B,
G
);
input [7:0] B;
output [7:0] G;
reg [7:0] G;
.. include-example:: convert_bin2gray.py
always @(B) begin: BIN2GRAY_LOGIC
integer i;
reg [9-1:0] Bext;
Bext = 9'h0;
Bext = B;
for (i=0; i<8; i=i+1) begin
G[i] <= (Bext[(i + 1)] ^ Bext[i]);
end
end
The generated Verilog code looks as follows:
endmodule
.. include-example:: bin2gray.v
The generated VHDL code looks as follows:
The generated VHDL code looks as follows::
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
use work.pck_myhdl_08.all;
entity bin2gray is
port (
B: in unsigned(7 downto 0);
G: out unsigned(7 downto 0)
);
end entity bin2gray;
architecture MyHDL of bin2gray is
begin
BIN2GRAY_LOGIC: process (B) is
variable Bext: unsigned(8 downto 0);
begin
Bext := to_unsigned(0, 9);
Bext := resize(B, 9);
for i in 0 to 8-1 loop
G(i) <= (Bext((i + 1)) xor Bext(i));
end loop;
end process BIN2GRAY_LOGIC;
end architecture MyHDL;
.. include-example:: bin2gray.vhd
.. _conv-usage-hier:
@ -249,156 +94,34 @@ A hierarchical design
The converter can handle designs with an arbitrarily deep hierarchy.
For example, suppose we want to design an incrementer with Gray code output.
Using the designs from previous sections, we can proceed as follows::
Using the designs from previous sections, we can proceed as follows:
def GrayInc(graycnt, enable, clock, reset, width):
bincnt = Signal(intbv(0)[width:])
inc_1 = inc(bincnt, enable, clock, reset, n=2**width)
bin2gray_1 = bin2gray(B=bincnt, G=graycnt, width=width)
return inc_1, bin2gray_1
.. include-example:: gray_inc.py
According to Gray code properties, only a single bit will change in consecutive
values. However, as the ``bin2gray`` module is combinatorial, the output bits
may have transient glitches, which may not be desirable. To solve this, let's
create an additional level of hierarchy and add an output register to the
design. (This will create an additional latency of a clock cycle, which may not
be acceptable, but we will ignore that here.) ::
be acceptable, but we will ignore that here.)
def GrayIncReg(graycnt, enable, clock, reset, width):
.. include-example:: gray_inc_reg.py
graycnt_comb = Signal(intbv(0)[width:])
gray_inc_1 = GrayInc(graycnt_comb, enable, clock, reset, width)
We can convert this hierarchical design as follows:
@always(clock.posedge)
def reg_1():
graycnt.next = graycnt_comb
return gray_inc_1, reg_1
We can convert this hierarchical design as before::
width = 8
graycnt = Signal(modbv(0)[width:])
enable = Signal(bool())
clock = Signal(bool())
reset = ResetSignal(0, active=0, async=True)
toVerilog(GrayIncReg, graycnt, enable, clock, reset, width)
toVHDL(GrayIncReg, graycnt, enable, clock, reset, width)
The Verilog output code looks as follows::
module GrayIncReg (
graycnt,
enable,
clock,
reset
);
output [7:0] graycnt;
reg [7:0] graycnt;
input enable;
input clock;
input reset;
reg [7:0] graycnt_comb;
reg [7:0] gray_inc_1_bincnt;
always @(posedge clock, negedge reset) begin: GRAYINCREG_GRAY_INC_1_INC_1_INCLOGIC
if (reset == 0) begin
gray_inc_1_bincnt <= 0;
end
else begin
if (enable) begin
gray_inc_1_bincnt <= (gray_inc_1_bincnt + 1);
end
end
end
always @(gray_inc_1_bincnt) begin: GRAYINCREG_GRAY_INC_1_BIN2GRAY_1_LOGIC
integer i;
reg [9-1:0] Bext;
Bext = 9'h0;
Bext = gray_inc_1_bincnt;
for (i=0; i<8; i=i+1) begin
graycnt_comb[i] = (Bext[(i + 1)] ^ Bext[i]);
end
end
always @(posedge clock) begin: GRAYINCREG_REG_1
graycnt <= graycnt_comb;
end
endmodule
The VHDL output code looks as follows::
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
use work.pck_myhdl_08.all;
entity GrayIncReg is
port (
graycnt: out unsigned(7 downto 0);
enable: in std_logic;
clock: in std_logic;
reset: in std_logic
);
end entity GrayIncReg;
architecture MyHDL of GrayIncReg is
signal graycnt_comb: unsigned(7 downto 0);
signal gray_inc_1_bincnt: unsigned(7 downto 0);
begin
GRAYINCREG_GRAY_INC_1_INC_1_INCLOGIC: process (clock, reset) is
begin
if (reset = '0') then
gray_inc_1_bincnt <= (others => '0');
elsif rising_edge(clock) then
if bool(enable) then
gray_inc_1_bincnt <= (gray_inc_1_bincnt + 1);
end if;
end if;
end process GRAYINCREG_GRAY_INC_1_INC_1_INCLOGIC;
GRAYINCREG_GRAY_INC_1_BIN2GRAY_1_LOGIC: process (gray_inc_1_bincnt) is
variable Bext: unsigned(8 downto 0);
begin
Bext := to_unsigned(0, 9);
Bext := resize(gray_inc_1_bincnt, 9);
for i in 0 to 8-1 loop
graycnt_comb(i) <= (Bext((i + 1)) xor Bext(i));
end loop;
end process GRAYINCREG_GRAY_INC_1_BIN2GRAY_1_LOGIC;
GRAYINCREG_REG_1: process (clock) is
begin
if rising_edge(clock) then
graycnt <= graycnt_comb;
end if;
end process GRAYINCREG_REG_1;
end architecture MyHDL;
.. include-example:: convert_gray_inc_reg.py
The Verilog output code looks as follows:
.. include-example:: gray_inc_reg.v
The VHDL output code looks as follows:
.. include-example:: gray_inc_reg.vhd
Note that the output is a flat "net list of blocks", and that hierarchical
signal names are generated as necessary.
.. _conv-usage-fsm:
Optimizations for finite state machines

View File

@ -41,22 +41,9 @@ from the previous chapters. Suppose that we want to synthesize it and write it
in Verilog for that purpose. Clearly we would like to reuse our unit test
verification environment.
To start, let's recall how the Gray encoder in MyHDL looks like::
To start, let's recall how the Gray encoder in MyHDL looks like:
def bin2gray(B, G, width):
""" Gray encoder.
B -- input intbv signal, binary encoded
G -- output intbv signal, gray encoded
width -- bit width
"""
@always_comb
def logic():
for i in range(width):
G.next[i] = B[i+1] ^ B[i]
return logic
.. include-example:: bin2gray.py
To show the co-simulation flow, we don't need the Verilog implementation yet,
but only the interface. Our Gray encoder in Verilog would have the following
@ -65,7 +52,7 @@ interface::
module bin2gray(B, G);
parameter width = 8;
input [width-1:0] B;
input [width-1:0] B;
output [width-1:0] G;
....
@ -135,11 +122,14 @@ simulator, this is done as follows::
from myhdl import Cosimulation
cmd = "iverilog -o bin2gray -Dwidth=%s bin2gray.v dut_bin2gray.v"
cmd = "iverilog -o bin2gray.o -Dwidth=%s " + \
"../../test/verilog/bin2gray.v " + \
"../../test/verilog/dut_bin2gray.v "
def bin2gray(B, G, width):
def bin2gray(B, G):
width = len(B)
os.system(cmd % width)
return Cosimulation("vvp -m ./myhdl.vpi bin2gray", B=B, G=G)
return Cosimulation("vvp -m ../myhdl.vpi bin2gray.o", B=B, G=G)
After the executable command argument, the ``Cosimulation`` constructor takes an
arbitrary number of keyword arguments. Those arguments make the link between
@ -154,37 +144,31 @@ definition to the existing unit test.
Let's try it on the Verilog design::
module bin2gray(B, G);
module bin2gray(B, G);
parameter width = 8;
input [width-1:0] B;
output [width-1:0] G;
reg [width-1:0] G;
integer i;
wire [width:0] extB;
parameter width = 8;
input [width-1:0] B;
output [width-1:0] G;
assign extB = {1'b0, B}; // zero-extend input
assign G = (B >> 1) ^ B;
always @(extB) begin
for (i=0; i < width; i=i+1)
G[i] <= extB[i+1] ^ extB[i];
end
endmodule // bin2gray
endmodule
When we run our unit tests, we get::
When we run our unit test, we get::
% python test_bin2gray.py
Check that only one bit changes in successive codewords ... ok
Check that all codewords occur exactly once ... ok
Check that the code is an original Gray code ... ok
% python test_gray.py
testSingleBitChange (test_gray_properties.TestGrayCodeProperties)
Check that only one bit changes in successive codewords. ... ok
testUniqueCodeWords (test_gray_properties.TestGrayCodeProperties)
Check that all codewords occur exactly once. ... ok
testOriginalGrayCode (test_gray_original.TestOriginalGrayCode)
Check that the code is an original Gray code. ... ok
----------------------------------------------------------------------
Ran 3 tests in 2.729s
Ran 3 tests in 0.706s
OK
.. _cosim-restr:
Restrictions

View File

@ -29,14 +29,13 @@ representation for bitwise operations. However, unlike :class:`int`, it is
a mutable type. This means that its value can be changed after object
creation, through methods and operators such as slice assignment.
:class:`intbv` supports the same operators as :class:`int` for arithmetic.
In addition, it provides a number of features to make it
suitable for hardware design. First, the range of allowed values can
be constrained. This makes it possible to check the value at run time
during simulation. Moreover, back end tools can determine the smallest
possible bit width for representing the object.
Secondly, it supports bit level operations by providing an indexing
and slicing interface.
:class:`intbv` supports the same operators as :class:`int` for arithmetic. In
addition, it provides a number of features to make it suitable for hardware
design. First, the range of allowed values can be constrained. This makes it
possible to check the value at run time during simulation. Moreover, back end
tools can determine the smallest possible bit width for representing the object.
Secondly, it supports bit level operations by providing an indexing and slicing
interface.
:class:`intbv` objects are constructed in general as follows::
@ -46,12 +45,12 @@ and slicing interface.
the value. Following the Python conventions, *min* is inclusive, and
*max* is exclusive. Therefore, the allowed value range is *min* .. *max*-1.
Let's us look at some examples. First, an unconstrained :class:`intbv`
object is created as follows:
Let's look at some examples. An unconstrained :class:`intbv` object is created
as follows::
>>> a = intbv(24)
.. index::
.. index::
single: intbv; min
single: intbv; max
single: intbv; bit width
@ -60,12 +59,14 @@ After object creation, *min* and *max* are available as attributes for
inspection. Also, the standard Python function :func:`len` can be used
to determine the bit width. If we inspect the previously created
object, we get::
>>> print a.min
>>> a
intbv(24)
>>> print(a.min)
None
>>> print a.max
>>> print(a.max)
None
>>> print len(a)
>>> len(a)
0
As the instantiation was unconstrained, the *min* and *max* attributes
@ -76,9 +77,10 @@ A constrained :class:`intbv` object is created as follows:
>>> a = intbv(24, min=0, max=25)
Inspecting the object now gives::
>>> a
intbv(24)
>>> a.min
0
>>> a.max
@ -89,55 +91,21 @@ Inspecting the object now gives::
We see that the allowed value range is 0 .. 24, and that 5 bits are
required to represent the object.
Sometimes hardware engineers prefer to constrain an object by defining
its bit width directly, instead of the range of allowed values.
The following example shows how to do that::
The *min* and *max* bound attributes enable fine-grained control and error
checking of the value range. In particular, the bound values do not have to be
symmetric or powers of 2. In all cases, the bit width is set appropriately to
represent the values in the range. For example::
>>> a = intbv(24)[5:]
What actually happens here is that first an unconstrained :class:`intbv`
is created, which is then sliced. Slicing an :class:`intbv` returns a new
:class:`intbv` with the constraints set up appropriately.
Inspecting the object now shows::
>>> a.min
0
>>> a.max
32
>>> a = intbv(6, min=0, max=7)
>>> len(a)
3
>>> a = intbv(6, min=-3, max=7)
>>> len(a)
4
>>> a = intbv(6, min=-13, max=7)
>>> len(a)
5
Note that the *max* attribute is 32, as with 5 bits it is possible to represent
the range 0 .. 31. Creating an :class:`intbv` this way has the disadvantage
that only positive value ranges can be specified. Slicing is described in more
detail in :ref:`hwtypes-slicing`.
To summarize, there are two ways to constrain an :class:`intbv` object: by
defining its bit width, or by defining its value range. The bit
width method is more traditional in hardware design. However, there
are two reasons to use the range method instead: to represent
negative values as observed above, and for fine-grained control over the
value range.
Fine-grained control over the value range permits better error
checking, as there is no need for the *min* and *max* bounds
to be symmetric or powers of 2. In all cases, the bit width
is set appropriately to represent all values in
the range. For example::
>>> a = intbv(6, min=0, max=7)
>>> len(a)
3
>>> a = intbv(6, min=-3, max=7)
>>> len(a)
4
>>> a = intbv(6, min=-13, max=7)
>>> len(a)
5
.. _hwtypes-indexing:
Bit indexing
@ -145,135 +113,102 @@ Bit indexing
.. index:: single: bit indexing
As an example, we will consider the design of a Gray encoder. The following code
is a Gray encoder modeled in MyHDL::
A common requirement in hardware design is access to the individual bits. The
:class:`intbv` class implements an indexing interface that provides access to
the bits of the underlying two's complement representation. The following
illustrates bit index read access::
from myhdl import Signal, delay, Simulation, always_comb, instance, intbv, bin
>>> from myhdl import bin
>>> a = intbv(24)
>>> bin(a)
'11000'
>>> int(a[0])
0
>>> int(a[3])
1
>>> b = intbv(-23)
>>> bin(b)
'101001'
>>> int(b[0])
1
>>> int(b[3])
1
>>> int(b[4])
0
def bin2gray(B, G, width):
""" Gray encoder.
B -- input intbv signal, binary encoded
G -- output intbv signal, gray encoded
width -- bit width
"""
@always_comb
def logic():
for i in range(width):
G.next[i] = B[i+1] ^ B[i]
return logic
This code introduces a few new concepts. The string in triple quotes at the
start of the function is a :dfn:`doc string`. This is standard Python practice
for structured documentation of code.
.. index::
single: decorator; always_comb
single: wait; for a signal value change
single: combinatorial logic
Furthermore, we introduce a third decorator: :func:`always_comb`. It is used
with a classic function and specifies that the resulting generator should wait
for a value change on any input signal. This is typically used to describe
combinatorial logic. The :func:`always_comb` decorator automatically infers
which signals are used as inputs.
Finally, the code contains bit indexing operations and an exclusive-or operator
as required for a Gray encoder. By convention, the lsb of an :class:`intbv`
object has index ``0``.
To verify the Gray encoder, we write a test bench that prints input and output
for all possible input values::
def testBench(width):
B = Signal(intbv(0))
G = Signal(intbv(0))
dut = bin2gray(B, G, width)
@instance
def stimulus():
for i in range(2**width):
B.next = intbv(i)
yield delay(10)
print "B: " + bin(B, width) + "| G: " + bin(G, width)
return dut, stimulus
We use the conversion function :func:`bin` to get a binary string representation of
the signal values. This function is exported by the :mod:`myhdl` package and
supplements the standard Python :func:`hex` and :func:`oct` conversion functions.
As a demonstration, we set up a simulation for a small width::
sim = Simulation(testBench(width=3))
sim.run()
The simulation produces the following output::
% python bin2gray.py
B: 000 | G: 000
B: 001 | G: 001
B: 010 | G: 011
B: 011 | G: 010
B: 100 | G: 110
B: 101 | G: 111
B: 110 | G: 101
B: 111 | G: 100
StopSimulation: No more events
We use the :func:`bin` function provide by MyHDL because it shows the two's
complement representation for negative values, unlike Python's builtin with the
same name. Note that lower indices correspond to less significant bits. The
following code illustrates bit index assignment::
>>> bin(a)
'11000'
>>> a[3] = 0
>>> bin(a)
'10000'
>>> a
intbv(16)
>>> b
intbv(-23)
>>> bin(b)
'101001'
>>> b[3] = 0
>>> bin(b)
'100001'
>>> b
intbv(-31)
.. _hwtypes-slicing:
Bit slicing
===========
.. index::
.. index::
single: bit slicing
single: concat(); example usage
For a change, we will use a traditional function as an example to illustrate
slicing. The following function calculates the HEC byte of an ATM header. ::
The :class:`intbv` type also supports bit slicing, for both read access
assignment. For example::
from myhdl import intbv, concat
>>> a = intbv(24)
>>> bin(a)
'11000'
>>> a[4:1]
intbv(4)
>>> bin(a[4:1])
'100'
>>> a[4:1] = 0b001
>>> bin(a)
'10010'
>>> a
intbv(18)
COSET = 0x55
In accordance with the most common hardware convention, and unlike standard
Python, slicing ranges are downward. As in standard Python, the slicing range
is half-open: the highest index bit is not included. Unlike standard Python
however, this index corresponds to the *leftmost* item.
def calculateHec(header):
""" Return hec for an ATM header, represented as an intbv.
Both indices can be omitted from the slice. If the rightmost index is omitted,
it is ``0`` by default. If the leftmost index is omitted, the meaning is to
access "all" higher order bits. For example::
The hec polynomial is 1 + x + x**2 + x**8.
"""
hec = intbv(0)
for bit in header[32:]:
hec[8:] = concat(hec[7:2],
bit ^ hec[1] ^ hec[7],
bit ^ hec[0] ^ hec[7],
bit ^ hec[7]
)
return hec ^ COSET
The code shows how slicing access and assignment is supported on the
:class:`intbv` data type. In accordance with the most common hardware
convention, and unlike standard Python, slicing ranges are downward. The code
also demonstrates concatenation of :class:`intbv` objects.
As in standard Python, the slicing range is half-open: the highest index bit is
not included. Unlike standard Python however, this index corresponds to the
*leftmost* item. Both indices can be omitted from the slice. If the leftmost
index is omitted, the meaning is to access "all" higher order bits. If the
rightmost index is omitted, it is ``0`` by default.
>>> bin(a)
'11000'
>>> bin(a[4:])
'1000'
>>> a[4:] = '0001'
>>> bin(a)
'10001'
>>> a[:] = 0b10101
>>> bin(a)
'10101'
The half-openness of a slice may seem awkward at first, but it helps to avoid
one-off count issues in practice. For example, the slice ``hex[8:]`` has exactly
``8`` bits. Likewise, the slice ``hex[7:2]`` has ``7-2=5`` bits. You can think
one-off count issues in practice. For example, the slice ``a[8:]`` has exactly
``8`` bits. Likewise, the slice ``a[7:2]`` has ``7-2=5`` bits. You can think
about it as follows: for a slice ``[i:j]``, only bits below index ``i`` are
included, and the bit with index ``j`` is the last bit included.
When an :class:`intbv` object is sliced, a new :class:`intbv` object is returned.
When an :class:`intbv` object is sliced, a new :class:`intbv` object is returned.
This new :class:`intbv` object is always positive, and the value bounds are
set up in accordance with the bit width specified by the slice. For example::
@ -281,7 +216,7 @@ set up in accordance with the bit width specified by the slice. For example::
>>> len(a)
4
>>> b = a[4:]
>>> b
>>> b
intbv(6L)
>>> len(b)
4
@ -295,8 +230,8 @@ The returned object has the same value and bit width, but its value
range consists of all positive values that can be represented by
the bit width.
The object returned by a slice is positive, even when the
original object is negative::
The object returned by a slice is positive, even when the original object is
negative::
>>> a = intbv(-3)
>>> bin(a, width=5)
@ -307,8 +242,31 @@ original object is negative::
>>> bin(b)
'11101'
The bit pattern of the two objects is identical within the bit width,
but their values have opposite sign.
In this example, the bit pattern of the two objects is identical within the bit
width, but their values have opposite sign.
Sometimes hardware engineers prefer to constrain an object by defining its bit
width directly, instead of the range of allowed values. Using the slicing
properties of the :class:`intbv` class one can do that as follows::
>>> a = intbv(24)[5:]
What actually happens here is that first an unconstrained :class:`intbv`
is created, which is then sliced. Slicing an :class:`intbv` returns a new
:class:`intbv` with the constraints set up appropriately.
Inspecting the object now shows::
>>> a.min
0
>>> a.max
32
>>> len(a)
5
Note that the *max* attribute is 32, as with 5 bits it is possible to represent
the range 0 .. 31. Creating an :class:`intbv` in this way is convenient but has
the disadvantage that only positive value ranges between 0 and a power of 2 can
be specified.
.. _hwtypes-modbv:
@ -363,7 +321,7 @@ In a typical case when ``min==0``, this reduces to::
Unsigned and signed representation
==================================
.. index::
.. index::
single: intbv; intbv.signed
:class:`intbv` is designed to be as high level as possible. The underlying
@ -402,7 +360,7 @@ bit width. For this purpose, :class:`intbv` provides the
>>> bin(b, width=4)
'1100'
:meth:`intbv.signed` extends the msb bit into the higher-order bits of the
:meth:`intbv.signed` extends the msb bit into the higher-order bits of the
underlying object value, and returns the result as an integer.
Naturally, for a "signed" the return value will always be identical
to the original value, as it has the sign bit already.
@ -420,5 +378,3 @@ the data bus and convert them as follows::
real.next = data_bus[8:4].signed()
imag.next = data_bus[4:].signed()

View File

@ -14,73 +14,58 @@ A basic MyHDL simulation
We will introduce MyHDL with a classic ``Hello World`` style example. All
example code can be found in the distribution directory under
:file:`example/manual/`. Here are the contents of a MyHDL simulation script
called :file:`hello1.py`::
called :file:`hello1.py`:
from myhdl import Signal, delay, always, now, Simulation
.. include-example:: hello1.py
def HelloWorld():
When we run this simulation, we get the following output:
interval = delay(10)
@always(interval)
def sayHello():
print "%s Hello World!" % now()
return sayHello
inst = HelloWorld()
sim = Simulation(inst)
sim.run(30)
When we run this simulation, we get the following output::
% python hello1.py
10 Hello World!
20 Hello World!
30 Hello World!
_SuspendSimulation: Simulated 30 timesteps
.. run-example:: hello1.py
The first line of the script imports a number of objects from the ``myhdl``
package. In Python we can only use identifiers that are literally defined in the
source file [#]_.
source file.
Then, we define a function called :func:`HelloWorld`. In MyHDL, hardware
modules can be modeled using classic functions. In particular, the parameter list
is then used to define the interface. In this first example, the interface is empty.
Then, we define a function called :func:`HelloWorld`. In MyHDL, a hardware
module is modeled by a function decorated with the :func:`block` decorator. The
name :dfn:`block` was chosen to avoid confusion with the Python concept
of a module. We will use this terminology further on.
The parameter list of the :func:`HelloWorld` function is used to define the
interface of the hardware block. In this first example, the interface is empty.
.. index:: single: decorator; always
Inside the top level function we declare a local function called
:func:`sayHello` that defines the desired behavior. This function is decorated
with an :func:`always` decorator that has a delay object as its parameter. The
meaning is that the function will be executed whenever the specified delay
interval has expired.
:func:`say_hello` that defines the desired behavior. This function is decorated
with an :func:`always` decorator that has a :func:`delay` object as its
parameter. The meaning is that the function will be executed whenever the
specified delay interval has expired.
Behind the curtains, the :func:`always` decorator creates a Python *generator*
and reuses the name of the decorated function for it. Generators are the
fundamental objects in MyHDL, and we will say much more about them further on.
Finally, the top level function returns the local generator. This is the
simplest case of the basic MyHDL code pattern to define the contents of a
hardware module. We will describe the general case further on.
Finally, the top level function returns the :func:`say_hello` generator. This is
the simplest case of the basic MyHDL code pattern to define the contents of a
hardware block. We will describe the general case further on.
In MyHDL, we create an *instance* of a hardware module by calling the
corresponding function. In the example, variable ``inst`` refers to an instance
of :func:`HelloWorld`. To simulate the instance, we pass it as an argument to a
:class:`Simulation` object constructor. We then run the simulation for the
desired amount of timesteps.
In MyHDL, we create an *instance* of a hardware block by calling the
corresponding function. The :func:`block` decorator make sure that the return
value is actually an instance of a block class, with a useful API. In the
example, variable ``inst`` refers to a :func:`HelloWorld` block instance.
To simulate the instance, we use its :meth:`run_sim` method. We can use it to
run the simulation for the desired amount of timesteps.
.. _intro-conc:
Signals, ports, and concurrency
===============================
Signals and concurrency
=======================
In the previous section, we simulated a design with a single generator and no
concurrency. Real hardware descriptions are typically
massively concurrent. MyHDL supports this by allowing an arbitrary number of
concurrently running generators.
An actual hardware design is typically massively concurrent, which means that a
large amount of functional units are running in parallel. MyHDL supports this
behavior by allowing an arbitrary number of concurrently running generators.
With concurrency comes the problem of deterministic communication. Hardware
languages use special objects to support deterministic communication between
@ -88,109 +73,64 @@ concurrent code. In particular, MyHDL has a :class:`Signal` object which is
roughly modeled after VHDL signals.
We will demonstrate signals and concurrency by extending and modifying our first
example. We define two hardware modules, one that drives a clock signal, and one
that is sensitive to a positive edge on a clock signal::
example. We define a hardware block that contains two generators, one that
drives a clock signal, and one that is sensitive to a positive edge on a clock
signal:
from myhdl import Signal, delay, always, now, Simulation
def ClkDriver(clk):
halfPeriod = delay(10)
@always(halfPeriod)
def driveClk():
clk.next = not clk
return driveClk
def HelloWorld(clk):
@always(clk.posedge)
def sayHello():
print "%s Hello World!" % now()
return sayHello
clk = Signal(0)
clkdriver_inst = ClkDriver(clk)
hello_inst = HelloWorld(clk)
sim = Simulation(clkdriver_inst, hello_inst)
sim.run(50)
.. include-example:: hello2.py
.. index::
single: VHDL; signal assignment
single: Verilog; non-blocking assignment
The clock driver function :func:`ClkDriver` has a clock signal as its parameter.
This is how a *port* is modeled in MyHDL. The function defines a generator that
continuously toggles a clock signal after a certain delay. A new value of a
signal is specified by assigning to its ``next`` attribute. This is the MyHDL
equivalent of the VHDL signal assignment and the Verilog non-blocking
assignment.
The clock driver function :func:`clk_driver` drives the clock signal. If defines
a generator that continuously toggles a clock signal after a certain delay. A
new value of a signal is specified by assigning to its ``next`` attribute. This
is the MyHDL equivalent of the VHDL signal assignment and the Verilog
non-blocking assignment.
.. index:: single: wait; for a rising edge
The :func:`HelloWorld` function is modified from the first example. It now also
takes a clock signal as parameter. Its generator is made sensitive to a rising
edge of the clock signal. This is specified by the ``posedge`` attribute of a
signal. The edge specifier is the argument of the ``always`` decorator. As a
result, the decorated function will be executed on every rising clock edge.
The :func:`say_hello` function is modified from the first example. It is made
sensitive to a rising edge of the clock signal, specified by the ``posedge``
attribute of a signal. The edge specifier is the argument of the ``always``
decorator. As a result, the decorated function will be executed on every rising
clock edge.
The ``clk`` signal is constructed with an initial value ``0``. When creating an
instance of each hardware module, the same clock signal is passed as the
argument. The result is that the instances are now connected through the clock
signal. The :class:`Simulation` object is constructed with the two instances.
The ``clk`` signal is constructed with an initial value ``0``. One generator
drives it, the other is sensitive to it. The result of this communication is
that the generators run in parallel, but that their actions are coordinated by
the clock signal.
When we run the simulation, we get::
% python hello2.py
10 Hello World!
30 Hello World!
50 Hello World!
_SuspendSimulation: Simulated 50 timesteps
When we run the simulation, we get:
.. run-example:: hello2.py
.. _intro-hier:
Parameters and hierarchy
========================
Parameters, ports and hierarchy
===============================
We have seen that MyHDL uses functions to model hardware modules. We have also
seen that ports are modeled by using signals as parameters. To make designs
reusable we will also want to use other objects as parameters. For example, we
can change the clock generator function to make it more general and reusable, by
making the clock period parametrizable, as follows::
We have seen that MyHDL uses functions to model hardware blocks. So far these
functions did not have parameters. However, to create general, reusable blocks we
will need parameters. For example, we can create a clock driver block as
follows:
from myhdl import Signal, delay, instance, always, now, Simulation
.. include-example:: ClkDriver.py
def ClkDriver(clk, period=20):
The block encapsulates a clock driver generator. It has two parameters.
lowTime = int(period/2)
highTime = period - lowTime
@instance
def driveClk():
while True:
yield delay(lowTime)
clk.next = 1
yield delay(highTime)
clk.next = 0
return driveClk
In addition to the clock signal, the clock period is a parameter, with a default
value of ``20``.
The first parameter is *clk* is the clock signal. A asignal parameter is
MyHDL's way to model a dfn:port:. The second parameter is the clock *period*,
with a default value of ``20``.
.. index:: single: decorator; instance
As the low time of the clock may differ from the high time in case of an odd
period, we cannot use the :func:`always` decorator with a single delay value
anymore. Instead, the :func:`driveClk` function is now a generator function with
an explicit definition of the desired behavior. It is decorated with the
:func:`instance` decorator. You can see that :func:`driveClk` is a generator
anymore. Instead, the :func:`drive_clk` function is now a generator function
with an explicit definition of the desired behavior. It is decorated with the
:func:`instance` decorator. You can see that :func:`drive_clk` is a generator
function because it contains ``yield`` statements.
When a generator function is called, it returns a generator object. This is
@ -199,23 +139,17 @@ than the :func:`always` decorator, but it can be used to create a generator from
any local generator function.
The ``yield`` statement is a general Python construct, but MyHDL uses it in a
dedicated way. In MyHDL, it has a similar meaning as the wait statement in
VHDL: the statement suspends execution of a generator, and its clauses specify
the conditions on which the generator should wait before resuming. In this case,
the generator waits for a certain delay.
specific way. It has a similar meaning as the wait statement in VHDL: the
statement suspends execution of a generator, and its clauses specify the
conditions on which the generator should wait before resuming. In this case, the
generator waits for a certain delay.
Note that to make sure that the generator runs "forever", we wrap its behavior
in a ``while True`` loop.
Similarly, we can define a general :func:`Hello` function as follows::
Similarly, we can define a general :func:`Hello` function as follows:
def Hello(clk, to="World!"):
@always(clk.posedge)
def sayHello():
print "%s Hello %s" % (now(), to)
return sayHello
.. include-example:: Hello.py
.. index:: single: instance; defined
@ -226,64 +160,50 @@ arbitrary number of hierarchical levels. Consequently, the general definition of
a MyHDL instance is recursive: an instance is either a sequence of instances, or
a generator.
As an example, we will create a higher-level function with four instances of the
lower-level functions, and simulate it::
lower-level functions, and simulate it:
def greetings():
clk1 = Signal(0)
clk2 = Signal(0)
clkdriver_1 = ClkDriver(clk1) # positional and default association
clkdriver_2 = ClkDriver(clk=clk2, period=19) # named association
hello_1 = Hello(clk=clk1) # named and default association
hello_2 = Hello(to="MyHDL", clk=clk2) # named association
return clkdriver_1, clkdriver_2, hello_1, hello_2
inst = greetings()
sim = Simulation(inst)
sim.run(50)
.. include-example:: greetings.py
As in standard Python, positional or named parameter association can be used in
instantiations, or a mix of both [#]_. All these styles are demonstrated in the
example above. Named association can be very useful if there are a lot of
parameters, as the argument order in the call does not matter in that case.
The simulation produces the following output::
The simulation produces the following output:
% python greetings.py
9 Hello MyHDL
10 Hello World!
28 Hello MyHDL
30 Hello World!
47 Hello MyHDL
50 Hello World!
_SuspendSimulation: Simulated 50 timesteps
.. run-example:: greetings.py
.. warning::
Terminology review
==================
Some commonly used terminology has different meanings in Python versus hardware
design. Rather than artificially changing terminology, I think it's best to keep
it and explicitly describing the differences.
Some commonly used terminology has different meanings in Python versus hardware
design. For a good understanding, it is important to make these differences
explicit.
.. index:: single: module; in Python versus hardware design
.. index:: single: module; in Python versus hardware design
A :dfn:`module` in Python refers to all source code in a particular file. A
module can be reused by other modules by importing. In hardware design, a module
is a reusable block of hardware with a well defined interface. It can be reused
in another module by :dfn:`instantiating` it.
A :dfn:`module` in Python refers to all source code in a particular file. A
module can be reused by other modules by importing it. In hardware design on the
other hand, a module typically refers to a reusable unit of hardware with a well
defined interface. Because these meanings are so different, the terminology
chosen for a hardware module in MyHDL is *block* instead, as explained earlier
in this chapter.
.. index:: single: instance; in Python versus hardware design
A hardware block can can be reused
in another block by :dfn:`instantiating` it.
An :dfn:`instance` in Python (and other object-oriented languages) refers to the
object created by a class constructor. In hardware design, an instance is a
particular incarnation of a hardware module.
.. index:: single: instance; in Python versus hardware design
Normally, the meaning should be clear from the context. Occasionally, I may
qualify terms with the words "hardware" or "MyHDL" to avoid ambiguity.
An :dfn:`instance` in Python (and other object-oriented languages) refers to the
object created by a class constructor. In hardware design, an instance is a
particular incarnation of a hardware block, created by *instantiating* the block.
In MyHDL, such as block instance is actually an instance of a particular class.
Therefore, the two meanings are not exactly the same, but they coincide nicely.
Normally, the meaning the words "block" and "instance" should be clear from the
context. Sometimes, we qualify them with the words "hardware" or "MyHDL" for
clarity.
.. _intro-python:
@ -301,9 +221,8 @@ To have Python as the underlying language is significant in several ways:
* Python is a very powerful high level language. This translates into high
productivity and elegant solutions to complex problems.
* Python is continuously improved by some very clever minds, supported by a
large and fast growing user base. Python profits fully from the open source
development model.
* Python is continuously improved by some very clever minds, supported by a
large user base. Python profits fully from the open source development model.
* Python comes with an extensive standard library. Some functionality is likely
to be of direct interest to MyHDL users: examples include string handling,
@ -312,14 +231,6 @@ To have Python as the underlying language is significant in several ways:
mathematics, database connections, networking programming, internet data
handling, and so on.
* Python has a powerful C extension model. All built-in types are written with
the same C API that is available for custom extensions. To a module user, there
is no difference between a standard Python module and a C extension module ---
except performance. The typical Python development model is to prototype
everything in Python until the application is stable, and (only) then rewrite
performance critical modules in C if necessary.
.. _intro-summary:
Summary and perspective
@ -330,13 +241,15 @@ Here is an overview of what we have learned in this chapter:
* Generators are the basic building blocks of MyHDL models. They provide the way
to model massive concurrency and sensitivity lists.
* MyHDL provides decorators that create useful generators from local functions.
* MyHDL provides decorators that create useful generators from local functions
and a decorator to create hardware blocks.
* Hardware structure and hierarchy is described with classic Python functions.
* Hardware structure and hierarchy is described with Python functions, decorated
with the :func:`block` decorator.
* :class:`Signal` objects are used to communicate between concurrent generators.
* A :class:`Simulation` object is used to simulate MyHDL models.
* A block instance provides a method to simulate it.
These concepts are sufficient to start modeling and simulating with MyHDL.
@ -355,15 +268,10 @@ from the following chapters:
* It is possible to co-simulate MyHDL models with other HDL languages such as
Verilog and VHDL. This is described in Chapter :ref:`cosim`.
* Last but not least, MyHDL models can be converted to Verilog, providing a path
to a silicon implementation. This is the topic of Chapter :ref:`conv`.
* Last but not least, MyHDL models can be converted to Verilog or VHDL,
providing a path to a silicon implementation. This is the topic of
Chapter :ref:`conv`.
.. rubric:: Footnotes
.. [#] The exception is the ``from module import *`` syntax, that imports all the
symbols from a module. Although this is generally considered bad practice, it
can be tolerated for large modules that export a lot of symbols. One may argue
that ``myhdl`` falls into that category.
.. [#] All positional parameters have to go before any named parameter.

View File

@ -23,14 +23,13 @@ hardware concurrency. Generators are best described as resumable
functions. MyHDL generators are similar to always blocks in Verilog
and processes in VHDL.
A hardware module is modeled as a function that returns
generators. This approach makes it straightforward to support features
such as arbitrary hierarchy, named port association, arrays of
instances, and conditional instantiation. Furthermore, MyHDL provides
classes that implement traditional hardware description concepts. It
provides a signal class to support communication between generators, a
class to support bit oriented operations, and a class for enumeration
types.
A hardware module (called a *block* in MyHDL terminology) is modeled as a
function that returns generators. This approach makes it straightforward to
support features such as arbitrary hierarchy, named port association, arrays of
instances, and conditional instantiation. Furthermore, MyHDL provides classes
that implement traditional hardware description concepts. It provides a signal
class to support communication between generators, a class to support bit
oriented operations, and a class for enumeration types.
*Simulation and Verification*

View File

@ -41,6 +41,14 @@ A :class:`Simulation` object has the following method:
Run the simulation forever (by default) or for a specified duration.
.. method:: Simulation.quit()
Quit the simulation after it has run for a specified duration. The method should
be called (the simulation instance must be quit) before another simulation
instance is created. The method is called by default when the simulation is run
forever.
.. _ref-simsupport:
Simulation support functions
@ -85,8 +93,18 @@ Waveform tracing
This attribute is used to overwrite the default top-level instance name and the
basename of the VCD output filename.
.. attribute:: directory
This attribute is used to set the directory to which VCD files are written. By
default, the current working directory is used.
.. attribute:: filename
This attribute is used to set the filename to which VCD files are written. By
default, the name attribbute is used.
.. attribute:: timescale
This attribute is used to set the timescale corresponding to unit steps,
according to the VCD format. The assigned value should be a string.
The default timescale is "1ns".
@ -212,7 +230,7 @@ Shadow signals
.. class:: _SliceSignal(sig, left[, right=None])
This class implements read-only structural slicing and indexing. It creates a new
signal that shadows the slice or index of the parent signal *sig*. If the
shadow signal of the slice or index of the parent signal *sig*. If the
*right* parameter is omitted, you get indexing instead of slicing.
Parameters *left* and *right* have the usual meaning for slice
indices: in particular, *left* is non-inclusive but *right*
@ -229,11 +247,15 @@ Shadow signals
.. class:: ConcatSignal(*args)
This class creates a new signal that shadows the concatenation
of its parent signal values. You can pass an arbitrary number
of signals to the constructor. The signal arguments should be bit-oriented
with a defined number of bits.
This class creates a new shadow signal of the concatenation of its arguments.
You can pass an arbitrary number of arguments to the constructor. The
arguments should be bit-oriented with a defined number of bits. The following
argument types are supported: :class:`intbv` objects with a defined bit width,
:class:`bool` objects, signals of the previous objects, and bit strings.
The new signal follows the value changes of the signal arguments. The non-signal
arguments are used to define constant values in the concatenation.
.. class:: TristateSignal(val)
@ -601,8 +623,10 @@ useful for hardware description.
The following argument types are supported: :class:`intbv` objects with a
defined bit width, :class:`bool` objects, signals of the previous objects, and
bit strings. All these objects have a defined bit width. The first argument
*base* is special as it doesn't need to have a defined bit width. In addition to
bit strings. All these objects have a defined bit width.
The first argument *base* is special as it does not need to have a
defined bit width. In addition to
the previously mentioned objects, unsized :class:`intbv`, :class:`int` and
:class:`long` objects are supported, as well as signals of such objects.
@ -762,6 +786,13 @@ Conversion
file. The assigned value should be a string. The default
library is ``work``.
.. attribute:: std_logic_ports
This boolean attribute can be used to have only ``std_logic`` type
ports on the top-level interface (when ``True``) instead of the
default ``signed/unsigned`` types (when ``False``, the default).
.. _ref-conv-user:

View File

@ -31,27 +31,26 @@ Combinatorial logic
Template
--------
.. testsetup:: *
from myhdl import *
Combinatorial logic is described with a code pattern as follows::
from myhdl import block, always_comb
@block
def top(<parameters>):
...
@always_comb
def combLogic():
def comb_logic():
<functional code>
...
return combLogic, ...
The :func:`always_comb` decorator describes combinatorial logic. [#]_. The
decorated function is a local function that specifies what happens when one of
the input signals of the logic changes. The :func:`always_comb` decorator
infers the input signals automatically. It returns a generator that is sensitive
to all inputs, and that executes the function whenever an input changes.
return comb_logic, ...
The :func:`always_comb` decorator describes combinatorial logic. The name refers
to a similar construct in SystemVerilog. The decorated function is a local
function that specifies what happens when one of the input signals of the logic
changes. The :func:`always_comb` decorator infers the input signals
automatically. It returns a generator that is sensitive to all inputs, and that
executes the function whenever an input changes.
.. _model-comb-ex:
@ -60,76 +59,21 @@ Example
The following is an example of a combinatorial multiplexer
.. include-example:: mux.py
.. testcode:: comb1
from myhdl import Signal, Simulation, delay, always_comb
def Mux(z, a, b, sel):
""" Multiplexer.
z -- mux output
a, b -- data inputs
sel -- control input: select a if asserted, otherwise b
"""
@always_comb
def muxLogic():
if sel == 1:
z.next = a
else:
z.next = b
return muxLogic
# Once we've created some signals...
z, a, b, sel = [Signal(intbv(0)) for i in range(4)]
# ...it can be instantiated as follows
mux_1 = Mux(z, a, b, sel)
To verify it, we will simulate the logic with some random patterns. The
``random`` module in Python's standard library comes in handy for such purposes.
The function ``randrange(n)`` returns a random natural integer smaller than *n*.
It is used in the test bench code to produce random input values
It is used in the test bench code to produce random input values.
.. testcode:: comb1
:hide:
.. include-example:: test_mux.py
import random
random.seed(0xDECAFBAD)
It is often useful to keep the random values reproducible. This can be
accomplished by providing a seed value as in the code. The run produces the
following output:
.. testcode:: comb1
from random import randrange
def test():
print "z a b sel"
for i in range(8):
a.next, b.next, sel.next = randrange(8), randrange(8), randrange(2)
yield delay(10)
print "%s %s %s %s" % (z, a, b, sel)
test_1 = test()
sim = Simulation(mux_1, test_1).run()
Because of the randomness, the simulation output varies between runs [#]_. One
particular run produced the following output
.. testoutput:: comb1
z a b sel
6 6 0 1
7 7 2 1
7 6 7 0
0 3 0 0
1 1 1 1
1 5 1 0
2 3 2 0
1 1 0 1
.. run-example:: test_mux.py
.. _model-seq:
@ -138,7 +82,6 @@ Sequential logic
.. index:: single: sequential logic
.. _model-seq-templ:
Template
@ -148,13 +91,16 @@ Sequential RTL models are sensitive to a clock edge. In addition, they may be
sensitive to a reset signal. The :func:`always_seq` decorator supports this
model directly::
from myhdl import block, always_seq
@instance
def top(<parameters>, clock, ..., reset, ...):
...
@always_seq(clock.posedge, reset=reset)
def seqLogic():
def seq_logic():
<functional code>
...
return seqLogic, ...
return seq_logic, ...
The :func:`always_seq` decorator automatically infers the reset
functionality. It detects which signals need to be reset, and uses their
@ -175,104 +121,20 @@ Example
-------
The following code is a description of an incrementer with enable, and an
asynchronous reset.
.. testcode:: seq1
from myhdl import *
ACTIVE_LOW, INACTIVE_HIGH = 0, 1
def Inc(count, enable, clock, reset, n):
""" Incrementer with enable.
count -- output
enable -- control input, increment when 1
clock -- clock input
reset -- asynchronous reset input
n -- counter max value
"""
@always_seq(clock.posedge, reset=reset)
def incLogic():
if enable:
count.next = (count + 1) % n
return incLogic
asynchronous reset.
.. include-example:: inc.py
For the test bench, we will use an independent clock generator, stimulus
generator, and monitor. After applying enough stimulus patterns, we can raise
the :func:`StopSimulation()` exception to stop the simulation run. The test bench for
a small incrementer and a small number of patterns is a follows
.. testcode:: seq1
:hide:
import random
random.seed(0xDECAFBAD)
.. testcode:: seq1
from random import randrange
def testbench():
count, enable, clock = [Signal(intbv(0)) for i in range(3)]
reset = ResetSignal(0, active=ACTIVE_LOW, async=True)
inc_1 = Inc(count, enable, clock, reset, n=4)
HALF_PERIOD = delay(10)
@always(HALF_PERIOD)
def clockGen():
clock.next = not clock
@instance
def stimulus():
reset.next = ACTIVE_LOW
yield clock.negedge
reset.next = INACTIVE_HIGH
for i in range(12):
enable.next = min(1, randrange(3))
yield clock.negedge
raise StopSimulation
@instance
def monitor():
print "enable count"
yield reset.posedge
while 1:
yield clock.posedge
yield delay(1)
print " %s %s" % (enable, count)
return clockGen, stimulus, inc_1, monitor
tb = testbench()
Simulation(tb).run()
.. include-example:: test_inc.py
The simulation produces the following output
.. testoutput:: seq1
enable count
1 1
0 1
1 2
1 3
0 3
1 0
1 1
1 2
1 3
1 0
0 0
1 1
.. run-example:: test_inc.py
.. _mode-seq-templ-alt:
@ -283,15 +145,20 @@ The template with the :func:`always_seq` decorator is convenient
as it infers the reset functionality automatically. Alternatively,
you can use a more explicit template as follows::
from myhdl import block, always
@block
def top(<parameters>, clock, ..., reset, ...):
...
@always(clock.posedge, reset.negedge)
def seqLogic():
def seq_logic():
if not reset:
<reset code>
else:
<functional code>
return seq_logic,...
With this template, the reset values have to be specified
explicitly.
@ -353,55 +220,7 @@ When the ``syncFlag`` is confirmed on the expected position, the FSM declares
``SYNC``, otherwise it falls back to the ``SEARCH`` state. This FSM can be
coded as follows
.. testcode:: sm1
from myhdl import *
ACTIVE_LOW = 0
FRAME_SIZE = 8
t_State = enum('SEARCH', 'CONFIRM', 'SYNC')
def FramerCtrl(SOF, state, syncFlag, clk, reset):
""" Framing control FSM.
SOF -- start-of-frame output bit
state -- FramerState output
syncFlag -- sync pattern found indication input
clk -- clock input
reset_n -- active low reset
"""
index = Signal(0) # position in frame
@always_seq(clk.posedge, reset=reset)
def FSM():
index.next = (index + 1) % FRAME_SIZE
SOF.next = 0
if state == t_State.SEARCH:
index.next = 1
if syncFlag:
state.next = t_State.CONFIRM
elif state == t_State.CONFIRM:
if index == 0:
if syncFlag:
state.next = t_State.SYNC
else:
state.next = t_State.SEARCH
elif state == t_State.SYNC:
if index == 0:
if not syncFlag:
state.next = t_State.SEARCH
SOF.next = (index == FRAME_SIZE-1)
else:
raise ValueError("Undefined state")
return FSM
.. include-example:: fsm.py
.. index:: single: waveform viewing
@ -410,7 +229,7 @@ waveform viewing. During simulation, signal changes can be written to a VCD
output file. The VCD file can then be loaded and viewed in a waveform viewer
tool such as :program:`gtkwave`.
.. %
.. %
The user interface of this feature consists of a single function,
:func:`traceSignals`. To explain how it works, recall that in MyHDL, an
@ -433,87 +252,8 @@ call.
A small test bench for our framing controller example, with signal tracing
enabled, is shown below:
.. testcode:: sm1
.. include-example:: test_fsm.py
def testbench():
SOF = Signal(bool(0))
syncFlag = Signal(bool(0))
clk = Signal(bool(0))
reset = ResetSignal(1, active=ACTIVE_LOW, async=True)
state = Signal(t_State.SEARCH)
framectrl = FramerCtrl(SOF, state, syncFlag, clk, reset)
@always(delay(10))
def clkgen():
clk.next = not clk
@instance
def stimulus():
for i in range(3):
yield clk.posedge
for n in (12, 8, 8, 4):
syncFlag.next = 1
yield clk.posedge
syncFlag.next = 0
for i in range(n-1):
yield clk.posedge
raise StopSimulation
@always_seq(clk.posedge, reset=reset)
def output_printer():
print syncFlag, SOF, state
return framectrl, clkgen, stimulus, output_printer
tb_fsm = traceSignals(testbench)
sim = Simulation(tb_fsm)
sim.run()
.. testoutput:: sm1
:hide:
False False SEARCH
False False SEARCH
False False SEARCH
1 False SEARCH
0 False CONFIRM
0 False CONFIRM
0 False CONFIRM
0 False CONFIRM
0 False CONFIRM
0 False CONFIRM
0 False CONFIRM
0 False CONFIRM
0 False SEARCH
0 False SEARCH
0 False SEARCH
1 False SEARCH
0 False CONFIRM
0 False CONFIRM
0 False CONFIRM
0 False CONFIRM
0 False CONFIRM
0 False CONFIRM
0 False CONFIRM
1 False CONFIRM
0 False SYNC
0 False SYNC
0 False SYNC
0 False SYNC
0 False SYNC
0 False SYNC
0 False SYNC
1 True SYNC
0 False SYNC
0 False SYNC
.. testcleanup:: sm1
import os
os.remove('testbench.vcd')
When we run the test bench, it generates a VCD file called
:file:`testbench.vcd`. When we load this file into :program:`gtkwave`, we can
view the waveforms:
@ -533,14 +273,3 @@ string representation, as returned by the standard :func:`str` function.
Support for literal string representations is not part of the VCD standard. It
is specific to :program:`gtkwave`. To generate a standard VCD file, you need to
use signals with a defined bit width only.
.. rubric:: Footnotes
.. [#] The name :func:`always_comb` refers to a construct with similar semantics in
SystemVerilog.
.. [#] It also possible to have a reproducible random output, by explicitly providing a
seed value. See the documentation of the ``random`` module.

View File

@ -18,13 +18,16 @@ sequence of instances, or a generator. Hierarchy is modeled by defining
instances in a higher-level function, and returning them. The following is a
schematic example of the basic case. ::
from myhdl import block
@block
def top(...):
...
instance_1 = module_1(...)
instance_2 = module_2(...)
...
instance_n = module_n(...)
...
...
return instance_1, instance_2, ... , instance_n
Note that MyHDL uses conventional procedural techniques for modeling structure.
@ -41,8 +44,11 @@ Conditional instantiation
To model conditional instantiation, we can select the returned instance under
parameter control. For example::
from myhdl import block
SLOW, MEDIUM, FAST = range(3)
@block
def top(..., speed=SLOW):
...
def slowAndSmall():
@ -70,6 +76,9 @@ Python lists are easy to create. We can use them to model lists of instances.
Suppose we have a top module that instantiates a single ``channel`` submodule,
as follows::
from myhdl import block, Signal
@block
def top(...):
din = Signal(0)
@ -79,11 +88,14 @@ as follows::
channel_inst = channel(dout, din, clk, reset)
return channel_inst
return channel_inst
If we wanted to support an arbitrary number of channels, we can use lists of
signals and a list of instances, as follows::
from myhdl import block, Signal
@block
def top(..., n=8):
din = [Signal(0) for i in range(n)]
@ -113,7 +125,7 @@ In MyHDL, you can address such cases by a concept called
shadow signals. A shadow signal is constructed out of
other signals and follows their value changes automatically.
For example, a :class:`_SliceSignal` follows the value of
an index or a slice from another signal. Likewise,
an index or a slice from another signal. Likewise,
A :class:`ConcatSignal` follows the
values of a number of signals as a concatenation.
@ -137,7 +149,7 @@ Such a module is typically based on bit vectors because
they are easy to process in RTL code. In MyHDL, a bit vector
is modeled using the :class:`intbv` type.
We need a way to "connect" the list of signals to the
We need a way to "connect" the list of signals to the
bit vector and vice versa. Of course, we can do this with explicit
code, but shadow signals can do this automatically. For
example, we can construct a ``request_vector`` as a
@ -178,8 +190,9 @@ may be convenient to assemble the list of instances automatically. For this
purpose, MyHDL provides the function :func:`instances`. Using the first example
in this section, it is used as follows::
from myhdl import instances
from myhdl import block, instances
@block
def top(...):
...
instance_1 = module_1(...)
@ -192,5 +205,3 @@ in this section, it is used as follows::
Function :func:`instances` uses introspection to inspect the type of the local
variables defined by the calling function. All variables that comply with the
definition of an instance are assembled in a list, and that list is returned.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -19,21 +19,20 @@ to hardware design.
.. index:: single: extreme programming
One software design approach that gets a lot of attention recently is *Extreme
Programming* (XP). It is a fascinating set of techniques and guidelines that
often seems to go against the conventional wisdom. On other occasions, XP just
seems to emphasize the common sense, which doesn't always coincide with common
practice. For example, XP stresses the importance of normal workweeks, if we are
to have the fresh mind needed for good software development.
One software design approach that deserves attention is *Extreme Programming*
(XP). It is a fascinating set of techniques and guidelines that often seems to
go against the conventional wisdom. On other occasions, XP just seems to
emphasize the common sense, which doesn't always coincide with common practice.
For example, XP stresses the importance of normal workweeks, if we are to have
the fresh mind needed for good software development.
.. %
.. %
It is not my intention nor qualification to present a tutorial on Extreme
Programming. Instead, in this section I will highlight one XP concept which I
think is very relevant to hardware design: the importance and methodology of
unit testing.
.. _unittest-why:
The importance of unit tests
@ -81,7 +80,7 @@ of :dfn:`codewords`, where a codeword is a bit string. A code of order ``n`` has
A well-known characteristic is the one that Gray codes are all about:
Consecutive codewords in a Gray code should differ in a single bit.
*Consecutive codewords in a Gray code should differ in a single bit.*
Is this sufficient? Not quite: suppose for example that an implementation
returns the lsb of each binary input. This would comply with the requirement,
@ -122,83 +121,39 @@ to be tests of the test case.
We will define a test case for the Gray code properties, and then write a test
for each of the requirements. The outline of the test case class is as follows::
from unittest import TestCase
import unittest
class TestGrayCodeProperties(TestCase):
class TestGrayCodeProperties(unittest.TestCase):
def testSingleBitChange(self):
""" Check that only one bit changes in successive codewords """
"""Check that only one bit changes in successive codewords."""
....
def testUniqueCodeWords(self):
""" Check that all codewords occur exactly once """
"""Check that all codewords occur exactly once."""
....
Each method will be a small test bench that tests a single requirement. To write
the tests, we don't need an implementation of the Gray encoder, but we do need
the interface of the design. We can specify this by a dummy implementation, as
follows::
follows:
def bin2gray(B, G, width):
### NOT IMPLEMENTED YET! ###
yield None
.. include-example:: bin2gray_dummy.py
For the first requirement, we will write a test bench that applies all
consecutive input numbers, and compares the current output with the previous one
for each input. Then we check that the difference is a single bit. We will test
all Gray codes up to a certain order ``MAX_WIDTH``. ::
For the first requirement, we will test all consecutive input numbers, and
compare the current output with the previous one For each input, we check that
the difference is exactly a single bit. For the second requirement, we will test
all input numbers and put the result in a list. The requirement implies that if
we sort the result list, we should get a range of numbers. For both
requirements, we will test all Gray codes up to a certain order ``MAX_WIDTH``.
The test code looks as follows:
def testSingleBitChange(self):
""" Check that only one bit changes in successive codewords """
def test(B, G, width):
B.next = intbv(0)
yield delay(10)
for i in range(1, 2**width):
G_Z.next = G
B.next = intbv(i)
yield delay(10)
diffcode = bin(G ^ G_Z)
self.assertEqual(diffcode.count('1'), 1)
for width in range(1, MAX_WIDTH):
B = Signal(intbv(-1))
G = Signal(intbv(0))
G_Z = Signal(intbv(0))
dut = bin2gray(B, G, width)
check = test(B, G, width)
sim = Simulation(dut, check)
sim.run(quiet=1)
.. include-example:: test_gray_properties.py
Note how the actual check is performed by a ``self.assertEqual`` method, defined
by the ``unittest.TestCase`` class.
Similarly, we write a test bench for the second requirement. Again, we simulate
all numbers, and put the result in a list. The requirement implies that if we
sort the result list, we should get a range of numbers::
def testUniqueCodeWords(self):
""" Check that all codewords occur exactly once """
def test(B, G, width):
actual = []
for i in range(2**width):
B.next = intbv(i)
yield delay(10)
actual.append(int(G))
actual.sort()
expected = range(2**width)
self.assertEqual(actual, expected)
for width in range(1, MAX_WIDTH):
B = Signal(intbv(-1))
G = Signal(intbv(0))
dut = bin2gray(B, G, width)
check = test(B, G, width)
sim = Simulation(dut, check)
sim.run(quiet=1)
by the ``unittest.TestCase`` class. Also, we have factored out running the
tests for all Gray codes in a separate method :func:`runTests`.
.. _unittest-impl:
@ -216,66 +171,70 @@ a call to its ``main`` method at the end of the test module::
Let's run the test using the dummy Gray encoder shown earlier::
% python test_gray.py -v
Check that only one bit changes in successive codewords ... FAIL
Check that all codewords occur exactly once ... FAIL
<trace backs not shown>
% python test_gray_properties.py
testSingleBitChange (__main__.TestGrayCodeProperties)
Check that only one bit changes in successive codewords. ... ERROR
testUniqueCodeWords (__main__.TestGrayCodeProperties)
Check that all codewords occur exactly once. ... ERROR
As expected, this fails completely. Let us try an incorrect implementation, that
puts the lsb of in the input on the output::
puts the lsb of in the input on the output:
def bin2gray(B, G, width):
### INCORRECT - DEMO PURPOSE ONLY! ###
@always_comb
def logic():
G.next = B[0]
return logic
.. include-example:: bin2gray_wrong.py
Running the test produces::
% python test_gray.py -v
Check that only one bit changes in successive codewords ... ok
Check that all codewords occur exactly once ... FAIL
python test_gray_properties.py
testSingleBitChange (__main__.TestGrayCodeProperties)
Check that only one bit changes in successive codewords. ... ok
testUniqueCodeWords (__main__.TestGrayCodeProperties)
Check that all codewords occur exactly once. ... FAIL
======================================================================
FAIL: Check that all codewords occur exactly once
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_gray.py", line 109, in testUniqueCodeWords
sim.run(quiet=1)
...
File "test_gray.py", line 104, in test
self.assertEqual(actual, expected)
File "/usr/local/lib/python2.2/unittest.py", line 286, in failUnlessEqual
raise self.failureException, \
AssertionError: [0, 0, 1, 1] != [0, 1, 2, 3]
======================================================================
FAIL: testUniqueCodeWords (__main__.TestGrayCodeProperties)
Check that all codewords occur exactly once.
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_gray_properties.py", line 42, in testUniqueCodeWords
self.runTests(test)
File "test_gray_properties.py", line 53, in runTests
sim.run(quiet=1)
File "/home/jand/dev/myhdl/myhdl/_Simulation.py", line 154, in run
waiter.next(waiters, actives, exc)
File "/home/jand/dev/myhdl/myhdl/_Waiter.py", line 127, in next
clause = next(self.generator)
File "test_gray_properties.py", line 40, in test
self.assertEqual(actual, expected)
AssertionError: Lists differ: [0, 0, 1, 1] != [0, 1, 2, 3]
----------------------------------------------------------------------
Ran 2 tests in 0.785s
First differing element 1:
0
1
- [0, 0, 1, 1]
+ [0, 1, 2, 3]
----------------------------------------------------------------------
Ran 2 tests in 0.083s
FAILED (failures=1)
Now the test passes the first requirement, as expected, but fails the second
one. After the test feedback, a full traceback is shown that can help to debug
the test output.
Finally, if we use the correct implementation as in section
:ref:`hwtypes-indexing`, the output is::
Finally, we use a correct implementation:
% python test_gray.py -v
Check that only one bit changes in successive codewords ... ok
Check that all codewords occur exactly once ... ok
.. include-example:: bin2gray.py
----------------------------------------------------------------------
Ran 2 tests in 6.364s
OK
Now the tests pass:
.. run-example:: test_gray_properties.py
.. _unittest-change:
Changing requirements
---------------------
Additional requirements
-----------------------
In the previous section, we concentrated on the general requirements of a Gray
code. It is possible to specify these without specifying the actual code. It is
@ -305,54 +264,19 @@ It is possible to specify these codes by a recursive algorithm, as follows:
of Ln0 and Ln1.
Python is well-known for its elegant algorithmic descriptions, and this is a
good example. We can write the algorithm in Python as follows::
good example. We can write the algorithm in Python as follows:
def nextLn(Ln):
""" Return Gray code Ln+1, given Ln. """
Ln0 = ['0' + codeword for codeword in Ln]
Ln1 = ['1' + codeword for codeword in Ln]
Ln1.reverse()
return Ln0 + Ln1
.. include-example:: next_gray_code.py
The code ``['0' + codeword for ...]`` is called a :dfn:`list comprehension`. It
is a concise way to describe lists built by short computations in a for loop.
The requirement is now that the output code matches the expected code Ln. We use
the ``nextLn`` function to compute the expected result. The new test case code
is as follows::
is as follows:
class TestOriginalGrayCode(TestCase):
.. include-example:: test_gray_original.py
def testOriginalGrayCode(self):
""" Check that the code is an original Gray code """
Rn = []
def stimulus(B, G, n):
for i in range(2**n):
B.next = intbv(i)
yield delay(10)
Rn.append(bin(G, width=n))
Ln = ['0', '1'] # n == 1
for n in range(2, MAX_WIDTH):
Ln = nextLn(Ln)
del Rn[:]
B = Signal(intbv(-1))
G = Signal(intbv(0))
dut = bin2gray(B, G, n)
stim = stimulus(B, G, n)
sim = Simulation(dut, stim)
sim.run(quiet=1)
self.assertEqual(Ln, Rn)
As it happens, our implementation is apparently an original Gray code::
% python test_gray.py -v TestOriginalGrayCode
Check that the code is an original Gray code ... ok
----------------------------------------------------------------------
Ran 1 tests in 3.091s
OK
As it happens, our implementation is apparently an original Gray code:
.. run-example:: test_gray_original.py

View File

@ -0,0 +1,35 @@
import subprocess
from docutils import nodes
from sphinx.util.compat import Directive
from sphinx.directives.code import LiteralInclude
example_dir = '/../../example/manual/'
class IncludeExample(LiteralInclude):
def run(self):
self.arguments[0] = '{}/{}'.format(example_dir, self.arguments[0])
return super(IncludeExample, self).run()
class RunExample(Directive):
has_content = False
required_arguments = 1
final_argument_whitespace = True
def run(self):
document = self.state.document
env = document.settings.env
_ , wd = env.relfn2path(example_dir)
prog = self.arguments[0]
out = subprocess.check_output(['python3', '-u', prog], cwd=wd,
stderr=subprocess.STDOUT,
universal_newlines=True)
out = '$ python {}\n{}'.format(prog, out)
ret = [nodes.literal_block(out, out)]
return ret
def setup(app):
app.add_directive('include-example', IncludeExample)
app.add_directive('run-example', RunExample)

8
doc/source/python3.rst Normal file
View File

@ -0,0 +1,8 @@
Python 3 Support
================
MyHDL supports Python 3.4 and above.
At the moment, core functions, cosimulation and Verilog conversion work perfectly.
However, there are a few unresolved VHDL conversion bugs.
All users are encouraged to try out their existing projects and tests with Python 3 and submit bug reports if anything goes wrong.

398
doc/source/whatsnew/0.3.rst Normal file
View File

@ -0,0 +1,398 @@
=======================
Whats New in MyHDL 0.3
=======================
:Author: Jan Decaluwe
VCD output for waveform viewing
===============================
|image|
MyHDL now has support for waveform viewing. During simulation, signal
changes can be written to a VCD output file that can be loaded into a
waveform viewer tool such as **gtkwave**.
The user interface of this feature consists of a single function,
:func:`traceSignals()`. To explain how it works, recall that in MyHDL,
an instance is created by assigning the result of a function call to an
instance name. For example:
::
tb_fsm = testbench()
To enable VCD tracing, the instance should be created as follows
instead:
::
tb_fsm = traceSignals(testbench)
All signals in the instance hierarchy will be traced in a VCD file
called . Note that first the argument of :func:`traceSignals()` consists
of the uncalled function. By calling the function under its control,
:func:`traceSignals()` gathers information about the hierarchy and the
signals to be traced. In addition to a function argument,
:func:`traceSignals()` accepts an arbitrary number of non-keyword and
keyword arguments that will be passed to the function call.
Signals are dumped in a suitable format. This format is inferred at the
:class:`Signal` construction time, from the type of the initial value.
In particular, :class:`bool` signals are dumped as single bits. (This
only works starting with Python 2.3, when :class:`bool` has become a
separate type). Likewise, :class:`intbv` signals with a defined bit
width are dumped as bit vectors. To support the general case, other
types of signals are dumped as a string representation, as returned by
the standard :func:`str()` function.
[warning] Support for literal string representations is not part of the
VCD standard. It is specific to **gtkwave**. To generate a standard VCD
file, you need to use signals with a defined bit width only.
Enumeration types
=================
It is often desirable to define a set of identifiers. A standard Python
idiom for this purpose is to assign a range of integers to a tuple of
identifiers, like so:
::
>>> SEARCH, CONFIRM, SYNC = range(3)
>>> CONFIRM
1
However, this technique has some drawbacks. Though it is clearly the
intention that the identifiers belong together, this information is lost
as soon as they are defined. Also, the identifiers evaluate to integers,
whereas a string representation of the identifiers would be preferable.
To solve these issues, we need an *enumeration type*.
MyHDL 0.3 supports enumeration types by providing a function
:func:`enum()`. The arguments to :func:`enum()` are the string
representations of the identifiers, and its return value is an
enumeration type. The identifiers are available as attributes of the
type. For example:
::
>>> from myhdl import enum
>>> t_State = enum('SEARCH', 'CONFIRM', 'SYNC')
>>> t_State
<Enum: SEARCH, CONFIRM, SYNC>
>>> t_State.CONFIRM
CONFIRM
Enumeration types are often used for the state variable in a finite
state machine. In the waveform in
Section \ `1 <#vcd-output-for-waveform-viewing>`__, you see a
:class:`Signal` called ``state``. Note how the waveforms show the string
representation of the enumeration type identifiers The ``state`` signal
has been constructed with an enumeration type identifier as its initial
value, as follows:
::
state = Signal(t_State.SEARCH)
Inferring the sensitivity list for combinatorial logic
======================================================
In MyHDL, combinatorial logic is described by a generator function with
a sensitivity list that contains all inputs signals (the signals that
are read inside the function).
It may be easy to forget some input signals, especially it there are a
lot of them or if the code is being modified. There are various ways to
solve this. One way is to use a sophisticated editor. Another way is
direct language support. For example, recent versions of Verilog have
the ``always @*`` construct, that infers all input signals. The
SystemVerilog 3.1 standard improves on this by introducing the
``always_comb`` block with slightly enhanced semantics.
MyHDL 0.3 provides a function called :func:`always_comb()` which is
named and modeled after the SystemVerilog counterpart.
:func:`always_comb()` takes a classic local function as its argument.
This function should specify the combinatorial logic behavior.
:func:`always_comb()` returns a generator that is sensitive to all
inputs, and that will run the function whenever an input changes.
For example, suppose that we have a mux module described as follows:
::
def mux(z, a, b, sel):
""" Multiplexer.
z -- mux output
a, b -- data inputs
sel -- control input
"""
def logic()
while 1:
yield a, b, sel
if sel == 1:
z.next = a
else:
z.next = b
mux_logic = logic()
return mux_logic
Using :func:`always_comb()`, we can describe it as follows instead:
::
def mux(z, a, b, sel):
""" Multiplexer.
z -- mux output
a, b -- data inputs
sel -- control input
"""
def logic()
if sel == 1:
z.next = a
else:
z.next = b
mux_logic = always_comb(logic)
return mux_logic
Note that in the first version, the sensitivity list is at the beginning
of the generator function code. This is traditionally done in
synthesizable RTL style modeling. However, the semantics of this style
are not entirely correct: at the start of the simulation, the
combinatorial output will not reflect the initial state of the inputs.
:func:`always_comb()` solves this by putting the sensitivity list at the
end of the code.
Inferring the list of instances
===============================
In MyHDL, the instances defined in a top level function need to be
returned explicitly. The following is a schematic example:
::
def top(...):
...
instance_1 = module_1(...)
instance_2 = module_2(...)
...
instance_n = module_n(...)
...
return instance_1, instance_2, ... , instance_n
It may be convenient to assemble the list of instances automatically,
especially if there are many instances. For this purpose, MyHDL 0.3
provides the function :func:`instances()`. It is used as follows:
::
from myhdl import instances
def top(...):
...
instance_1 = module_1(...)
instance_2 = module_2(...)
...
instance_n = module_n(...)
...
return instances()
Function :func:`instances()` uses introspection to inspect the type of
the local variables defined by the calling function. All variables that
comply with the definition of an instance are assembled in a list, and
that list is returned.
Inferring the list of processes
===============================
In addition to instances, a top level function may also define local
generators functions, which I will call *processes* because of the
analogy with VHDL. Like instances, processes need to be returned
explicitly, with the qualification that they have to be called first to
turn them into generators. The following is a schematic example:
::
def top(...):
...
def process_1():
...
def process_2():
...
...
def process_n():
...
...
return process_1(), process_2(), ..., process_n()
As for instances, it may be more convenient to assemble the list of
processes automatically. One option is to turn each process into an
instance by calling it and assigning the returned generator to a local
variable. Those instances will then be found by the :func:`instances()`
function described in
Section \ `4 <#inferring-the-list-of-instances>`__.
Another option is to use the function :func:`processes()` provided by
MyHDL 0.3. This function uses introspection to find the processes, calls
each of them, and assembles the returned generators into a list. It can
be used as follows:
::
from myhdl import processes
def top(...):
...
def process_1():
...
def process_2():
...
...
def process_n():
...
...
return processes()
To conclude, a top level function with both instances and processes can
use the following idiomatic code to return all of them:
::
return instances(), processes()
Class :class:`intbv` enhancements
=================================
Class :class:`intbv` has been enhanced with new features.
It is now possible to leave the left index of a slicing operation
unspecified. The meaning is to access “all” higher order bits. For
example:
::
>>> from myhdl import intbv
>>> n = intbv()
>>> hex(n)
'0x0'
>>> n[:] = 0xde
>>> hex(n)
'0xde'
>>> n[:8] = 0xfa
>>> hex(n)
'0xfade'
>>> n[8:] = 0xb4
>>> hex(n)
'0xfab4'
:class:`intbv` objects now have ``min`` and ``max`` attributes that can
be specified at construction time. The meaning is that only values
within ``range(min, max)`` are permitted. The default value for these
attributes is ``None``, meaning “infinite”. For example (traceback
output shortened for clarity):
::
>>> n = intbv(min=-17, max=53)
>>> n
intbv(0)
>>> n.min
-17
>>> n.max
53
>>> n[:] = 28
>>> n
intbv(28)
>>> n[:] = -18
Traceback (most recent call last):
....
ValueError: intbv value -18 < minimum -17
>>> n[:] = 53
Traceback (most recent call last):
....
ValueError: intbv value 53 >= maximum 53
When a slice is taken from an :class:`intbv` object, the return value is
a new :class:`intbv` object with a defined bit width. As in Verilog, the
value of the new :class:`intbv` object is always positive, regardless of
the sign of the original value. In addition, the ``min`` and ``max``
attributes are set implicitly:
::
>>> v = intbv()[6:]
>>> v
intbv(0)
>>> v.min
0
>>> v.max
64
Lastly, a small change was implemented with regard to binary operations.
In previous versions, both numeric and bit-wise operations always
returned a new :class:`intbv` object, even in mixed-mode operations with
:class:`int` objects. This has changed: numeric operations return an
:class:`int`, and bitwise operations return a :class:`intbv`. In this
way, the return value corresponds better to the nature of the operation.
Function :func:`concat()`
==========================
In previous versions, the :class:`intbv` class provided a method. This
method is no longer available. Instead, there is now a :func:`concat()`
function that supports a much broader range of objects.
A function is more natural because MyHDL objects of various types can be
concatenated: :class:`intbv` objects with a defined bit width,
:class:`bool` objects, the corresponding signal objects, and bit
strings. All these objects have a defined bit width. Moreover, the first
argument doesnt need to have a defined bit width. It can also be an
unsized :class:`intbv`, an :class:`int`, a :class:`long`, or a
corresponding signal object. Function :func:`concat()` returns an
:class:`intbv` object.
Python 2.3 support
==================
Python 2.3 was released on July 29, 2003, and as of this writing, it is
the latest stable Python release. MyHDL 0.3 works with both Python 2.2
and Python 2.3. In good Python tradition, MyHDL code developed with
Python 2.2 should run without changes or problems in Python 2.3.
In general, I am not that keen on early upgrading. However, as it
happens, the evolution of Python enables features that are really
important or even crucial to MyHDL. Python 2.2 generators are the best
example: they are the cornerstone of MyHDL. But Python 2.3 also has
significant benefits, which I will summarize below.
First, generators and the ``yield`` statement are a default Python 2.3
feature. This means that statements are no longer required.
Second, Python 2.3 has a :class:`bool` type, which is implemented as a
subtype of :class:`int`. For general Python use, the implications are
rather limited - the main difference is that logical result values will
print as ``False`` and ``True`` instead of ``0`` and ``1``. However, in
MyHDL, I can use the :class:`bool` type to infer a bit width. If a
:class:`Signal` is constructed with a :class:`bool` value, it is a
single bit :class:`Signal`. One application is waveform viewing as in
Section \ `1 <#vcd-output-for-waveform-viewing>`__ In the waveform, note
how single bit signals are displayed as level changes. With Python 2.2,
the waveforms of these signals would only show value changes, which is
not as clear for single bits.
Finally, Python 2.3 is significantly faster. MyHDL code runs 2535%
faster in Python 2.3. This is a very nice speedup compared to the small
burden of a straightforward upgrade.
Python is a very stable language, so upgrading to Python 2.3 is
virtually risk free. Given the additional benefits, I recommend
MyHDL users to do so as soon as possible. For the next major
MyHDLrelease, the new features will become required and only Python 2.3
(and higher) will be supported.
.. |image| image:: ../manual/tbfsm.png

796
doc/source/whatsnew/0.4.rst Normal file
View File

@ -0,0 +1,796 @@
==============================================
What's new in MyHDL 0.4: Conversion to Verilog
==============================================
:Author: Jan Decaluwe
Introduction
============
MyHDL 0.4 supports the automatic conversion of a subset of MyHDL code to
synthesizable Verilog code. This feature provides a direct path from
Python to an FPGA or ASIC implementation.
MyHDL aims to be a complete design language, for tasks such as high
level modeling and verification, but also for implementation. However,
prior to 0.4 a user had to translate MyHDL code manually to Verilog or
VHDL. Needless to say, this was inconvenient. With MyHDL0.4, this manual
step is no longer necessary.
Solution description
====================
The solution works as follows. The hardware description should be
modeled in MyHDL style, and satisfy certain constraints that are typical
for implementation-oriented hardware modeling. Subsequently, such a
design is converted to an equivalent model in the Verilog language,
using the function :func:`toVerilog` from the MyHDLlibrary. Finally, a
third-party *synthesis tool* is used to convert the Verilog design to a
gate implementation for an ASIC or FPGA. There are a number of Verilog
synthesis tools available, varying in price, capabilities, and target
implementation technology.
The conversion does not start from source files, but from a design that
has been *elaborated* by the Python interpreter. The converter uses the
Python profiler to track the interpreters operation and to infer the
design structure and name spaces. It then selectively compiles pieces of
source code for additional analysis and for conversion. This is done
using the Python compiler package.
Features
========
The design is converted after elaboration
-----------------------------------------
*Elaboration* refers to the initial processing of a hardware description
to achieve a representation of a design instance that is ready for
simulation or synthesis. In particular, structural parameters and
constructs are processed in this step. In MyHDL, the Python interpreter
itself is used for elaboration. A :class:`Simulation` object is
constructed with elaborated design instances as arguments. Likewise, the
Verilog conversion works on an elaborated design instance. The Python
interpreter is thus used as much as possible.
The structural description can be arbitrarily complex and hierarchical
----------------------------------------------------------------------
As the conversion works on an elaborated design instance, any modeling
constraints only apply to the leaf elements of the design structure,
that is, the co-operating generators. In other words, there are no
restrictions on the description of the design structure: Pythons full
power can be used for that purpose. Also, the design hierarchy can be
arbitrarily deep.
Generators are mapped to Verilog always or initial blocks
---------------------------------------------------------
The converter analyzes the code of each generator and maps it to a
Verilog ``always`` blocks if possible, and to an ``initial`` block
otherwise. The converted Verilog design will be a flat “net list of
blocks”.
The Verilog module interface is inferred from signal usage
----------------------------------------------------------
In MyHDL, the input or output direction of interface signals is not
explicitly declared. The converter investigates signal usage in the
design hierarchy to infer whether a signal is used as input, output, or
as an internal signal. Internal signals are given a hierarchical name in
the Verilog output.
Function calls are mapped to a unique Verilog function or task call
-------------------------------------------------------------------
The converter analyzes function calls and function code to see if they
should be mapped to Verilog functions or to tasks. Python functions are
much more powerful than Verilog subprograms; for example, they are
inherently generic, and they can be called with named association. To
support this power in Verilog, a unique Verilog function or task is
generated per Python function call.
If-then-else structures may be mapped to Verilog case statements
----------------------------------------------------------------
Python does not provide a case statement. However, the converter
recognizes if-then-else structures in which a variable is sequentially
compared to items of an enumeration type, and maps such a structure to a
Verilog case statement with the appropriate synthesis attributes.
Choice of encoding schemes for enumeration types
------------------------------------------------
The :func:`enum` function in MyHDL returns an enumeration type. This
function takes an additional parameter ``encoding`` that specifies the
desired encoding in the implementation: binary, one hot, or one cold.
The Verilog converter generates the appropriate code.
The convertible subset
======================
Introduction
------------
Unsurprisingly, not all MyHDL code can be converted to Verilog. In fact,
there are very important restrictions. As the goal of the conversion
functionality is implementation, this should not be a big issue: anyone
familiar with synthesis is used to similar restrictions in the
*synthesizable subset* of Verilog and VHDL. The converter attempts to
issue clear error messages when it encounters a construct that cannot be
converted.
In practice, the synthesizable subset usually refers to RTL synthesis,
which is by far the most popular type of synthesis today. There are
industry standards that define the RTL synthesis subset. However, those
were not used as a model for the restrictions of the MyHDL converter,
but as a minimal starting point. On that basis, whenever it was judged
easy or useful to support an additional feature, this was done. For
example, it is actually easier to convert :keyword:`while` loops than
:keyword:`for` loops even though they are not RTL-synthesizable. As
another example, :keyword:`print` is supported because its so useful
for debugging, even though its not synthesizable. In summary, the
convertible subset is a superset of the standard RTL synthesis subset,
and supports synthesis tools with more advanced capabilities, such as
behavioral synthesis.
Recall that any restrictions only apply to the design post elaboration.
In practice, this means that they apply only to the code of the
generators, that are the leaf functional blocks in a MyHDL design.
Coding style
------------
A natural restriction on convertible code is that it should be written
in MyHDL style: cooperating generators, communicating through signals,
and with ``yield`` statements specifying wait points and resume
conditions. Supported resume conditions are a signal edge, a signal
change, or a tuple of such conditions.
Supported types
---------------
The most important restriction regards object types. Verilog is an
almost typeless language, while Python is strongly (albeit dynamically)
typed. The converter has to infer the types of names used in the code,
and map those names to Verilog variables.
Only a limited amount of types can be converted. Python :class:`int` and
:class:`long` objects are mapped to Verilog integers. All other
supported types are mapped to Verilog regs (or wires), and therefore
need to have a defined bit width. The supported types are the Python
:class:`bool` type, the MyHDL :class:`intbv` type, and MyHDL enumeration
types returned by function :func:`enum`. The latter objects can also be
used as the base object of a :class:`Signal`.
:class:`intbv` objects must be constructed so that a bit width can be
inferred. This can be done by specifying minimum and maximum values,
e.g. as follows:
::
index = intbv(0, min=0, max=2**N)
Alternatively, a slice can be taken from an :class:`intbv` object as
follows:
::
index = intbv(0)[N:]
Such as slice returns a new :class:`intbv` object, with minimum value
``0`` , and maximum value ``2**N``.
Supported statements
--------------------
The following is a list of the statements that are supported by the
Verilog converter, possibly qualified with restrictions or usage notes.
The :keyword:`break` statement.
The :keyword:`continue` statement.
The :keyword:`def` statement.
The :keyword:`for` statement.
The only supported iteration scheme is iterating through sequences
of integers returned by built-in function :func:`range` or
MyHDLfunction :func:`downrange`. The optional :keyword:`else` clause
is not supported.
The :keyword:`if` statement.
:keyword:`if`, :keyword:`elif`, and :keyword:`else` clauses are
fully supported.
The :keyword:`pass` statement.
The :keyword:`print` statement.
When printing an interpolated string, the format specifiers are
copied verbatim to the Verilog output. Printing to a file (with
syntax ``>>``) is not supported.
The :keyword:`raise` statement.
This statement is mapped to Verilog statements that end the
simulation with an error message.
The :keyword:`return` statement.
The :keyword:`yield` statement.
The yielded expression can be a signal, a signal edge as specified
by MyHDL functions :func:`posedge` or :func:`negedge`, or a tuple of
signals and edge specifications.
The :keyword:`while` statement.
The optional :keyword:`else` clause is not supported.
Methodology notes
=================
Simulation
----------
In the Python philosophy, the run-time rules. The Python compiler
doesnt attempt to detect a lot of errors beyond syntax errors, which
given Pythons ultra-dynamic nature would be an almost impossible task
anyway. To verify a Python program, one should run it, preferably using
unit testing to verify each feature.
The same philosophy should be used when converting a MyHDL description
to Verilog: make sure the simulation runs fine first. Although the
converter checks many things and attempts to issue clear error messages,
there is no guarantee that it does a meaningful job unless the
simulation runs fine.
Conversion output verification
------------------------------
It is always prudent to verify the converted Verilog output. To make
this task easier, the converter also generates a test bench that makes
it possible to simulate the Verilog design using the Verilog
co-simulation interface. This permits to verify the Verilog code with
the same test bench used for the MyHDL code. This is also how the
Verilog converter development is being verified.
Assignment issues
-----------------
Name assignment in Python
~~~~~~~~~~~~~~~~~~~~~~~~~
Name assignment in Python is a different concept than in many other
languages. This point is very important for effective modeling in
Python, and even more so for synthesizable MyHDL code. Therefore, the
issues are discussed here explicitly.
Consider the following name assignments:
::
a = 4
a = ``a string''
a = False
In many languages, the meaning would be that an existing variable ``a``
gets a number of different values. In Python, such a concept of a
variable doesnt exist. Instead, assignment merely creates a new binding
of a name to a certain object, that replaces any previous binding. So in
the example, the name ``a`` is bound a number of different objects in
sequence.
The Verilog converter has to investigate name assignment and usage in
MyHDL code, and to map names to Verilog variables. To achieve that, it
tries to infer the type and possibly the bit width of each expression
that is assigned to a name.
Multiple assignments to the same name can be supported if it can be
determined that a consistent type and bit width is being used in the
assignments. This can be done for boolean expressions, numeric
expressions, and enumeration type literals. In Verilog, the
corresponding name is mapped to a single bit ``reg``, an ``integer``, or
a ``reg`` with the appropriate width, respectively.
In other cases, a single assignment should be used when an object is
created. Subsequent value changes are then achieved by modification of
an existing object. This technique should be used for :class:`Signal`
and :class:`intbv` objects.
Signal assignment
~~~~~~~~~~~~~~~~~
Signal assignment in MyHDL is implemented using attribute assignment to
attribute ``next``. Value changes are thus modeled by modification of
the existing object. The converter investigates the :class:`Signal`
object to infer the type and bit width of the corresponding Verilog
variable.
:class:`intbv` objects
~~~~~~~~~~~~~~~~~~~~~~
Type :class:`intbv` is likely to be the workhorse for synthesizable
modeling in MyHDL. An :class:`intbv` instance behaves like a (mutable)
integer whose individual bits can be accessed and modified. Also, it is
possible to constrain its set of values. In addition to error checking,
this makes it possible to infer a bit width, which is required for
implementation.
In Verilog, an :class:`intbv` instance will be mapped to a ``reg`` with
an appropriate width. As noted before, it is not possible to modify its
value using name assignment. In the following, we will show how it can
be done instead. Consider:
::
a = intbv(0)[8:]
This is an :class:`intbv` object with initial value ``0`` and bit width
8. The change its value to ``5``, we can use slice assignment:
::
a[8:] = 5
The same can be achieved by leaving the bit width unspecified, which has
the meaning to change “all” bits:
::
a[:] = 5
Often the new value will depend on the old one. For example, to
increment an :class:`intbv` with the technique above:
::
a[:] = a + 1
Python also provides *augmented* assignment operators, which can be used
to implement in-place operations. These are supported on :class:`intbv`
objects and by the converter, so that the increment can also be done as
follows:
::
a += 1
Converter usage
===============
We will demonstrate the conversion process by showing some examples.
A small design with a single generator
--------------------------------------
Consider the following MyHDL code for an incrementer module:
::
def inc(count, enable, clock, reset, n):
""" Incrementer with enable.
count -- output
enable -- control input, increment when 1
clock -- clock input
reset -- asynchronous reset input
n -- counter max value
"""
def incProcess():
while 1:
yield posedge(clock), negedge(reset)
if reset == ACTIVE_LOW:
count.next = 0
else:
if enable:
count.next = (count + 1) % n
return incProcess()
In Verilog terminology, function :func:`inc` corresponds to a module,
while generator function :func:`incProcess` roughly corresponds to an
always block.
Normally, to simulate the design, we would “elaborate” an instance as
follows:
::
m = 8
n = 2 ** m
count = Signal(intbv(0)[m:])
enable = Signal(bool(0))
clock, reset = [Signal(bool()) for i in range(2)]
inc_inst = inc(count, enable, clock, reset, n=n)
``incinst`` is an elaborated design instance that can be simulated. To
convert it to Verilog, we change the last line as follows:
::
inc_inst = toVerilog(inc, count, enable, clock, reset, n=n)
Again, this creates an instance that can be simulated, but as a side
effect, it also generates an equivalent Verilog module in file . The
Verilog code looks as follows:
::
module inc_inst (
count,
enable,
clock,
reset
);
output [7:0] count;
reg [7:0] count;
input enable;
input clock;
input reset;
always @(posedge clock or negedge reset) begin: _MYHDL1_BLOCK
if ((reset == 0)) begin
count <= 0;
end
else begin
if (enable) begin
count <= ((count + 1) % 256);
end
end
end
endmodule
You can see the module interface and the always block, as expected from
the MyHDL design.
Converting a generator directly
-------------------------------
It is also possible to convert a generator directly. For example,
consider the following generator function:
::
def bin2gray(B, G, width):
""" Gray encoder.
B -- input intbv signal, binary encoded
G -- output intbv signal, gray encoded
width -- bit width
"""
Bext = intbv(0)[width+1:]
while 1:
yield B
Bext[:] = B
for i in range(width):
G.next[i] = Bext[i+1] ^ Bext[i]
As before, you can create an instance and convert to Verilog as follows:
::
width = 8
B = Signal(intbv(0)[width:])
G = Signal(intbv(0)[width:])
bin2gray_inst = toVerilog(bin2gray, B, G, width)
The generated Verilog code looks as follows:
::
module bin2gray_inst (
B,
G
);
input [7:0] B;
output [7:0] G;
reg [7:0] G;
always @(B) begin: _MYHDL1_BLOCK
integer i;
reg [9-1:0] Bext;
Bext[9-1:0] = B;
for (i=0; i<8; i=i+1) begin
G[i] <= (Bext[(i + 1)] ^ Bext[i]);
end
end
endmodule
A hierarchical design
---------------------
The hierarchy of convertible designs can be arbitrarily deep.
For example, suppose we want to design an incrementer with Gray code
output. Using the designs from previous sections, we can proceed as
follows:
::
def GrayInc(graycnt, enable, clock, reset, width):
bincnt = Signal(intbv()[width:])
INC_1 = inc(bincnt, enable, clock, reset, n=2**width)
BIN2GRAY_1 = bin2gray(B=bincnt, G=graycnt, width=width)
return INC_1, BIN2GRAY_1
According to Gray code properties, only a single bit will change in
consecutive values. However, as the ``bin2gray`` module is
combinatorial, the output bits may have transient glitches, which may
not be desirable. To solve this, lets create an additional level of
hierarchy and add an output register to the design. (This will create an
additional latency of a clock cycle, which may not be acceptable, but we
will ignore that here.)
::
def GrayIncReg(graycnt, enable, clock, reset, width):
graycnt_comb = Signal(intbv()[width:])
GRAY_INC_1 = GrayInc(graycnt_comb, enable, clock, reset, width)
def reg():
while 1:
yield posedge(clock)
graycnt.next = graycnt_comb
REG_1 = reg()
return GRAY_INC_1, REG_1
We can convert this hierarchical design as before:
::
width = 8
graycnt = Signal(intbv()[width:])
enable, clock, reset = [Signal(bool()) for i in range(3)]
GRAY_INC_REG_1 = toVerilog(GrayIncReg, graycnt, enable, clock, reset, width)
The Verilog output code looks as follows:
::
module GRAY_INC_REG_1 (
graycnt,
enable,
clock,
reset
);
output [7:0] graycnt;
reg [7:0] graycnt;
input enable;
input clock;
input reset;
reg [7:0] graycnt_comb;
reg [7:0] _GRAY_INC_1_bincnt;
always @(posedge clock or negedge reset) begin: _MYHDL1_BLOCK
if ((reset == 0)) begin
_GRAY_INC_1_bincnt <= 0;
end
else begin
if (enable) begin
_GRAY_INC_1_bincnt <= ((_GRAY_INC_1_bincnt + 1) % 256);
end
end
end
always @(_GRAY_INC_1_bincnt) begin: _MYHDL4_BLOCK
integer i;
reg [9-1:0] Bext;
Bext[9-1:0] = _GRAY_INC_1_bincnt;
for (i=0; i<8; i=i+1) begin
graycnt_comb[i] <= (Bext[(i + 1)] ^ Bext[i]);
end
end
always @(posedge clock) begin: _MYHDL9_BLOCK
graycnt <= graycnt_comb;
end
endmodule
Note that the output is a flat “net list of blocks”, and that
hierarchical signal names are generated as necessary.
Optimizations for finite state machines
---------------------------------------
As often in hardware design, finite state machines deserve special
attention.
In Verilog and VHDL, finite state machines are typically described using
case statements. Python doesnt have a case statement, but the converter
recognizes particular if-then-else structures and maps them to case
statements. This optimization occurs when a variable whose type is an
enumerated type is sequentially tested against enumeration items in an
if-then-else structure. Also, the appropriate synthesis pragmas for
efficient synthesis are generated in the Verilog code.
As a further optimization, function :func:`enum` was enhanced to support
alternative encoding schemes elegantly, using an additional parameter
``encoding``. For example:
::
t_State = enum('SEARCH', 'CONFIRM', 'SYNC', encoding='one_hot')
The default encoding is ``binary``; the other possibilities are
``onehot`` and ``onecold``. This parameter only affects the
conversion output, not the behavior of the type. The generated Verilog
code for case statements is optimized for an efficient implementation
according to the encoding. Note that in contrast, a Verilog designer has
to make nontrivial code changes to implement a different encoding
scheme.
As an example, consider the following finite state machine, whose state
variable uses the enumeration type defined above:
::
FRAME_SIZE = 8
def FramerCtrl(SOF, state, syncFlag, clk, reset_n):
""" Framing control FSM.
SOF -- start-of-frame output bit
state -- FramerState output
syncFlag -- sync pattern found indication input
clk -- clock input
reset_n -- active low reset
"""
index = intbv(0, min=0, max=8) # position in frame
while 1:
yield posedge(clk), negedge(reset_n)
if reset_n == ACTIVE_LOW:
SOF.next = 0
index[:] = 0
state.next = t_State.SEARCH
else:
SOF.next = 0
if state == t_State.SEARCH:
index[:] = 0
if syncFlag:
state.next = t_State.CONFIRM
elif state == t_State.CONFIRM:
if index == 0:
if syncFlag:
state.next = t_State.SYNC
else:
state.next = t_State.SEARCH
elif state == t_State.SYNC:
if index == 0:
if not syncFlag:
state.next = t_State.SEARCH
SOF.next = (index == FRAME_SIZE-1)
else:
raise ValueError("Undefined state")
index[:]= (index + 1) % FRAME_SIZE
The conversion is done as before:
::
SOF = Signal(bool(0))
syncFlag = Signal(bool(0))
clk = Signal(bool(0))
reset_n = Signal(bool(1))
state = Signal(t_State.SEARCH)
framerctrl_inst = toVerilog(FramerCtrl, SOF, state, syncFlag, clk, reset_n)
The Verilog output looks as follows:
::
module framerctrl_inst (
SOF,
state,
syncFlag,
clk,
reset_n
);
output SOF;
reg SOF;
output [2:0] state;
reg [2:0] state;
input syncFlag;
input clk;
input reset_n;
always @(posedge clk or negedge reset_n) begin: _MYHDL1_BLOCK
reg [3-1:0] index;
if ((reset_n == 0)) begin
SOF <= 0;
index[3-1:0] = 0;
state <= 3'b001;
end
else begin
SOF <= 0;
// synthesis parallel_case full_case
casez (state)
3'b??1: begin
index[3-1:0] = 0;
if (syncFlag) begin
state <= 3'b010;
end
end
3'b?1?: begin
if ((index == 0)) begin
if (syncFlag) begin
state <= 3'b100;
end
else begin
state <= 3'b001;
end
end
end
3'b1??: begin
if ((index == 0)) begin
if ((!syncFlag)) begin
state <= 3'b001;
end
end
SOF <= (index == (8 - 1));
end
default: begin
$display("Verilog: ValueError(Undefined state)");
$finish;
end
endcase
index[3-1:0] = ((index + 1) % 8);
end
end
endmodule
Known issues
============
Negative values of :class:`intbv` instances are not supported.
The :class:`intbv` class is quite capable of representing negative
values. However, the ``signed`` type support in Verilog is
relatively recent and mapping to it may be tricky. In my judgment,
this was not the most urgent requirement, so I decided to leave this
for later.
Verilog integers are 32 bit wide
Usually, Verilog integers are 32 bit wide. In contrast, Python is
moving toward integers with undefined width. Python :class:`int` and
:class:`long` variables are mapped to Verilog integers; so for
values wider than 32 bit this mapping is incorrect.
Synthesis pragmas are specified as Verilog comments.
The recommended way to specify synthesis pragmas in Verilog is
through attribute lists. However, my Verilog simulator (Icarus)
doesnt support them for ``case`` statements (to specify
``parallelcase`` and ``fullcase`` pragmas). Therefore, I still used
the old but deprecated method of synthesis pragmas in Verilog
comments.
Inconsistent place of the sensitivity list inferred from ``alwayscomb``.
The semantics of ``alwayscomb``, both in Verilog and MyHDL, is to
have an implicit sensitivity list at the end of the code. However,
this may not be synthesizable. Therefore, the inferred sensitivity
list is put at the top of the corresponding ``always`` block. This
may cause inconsistent behavior at the start of the simulation. The
workaround is to create events at time 0.
Non-blocking assignments to task arguments dont work.
I didnt get non-blocking (signal) assignments to task arguments to
work. I dont know yet whether the issue is my own, a Verilog issue,
or an issue with my Verilog simulator Icarus. Ill need to check
this further.

587
doc/source/whatsnew/0.5.rst Normal file
View File

@ -0,0 +1,587 @@
.. currentmodule:: myhdl
.. _new05:
=======================
What's new in MyHDL 0.5
=======================
:Author: Jan Decaluwe
Modeling
========
Creating generators with decorators
-----------------------------------
Introduction
~~~~~~~~~~~~
Python 2.4 introduced a new feature called *decorators*. A decorator consists
of special syntax in front of a function declaration. It refers to a decorator
function. The decorator function automatically transforms the declared function
into some other callable object.
MyHDL 0.5 defines decorators that can be used to create ready-to-run generators
from local functions. The use of decorators results in clearer, more explicit
code.
The ``@instance`` decorator
~~~~~~~~~~~~~~~~~~~~~~~~~~~
The ``@instance`` decorator is the most general decorator in MyHDL.
In earlier versions of MyHDL, local generator functions are typically used as
follows:
::
def top(...):
...
def gen_func():
<generator body>
...
inst = gen_func()
...
return inst, ...
Note that the generator function :func:`gen_func()` is intended to be called
exactly once, and that its name is not necessary anymore afterwards. In MyHDL
0.5, this can be rewritten as follows, using the ``@instance`` decorator:
::
def top(...):
...
@instance
def inst():
<generator body>
...
return inst, ...
Behind the curtains, the ``@instance`` decorator automatically creates a
generator by calling the generator function, and by reusing its name. Note that
it is placed immediately in front of the corresponding generator function,
resulting in clearer code.
The ``@always`` decorator
~~~~~~~~~~~~~~~~~~~~~~~~~
The ``@always`` decorator is a specialized decorator that targets a very
popular coding pattern. It is used as follows:
::
def top(...):
...
@always(event1, event2, ...)
def inst()
<body>
...
return inst, ...
The meaning of this code is that the decorated function is executed whenever
one of the events occurs. The argument list of the decorator corresponds to the
sensitivity list. Appropriate events are edge specifiers, signals, and delay
objects. The decorated function is a classic function instead of a generator
function.
Behind the curtains, the ``always`` decorator creates an enclosing ``while
True`` loop automatically, and inserts a ``yield`` statement with the
sensitivity list.
The ``@always_comb`` decorator
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The ``@always_comb`` decorator is used to describe combinatorial logic. It is
nothing else than the :func:`always_comb` function from earlier MyHDL versions
used as a decorator:
::
def top(...):
...
@always_comb
def comb_inst():
<combinatorial body>
...
return comb_inst, ...
The ``@always_comb`` decorator infers the inputs of the combinatorial logic and
the corresponding sensitivity list automatically.
More information
~~~~~~~~~~~~~~~~
For more information about the background and the design decisions regarding
MyHDL decorators, see `mep-100`_.
Recommended style changes
-------------------------
Decorator usage
~~~~~~~~~~~~~~~
The use of decorators has clear advantages in terms of code clarity. Therefore,
it is recommended that all local generators be created using decorators.
Edge specifiers
~~~~~~~~~~~~~~~
Signal edges are typically specified using the :func:`posedge()` and
:func:`negedge()` functions in MyHDL. However, these functions are simply
wrappers around attributes with the same name. The design decision to use
functions have been reviewed and found questionable. In fact, using the
attributes directly instead has significant advantages, listed in order of
increasing significance:
* one character less to type
* more object-oriented style
* less symbols in the ``myhdl`` namespace
* no brackets, which is better for clarity
* no function call overhead
From MyHDL 0.5 on, it is therefore recommended to use the edge specifier
attributes. For example:
::
clk.posedge # instead of posedge(clk)
rst.negedge # instead of negedge(clk)
Deprecated features
-------------------
Edge specifier functions
~~~~~~~~~~~~~~~~~~~~~~~~
Functions :func:`posedge()` and :func:`negedge()` are deprecated. As discussed
before, it is recommended to use the signal attributes with the same name
instead.
In MyHDL 0.5, the functions will be removed from all documentation and
examples. They will be removed from MyHDL in a future version.
processes() function
~~~~~~~~~~~~~~~~~~~~
Function :func:`processes()` is deprecated. It looks up local generator functions and
calls them to create generators. When MyHDL 0.5 decorators are used as
recommended, this functionality becomes superfluous as it is part of the
decorator functionality.
On the other hand, the companion function :func:`instances()` continues to be
relevant and useful. It merely looks up instances in a local namespace. Having
a single lookup function will also improve usability.
In MyHDL 0.5, the :func:`processes()` function will be removed from all documentation
and examples. It will be removed from MyHDL in a future version.
Backwards incompatible changes
------------------------------
Default initial value of an intbv instance
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
It has always been possible to construct an :class:`intbv` instance without
explicit initial value:
::
m = intbv()
Prior to MyHDL 0.4, the default initial value was ``0``. In MyHDL 0.5, this has
been changed to ``None``. This is a first step towards support for ``X`` and
``Z`` functionality as found in other HDLs. This may be occasionally useful :-)
For example, it may be meaningful to initialize memory locations to ``None`` to
make sure that they will not be read before they have been initialized. If
``None`` is supported, it seems also logical to make it the default initial
value, to be interpreted as "No value".
**Warning**: if you have calls like the above in your code, it will probably
fail with MyHDL 0.5, as many integer-like operations are not supported with
`None` values.
**Workaround**: change your existing code by using ``0`` as an explicit initial
value, like so::
m = intbv(0)
Python version
--------------
Because of the usage of new features such as decorators, MyHDL 0.5 requires
upgrading to Python 2.4 or higher.
Verilog conversion
==================
Decorator support
-----------------
The Verilog convertor was enhanced to support the proposed decorators.
Mapping a list of signals to a RAM memory
-----------------------------------------
Certain synthesis tools can map Verilog memories to memory structures. For
example, this is supported by the Xilinx toolset. To support this interesting
feature, the Verilog convertor now maps lists of signals in MyHDL to Verilog
memories.
The following MyHDL example is a ram model that uses a list of signals to model
the internal memory.
::
def RAM(dout, din, addr, we, clk, depth=128):
""" Ram model """
mem = [Signal(intbv(0)[8:]) for i in range(depth)]
@always(clk.posedge)
def write():
if we:
mem[int(addr)].next = din
@always_comb
def read():
dout.next = mem[int(addr)]
return write, read
With the appropriate signal definitions for the interface ports, it is mapped
by :func:`toVerilog` to the following Verilog code. Note how the list of signals
``mem`` is mapped to a Verilog memory.
::
module RAM (
dout,
din,
addr,
we,
clk
);
output [7:0] dout;
wire [7:0] dout;
input [7:0] din;
input [6:0] addr;
input we;
input clk;
reg [7:0] mem [0:128-1];
always @(posedge clk) begin: _RAM_write
if (we) begin
mem[addr] <= din;
end
end
assign dout = mem[addr];
endmodule
Lists of signals can also be used in MyHDL to elegantly describe iterative
hierarchical structures. (See the MyHDL manual.) However, there is an important
difference: such signals will have a name at some level of the hierarchy, while
in the case described above, the individual signals are anonymous. The
:func:`toVerilog` convertor detects which case we are in. In the first case,
the individual signals will still be declared in the Verilog output, using the
highest-level hierarchical name. It is only in the second case that the list of
signals is declared as a Verilog memory.
Mapping combinatorial logic to assign statements
------------------------------------------------
When possible, combinatorial logic is now converted to Verilog assign
statements. There are two conditions for this to happen. First, the logic has
to be explicitly described as a combinatorial function using the
``@always_comb`` decorator. Secondly, the function has to be simple enough so
that a mapping to assign statements is possible: only signal assignments are
permitted. Otherwise, a Verilog always block is used as previously.
See the RAM model of the previous section for an example.
This was done because certain synthesis tools require assign statements to
recognize code templates.
Mapping a tuple of integers to a ROM memory
--------------------------------------------
Some synthesis tools, such as the Xilinx tool, can infer a ROM memory from a
case statement. :func:`toVerilog` has been enhanced to do the expansion into a
case statement automatically, based on a higher level description. The rom
access is described in a single line, by indexing into a tuple of integers. The
tuple can be described manually, but also by programmatical means. Note that a
tuple is used instead of a list to stress the read-only character of the
memory.
The following example illustrates this functionality.
::
def rom(dout, addr, CONTENT):
@always_comb
def read():
dout.next = CONTENT[int(addr)]
return read
dout = Signal(intbv(0)[8:])
addr = Signal(intbv(0)[4:])
CONTENT = (17, 134, 52, 9)
toVerilog(rom, dout, addr, CONTENT)
The output Verilog code is as follows:
::
module rom (
dout,
addr
);
output [7:0] dout;
reg [7:0] dout;
input [3:0] addr;
always @(addr) begin: _rom_read
// synthesis parallel_case full_case
case (addr)
0: dout <= 17;
1: dout <= 134;
2: dout <= 52;
default: dout <= 9;
endcase
end
endmodule
Support for signed arithmetic
-----------------------------
Getting signed representations right in Verilog is tricky. One issue is that a
signed representation is treated as a special case, and unsigned as the rule.
For example, whenever one of the operands in an expression is unsigned, all
others are also treated like unsigned. While this is understandable from a
historical perspective (for backwards compatibility reasons) it is the opposite
from what one expects from a high-level point of view, when working with
negative numbers. The basic problem is that a Verilog user has to deal with
representation explicitly in all cases, even for abstract integer operations.
It would be much better to leave representational issues to a tool.
MyHDL doesn't make the distinction between signed and unsigned. The
:class:`intbv` class can handle any kind of integer, including negative ones.
If required, you can access the 2's complement representation of an
:class:`intbv` object, but for integer operations such a counting, there is no
need to worry about this.
Of course, the Verilog convertor has to deal with the representation carefully.
MyHDL 0.4 avoided the issue by simply prohibiting :class:`intbv` objects with
negative values. MyHDL 0.5 adds support for negative values and uses the signed
Verilog representation to accomplish this.
The problematic cases are those when signed and unsigned representations are
mixed in Verilog expressions. The convertor avoids this by making sure that
signed arithmetic is used whenever one of the operands is signed. Note that
this is exactly the opposite of the Verilog default. More specifically, the
convertor may convert an unsigned operand by adding a sign bit and casting to a
signed interpretation, using the Verilog ``$signed`` function. Operands that
are treated like this are positive :class:`intbv` objects, slices and
subscripts of :class:`intbv` objects, and :class:`bool` objects.
Integer constants are treated as a special case. Unsized integer numbers were
always treated as signed numbers in Verilog. However, as their representation
is minimally 32 bits wide, they usually don't give problems when mixed with
unsigned numbers. Therefore, integer constants don't cause signed casting of
other operands in the same expression: users would actually find it surprizing
if they did.
Support for user-defined Verilog code
-------------------------------------
Introduction
~~~~~~~~~~~~
In order to provide a path to implementation, MyHDL code can be converted to
Verilog. However, in some cases the conversion may fail or the result may not
be acceptable. For example:
* conversion will fail if the MyHDL code doesn't follow the rules of the convertible subset
* a user may want to explicitly instantiate an existing Verilog module, instead of converting the corresponding MyHDL code
* it may be necessary to include technology-dependent modules in the Verilog output
As a conclusion, MyHDL users need a method to include user-defined Verilog code
during the conversion process.
Solution
~~~~~~~~
MyHDL 0.5 defines a hook that is understood by ``toVerilog`` but ignored by the
MyHDL simulator. The hook is called ``__verilog__``. Its operation can be
understood as a special return value. When a MyHDL function defines
``__verilog__``, the Verilog converter will use its value instead of the
regular return value.
The value of ``__verilog__`` should be a format string that uses keys in its
format specifiers. The keys refer to the variable names in the context of the
string.
Example::
def inc_comb(nextCount, count, n):
@always_comb
def logic():
nextCount.next = (count + 1) % n
__verilog__ = \
"""
assign %(nextCount)s = (%(count)s + 1) %% %(n)s;
"""
nextCount.driven = "wire"
return logic
In this example, conversion of the ``inc_comb`` function is bypassed and the
user-defined Verilog code is inserted instead. Note that the user-defined code
refers to signals and parameters in the MyHDL context by using format
specifiers. During conversion, the appropriate hierarchical names and parameter
values will be filled in. Note also that the format specifier indicator `%`
needs to be escaped (by doubling it) if it is required in the user-defined
code.
There is one more issue that needs user attention. Normally, the Verilog
convertor infers inputs, internal signals, and outputs. It also detects
undriven and multiple driven signals. To do this, it assumes that signals are
not driven by default. It then processes the code to find out which signals are
driven from where. However, it cannot do this for user-defined code. Without
additional help, this will result in warnings or errors during the inference
process, or in compilation errors from invalid Verilog code. The user should
solve this by setting the ``driven`` attribute for signals that are driven from
the user-defined code. In the example code above, note the following
assignment::
nextCount.driven = "wire"
This specifies that the ``nextCount`` signal is driven as a Verilog wire from
this module. The allowed values of the ``driven`` attribute are ``"wire"`` and
``"reg"``. The value specifies how the user-defined Verilog code drives the
signal in Verilog. To decide which value to use, consider how the signal should
be declared in Verilog after the user-defined code is inserted.
Limitations
~~~~~~~~~~~
It is not possible to use the ``__verilog__`` hook in a generator function -
it should be in a classic function. This is because in MyHDL those functions
are completely run (elaborated) before the conversion starts, while generator
functions are not.
More info
~~~~~~~~~
For more information about the background and the design decisions regarding
user-defined Verilog code, see `mep-101`_.
Backwards incompatible changes
------------------------------
Verilog conversion output filename
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A Verilog conversion is performed with a call that looks as follows::
instance_name = toVerilog(func, ...)
In MyHDL 0.4, the Verilog output filename was called ``instance_name.v``. In
MyHDL 0.5, the default output filename is ``func_name.v``, where ``func_name``
is the name of the function, available as the ``func.func_name`` attribute.
This was done for the following reasons. The MyHDL 0.4 was overly clever and
therefore complicated. It involves frame handling and parsing the source file
for the assignment pattern. Besides being too clever, it also had awkward
limitations. For example, it was not possible to construct a dynamic name for
the instance, which is very un-Pythonic behavior.
Both the implementation complexity and the limitations are gone with the new
behavior: the name of the top-level function argument is simply used. In
addition, it is now possible to specify a user-defined name for the instance as
follows::
toVerilog.name = "my_name"
toVerilog(func, ....)
To support this feature, it was necessary to make toVerilog an instance of a
class with a call interface.
**Warning**: When existing converting code is re-run, the Verilog output
filename will be different than in 0.4.
Simulation
==========
Performance optimizations
-------------------------
To improve the simulation performance of MyHDL, we mainly put our trust in
Python development itself. There are good reasons to be optimistic.
What MyHDL itself can do is to minimize the overhead of the simulation loop. In
MyHDL 0.5, a first step was taken in this respect.
MyHDL supports a number of "trigger objects". These are the objects that can
occur in ``yield`` statements, for example :class:`delay`, ``posedge``,
:class:`Signal`, and generator objects. Each of these are handled differently
and so the simulation loop has to account for the object type. Prior to MyHDL
0.5, this type check was explicitly done for each occurence of a ``yield``
statement during simulation. As many generators will loop endlessly, it is
clear that the same things will be checked over and over again, resulting in an
important overhead.
In MyHDL 0.5, all generators are predigested. Certain trigger object patterns
that tend to occur often are given specialized simulation handlers, so that
continuously performing the same type check is avoided. More specifically, they
consist of generators that only contain ``yield`` statements with a specific
argument. Currently, 5 different kinds of generators are recognized and
accelerated, corresponding to the following ``yield`` statement arguments:
* a :class:`delay` object
* a :class:`Signal` object
* a tuple of :class:`Signal` objects
* a ``posedge`` or ``negedge`` object
* a tuple of ``posedge`` and/or ``negedge`` objects
Backwards incompatible changes
------------------------------
Waveform tracing output filename
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Waveform tracing is initiated by a call that looks as follows::
instance_name = traceSignals(func, ...)
In MyHDL 0.4, the output filename was called `instance_name.vcd`. In MyHDL 0.5,
the default output filename is `func_name.vcd`, where `func_name` is the name
of the function, available as the `func.func_name` attribute.
This was done for the same reasons as in the similar case for `toVerilog`, as
described earlier.
A user-defined name for the output file can be specified as follows::
traceSignals.name = "my_name"
inst = traceSignals(func, ....)
**Warning**: When existing converting code is re-run, the vcd output filename
will be different than in 0.4.
.. _mep-100: http://dev.myhdl.org/meps/mep-100.html
.. _mep-101: http://dev.myhdl.org/meps/mep-101.html

View File

@ -6,22 +6,26 @@
What's new in MyHDL 0.9
***********************
Interfaces
===========
Python 3 support
================
Experimental Python 3 support has been added to MyHDL 0.9.
This was a major effort to modernize the code. As a result,
Python 2 and 3 are supported from a single codebase.
See :doc:`/python3` for more info.
Interfaces (Conversion of attribute accesses)
=============================================
Rationale
---------
Complex designs often have many signals (ports) that are passed to
different levels of hierarchy. Typically, many of the signals can
logically be grouped together. Grouping the signals into an
*interface* simplifies the code, improves efficiency, and reduces
errors.
An *interface* is a collection of signals (:class:`Signal`) embedded
in an class/object as attributes. This provides a natural method
to group related signals and provides intuitive access through
attributes. Multiple level of objects and attibutes provides a
hierarchy of signal structure if desired.
Complex designs often have many signals that are passed to different levels of
hierarchy. Typically, many signals logically belong together. This can be
modelled by an *interface*: an object that has a number of :class:`Signal`
objects as its attributes. Grouping signals into an interface simplifies the
code, improves efficiency, and reduces errors.
The following is an example of an *interface* definition::
@ -31,18 +35,10 @@ The following is an example of an *interface* definition::
self.imag = Signal(intbv(0, min=min, max=max))
Previous versions supported *interfaces* for modeling and for
conversion if the attributes were locally referenced in a MyHDL
module outside of the `MyHDL generator`_. If the attributes were
directly referenced in the `MyHDL generator`_ the code would not be
convertible.
Although previous versions supported interfaces for modeling, they were not
convertible. MyHDL 0.9 now supports conversion of designs that use interfaces.
This features adds the ability to convert attributes that are
:class:`Signal` and referenced in the `MyHDL generator`_. This is
an evolution of a useful construct.
The following
is an example using the above ``Complex`` interface definition::
The following is an example using the above ``Complex`` interface definition::
a,b = Complex(-8,8), Complex(-8,8)
c = Complex(-128,128)
@ -59,34 +55,18 @@ is an example using the above ``Complex`` interface definition::
Solution
--------
The proposed solution is to create unique names for attributes which
are type :class:`Signal` and used by a `MyHDL generator`_. The
converter will create a unique name by using the name of the parent
and the name of the attribute along with the name of the MyHDL module
instance (if required for uniqueness). The converter will essentially
replace the "." with an "_" for each *interface* element.
Even though the target HDLs do not support *interfaces*, MyHDL is
able to add high-level features that compile during conversion to the
target HDL (Verilog and VHDL).
Conversion
----------
.. add details of the conversion, what policies are used to name
.. extend the Signals. Any useful information about the approach
.. or structure in the converter used.
Limitations
-----------
The current implementation only converts ``Signal`` attributes and
constants (read-only ints). Other Python structures will not be
analyzed (e.g. dict) and attributes used as variables will not be
converted.
The proposed solution is to create unique names for attributes which are used
by `MyHDL generator`_\s. The converter will create a unique name by using the
name of the parent and the name of the attribute along with the name of the
MyHDL module instance. The converter will essentially replace the "." with an
"_" for each interface element. In essence, interfaces are supported
using hierarchical name expansion and name mangling.
Note that the MyHDL convertor supports interfaces, even though
the target HDLs do not. This is another great example where the
convertor supports a high-level feature that is not available
in the target HDLs.
See also
--------
@ -94,3 +74,41 @@ For additional information see the original proposal `mep-107`_.
.. _mep-107: http://dev.myhdl.org/meps/mep-107.html
.. _MyHDL generator: http://docs.myhdl.org/en/latest/manual/reference.html#myhdl-generators-and-trigger-objects
Other noteworthy improvements
=============================
``ConcatSignal`` interface
--------------------------
The interface of :class:`ConcatSignal` was enhanced. In
addition to signals, you can now also use constant values
in the concatenation.
``std_logic`` type ports
------------------------
:func:`toVHDL` has a new attibute ``std_logic_ports``. When
set, only ``std_logic`` type ports are used in the interface
of the top-level VHDL module.
Development flow
----------------
The MyHDL development flow has been modernized by moving to git and `github`_
for version control. In addition, travis has set up so that all pull requests
are tested automatically, enabling continuous intergration.
Acknowledgments
===============
The Python 3 support effort was coordinated by Keerthan Jaic, who also
implemented most of if. Convertible interfaces were championed by Chris Felton,
and implemented by Keerthan Jaic.
MyHDL development is a collaborative effort, as can be seen on `github`_.
Thanks to all who contributed with suggestions, issues and pull requests.
.. _github: https://www.github.com/jandecaluwe/myhdl

View File

@ -0,0 +1,14 @@
.. currentmodule:: myhdl
.. _new10:
***********************
What's new in MyHDL 1.0
***********************
The `block` decorator
=====================
See `mep-114`_.
.. _mep-114: http://dev.myhdl.org/meps/mep-114.html

View File

@ -1,3 +1,4 @@
import myhdl
from myhdl import *
from arith_utils import BEHAVIOR
from PrefixAnd import PrefixAnd

View File

@ -1,3 +1,4 @@
import myhdl
from myhdl import *
from arith_utils import BEHAVIOR
from PrefixAnd import PrefixAnd

View File

@ -1,3 +1,4 @@
import myhdl
from myhdl import *
from arith_utils import log2ceil

View File

@ -1,6 +1,7 @@
import unittest
from unittest import TestCase
import myhdl
from myhdl import *
from arith_utils import BEHAVIOR, STRUCTURE

View File

@ -1,6 +1,7 @@
import unittest
from unittest import TestCase
import myhdl
from myhdl import *
from arith_utils import BEHAVIOR, STRUCTURE

View File

@ -0,0 +1,497 @@
// File: Array8Sorter.v
// Generated by MyHDL 1.0dev
// Date: Sun May 15 11:40:06 2016
`timescale 1ns/10ps
module Array8Sorter (
a0,
a1,
a2,
a3,
a4,
a5,
a6,
a7,
z0,
z1,
z2,
z3,
z4,
z5,
z6,
z7
);
input [3:0] a0;
input [3:0] a1;
input [3:0] a2;
input [3:0] a3;
input [3:0] a4;
input [3:0] a5;
input [3:0] a6;
input [3:0] a7;
output [3:0] z0;
wire [3:0] z0;
output [3:0] z1;
wire [3:0] z1;
output [3:0] z2;
wire [3:0] z2;
output [3:0] z3;
wire [3:0] z3;
output [3:0] z4;
wire [3:0] z4;
output [3:0] z5;
wire [3:0] z5;
output [3:0] z6;
wire [3:0] z6;
output [3:0] z7;
wire [3:0] z7;
wire [3:0] sort_losort_losort_losort_feedthru_32_z;
wire [3:0] sort_losort_losort_hisort_feedthru_33_z;
reg [3:0] sort_losort_losort_merge_comp_24_z1;
reg [3:0] sort_losort_losort_merge_comp_24_z2;
wire [3:0] sort_losort_losort_merge_lomerge_feedthru_34_z;
wire [3:0] sort_losort_losort_merge_hiMerge_feedthru_35_z;
wire [3:0] sort_losort_hisort_losort_feedthru_36_z;
wire [3:0] sort_losort_hisort_hisort_feedthru_37_z;
reg [3:0] sort_losort_hisort_merge_comp_25_z1;
reg [3:0] sort_losort_hisort_merge_comp_25_z2;
wire [3:0] sort_losort_hisort_merge_lomerge_feedthru_38_z;
wire [3:0] sort_losort_hisort_merge_hiMerge_feedthru_39_z;
reg [3:0] sort_losort_merge_comp_26_z1;
reg [3:0] sort_losort_merge_comp_26_z2;
reg [3:0] sort_losort_merge_comp_27_z1;
reg [3:0] sort_losort_merge_comp_27_z2;
reg [3:0] sort_losort_merge_lomerge_comp_28_z1;
reg [3:0] sort_losort_merge_lomerge_comp_28_z2;
wire [3:0] sort_losort_merge_lomerge_lomerge_feedthru_40_z;
wire [3:0] sort_losort_merge_lomerge_hiMerge_feedthru_41_z;
reg [3:0] sort_losort_merge_hiMerge_comp_29_z1;
reg [3:0] sort_losort_merge_hiMerge_comp_29_z2;
wire [3:0] sort_losort_merge_hiMerge_lomerge_feedthru_42_z;
wire [3:0] sort_losort_merge_hiMerge_hiMerge_feedthru_43_z;
wire [3:0] sort_hisort_losort_losort_feedthru_44_z;
wire [3:0] sort_hisort_losort_hisort_feedthru_45_z;
reg [3:0] sort_hisort_losort_merge_comp_30_z1;
reg [3:0] sort_hisort_losort_merge_comp_30_z2;
wire [3:0] sort_hisort_losort_merge_lomerge_feedthru_46_z;
wire [3:0] sort_hisort_losort_merge_hiMerge_feedthru_47_z;
wire [3:0] sort_hisort_hisort_losort_feedthru_48_z;
wire [3:0] sort_hisort_hisort_hisort_feedthru_49_z;
reg [3:0] sort_hisort_hisort_merge_comp_31_z1;
reg [3:0] sort_hisort_hisort_merge_comp_31_z2;
wire [3:0] sort_hisort_hisort_merge_lomerge_feedthru_50_z;
wire [3:0] sort_hisort_hisort_merge_hiMerge_feedthru_51_z;
reg [3:0] sort_hisort_merge_comp_32_z1;
reg [3:0] sort_hisort_merge_comp_32_z2;
reg [3:0] sort_hisort_merge_comp_33_z1;
reg [3:0] sort_hisort_merge_comp_33_z2;
reg [3:0] sort_hisort_merge_lomerge_comp_34_z1;
reg [3:0] sort_hisort_merge_lomerge_comp_34_z2;
wire [3:0] sort_hisort_merge_lomerge_lomerge_feedthru_52_z;
wire [3:0] sort_hisort_merge_lomerge_hiMerge_feedthru_53_z;
reg [3:0] sort_hisort_merge_hiMerge_comp_35_z1;
reg [3:0] sort_hisort_merge_hiMerge_comp_35_z2;
wire [3:0] sort_hisort_merge_hiMerge_lomerge_feedthru_54_z;
wire [3:0] sort_hisort_merge_hiMerge_hiMerge_feedthru_55_z;
reg [3:0] sort_merge_comp_36_z1;
reg [3:0] sort_merge_comp_36_z2;
reg [3:0] sort_merge_comp_37_z1;
reg [3:0] sort_merge_comp_37_z2;
reg [3:0] sort_merge_comp_38_z1;
reg [3:0] sort_merge_comp_38_z2;
reg [3:0] sort_merge_comp_39_z1;
reg [3:0] sort_merge_comp_39_z2;
reg [3:0] sort_merge_lomerge_comp_40_z1;
reg [3:0] sort_merge_lomerge_comp_40_z2;
reg [3:0] sort_merge_lomerge_comp_41_z1;
reg [3:0] sort_merge_lomerge_comp_41_z2;
reg [3:0] sort_merge_lomerge_lomerge_comp_42_z1;
reg [3:0] sort_merge_lomerge_lomerge_comp_42_z2;
reg [3:0] sort_merge_lomerge_hiMerge_comp_43_z1;
reg [3:0] sort_merge_lomerge_hiMerge_comp_43_z2;
reg [3:0] sort_merge_hiMerge_comp_44_z1;
reg [3:0] sort_merge_hiMerge_comp_44_z2;
reg [3:0] sort_merge_hiMerge_comp_45_z1;
reg [3:0] sort_merge_hiMerge_comp_45_z2;
reg [3:0] sort_merge_hiMerge_lomerge_comp_46_z1;
reg [3:0] sort_merge_hiMerge_lomerge_comp_46_z2;
reg [3:0] sort_merge_hiMerge_hiMerge_comp_47_z1;
reg [3:0] sort_merge_hiMerge_hiMerge_comp_47_z2;
assign sort_losort_losort_losort_feedthru_32_z = a0;
assign sort_losort_losort_hisort_feedthru_33_z = a1;
always @(sort_losort_losort_losort_feedthru_32_z, sort_losort_losort_hisort_feedthru_33_z) begin: ARRAY8SORTER_SORT_LOSORT_LOSORT_MERGE_COMP_24_LOGIC
sort_losort_losort_merge_comp_24_z1 = sort_losort_losort_losort_feedthru_32_z;
sort_losort_losort_merge_comp_24_z2 = sort_losort_losort_hisort_feedthru_33_z;
if ((1'b1 == (sort_losort_losort_losort_feedthru_32_z > sort_losort_losort_hisort_feedthru_33_z))) begin
sort_losort_losort_merge_comp_24_z1 = sort_losort_losort_hisort_feedthru_33_z;
sort_losort_losort_merge_comp_24_z2 = sort_losort_losort_losort_feedthru_32_z;
end
end
assign sort_losort_losort_merge_lomerge_feedthru_34_z = sort_losort_losort_merge_comp_24_z1;
assign sort_losort_losort_merge_hiMerge_feedthru_35_z = sort_losort_losort_merge_comp_24_z2;
assign sort_losort_hisort_losort_feedthru_36_z = a2;
assign sort_losort_hisort_hisort_feedthru_37_z = a3;
always @(sort_losort_hisort_losort_feedthru_36_z, sort_losort_hisort_hisort_feedthru_37_z) begin: ARRAY8SORTER_SORT_LOSORT_HISORT_MERGE_COMP_25_LOGIC
sort_losort_hisort_merge_comp_25_z1 = sort_losort_hisort_losort_feedthru_36_z;
sort_losort_hisort_merge_comp_25_z2 = sort_losort_hisort_hisort_feedthru_37_z;
if ((1'b0 == (sort_losort_hisort_losort_feedthru_36_z > sort_losort_hisort_hisort_feedthru_37_z))) begin
sort_losort_hisort_merge_comp_25_z1 = sort_losort_hisort_hisort_feedthru_37_z;
sort_losort_hisort_merge_comp_25_z2 = sort_losort_hisort_losort_feedthru_36_z;
end
end
assign sort_losort_hisort_merge_lomerge_feedthru_38_z = sort_losort_hisort_merge_comp_25_z1;
assign sort_losort_hisort_merge_hiMerge_feedthru_39_z = sort_losort_hisort_merge_comp_25_z2;
always @(sort_losort_losort_merge_lomerge_feedthru_34_z, sort_losort_hisort_merge_lomerge_feedthru_38_z) begin: ARRAY8SORTER_SORT_LOSORT_MERGE_COMP_26_LOGIC
sort_losort_merge_comp_26_z1 = sort_losort_losort_merge_lomerge_feedthru_34_z;
sort_losort_merge_comp_26_z2 = sort_losort_hisort_merge_lomerge_feedthru_38_z;
if ((1'b1 == (sort_losort_losort_merge_lomerge_feedthru_34_z > sort_losort_hisort_merge_lomerge_feedthru_38_z))) begin
sort_losort_merge_comp_26_z1 = sort_losort_hisort_merge_lomerge_feedthru_38_z;
sort_losort_merge_comp_26_z2 = sort_losort_losort_merge_lomerge_feedthru_34_z;
end
end
always @(sort_losort_losort_merge_hiMerge_feedthru_35_z, sort_losort_hisort_merge_hiMerge_feedthru_39_z) begin: ARRAY8SORTER_SORT_LOSORT_MERGE_COMP_27_LOGIC
sort_losort_merge_comp_27_z1 = sort_losort_losort_merge_hiMerge_feedthru_35_z;
sort_losort_merge_comp_27_z2 = sort_losort_hisort_merge_hiMerge_feedthru_39_z;
if ((1'b1 == (sort_losort_losort_merge_hiMerge_feedthru_35_z > sort_losort_hisort_merge_hiMerge_feedthru_39_z))) begin
sort_losort_merge_comp_27_z1 = sort_losort_hisort_merge_hiMerge_feedthru_39_z;
sort_losort_merge_comp_27_z2 = sort_losort_losort_merge_hiMerge_feedthru_35_z;
end
end
always @(sort_losort_merge_comp_26_z1, sort_losort_merge_comp_27_z1) begin: ARRAY8SORTER_SORT_LOSORT_MERGE_LOMERGE_COMP_28_LOGIC
sort_losort_merge_lomerge_comp_28_z1 = sort_losort_merge_comp_26_z1;
sort_losort_merge_lomerge_comp_28_z2 = sort_losort_merge_comp_27_z1;
if ((1'b1 == (sort_losort_merge_comp_26_z1 > sort_losort_merge_comp_27_z1))) begin
sort_losort_merge_lomerge_comp_28_z1 = sort_losort_merge_comp_27_z1;
sort_losort_merge_lomerge_comp_28_z2 = sort_losort_merge_comp_26_z1;
end
end
assign sort_losort_merge_lomerge_lomerge_feedthru_40_z = sort_losort_merge_lomerge_comp_28_z1;
assign sort_losort_merge_lomerge_hiMerge_feedthru_41_z = sort_losort_merge_lomerge_comp_28_z2;
always @(sort_losort_merge_comp_26_z2, sort_losort_merge_comp_27_z2) begin: ARRAY8SORTER_SORT_LOSORT_MERGE_HIMERGE_COMP_29_LOGIC
sort_losort_merge_hiMerge_comp_29_z1 = sort_losort_merge_comp_26_z2;
sort_losort_merge_hiMerge_comp_29_z2 = sort_losort_merge_comp_27_z2;
if ((1'b1 == (sort_losort_merge_comp_26_z2 > sort_losort_merge_comp_27_z2))) begin
sort_losort_merge_hiMerge_comp_29_z1 = sort_losort_merge_comp_27_z2;
sort_losort_merge_hiMerge_comp_29_z2 = sort_losort_merge_comp_26_z2;
end
end
assign sort_losort_merge_hiMerge_lomerge_feedthru_42_z = sort_losort_merge_hiMerge_comp_29_z1;
assign sort_losort_merge_hiMerge_hiMerge_feedthru_43_z = sort_losort_merge_hiMerge_comp_29_z2;
assign sort_hisort_losort_losort_feedthru_44_z = a4;
assign sort_hisort_losort_hisort_feedthru_45_z = a5;
always @(sort_hisort_losort_losort_feedthru_44_z, sort_hisort_losort_hisort_feedthru_45_z) begin: ARRAY8SORTER_SORT_HISORT_LOSORT_MERGE_COMP_30_LOGIC
sort_hisort_losort_merge_comp_30_z1 = sort_hisort_losort_losort_feedthru_44_z;
sort_hisort_losort_merge_comp_30_z2 = sort_hisort_losort_hisort_feedthru_45_z;
if ((1'b1 == (sort_hisort_losort_losort_feedthru_44_z > sort_hisort_losort_hisort_feedthru_45_z))) begin
sort_hisort_losort_merge_comp_30_z1 = sort_hisort_losort_hisort_feedthru_45_z;
sort_hisort_losort_merge_comp_30_z2 = sort_hisort_losort_losort_feedthru_44_z;
end
end
assign sort_hisort_losort_merge_lomerge_feedthru_46_z = sort_hisort_losort_merge_comp_30_z1;
assign sort_hisort_losort_merge_hiMerge_feedthru_47_z = sort_hisort_losort_merge_comp_30_z2;
assign sort_hisort_hisort_losort_feedthru_48_z = a6;
assign sort_hisort_hisort_hisort_feedthru_49_z = a7;
always @(sort_hisort_hisort_losort_feedthru_48_z, sort_hisort_hisort_hisort_feedthru_49_z) begin: ARRAY8SORTER_SORT_HISORT_HISORT_MERGE_COMP_31_LOGIC
sort_hisort_hisort_merge_comp_31_z1 = sort_hisort_hisort_losort_feedthru_48_z;
sort_hisort_hisort_merge_comp_31_z2 = sort_hisort_hisort_hisort_feedthru_49_z;
if ((1'b0 == (sort_hisort_hisort_losort_feedthru_48_z > sort_hisort_hisort_hisort_feedthru_49_z))) begin
sort_hisort_hisort_merge_comp_31_z1 = sort_hisort_hisort_hisort_feedthru_49_z;
sort_hisort_hisort_merge_comp_31_z2 = sort_hisort_hisort_losort_feedthru_48_z;
end
end
assign sort_hisort_hisort_merge_lomerge_feedthru_50_z = sort_hisort_hisort_merge_comp_31_z1;
assign sort_hisort_hisort_merge_hiMerge_feedthru_51_z = sort_hisort_hisort_merge_comp_31_z2;
always @(sort_hisort_losort_merge_lomerge_feedthru_46_z, sort_hisort_hisort_merge_lomerge_feedthru_50_z) begin: ARRAY8SORTER_SORT_HISORT_MERGE_COMP_32_LOGIC
sort_hisort_merge_comp_32_z1 = sort_hisort_losort_merge_lomerge_feedthru_46_z;
sort_hisort_merge_comp_32_z2 = sort_hisort_hisort_merge_lomerge_feedthru_50_z;
if ((1'b0 == (sort_hisort_losort_merge_lomerge_feedthru_46_z > sort_hisort_hisort_merge_lomerge_feedthru_50_z))) begin
sort_hisort_merge_comp_32_z1 = sort_hisort_hisort_merge_lomerge_feedthru_50_z;
sort_hisort_merge_comp_32_z2 = sort_hisort_losort_merge_lomerge_feedthru_46_z;
end
end
always @(sort_hisort_losort_merge_hiMerge_feedthru_47_z, sort_hisort_hisort_merge_hiMerge_feedthru_51_z) begin: ARRAY8SORTER_SORT_HISORT_MERGE_COMP_33_LOGIC
sort_hisort_merge_comp_33_z1 = sort_hisort_losort_merge_hiMerge_feedthru_47_z;
sort_hisort_merge_comp_33_z2 = sort_hisort_hisort_merge_hiMerge_feedthru_51_z;
if ((1'b0 == (sort_hisort_losort_merge_hiMerge_feedthru_47_z > sort_hisort_hisort_merge_hiMerge_feedthru_51_z))) begin
sort_hisort_merge_comp_33_z1 = sort_hisort_hisort_merge_hiMerge_feedthru_51_z;
sort_hisort_merge_comp_33_z2 = sort_hisort_losort_merge_hiMerge_feedthru_47_z;
end
end
always @(sort_hisort_merge_comp_32_z1, sort_hisort_merge_comp_33_z1) begin: ARRAY8SORTER_SORT_HISORT_MERGE_LOMERGE_COMP_34_LOGIC
sort_hisort_merge_lomerge_comp_34_z1 = sort_hisort_merge_comp_32_z1;
sort_hisort_merge_lomerge_comp_34_z2 = sort_hisort_merge_comp_33_z1;
if ((1'b0 == (sort_hisort_merge_comp_32_z1 > sort_hisort_merge_comp_33_z1))) begin
sort_hisort_merge_lomerge_comp_34_z1 = sort_hisort_merge_comp_33_z1;
sort_hisort_merge_lomerge_comp_34_z2 = sort_hisort_merge_comp_32_z1;
end
end
assign sort_hisort_merge_lomerge_lomerge_feedthru_52_z = sort_hisort_merge_lomerge_comp_34_z1;
assign sort_hisort_merge_lomerge_hiMerge_feedthru_53_z = sort_hisort_merge_lomerge_comp_34_z2;
always @(sort_hisort_merge_comp_32_z2, sort_hisort_merge_comp_33_z2) begin: ARRAY8SORTER_SORT_HISORT_MERGE_HIMERGE_COMP_35_LOGIC
sort_hisort_merge_hiMerge_comp_35_z1 = sort_hisort_merge_comp_32_z2;
sort_hisort_merge_hiMerge_comp_35_z2 = sort_hisort_merge_comp_33_z2;
if ((1'b0 == (sort_hisort_merge_comp_32_z2 > sort_hisort_merge_comp_33_z2))) begin
sort_hisort_merge_hiMerge_comp_35_z1 = sort_hisort_merge_comp_33_z2;
sort_hisort_merge_hiMerge_comp_35_z2 = sort_hisort_merge_comp_32_z2;
end
end
assign sort_hisort_merge_hiMerge_lomerge_feedthru_54_z = sort_hisort_merge_hiMerge_comp_35_z1;
assign sort_hisort_merge_hiMerge_hiMerge_feedthru_55_z = sort_hisort_merge_hiMerge_comp_35_z2;
always @(sort_losort_merge_lomerge_lomerge_feedthru_40_z, sort_hisort_merge_lomerge_lomerge_feedthru_52_z) begin: ARRAY8SORTER_SORT_MERGE_COMP_36_LOGIC
sort_merge_comp_36_z1 = sort_losort_merge_lomerge_lomerge_feedthru_40_z;
sort_merge_comp_36_z2 = sort_hisort_merge_lomerge_lomerge_feedthru_52_z;
if ((1'b1 == (sort_losort_merge_lomerge_lomerge_feedthru_40_z > sort_hisort_merge_lomerge_lomerge_feedthru_52_z))) begin
sort_merge_comp_36_z1 = sort_hisort_merge_lomerge_lomerge_feedthru_52_z;
sort_merge_comp_36_z2 = sort_losort_merge_lomerge_lomerge_feedthru_40_z;
end
end
always @(sort_losort_merge_lomerge_hiMerge_feedthru_41_z, sort_hisort_merge_lomerge_hiMerge_feedthru_53_z) begin: ARRAY8SORTER_SORT_MERGE_COMP_37_LOGIC
sort_merge_comp_37_z1 = sort_losort_merge_lomerge_hiMerge_feedthru_41_z;
sort_merge_comp_37_z2 = sort_hisort_merge_lomerge_hiMerge_feedthru_53_z;
if ((1'b1 == (sort_losort_merge_lomerge_hiMerge_feedthru_41_z > sort_hisort_merge_lomerge_hiMerge_feedthru_53_z))) begin
sort_merge_comp_37_z1 = sort_hisort_merge_lomerge_hiMerge_feedthru_53_z;
sort_merge_comp_37_z2 = sort_losort_merge_lomerge_hiMerge_feedthru_41_z;
end
end
always @(sort_losort_merge_hiMerge_lomerge_feedthru_42_z, sort_hisort_merge_hiMerge_lomerge_feedthru_54_z) begin: ARRAY8SORTER_SORT_MERGE_COMP_38_LOGIC
sort_merge_comp_38_z1 = sort_losort_merge_hiMerge_lomerge_feedthru_42_z;
sort_merge_comp_38_z2 = sort_hisort_merge_hiMerge_lomerge_feedthru_54_z;
if ((1'b1 == (sort_losort_merge_hiMerge_lomerge_feedthru_42_z > sort_hisort_merge_hiMerge_lomerge_feedthru_54_z))) begin
sort_merge_comp_38_z1 = sort_hisort_merge_hiMerge_lomerge_feedthru_54_z;
sort_merge_comp_38_z2 = sort_losort_merge_hiMerge_lomerge_feedthru_42_z;
end
end
always @(sort_losort_merge_hiMerge_hiMerge_feedthru_43_z, sort_hisort_merge_hiMerge_hiMerge_feedthru_55_z) begin: ARRAY8SORTER_SORT_MERGE_COMP_39_LOGIC
sort_merge_comp_39_z1 = sort_losort_merge_hiMerge_hiMerge_feedthru_43_z;
sort_merge_comp_39_z2 = sort_hisort_merge_hiMerge_hiMerge_feedthru_55_z;
if ((1'b1 == (sort_losort_merge_hiMerge_hiMerge_feedthru_43_z > sort_hisort_merge_hiMerge_hiMerge_feedthru_55_z))) begin
sort_merge_comp_39_z1 = sort_hisort_merge_hiMerge_hiMerge_feedthru_55_z;
sort_merge_comp_39_z2 = sort_losort_merge_hiMerge_hiMerge_feedthru_43_z;
end
end
always @(sort_merge_comp_36_z1, sort_merge_comp_38_z1) begin: ARRAY8SORTER_SORT_MERGE_LOMERGE_COMP_40_LOGIC
sort_merge_lomerge_comp_40_z1 = sort_merge_comp_36_z1;
sort_merge_lomerge_comp_40_z2 = sort_merge_comp_38_z1;
if ((1'b1 == (sort_merge_comp_36_z1 > sort_merge_comp_38_z1))) begin
sort_merge_lomerge_comp_40_z1 = sort_merge_comp_38_z1;
sort_merge_lomerge_comp_40_z2 = sort_merge_comp_36_z1;
end
end
always @(sort_merge_comp_37_z1, sort_merge_comp_39_z1) begin: ARRAY8SORTER_SORT_MERGE_LOMERGE_COMP_41_LOGIC
sort_merge_lomerge_comp_41_z1 = sort_merge_comp_37_z1;
sort_merge_lomerge_comp_41_z2 = sort_merge_comp_39_z1;
if ((1'b1 == (sort_merge_comp_37_z1 > sort_merge_comp_39_z1))) begin
sort_merge_lomerge_comp_41_z1 = sort_merge_comp_39_z1;
sort_merge_lomerge_comp_41_z2 = sort_merge_comp_37_z1;
end
end
always @(sort_merge_lomerge_comp_40_z1, sort_merge_lomerge_comp_41_z1) begin: ARRAY8SORTER_SORT_MERGE_LOMERGE_LOMERGE_COMP_42_LOGIC
sort_merge_lomerge_lomerge_comp_42_z1 = sort_merge_lomerge_comp_40_z1;
sort_merge_lomerge_lomerge_comp_42_z2 = sort_merge_lomerge_comp_41_z1;
if ((1'b1 == (sort_merge_lomerge_comp_40_z1 > sort_merge_lomerge_comp_41_z1))) begin
sort_merge_lomerge_lomerge_comp_42_z1 = sort_merge_lomerge_comp_41_z1;
sort_merge_lomerge_lomerge_comp_42_z2 = sort_merge_lomerge_comp_40_z1;
end
end
assign z0 = sort_merge_lomerge_lomerge_comp_42_z1;
assign z1 = sort_merge_lomerge_lomerge_comp_42_z2;
always @(sort_merge_lomerge_comp_40_z2, sort_merge_lomerge_comp_41_z2) begin: ARRAY8SORTER_SORT_MERGE_LOMERGE_HIMERGE_COMP_43_LOGIC
sort_merge_lomerge_hiMerge_comp_43_z1 = sort_merge_lomerge_comp_40_z2;
sort_merge_lomerge_hiMerge_comp_43_z2 = sort_merge_lomerge_comp_41_z2;
if ((1'b1 == (sort_merge_lomerge_comp_40_z2 > sort_merge_lomerge_comp_41_z2))) begin
sort_merge_lomerge_hiMerge_comp_43_z1 = sort_merge_lomerge_comp_41_z2;
sort_merge_lomerge_hiMerge_comp_43_z2 = sort_merge_lomerge_comp_40_z2;
end
end
assign z2 = sort_merge_lomerge_hiMerge_comp_43_z1;
assign z3 = sort_merge_lomerge_hiMerge_comp_43_z2;
always @(sort_merge_comp_36_z2, sort_merge_comp_38_z2) begin: ARRAY8SORTER_SORT_MERGE_HIMERGE_COMP_44_LOGIC
sort_merge_hiMerge_comp_44_z1 = sort_merge_comp_36_z2;
sort_merge_hiMerge_comp_44_z2 = sort_merge_comp_38_z2;
if ((1'b1 == (sort_merge_comp_36_z2 > sort_merge_comp_38_z2))) begin
sort_merge_hiMerge_comp_44_z1 = sort_merge_comp_38_z2;
sort_merge_hiMerge_comp_44_z2 = sort_merge_comp_36_z2;
end
end
always @(sort_merge_comp_37_z2, sort_merge_comp_39_z2) begin: ARRAY8SORTER_SORT_MERGE_HIMERGE_COMP_45_LOGIC
sort_merge_hiMerge_comp_45_z1 = sort_merge_comp_37_z2;
sort_merge_hiMerge_comp_45_z2 = sort_merge_comp_39_z2;
if ((1'b1 == (sort_merge_comp_37_z2 > sort_merge_comp_39_z2))) begin
sort_merge_hiMerge_comp_45_z1 = sort_merge_comp_39_z2;
sort_merge_hiMerge_comp_45_z2 = sort_merge_comp_37_z2;
end
end
always @(sort_merge_hiMerge_comp_44_z1, sort_merge_hiMerge_comp_45_z1) begin: ARRAY8SORTER_SORT_MERGE_HIMERGE_LOMERGE_COMP_46_LOGIC
sort_merge_hiMerge_lomerge_comp_46_z1 = sort_merge_hiMerge_comp_44_z1;
sort_merge_hiMerge_lomerge_comp_46_z2 = sort_merge_hiMerge_comp_45_z1;
if ((1'b1 == (sort_merge_hiMerge_comp_44_z1 > sort_merge_hiMerge_comp_45_z1))) begin
sort_merge_hiMerge_lomerge_comp_46_z1 = sort_merge_hiMerge_comp_45_z1;
sort_merge_hiMerge_lomerge_comp_46_z2 = sort_merge_hiMerge_comp_44_z1;
end
end
assign z4 = sort_merge_hiMerge_lomerge_comp_46_z1;
assign z5 = sort_merge_hiMerge_lomerge_comp_46_z2;
always @(sort_merge_hiMerge_comp_44_z2, sort_merge_hiMerge_comp_45_z2) begin: ARRAY8SORTER_SORT_MERGE_HIMERGE_HIMERGE_COMP_47_LOGIC
sort_merge_hiMerge_hiMerge_comp_47_z1 = sort_merge_hiMerge_comp_44_z2;
sort_merge_hiMerge_hiMerge_comp_47_z2 = sort_merge_hiMerge_comp_45_z2;
if ((1'b1 == (sort_merge_hiMerge_comp_44_z2 > sort_merge_hiMerge_comp_45_z2))) begin
sort_merge_hiMerge_hiMerge_comp_47_z1 = sort_merge_hiMerge_comp_45_z2;
sort_merge_hiMerge_hiMerge_comp_47_z2 = sort_merge_hiMerge_comp_44_z2;
end
end
assign z6 = sort_merge_hiMerge_hiMerge_comp_47_z1;
assign z7 = sort_merge_hiMerge_hiMerge_comp_47_z2;
endmodule

View File

@ -1,10 +1,14 @@
import subprocess
import myhdl
from myhdl import *
from myhdl.conversion import analyze
DESCENDING, ASCENDING = False, True
def compare(a1, a2, z1, z2, dir):
@block
def comp(a1, a2, z1, z2, dir):
@always_comb
def logic():
z1.next = a1
@ -12,71 +16,79 @@ def compare(a1, a2, z1, z2, dir):
if dir == (a1 > a2):
z1.next = a2
z2.next = a1
return logic
@block
def feedthru(a, z):
@always_comb
def logic():
z.next = a
return logic
@block
def bitonicMerge(a, z, dir):
n = len(a)
k = n//2
w = len(a[0])
if n > 1:
t = [Signal(intbv(0)[w:]) for i in range(n)]
comp = [compare(a[i], a[i+k], t[i], t[i+k], dir) for i in range(k)]
loMerge = bitonicMerge(t[:k], z[:k], dir)
hiMerge = bitonicMerge(t[k:], z[k:], dir)
return comp, loMerge, hiMerge
comps = [comp(a[i], a[i+k], t[i], t[i+k], dir) for i in range(k)]
lomerge = bitonicMerge(t[:k], z[:k], dir)
himerge = bitonicMerge(t[k:], z[k:], dir)
lomerge.name = "lomerge"
himerge.name = "hiMerge"
return comps, lomerge, himerge
else:
feed = feedthru(a[0], z[0])
return feed
return feedthru(a[0], z[0])
@block
def bitonicSort(a, z, dir):
n = len(a)
k = n//2
w = len(a[0])
if n > 1:
t = [Signal(intbv(0)[w:]) for i in range(n)]
loSort = bitonicSort(a[:k], t[:k], ASCENDING)
hiSort = bitonicSort(a[k:], t[k:], DESCENDING)
losort = bitonicSort(a[:k], t[:k], ASCENDING)
hisort = bitonicSort(a[k:], t[k:], DESCENDING)
merge = bitonicMerge(t, z, dir)
return loSort, hiSort, merge
losort.name = "losort"
hisort.name = "hisort"
merge.name = "merge"
return losort, hisort, merge
else:
feed = feedthru(a[0], z[0])
return feed
return feedthru(a[0], z[0])
@block
def Array8Sorter(a0, a1, a2, a3, a4, a5, a6, a7,
z0, z1, z2, z3, z4, z5, z6, z7):
a = [a0, a1, a2, a3, a4, a5, a6, a7]
z = [z0, z1, z2, z3, z4, z5, z6, z7]
sort = bitonicSort(a, z, ASCENDING)
sort.name = "sort"
return sort
def Array8Sorter_v(a0, a1, a2, a3, a4, a5, a6, a7,
z0, z1, z2, z3, z4, z5, z6, z7):
toVerilog(Array8Sorter, a0, a1, a2, a3, a4, a5, a6, a7,
z0, z1, z2, z3, z4, z5, z6, z7)
analyze(Array8Sorter, a0, a1, a2, a3, a4, a5, a6, a7,
z0, z1, z2, z3, z4, z5, z6, z7)
cmd = "cver -q +loadvpi=../../../cosimulation/cver/myhdl_vpi:vpi_compat_bootstrap " + \
"Array8Sorter.v tb_Array8Sorter.v"
analyze.simulator = 'iverilog'
toVerilog(Array8Sorter(a0, a1, a2, a3, a4, a5, a6, a7,
z0, z1, z2, z3, z4, z5, z6, z7))
analyze(Array8Sorter(a0, a1, a2, a3, a4, a5, a6, a7,
z0, z1, z2, z3, z4, z5, z6, z7))
# cmd = "cver -q +loadvpi=../../../cosimulation/cver/myhdl_vpi:vpi_compat_bootstrap " + \
# "Array8Sorter.v tb_Array8Sorter.v"
subprocess.call("iverilog -o Array8Sorter.o Array8Sorter.v tb_Array8Sorter.v", shell=True)
cmd = "vvp -m ../../../cosimulation/icarus/myhdl.vpi Array8Sorter.o"
return Cosimulation(cmd, **locals())

View File

@ -0,0 +1,497 @@
// File: Array8Sorter.v
// Generated by MyHDL 1.0dev
// Date: Sat Mar 19 15:40:10 2016
`timescale 1ns/10ps
module Array8Sorter (
a0,
a1,
a2,
a3,
a4,
a5,
a6,
a7,
z0,
z1,
z2,
z3,
z4,
z5,
z6,
z7
);
input [3:0] a0;
input [3:0] a1;
input [3:0] a2;
input [3:0] a3;
input [3:0] a4;
input [3:0] a5;
input [3:0] a6;
input [3:0] a7;
output [3:0] z0;
wire [3:0] z0;
output [3:0] z1;
wire [3:0] z1;
output [3:0] z2;
wire [3:0] z2;
output [3:0] z3;
wire [3:0] z3;
output [3:0] z4;
wire [3:0] z4;
output [3:0] z5;
wire [3:0] z5;
output [3:0] z6;
wire [3:0] z6;
output [3:0] z7;
wire [3:0] z7;
wire [3:0] sort_losort_losort_losort_feedthru_32_z;
wire [3:0] sort_losort_losort_hisort_feedthru_33_z;
reg [3:0] sort_losort_losort_merge_comp_24_z1;
reg [3:0] sort_losort_losort_merge_comp_24_z2;
wire [3:0] sort_losort_losort_merge_lomerge_feedthru_34_z;
wire [3:0] sort_losort_losort_merge_hiMerge_feedthru_35_z;
wire [3:0] sort_losort_hisort_losort_feedthru_36_z;
wire [3:0] sort_losort_hisort_hisort_feedthru_37_z;
reg [3:0] sort_losort_hisort_merge_comp_25_z1;
reg [3:0] sort_losort_hisort_merge_comp_25_z2;
wire [3:0] sort_losort_hisort_merge_lomerge_feedthru_38_z;
wire [3:0] sort_losort_hisort_merge_hiMerge_feedthru_39_z;
reg [3:0] sort_losort_merge_comp_26_z1;
reg [3:0] sort_losort_merge_comp_26_z2;
reg [3:0] sort_losort_merge_comp_27_z1;
reg [3:0] sort_losort_merge_comp_27_z2;
reg [3:0] sort_losort_merge_lomerge_comp_28_z1;
reg [3:0] sort_losort_merge_lomerge_comp_28_z2;
wire [3:0] sort_losort_merge_lomerge_lomerge_feedthru_40_z;
wire [3:0] sort_losort_merge_lomerge_hiMerge_feedthru_41_z;
reg [3:0] sort_losort_merge_hiMerge_comp_29_z1;
reg [3:0] sort_losort_merge_hiMerge_comp_29_z2;
wire [3:0] sort_losort_merge_hiMerge_lomerge_feedthru_42_z;
wire [3:0] sort_losort_merge_hiMerge_hiMerge_feedthru_43_z;
wire [3:0] sort_hisort_losort_losort_feedthru_44_z;
wire [3:0] sort_hisort_losort_hisort_feedthru_45_z;
reg [3:0] sort_hisort_losort_merge_comp_30_z1;
reg [3:0] sort_hisort_losort_merge_comp_30_z2;
wire [3:0] sort_hisort_losort_merge_lomerge_feedthru_46_z;
wire [3:0] sort_hisort_losort_merge_hiMerge_feedthru_47_z;
wire [3:0] sort_hisort_hisort_losort_feedthru_48_z;
wire [3:0] sort_hisort_hisort_hisort_feedthru_49_z;
reg [3:0] sort_hisort_hisort_merge_comp_31_z1;
reg [3:0] sort_hisort_hisort_merge_comp_31_z2;
wire [3:0] sort_hisort_hisort_merge_lomerge_feedthru_50_z;
wire [3:0] sort_hisort_hisort_merge_hiMerge_feedthru_51_z;
reg [3:0] sort_hisort_merge_comp_32_z1;
reg [3:0] sort_hisort_merge_comp_32_z2;
reg [3:0] sort_hisort_merge_comp_33_z1;
reg [3:0] sort_hisort_merge_comp_33_z2;
reg [3:0] sort_hisort_merge_lomerge_comp_34_z1;
reg [3:0] sort_hisort_merge_lomerge_comp_34_z2;
wire [3:0] sort_hisort_merge_lomerge_lomerge_feedthru_52_z;
wire [3:0] sort_hisort_merge_lomerge_hiMerge_feedthru_53_z;
reg [3:0] sort_hisort_merge_hiMerge_comp_35_z1;
reg [3:0] sort_hisort_merge_hiMerge_comp_35_z2;
wire [3:0] sort_hisort_merge_hiMerge_lomerge_feedthru_54_z;
wire [3:0] sort_hisort_merge_hiMerge_hiMerge_feedthru_55_z;
reg [3:0] sort_merge_comp_36_z1;
reg [3:0] sort_merge_comp_36_z2;
reg [3:0] sort_merge_comp_37_z1;
reg [3:0] sort_merge_comp_37_z2;
reg [3:0] sort_merge_comp_38_z1;
reg [3:0] sort_merge_comp_38_z2;
reg [3:0] sort_merge_comp_39_z1;
reg [3:0] sort_merge_comp_39_z2;
reg [3:0] sort_merge_lomerge_comp_40_z1;
reg [3:0] sort_merge_lomerge_comp_40_z2;
reg [3:0] sort_merge_lomerge_comp_41_z1;
reg [3:0] sort_merge_lomerge_comp_41_z2;
reg [3:0] sort_merge_lomerge_lomerge_comp_42_z1;
reg [3:0] sort_merge_lomerge_lomerge_comp_42_z2;
reg [3:0] sort_merge_lomerge_hiMerge_comp_43_z1;
reg [3:0] sort_merge_lomerge_hiMerge_comp_43_z2;
reg [3:0] sort_merge_hiMerge_comp_44_z1;
reg [3:0] sort_merge_hiMerge_comp_44_z2;
reg [3:0] sort_merge_hiMerge_comp_45_z1;
reg [3:0] sort_merge_hiMerge_comp_45_z2;
reg [3:0] sort_merge_hiMerge_lomerge_comp_46_z1;
reg [3:0] sort_merge_hiMerge_lomerge_comp_46_z2;
reg [3:0] sort_merge_hiMerge_hiMerge_comp_47_z1;
reg [3:0] sort_merge_hiMerge_hiMerge_comp_47_z2;
assign sort_losort_losort_losort_feedthru_32_z = a0;
assign sort_losort_losort_hisort_feedthru_33_z = a1;
always @(sort_losort_losort_losort_feedthru_32_z, sort_losort_losort_hisort_feedthru_33_z) begin: ARRAY8SORTER_SORT_LOSORT_LOSORT_MERGE_COMP_24_LOGIC
sort_losort_losort_merge_comp_24_z1 = sort_losort_losort_losort_feedthru_32_z;
sort_losort_losort_merge_comp_24_z2 = sort_losort_losort_hisort_feedthru_33_z;
if ((1'b1 == (sort_losort_losort_losort_feedthru_32_z > sort_losort_losort_hisort_feedthru_33_z))) begin
sort_losort_losort_merge_comp_24_z1 = sort_losort_losort_hisort_feedthru_33_z;
sort_losort_losort_merge_comp_24_z2 = sort_losort_losort_losort_feedthru_32_z;
end
end
assign sort_losort_losort_merge_lomerge_feedthru_34_z = sort_losort_losort_merge_comp_24_z1;
assign sort_losort_losort_merge_hiMerge_feedthru_35_z = sort_losort_losort_merge_comp_24_z2;
assign sort_losort_hisort_losort_feedthru_36_z = a2;
assign sort_losort_hisort_hisort_feedthru_37_z = a3;
always @(sort_losort_hisort_losort_feedthru_36_z, sort_losort_hisort_hisort_feedthru_37_z) begin: ARRAY8SORTER_SORT_LOSORT_HISORT_MERGE_COMP_25_LOGIC
sort_losort_hisort_merge_comp_25_z1 = sort_losort_hisort_losort_feedthru_36_z;
sort_losort_hisort_merge_comp_25_z2 = sort_losort_hisort_hisort_feedthru_37_z;
if ((1'b0 == (sort_losort_hisort_losort_feedthru_36_z > sort_losort_hisort_hisort_feedthru_37_z))) begin
sort_losort_hisort_merge_comp_25_z1 = sort_losort_hisort_hisort_feedthru_37_z;
sort_losort_hisort_merge_comp_25_z2 = sort_losort_hisort_losort_feedthru_36_z;
end
end
assign sort_losort_hisort_merge_lomerge_feedthru_38_z = sort_losort_hisort_merge_comp_25_z1;
assign sort_losort_hisort_merge_hiMerge_feedthru_39_z = sort_losort_hisort_merge_comp_25_z2;
always @(sort_losort_losort_merge_lomerge_feedthru_34_z, sort_losort_hisort_merge_lomerge_feedthru_38_z) begin: ARRAY8SORTER_SORT_LOSORT_MERGE_COMP_26_LOGIC
sort_losort_merge_comp_26_z1 = sort_losort_losort_merge_lomerge_feedthru_34_z;
sort_losort_merge_comp_26_z2 = sort_losort_hisort_merge_lomerge_feedthru_38_z;
if ((1'b1 == (sort_losort_losort_merge_lomerge_feedthru_34_z > sort_losort_hisort_merge_lomerge_feedthru_38_z))) begin
sort_losort_merge_comp_26_z1 = sort_losort_hisort_merge_lomerge_feedthru_38_z;
sort_losort_merge_comp_26_z2 = sort_losort_losort_merge_lomerge_feedthru_34_z;
end
end
always @(sort_losort_losort_merge_hiMerge_feedthru_35_z, sort_losort_hisort_merge_hiMerge_feedthru_39_z) begin: ARRAY8SORTER_SORT_LOSORT_MERGE_COMP_27_LOGIC
sort_losort_merge_comp_27_z1 = sort_losort_losort_merge_hiMerge_feedthru_35_z;
sort_losort_merge_comp_27_z2 = sort_losort_hisort_merge_hiMerge_feedthru_39_z;
if ((1'b1 == (sort_losort_losort_merge_hiMerge_feedthru_35_z > sort_losort_hisort_merge_hiMerge_feedthru_39_z))) begin
sort_losort_merge_comp_27_z1 = sort_losort_hisort_merge_hiMerge_feedthru_39_z;
sort_losort_merge_comp_27_z2 = sort_losort_losort_merge_hiMerge_feedthru_35_z;
end
end
always @(sort_losort_merge_comp_26_z1, sort_losort_merge_comp_27_z1) begin: ARRAY8SORTER_SORT_LOSORT_MERGE_LOMERGE_COMP_28_LOGIC
sort_losort_merge_lomerge_comp_28_z1 = sort_losort_merge_comp_26_z1;
sort_losort_merge_lomerge_comp_28_z2 = sort_losort_merge_comp_27_z1;
if ((1'b1 == (sort_losort_merge_comp_26_z1 > sort_losort_merge_comp_27_z1))) begin
sort_losort_merge_lomerge_comp_28_z1 = sort_losort_merge_comp_27_z1;
sort_losort_merge_lomerge_comp_28_z2 = sort_losort_merge_comp_26_z1;
end
end
assign sort_losort_merge_lomerge_lomerge_feedthru_40_z = sort_losort_merge_lomerge_comp_28_z1;
assign sort_losort_merge_lomerge_hiMerge_feedthru_41_z = sort_losort_merge_lomerge_comp_28_z2;
always @(sort_losort_merge_comp_26_z2, sort_losort_merge_comp_27_z2) begin: ARRAY8SORTER_SORT_LOSORT_MERGE_HIMERGE_COMP_29_LOGIC
sort_losort_merge_hiMerge_comp_29_z1 = sort_losort_merge_comp_26_z2;
sort_losort_merge_hiMerge_comp_29_z2 = sort_losort_merge_comp_27_z2;
if ((1'b1 == (sort_losort_merge_comp_26_z2 > sort_losort_merge_comp_27_z2))) begin
sort_losort_merge_hiMerge_comp_29_z1 = sort_losort_merge_comp_27_z2;
sort_losort_merge_hiMerge_comp_29_z2 = sort_losort_merge_comp_26_z2;
end
end
assign sort_losort_merge_hiMerge_lomerge_feedthru_42_z = sort_losort_merge_hiMerge_comp_29_z1;
assign sort_losort_merge_hiMerge_hiMerge_feedthru_43_z = sort_losort_merge_hiMerge_comp_29_z2;
assign sort_hisort_losort_losort_feedthru_44_z = a4;
assign sort_hisort_losort_hisort_feedthru_45_z = a5;
always @(sort_hisort_losort_losort_feedthru_44_z, sort_hisort_losort_hisort_feedthru_45_z) begin: ARRAY8SORTER_SORT_HISORT_LOSORT_MERGE_COMP_30_LOGIC
sort_hisort_losort_merge_comp_30_z1 = sort_hisort_losort_losort_feedthru_44_z;
sort_hisort_losort_merge_comp_30_z2 = sort_hisort_losort_hisort_feedthru_45_z;
if ((1'b1 == (sort_hisort_losort_losort_feedthru_44_z > sort_hisort_losort_hisort_feedthru_45_z))) begin
sort_hisort_losort_merge_comp_30_z1 = sort_hisort_losort_hisort_feedthru_45_z;
sort_hisort_losort_merge_comp_30_z2 = sort_hisort_losort_losort_feedthru_44_z;
end
end
assign sort_hisort_losort_merge_lomerge_feedthru_46_z = sort_hisort_losort_merge_comp_30_z1;
assign sort_hisort_losort_merge_hiMerge_feedthru_47_z = sort_hisort_losort_merge_comp_30_z2;
assign sort_hisort_hisort_losort_feedthru_48_z = a6;
assign sort_hisort_hisort_hisort_feedthru_49_z = a7;
always @(sort_hisort_hisort_losort_feedthru_48_z, sort_hisort_hisort_hisort_feedthru_49_z) begin: ARRAY8SORTER_SORT_HISORT_HISORT_MERGE_COMP_31_LOGIC
sort_hisort_hisort_merge_comp_31_z1 = sort_hisort_hisort_losort_feedthru_48_z;
sort_hisort_hisort_merge_comp_31_z2 = sort_hisort_hisort_hisort_feedthru_49_z;
if ((1'b0 == (sort_hisort_hisort_losort_feedthru_48_z > sort_hisort_hisort_hisort_feedthru_49_z))) begin
sort_hisort_hisort_merge_comp_31_z1 = sort_hisort_hisort_hisort_feedthru_49_z;
sort_hisort_hisort_merge_comp_31_z2 = sort_hisort_hisort_losort_feedthru_48_z;
end
end
assign sort_hisort_hisort_merge_lomerge_feedthru_50_z = sort_hisort_hisort_merge_comp_31_z1;
assign sort_hisort_hisort_merge_hiMerge_feedthru_51_z = sort_hisort_hisort_merge_comp_31_z2;
always @(sort_hisort_losort_merge_lomerge_feedthru_46_z, sort_hisort_hisort_merge_lomerge_feedthru_50_z) begin: ARRAY8SORTER_SORT_HISORT_MERGE_COMP_32_LOGIC
sort_hisort_merge_comp_32_z1 = sort_hisort_losort_merge_lomerge_feedthru_46_z;
sort_hisort_merge_comp_32_z2 = sort_hisort_hisort_merge_lomerge_feedthru_50_z;
if ((1'b0 == (sort_hisort_losort_merge_lomerge_feedthru_46_z > sort_hisort_hisort_merge_lomerge_feedthru_50_z))) begin
sort_hisort_merge_comp_32_z1 = sort_hisort_hisort_merge_lomerge_feedthru_50_z;
sort_hisort_merge_comp_32_z2 = sort_hisort_losort_merge_lomerge_feedthru_46_z;
end
end
always @(sort_hisort_losort_merge_hiMerge_feedthru_47_z, sort_hisort_hisort_merge_hiMerge_feedthru_51_z) begin: ARRAY8SORTER_SORT_HISORT_MERGE_COMP_33_LOGIC
sort_hisort_merge_comp_33_z1 = sort_hisort_losort_merge_hiMerge_feedthru_47_z;
sort_hisort_merge_comp_33_z2 = sort_hisort_hisort_merge_hiMerge_feedthru_51_z;
if ((1'b0 == (sort_hisort_losort_merge_hiMerge_feedthru_47_z > sort_hisort_hisort_merge_hiMerge_feedthru_51_z))) begin
sort_hisort_merge_comp_33_z1 = sort_hisort_hisort_merge_hiMerge_feedthru_51_z;
sort_hisort_merge_comp_33_z2 = sort_hisort_losort_merge_hiMerge_feedthru_47_z;
end
end
always @(sort_hisort_merge_comp_32_z1, sort_hisort_merge_comp_33_z1) begin: ARRAY8SORTER_SORT_HISORT_MERGE_LOMERGE_COMP_34_LOGIC
sort_hisort_merge_lomerge_comp_34_z1 = sort_hisort_merge_comp_32_z1;
sort_hisort_merge_lomerge_comp_34_z2 = sort_hisort_merge_comp_33_z1;
if ((1'b0 == (sort_hisort_merge_comp_32_z1 > sort_hisort_merge_comp_33_z1))) begin
sort_hisort_merge_lomerge_comp_34_z1 = sort_hisort_merge_comp_33_z1;
sort_hisort_merge_lomerge_comp_34_z2 = sort_hisort_merge_comp_32_z1;
end
end
assign sort_hisort_merge_lomerge_lomerge_feedthru_52_z = sort_hisort_merge_lomerge_comp_34_z1;
assign sort_hisort_merge_lomerge_hiMerge_feedthru_53_z = sort_hisort_merge_lomerge_comp_34_z2;
always @(sort_hisort_merge_comp_32_z2, sort_hisort_merge_comp_33_z2) begin: ARRAY8SORTER_SORT_HISORT_MERGE_HIMERGE_COMP_35_LOGIC
sort_hisort_merge_hiMerge_comp_35_z1 = sort_hisort_merge_comp_32_z2;
sort_hisort_merge_hiMerge_comp_35_z2 = sort_hisort_merge_comp_33_z2;
if ((1'b0 == (sort_hisort_merge_comp_32_z2 > sort_hisort_merge_comp_33_z2))) begin
sort_hisort_merge_hiMerge_comp_35_z1 = sort_hisort_merge_comp_33_z2;
sort_hisort_merge_hiMerge_comp_35_z2 = sort_hisort_merge_comp_32_z2;
end
end
assign sort_hisort_merge_hiMerge_lomerge_feedthru_54_z = sort_hisort_merge_hiMerge_comp_35_z1;
assign sort_hisort_merge_hiMerge_hiMerge_feedthru_55_z = sort_hisort_merge_hiMerge_comp_35_z2;
always @(sort_losort_merge_lomerge_lomerge_feedthru_40_z, sort_hisort_merge_lomerge_lomerge_feedthru_52_z) begin: ARRAY8SORTER_SORT_MERGE_COMP_36_LOGIC
sort_merge_comp_36_z1 = sort_losort_merge_lomerge_lomerge_feedthru_40_z;
sort_merge_comp_36_z2 = sort_hisort_merge_lomerge_lomerge_feedthru_52_z;
if ((1'b1 == (sort_losort_merge_lomerge_lomerge_feedthru_40_z > sort_hisort_merge_lomerge_lomerge_feedthru_52_z))) begin
sort_merge_comp_36_z1 = sort_hisort_merge_lomerge_lomerge_feedthru_52_z;
sort_merge_comp_36_z2 = sort_losort_merge_lomerge_lomerge_feedthru_40_z;
end
end
always @(sort_losort_merge_lomerge_hiMerge_feedthru_41_z, sort_hisort_merge_lomerge_hiMerge_feedthru_53_z) begin: ARRAY8SORTER_SORT_MERGE_COMP_37_LOGIC
sort_merge_comp_37_z1 = sort_losort_merge_lomerge_hiMerge_feedthru_41_z;
sort_merge_comp_37_z2 = sort_hisort_merge_lomerge_hiMerge_feedthru_53_z;
if ((1'b1 == (sort_losort_merge_lomerge_hiMerge_feedthru_41_z > sort_hisort_merge_lomerge_hiMerge_feedthru_53_z))) begin
sort_merge_comp_37_z1 = sort_hisort_merge_lomerge_hiMerge_feedthru_53_z;
sort_merge_comp_37_z2 = sort_losort_merge_lomerge_hiMerge_feedthru_41_z;
end
end
always @(sort_losort_merge_hiMerge_lomerge_feedthru_42_z, sort_hisort_merge_hiMerge_lomerge_feedthru_54_z) begin: ARRAY8SORTER_SORT_MERGE_COMP_38_LOGIC
sort_merge_comp_38_z1 = sort_losort_merge_hiMerge_lomerge_feedthru_42_z;
sort_merge_comp_38_z2 = sort_hisort_merge_hiMerge_lomerge_feedthru_54_z;
if ((1'b1 == (sort_losort_merge_hiMerge_lomerge_feedthru_42_z > sort_hisort_merge_hiMerge_lomerge_feedthru_54_z))) begin
sort_merge_comp_38_z1 = sort_hisort_merge_hiMerge_lomerge_feedthru_54_z;
sort_merge_comp_38_z2 = sort_losort_merge_hiMerge_lomerge_feedthru_42_z;
end
end
always @(sort_losort_merge_hiMerge_hiMerge_feedthru_43_z, sort_hisort_merge_hiMerge_hiMerge_feedthru_55_z) begin: ARRAY8SORTER_SORT_MERGE_COMP_39_LOGIC
sort_merge_comp_39_z1 = sort_losort_merge_hiMerge_hiMerge_feedthru_43_z;
sort_merge_comp_39_z2 = sort_hisort_merge_hiMerge_hiMerge_feedthru_55_z;
if ((1'b1 == (sort_losort_merge_hiMerge_hiMerge_feedthru_43_z > sort_hisort_merge_hiMerge_hiMerge_feedthru_55_z))) begin
sort_merge_comp_39_z1 = sort_hisort_merge_hiMerge_hiMerge_feedthru_55_z;
sort_merge_comp_39_z2 = sort_losort_merge_hiMerge_hiMerge_feedthru_43_z;
end
end
always @(sort_merge_comp_36_z1, sort_merge_comp_38_z1) begin: ARRAY8SORTER_SORT_MERGE_LOMERGE_COMP_40_LOGIC
sort_merge_lomerge_comp_40_z1 = sort_merge_comp_36_z1;
sort_merge_lomerge_comp_40_z2 = sort_merge_comp_38_z1;
if ((1'b1 == (sort_merge_comp_36_z1 > sort_merge_comp_38_z1))) begin
sort_merge_lomerge_comp_40_z1 = sort_merge_comp_38_z1;
sort_merge_lomerge_comp_40_z2 = sort_merge_comp_36_z1;
end
end
always @(sort_merge_comp_37_z1, sort_merge_comp_39_z1) begin: ARRAY8SORTER_SORT_MERGE_LOMERGE_COMP_41_LOGIC
sort_merge_lomerge_comp_41_z1 = sort_merge_comp_37_z1;
sort_merge_lomerge_comp_41_z2 = sort_merge_comp_39_z1;
if ((1'b1 == (sort_merge_comp_37_z1 > sort_merge_comp_39_z1))) begin
sort_merge_lomerge_comp_41_z1 = sort_merge_comp_39_z1;
sort_merge_lomerge_comp_41_z2 = sort_merge_comp_37_z1;
end
end
always @(sort_merge_lomerge_comp_40_z1, sort_merge_lomerge_comp_41_z1) begin: ARRAY8SORTER_SORT_MERGE_LOMERGE_LOMERGE_COMP_42_LOGIC
sort_merge_lomerge_lomerge_comp_42_z1 = sort_merge_lomerge_comp_40_z1;
sort_merge_lomerge_lomerge_comp_42_z2 = sort_merge_lomerge_comp_41_z1;
if ((1'b1 == (sort_merge_lomerge_comp_40_z1 > sort_merge_lomerge_comp_41_z1))) begin
sort_merge_lomerge_lomerge_comp_42_z1 = sort_merge_lomerge_comp_41_z1;
sort_merge_lomerge_lomerge_comp_42_z2 = sort_merge_lomerge_comp_40_z1;
end
end
assign z0 = sort_merge_lomerge_lomerge_comp_42_z1;
assign z1 = sort_merge_lomerge_lomerge_comp_42_z2;
always @(sort_merge_lomerge_comp_40_z2, sort_merge_lomerge_comp_41_z2) begin: ARRAY8SORTER_SORT_MERGE_LOMERGE_HIMERGE_COMP_43_LOGIC
sort_merge_lomerge_hiMerge_comp_43_z1 = sort_merge_lomerge_comp_40_z2;
sort_merge_lomerge_hiMerge_comp_43_z2 = sort_merge_lomerge_comp_41_z2;
if ((1'b1 == (sort_merge_lomerge_comp_40_z2 > sort_merge_lomerge_comp_41_z2))) begin
sort_merge_lomerge_hiMerge_comp_43_z1 = sort_merge_lomerge_comp_41_z2;
sort_merge_lomerge_hiMerge_comp_43_z2 = sort_merge_lomerge_comp_40_z2;
end
end
assign z2 = sort_merge_lomerge_hiMerge_comp_43_z1;
assign z3 = sort_merge_lomerge_hiMerge_comp_43_z2;
always @(sort_merge_comp_36_z2, sort_merge_comp_38_z2) begin: ARRAY8SORTER_SORT_MERGE_HIMERGE_COMP_44_LOGIC
sort_merge_hiMerge_comp_44_z1 = sort_merge_comp_36_z2;
sort_merge_hiMerge_comp_44_z2 = sort_merge_comp_38_z2;
if ((1'b1 == (sort_merge_comp_36_z2 > sort_merge_comp_38_z2))) begin
sort_merge_hiMerge_comp_44_z1 = sort_merge_comp_38_z2;
sort_merge_hiMerge_comp_44_z2 = sort_merge_comp_36_z2;
end
end
always @(sort_merge_comp_37_z2, sort_merge_comp_39_z2) begin: ARRAY8SORTER_SORT_MERGE_HIMERGE_COMP_45_LOGIC
sort_merge_hiMerge_comp_45_z1 = sort_merge_comp_37_z2;
sort_merge_hiMerge_comp_45_z2 = sort_merge_comp_39_z2;
if ((1'b1 == (sort_merge_comp_37_z2 > sort_merge_comp_39_z2))) begin
sort_merge_hiMerge_comp_45_z1 = sort_merge_comp_39_z2;
sort_merge_hiMerge_comp_45_z2 = sort_merge_comp_37_z2;
end
end
always @(sort_merge_hiMerge_comp_44_z1, sort_merge_hiMerge_comp_45_z1) begin: ARRAY8SORTER_SORT_MERGE_HIMERGE_LOMERGE_COMP_46_LOGIC
sort_merge_hiMerge_lomerge_comp_46_z1 = sort_merge_hiMerge_comp_44_z1;
sort_merge_hiMerge_lomerge_comp_46_z2 = sort_merge_hiMerge_comp_45_z1;
if ((1'b1 == (sort_merge_hiMerge_comp_44_z1 > sort_merge_hiMerge_comp_45_z1))) begin
sort_merge_hiMerge_lomerge_comp_46_z1 = sort_merge_hiMerge_comp_45_z1;
sort_merge_hiMerge_lomerge_comp_46_z2 = sort_merge_hiMerge_comp_44_z1;
end
end
assign z4 = sort_merge_hiMerge_lomerge_comp_46_z1;
assign z5 = sort_merge_hiMerge_lomerge_comp_46_z2;
always @(sort_merge_hiMerge_comp_44_z2, sort_merge_hiMerge_comp_45_z2) begin: ARRAY8SORTER_SORT_MERGE_HIMERGE_HIMERGE_COMP_47_LOGIC
sort_merge_hiMerge_hiMerge_comp_47_z1 = sort_merge_hiMerge_comp_44_z2;
sort_merge_hiMerge_hiMerge_comp_47_z2 = sort_merge_hiMerge_comp_45_z2;
if ((1'b1 == (sort_merge_hiMerge_comp_44_z2 > sort_merge_hiMerge_comp_45_z2))) begin
sort_merge_hiMerge_hiMerge_comp_47_z1 = sort_merge_hiMerge_comp_45_z2;
sort_merge_hiMerge_hiMerge_comp_47_z2 = sort_merge_hiMerge_comp_44_z2;
end
end
assign z6 = sort_merge_hiMerge_hiMerge_comp_47_z1;
assign z7 = sort_merge_hiMerge_hiMerge_comp_47_z2;
endmodule

View File

@ -0,0 +1,62 @@
module tb_Array8Sorter;
reg [3:0] a0;
reg [3:0] a1;
reg [3:0] a2;
reg [3:0] a3;
reg [3:0] a4;
reg [3:0] a5;
reg [3:0] a6;
reg [3:0] a7;
wire [3:0] z0;
wire [3:0] z1;
wire [3:0] z2;
wire [3:0] z3;
wire [3:0] z4;
wire [3:0] z5;
wire [3:0] z6;
wire [3:0] z7;
initial begin
$from_myhdl(
a0,
a1,
a2,
a3,
a4,
a5,
a6,
a7
);
$to_myhdl(
z0,
z1,
z2,
z3,
z4,
z5,
z6,
z7
);
end
Array8Sorter dut(
a0,
a1,
a2,
a3,
a4,
a5,
a6,
a7,
z0,
z1,
z2,
z3,
z4,
z5,
z6,
z7
);
endmodule

View File

@ -1,18 +1,20 @@
from random import randrange
import myhdl
from myhdl import *
from bitonic import Array8Sorter, Array8Sorter_v
@block
def bench():
n = 8
w = 4
a0, a1, a2, a3, a4, a5, a6, a7 = inputs = [Signal(intbv(0)[w:]) for i in range(n)]
z0, z1, z2, z3, z4, z5, z6, z7 = outputs = [Signal(intbv(0)[w:]) for i in range(n)]
inst = Array8Sorter_v(a0, a1, a2, a3, a4, a5, a6, a7,
z0, z1, z2, z3, z4, z5, z6, z7)
@ -30,11 +32,7 @@ def bench():
def test_bench():
sim = Simulation(bench())
sim.run()
bench().run_sim()
if __name__ == '__main__':
test_bench()

View File

@ -0,0 +1,497 @@
// File: Array8Sorter.v
// Generated by MyHDL 1.0dev
// Date: Sat Mar 19 15:39:54 2016
`timescale 1ns/10ps
module Array8Sorter (
a0,
a1,
a2,
a3,
a4,
a5,
a6,
a7,
z0,
z1,
z2,
z3,
z4,
z5,
z6,
z7
);
input [3:0] a0;
input [3:0] a1;
input [3:0] a2;
input [3:0] a3;
input [3:0] a4;
input [3:0] a5;
input [3:0] a6;
input [3:0] a7;
output [3:0] z0;
wire [3:0] z0;
output [3:0] z1;
wire [3:0] z1;
output [3:0] z2;
wire [3:0] z2;
output [3:0] z3;
wire [3:0] z3;
output [3:0] z4;
wire [3:0] z4;
output [3:0] z5;
wire [3:0] z5;
output [3:0] z6;
wire [3:0] z6;
output [3:0] z7;
wire [3:0] z7;
wire [3:0] sort_losort_losort_losort_feedthru_34_z;
wire [3:0] sort_losort_losort_hisort_feedthru_35_z;
reg [3:0] sort_losort_losort_merge_comp_26_z1;
reg [3:0] sort_losort_losort_merge_comp_26_z2;
wire [3:0] sort_losort_losort_merge_lomerge_feedthru_36_z;
wire [3:0] sort_losort_losort_merge_hiMerge_feedthru_37_z;
wire [3:0] sort_losort_hisort_losort_feedthru_38_z;
wire [3:0] sort_losort_hisort_hisort_feedthru_39_z;
reg [3:0] sort_losort_hisort_merge_comp_27_z1;
reg [3:0] sort_losort_hisort_merge_comp_27_z2;
wire [3:0] sort_losort_hisort_merge_lomerge_feedthru_40_z;
wire [3:0] sort_losort_hisort_merge_hiMerge_feedthru_41_z;
reg [3:0] sort_losort_merge_comp_28_z1;
reg [3:0] sort_losort_merge_comp_28_z2;
reg [3:0] sort_losort_merge_comp_29_z1;
reg [3:0] sort_losort_merge_comp_29_z2;
reg [3:0] sort_losort_merge_lomerge_comp_30_z1;
reg [3:0] sort_losort_merge_lomerge_comp_30_z2;
wire [3:0] sort_losort_merge_lomerge_lomerge_feedthru_42_z;
wire [3:0] sort_losort_merge_lomerge_hiMerge_feedthru_43_z;
reg [3:0] sort_losort_merge_hiMerge_comp_31_z1;
reg [3:0] sort_losort_merge_hiMerge_comp_31_z2;
wire [3:0] sort_losort_merge_hiMerge_lomerge_feedthru_44_z;
wire [3:0] sort_losort_merge_hiMerge_hiMerge_feedthru_45_z;
wire [3:0] sort_hisort_losort_losort_feedthru_46_z;
wire [3:0] sort_hisort_losort_hisort_feedthru_47_z;
reg [3:0] sort_hisort_losort_merge_comp_32_z1;
reg [3:0] sort_hisort_losort_merge_comp_32_z2;
wire [3:0] sort_hisort_losort_merge_lomerge_feedthru_48_z;
wire [3:0] sort_hisort_losort_merge_hiMerge_feedthru_49_z;
wire [3:0] sort_hisort_hisort_losort_feedthru_50_z;
wire [3:0] sort_hisort_hisort_hisort_feedthru_51_z;
reg [3:0] sort_hisort_hisort_merge_comp_33_z1;
reg [3:0] sort_hisort_hisort_merge_comp_33_z2;
wire [3:0] sort_hisort_hisort_merge_lomerge_feedthru_52_z;
wire [3:0] sort_hisort_hisort_merge_hiMerge_feedthru_53_z;
reg [3:0] sort_hisort_merge_comp_34_z1;
reg [3:0] sort_hisort_merge_comp_34_z2;
reg [3:0] sort_hisort_merge_comp_35_z1;
reg [3:0] sort_hisort_merge_comp_35_z2;
reg [3:0] sort_hisort_merge_lomerge_comp_36_z1;
reg [3:0] sort_hisort_merge_lomerge_comp_36_z2;
wire [3:0] sort_hisort_merge_lomerge_lomerge_feedthru_54_z;
wire [3:0] sort_hisort_merge_lomerge_hiMerge_feedthru_55_z;
reg [3:0] sort_hisort_merge_hiMerge_comp_37_z1;
reg [3:0] sort_hisort_merge_hiMerge_comp_37_z2;
wire [3:0] sort_hisort_merge_hiMerge_lomerge_feedthru_56_z;
wire [3:0] sort_hisort_merge_hiMerge_hiMerge_feedthru_57_z;
reg [3:0] sort_merge_comp_38_z1;
reg [3:0] sort_merge_comp_38_z2;
reg [3:0] sort_merge_comp_39_z1;
reg [3:0] sort_merge_comp_39_z2;
reg [3:0] sort_merge_comp_40_z1;
reg [3:0] sort_merge_comp_40_z2;
reg [3:0] sort_merge_comp_41_z1;
reg [3:0] sort_merge_comp_41_z2;
reg [3:0] sort_merge_lomerge_comp_42_z1;
reg [3:0] sort_merge_lomerge_comp_42_z2;
reg [3:0] sort_merge_lomerge_comp_43_z1;
reg [3:0] sort_merge_lomerge_comp_43_z2;
reg [3:0] sort_merge_lomerge_lomerge_comp_44_z1;
reg [3:0] sort_merge_lomerge_lomerge_comp_44_z2;
reg [3:0] sort_merge_lomerge_hiMerge_comp_45_z1;
reg [3:0] sort_merge_lomerge_hiMerge_comp_45_z2;
reg [3:0] sort_merge_hiMerge_comp_46_z1;
reg [3:0] sort_merge_hiMerge_comp_46_z2;
reg [3:0] sort_merge_hiMerge_comp_47_z1;
reg [3:0] sort_merge_hiMerge_comp_47_z2;
reg [3:0] sort_merge_hiMerge_lomerge_comp_48_z1;
reg [3:0] sort_merge_hiMerge_lomerge_comp_48_z2;
reg [3:0] sort_merge_hiMerge_hiMerge_comp_49_z1;
reg [3:0] sort_merge_hiMerge_hiMerge_comp_49_z2;
assign sort_losort_losort_losort_feedthru_34_z = a0;
assign sort_losort_losort_hisort_feedthru_35_z = a1;
always @(sort_losort_losort_losort_feedthru_34_z, sort_losort_losort_hisort_feedthru_35_z) begin: ARRAY8SORTER_SORT_LOSORT_LOSORT_MERGE_COMP_26_LOGIC
sort_losort_losort_merge_comp_26_z1 = sort_losort_losort_losort_feedthru_34_z;
sort_losort_losort_merge_comp_26_z2 = sort_losort_losort_hisort_feedthru_35_z;
if ((1'b1 == (sort_losort_losort_losort_feedthru_34_z > sort_losort_losort_hisort_feedthru_35_z))) begin
sort_losort_losort_merge_comp_26_z1 = sort_losort_losort_hisort_feedthru_35_z;
sort_losort_losort_merge_comp_26_z2 = sort_losort_losort_losort_feedthru_34_z;
end
end
assign sort_losort_losort_merge_lomerge_feedthru_36_z = sort_losort_losort_merge_comp_26_z1;
assign sort_losort_losort_merge_hiMerge_feedthru_37_z = sort_losort_losort_merge_comp_26_z2;
assign sort_losort_hisort_losort_feedthru_38_z = a2;
assign sort_losort_hisort_hisort_feedthru_39_z = a3;
always @(sort_losort_hisort_losort_feedthru_38_z, sort_losort_hisort_hisort_feedthru_39_z) begin: ARRAY8SORTER_SORT_LOSORT_HISORT_MERGE_COMP_27_LOGIC
sort_losort_hisort_merge_comp_27_z1 = sort_losort_hisort_losort_feedthru_38_z;
sort_losort_hisort_merge_comp_27_z2 = sort_losort_hisort_hisort_feedthru_39_z;
if ((1'b0 == (sort_losort_hisort_losort_feedthru_38_z > sort_losort_hisort_hisort_feedthru_39_z))) begin
sort_losort_hisort_merge_comp_27_z1 = sort_losort_hisort_hisort_feedthru_39_z;
sort_losort_hisort_merge_comp_27_z2 = sort_losort_hisort_losort_feedthru_38_z;
end
end
assign sort_losort_hisort_merge_lomerge_feedthru_40_z = sort_losort_hisort_merge_comp_27_z1;
assign sort_losort_hisort_merge_hiMerge_feedthru_41_z = sort_losort_hisort_merge_comp_27_z2;
always @(sort_losort_losort_merge_lomerge_feedthru_36_z, sort_losort_hisort_merge_lomerge_feedthru_40_z) begin: ARRAY8SORTER_SORT_LOSORT_MERGE_COMP_28_LOGIC
sort_losort_merge_comp_28_z1 = sort_losort_losort_merge_lomerge_feedthru_36_z;
sort_losort_merge_comp_28_z2 = sort_losort_hisort_merge_lomerge_feedthru_40_z;
if ((1'b1 == (sort_losort_losort_merge_lomerge_feedthru_36_z > sort_losort_hisort_merge_lomerge_feedthru_40_z))) begin
sort_losort_merge_comp_28_z1 = sort_losort_hisort_merge_lomerge_feedthru_40_z;
sort_losort_merge_comp_28_z2 = sort_losort_losort_merge_lomerge_feedthru_36_z;
end
end
always @(sort_losort_losort_merge_hiMerge_feedthru_37_z, sort_losort_hisort_merge_hiMerge_feedthru_41_z) begin: ARRAY8SORTER_SORT_LOSORT_MERGE_COMP_29_LOGIC
sort_losort_merge_comp_29_z1 = sort_losort_losort_merge_hiMerge_feedthru_37_z;
sort_losort_merge_comp_29_z2 = sort_losort_hisort_merge_hiMerge_feedthru_41_z;
if ((1'b1 == (sort_losort_losort_merge_hiMerge_feedthru_37_z > sort_losort_hisort_merge_hiMerge_feedthru_41_z))) begin
sort_losort_merge_comp_29_z1 = sort_losort_hisort_merge_hiMerge_feedthru_41_z;
sort_losort_merge_comp_29_z2 = sort_losort_losort_merge_hiMerge_feedthru_37_z;
end
end
always @(sort_losort_merge_comp_28_z1, sort_losort_merge_comp_29_z1) begin: ARRAY8SORTER_SORT_LOSORT_MERGE_LOMERGE_COMP_30_LOGIC
sort_losort_merge_lomerge_comp_30_z1 = sort_losort_merge_comp_28_z1;
sort_losort_merge_lomerge_comp_30_z2 = sort_losort_merge_comp_29_z1;
if ((1'b1 == (sort_losort_merge_comp_28_z1 > sort_losort_merge_comp_29_z1))) begin
sort_losort_merge_lomerge_comp_30_z1 = sort_losort_merge_comp_29_z1;
sort_losort_merge_lomerge_comp_30_z2 = sort_losort_merge_comp_28_z1;
end
end
assign sort_losort_merge_lomerge_lomerge_feedthru_42_z = sort_losort_merge_lomerge_comp_30_z1;
assign sort_losort_merge_lomerge_hiMerge_feedthru_43_z = sort_losort_merge_lomerge_comp_30_z2;
always @(sort_losort_merge_comp_28_z2, sort_losort_merge_comp_29_z2) begin: ARRAY8SORTER_SORT_LOSORT_MERGE_HIMERGE_COMP_31_LOGIC
sort_losort_merge_hiMerge_comp_31_z1 = sort_losort_merge_comp_28_z2;
sort_losort_merge_hiMerge_comp_31_z2 = sort_losort_merge_comp_29_z2;
if ((1'b1 == (sort_losort_merge_comp_28_z2 > sort_losort_merge_comp_29_z2))) begin
sort_losort_merge_hiMerge_comp_31_z1 = sort_losort_merge_comp_29_z2;
sort_losort_merge_hiMerge_comp_31_z2 = sort_losort_merge_comp_28_z2;
end
end
assign sort_losort_merge_hiMerge_lomerge_feedthru_44_z = sort_losort_merge_hiMerge_comp_31_z1;
assign sort_losort_merge_hiMerge_hiMerge_feedthru_45_z = sort_losort_merge_hiMerge_comp_31_z2;
assign sort_hisort_losort_losort_feedthru_46_z = a4;
assign sort_hisort_losort_hisort_feedthru_47_z = a5;
always @(sort_hisort_losort_losort_feedthru_46_z, sort_hisort_losort_hisort_feedthru_47_z) begin: ARRAY8SORTER_SORT_HISORT_LOSORT_MERGE_COMP_32_LOGIC
sort_hisort_losort_merge_comp_32_z1 = sort_hisort_losort_losort_feedthru_46_z;
sort_hisort_losort_merge_comp_32_z2 = sort_hisort_losort_hisort_feedthru_47_z;
if ((1'b1 == (sort_hisort_losort_losort_feedthru_46_z > sort_hisort_losort_hisort_feedthru_47_z))) begin
sort_hisort_losort_merge_comp_32_z1 = sort_hisort_losort_hisort_feedthru_47_z;
sort_hisort_losort_merge_comp_32_z2 = sort_hisort_losort_losort_feedthru_46_z;
end
end
assign sort_hisort_losort_merge_lomerge_feedthru_48_z = sort_hisort_losort_merge_comp_32_z1;
assign sort_hisort_losort_merge_hiMerge_feedthru_49_z = sort_hisort_losort_merge_comp_32_z2;
assign sort_hisort_hisort_losort_feedthru_50_z = a6;
assign sort_hisort_hisort_hisort_feedthru_51_z = a7;
always @(sort_hisort_hisort_losort_feedthru_50_z, sort_hisort_hisort_hisort_feedthru_51_z) begin: ARRAY8SORTER_SORT_HISORT_HISORT_MERGE_COMP_33_LOGIC
sort_hisort_hisort_merge_comp_33_z1 = sort_hisort_hisort_losort_feedthru_50_z;
sort_hisort_hisort_merge_comp_33_z2 = sort_hisort_hisort_hisort_feedthru_51_z;
if ((1'b0 == (sort_hisort_hisort_losort_feedthru_50_z > sort_hisort_hisort_hisort_feedthru_51_z))) begin
sort_hisort_hisort_merge_comp_33_z1 = sort_hisort_hisort_hisort_feedthru_51_z;
sort_hisort_hisort_merge_comp_33_z2 = sort_hisort_hisort_losort_feedthru_50_z;
end
end
assign sort_hisort_hisort_merge_lomerge_feedthru_52_z = sort_hisort_hisort_merge_comp_33_z1;
assign sort_hisort_hisort_merge_hiMerge_feedthru_53_z = sort_hisort_hisort_merge_comp_33_z2;
always @(sort_hisort_losort_merge_lomerge_feedthru_48_z, sort_hisort_hisort_merge_lomerge_feedthru_52_z) begin: ARRAY8SORTER_SORT_HISORT_MERGE_COMP_34_LOGIC
sort_hisort_merge_comp_34_z1 = sort_hisort_losort_merge_lomerge_feedthru_48_z;
sort_hisort_merge_comp_34_z2 = sort_hisort_hisort_merge_lomerge_feedthru_52_z;
if ((1'b0 == (sort_hisort_losort_merge_lomerge_feedthru_48_z > sort_hisort_hisort_merge_lomerge_feedthru_52_z))) begin
sort_hisort_merge_comp_34_z1 = sort_hisort_hisort_merge_lomerge_feedthru_52_z;
sort_hisort_merge_comp_34_z2 = sort_hisort_losort_merge_lomerge_feedthru_48_z;
end
end
always @(sort_hisort_losort_merge_hiMerge_feedthru_49_z, sort_hisort_hisort_merge_hiMerge_feedthru_53_z) begin: ARRAY8SORTER_SORT_HISORT_MERGE_COMP_35_LOGIC
sort_hisort_merge_comp_35_z1 = sort_hisort_losort_merge_hiMerge_feedthru_49_z;
sort_hisort_merge_comp_35_z2 = sort_hisort_hisort_merge_hiMerge_feedthru_53_z;
if ((1'b0 == (sort_hisort_losort_merge_hiMerge_feedthru_49_z > sort_hisort_hisort_merge_hiMerge_feedthru_53_z))) begin
sort_hisort_merge_comp_35_z1 = sort_hisort_hisort_merge_hiMerge_feedthru_53_z;
sort_hisort_merge_comp_35_z2 = sort_hisort_losort_merge_hiMerge_feedthru_49_z;
end
end
always @(sort_hisort_merge_comp_34_z1, sort_hisort_merge_comp_35_z1) begin: ARRAY8SORTER_SORT_HISORT_MERGE_LOMERGE_COMP_36_LOGIC
sort_hisort_merge_lomerge_comp_36_z1 = sort_hisort_merge_comp_34_z1;
sort_hisort_merge_lomerge_comp_36_z2 = sort_hisort_merge_comp_35_z1;
if ((1'b0 == (sort_hisort_merge_comp_34_z1 > sort_hisort_merge_comp_35_z1))) begin
sort_hisort_merge_lomerge_comp_36_z1 = sort_hisort_merge_comp_35_z1;
sort_hisort_merge_lomerge_comp_36_z2 = sort_hisort_merge_comp_34_z1;
end
end
assign sort_hisort_merge_lomerge_lomerge_feedthru_54_z = sort_hisort_merge_lomerge_comp_36_z1;
assign sort_hisort_merge_lomerge_hiMerge_feedthru_55_z = sort_hisort_merge_lomerge_comp_36_z2;
always @(sort_hisort_merge_comp_34_z2, sort_hisort_merge_comp_35_z2) begin: ARRAY8SORTER_SORT_HISORT_MERGE_HIMERGE_COMP_37_LOGIC
sort_hisort_merge_hiMerge_comp_37_z1 = sort_hisort_merge_comp_34_z2;
sort_hisort_merge_hiMerge_comp_37_z2 = sort_hisort_merge_comp_35_z2;
if ((1'b0 == (sort_hisort_merge_comp_34_z2 > sort_hisort_merge_comp_35_z2))) begin
sort_hisort_merge_hiMerge_comp_37_z1 = sort_hisort_merge_comp_35_z2;
sort_hisort_merge_hiMerge_comp_37_z2 = sort_hisort_merge_comp_34_z2;
end
end
assign sort_hisort_merge_hiMerge_lomerge_feedthru_56_z = sort_hisort_merge_hiMerge_comp_37_z1;
assign sort_hisort_merge_hiMerge_hiMerge_feedthru_57_z = sort_hisort_merge_hiMerge_comp_37_z2;
always @(sort_losort_merge_lomerge_lomerge_feedthru_42_z, sort_hisort_merge_lomerge_lomerge_feedthru_54_z) begin: ARRAY8SORTER_SORT_MERGE_COMP_38_LOGIC
sort_merge_comp_38_z1 = sort_losort_merge_lomerge_lomerge_feedthru_42_z;
sort_merge_comp_38_z2 = sort_hisort_merge_lomerge_lomerge_feedthru_54_z;
if ((1'b1 == (sort_losort_merge_lomerge_lomerge_feedthru_42_z > sort_hisort_merge_lomerge_lomerge_feedthru_54_z))) begin
sort_merge_comp_38_z1 = sort_hisort_merge_lomerge_lomerge_feedthru_54_z;
sort_merge_comp_38_z2 = sort_losort_merge_lomerge_lomerge_feedthru_42_z;
end
end
always @(sort_losort_merge_lomerge_hiMerge_feedthru_43_z, sort_hisort_merge_lomerge_hiMerge_feedthru_55_z) begin: ARRAY8SORTER_SORT_MERGE_COMP_39_LOGIC
sort_merge_comp_39_z1 = sort_losort_merge_lomerge_hiMerge_feedthru_43_z;
sort_merge_comp_39_z2 = sort_hisort_merge_lomerge_hiMerge_feedthru_55_z;
if ((1'b1 == (sort_losort_merge_lomerge_hiMerge_feedthru_43_z > sort_hisort_merge_lomerge_hiMerge_feedthru_55_z))) begin
sort_merge_comp_39_z1 = sort_hisort_merge_lomerge_hiMerge_feedthru_55_z;
sort_merge_comp_39_z2 = sort_losort_merge_lomerge_hiMerge_feedthru_43_z;
end
end
always @(sort_losort_merge_hiMerge_lomerge_feedthru_44_z, sort_hisort_merge_hiMerge_lomerge_feedthru_56_z) begin: ARRAY8SORTER_SORT_MERGE_COMP_40_LOGIC
sort_merge_comp_40_z1 = sort_losort_merge_hiMerge_lomerge_feedthru_44_z;
sort_merge_comp_40_z2 = sort_hisort_merge_hiMerge_lomerge_feedthru_56_z;
if ((1'b1 == (sort_losort_merge_hiMerge_lomerge_feedthru_44_z > sort_hisort_merge_hiMerge_lomerge_feedthru_56_z))) begin
sort_merge_comp_40_z1 = sort_hisort_merge_hiMerge_lomerge_feedthru_56_z;
sort_merge_comp_40_z2 = sort_losort_merge_hiMerge_lomerge_feedthru_44_z;
end
end
always @(sort_losort_merge_hiMerge_hiMerge_feedthru_45_z, sort_hisort_merge_hiMerge_hiMerge_feedthru_57_z) begin: ARRAY8SORTER_SORT_MERGE_COMP_41_LOGIC
sort_merge_comp_41_z1 = sort_losort_merge_hiMerge_hiMerge_feedthru_45_z;
sort_merge_comp_41_z2 = sort_hisort_merge_hiMerge_hiMerge_feedthru_57_z;
if ((1'b1 == (sort_losort_merge_hiMerge_hiMerge_feedthru_45_z > sort_hisort_merge_hiMerge_hiMerge_feedthru_57_z))) begin
sort_merge_comp_41_z1 = sort_hisort_merge_hiMerge_hiMerge_feedthru_57_z;
sort_merge_comp_41_z2 = sort_losort_merge_hiMerge_hiMerge_feedthru_45_z;
end
end
always @(sort_merge_comp_38_z1, sort_merge_comp_40_z1) begin: ARRAY8SORTER_SORT_MERGE_LOMERGE_COMP_42_LOGIC
sort_merge_lomerge_comp_42_z1 = sort_merge_comp_38_z1;
sort_merge_lomerge_comp_42_z2 = sort_merge_comp_40_z1;
if ((1'b1 == (sort_merge_comp_38_z1 > sort_merge_comp_40_z1))) begin
sort_merge_lomerge_comp_42_z1 = sort_merge_comp_40_z1;
sort_merge_lomerge_comp_42_z2 = sort_merge_comp_38_z1;
end
end
always @(sort_merge_comp_39_z1, sort_merge_comp_41_z1) begin: ARRAY8SORTER_SORT_MERGE_LOMERGE_COMP_43_LOGIC
sort_merge_lomerge_comp_43_z1 = sort_merge_comp_39_z1;
sort_merge_lomerge_comp_43_z2 = sort_merge_comp_41_z1;
if ((1'b1 == (sort_merge_comp_39_z1 > sort_merge_comp_41_z1))) begin
sort_merge_lomerge_comp_43_z1 = sort_merge_comp_41_z1;
sort_merge_lomerge_comp_43_z2 = sort_merge_comp_39_z1;
end
end
always @(sort_merge_lomerge_comp_42_z1, sort_merge_lomerge_comp_43_z1) begin: ARRAY8SORTER_SORT_MERGE_LOMERGE_LOMERGE_COMP_44_LOGIC
sort_merge_lomerge_lomerge_comp_44_z1 = sort_merge_lomerge_comp_42_z1;
sort_merge_lomerge_lomerge_comp_44_z2 = sort_merge_lomerge_comp_43_z1;
if ((1'b1 == (sort_merge_lomerge_comp_42_z1 > sort_merge_lomerge_comp_43_z1))) begin
sort_merge_lomerge_lomerge_comp_44_z1 = sort_merge_lomerge_comp_43_z1;
sort_merge_lomerge_lomerge_comp_44_z2 = sort_merge_lomerge_comp_42_z1;
end
end
assign z0 = sort_merge_lomerge_lomerge_comp_44_z1;
assign z1 = sort_merge_lomerge_lomerge_comp_44_z2;
always @(sort_merge_lomerge_comp_42_z2, sort_merge_lomerge_comp_43_z2) begin: ARRAY8SORTER_SORT_MERGE_LOMERGE_HIMERGE_COMP_45_LOGIC
sort_merge_lomerge_hiMerge_comp_45_z1 = sort_merge_lomerge_comp_42_z2;
sort_merge_lomerge_hiMerge_comp_45_z2 = sort_merge_lomerge_comp_43_z2;
if ((1'b1 == (sort_merge_lomerge_comp_42_z2 > sort_merge_lomerge_comp_43_z2))) begin
sort_merge_lomerge_hiMerge_comp_45_z1 = sort_merge_lomerge_comp_43_z2;
sort_merge_lomerge_hiMerge_comp_45_z2 = sort_merge_lomerge_comp_42_z2;
end
end
assign z2 = sort_merge_lomerge_hiMerge_comp_45_z1;
assign z3 = sort_merge_lomerge_hiMerge_comp_45_z2;
always @(sort_merge_comp_38_z2, sort_merge_comp_40_z2) begin: ARRAY8SORTER_SORT_MERGE_HIMERGE_COMP_46_LOGIC
sort_merge_hiMerge_comp_46_z1 = sort_merge_comp_38_z2;
sort_merge_hiMerge_comp_46_z2 = sort_merge_comp_40_z2;
if ((1'b1 == (sort_merge_comp_38_z2 > sort_merge_comp_40_z2))) begin
sort_merge_hiMerge_comp_46_z1 = sort_merge_comp_40_z2;
sort_merge_hiMerge_comp_46_z2 = sort_merge_comp_38_z2;
end
end
always @(sort_merge_comp_39_z2, sort_merge_comp_41_z2) begin: ARRAY8SORTER_SORT_MERGE_HIMERGE_COMP_47_LOGIC
sort_merge_hiMerge_comp_47_z1 = sort_merge_comp_39_z2;
sort_merge_hiMerge_comp_47_z2 = sort_merge_comp_41_z2;
if ((1'b1 == (sort_merge_comp_39_z2 > sort_merge_comp_41_z2))) begin
sort_merge_hiMerge_comp_47_z1 = sort_merge_comp_41_z2;
sort_merge_hiMerge_comp_47_z2 = sort_merge_comp_39_z2;
end
end
always @(sort_merge_hiMerge_comp_46_z1, sort_merge_hiMerge_comp_47_z1) begin: ARRAY8SORTER_SORT_MERGE_HIMERGE_LOMERGE_COMP_48_LOGIC
sort_merge_hiMerge_lomerge_comp_48_z1 = sort_merge_hiMerge_comp_46_z1;
sort_merge_hiMerge_lomerge_comp_48_z2 = sort_merge_hiMerge_comp_47_z1;
if ((1'b1 == (sort_merge_hiMerge_comp_46_z1 > sort_merge_hiMerge_comp_47_z1))) begin
sort_merge_hiMerge_lomerge_comp_48_z1 = sort_merge_hiMerge_comp_47_z1;
sort_merge_hiMerge_lomerge_comp_48_z2 = sort_merge_hiMerge_comp_46_z1;
end
end
assign z4 = sort_merge_hiMerge_lomerge_comp_48_z1;
assign z5 = sort_merge_hiMerge_lomerge_comp_48_z2;
always @(sort_merge_hiMerge_comp_46_z2, sort_merge_hiMerge_comp_47_z2) begin: ARRAY8SORTER_SORT_MERGE_HIMERGE_HIMERGE_COMP_49_LOGIC
sort_merge_hiMerge_hiMerge_comp_49_z1 = sort_merge_hiMerge_comp_46_z2;
sort_merge_hiMerge_hiMerge_comp_49_z2 = sort_merge_hiMerge_comp_47_z2;
if ((1'b1 == (sort_merge_hiMerge_comp_46_z2 > sort_merge_hiMerge_comp_47_z2))) begin
sort_merge_hiMerge_hiMerge_comp_49_z1 = sort_merge_hiMerge_comp_47_z2;
sort_merge_hiMerge_hiMerge_comp_49_z2 = sort_merge_hiMerge_comp_46_z2;
end
end
assign z6 = sort_merge_hiMerge_hiMerge_comp_49_z1;
assign z7 = sort_merge_hiMerge_hiMerge_comp_49_z2;
endmodule

View File

@ -1,3 +1,4 @@
import myhdl
from myhdl import *
from myhdl.conversion import analyze
@ -33,6 +34,7 @@ def simulate(timesteps):
tb = traceSignals(test_dff)
sim = Simulation(tb)
sim.run(timesteps)
sim.quit()
simulate(2000)

View File

@ -1,3 +1,4 @@
import myhdl
from myhdl import *
def dffa(q, d, clk, rst):
@ -44,6 +45,7 @@ def simulate(timesteps):
tb = traceSignals(test_dffa)
sim = Simulation(tb)
sim.run(timesteps)
sim.quit()
simulate(20000)

View File

@ -1,3 +1,4 @@
import myhdl
from myhdl import *
ACTIVE = 0

View File

@ -1,3 +1,4 @@
import myhdl
from myhdl import *
ACTIVE = 0

View File

@ -1,3 +1,4 @@
import myhdl
from myhdl import *
ACTIVE, INACTIVE = bool(0), bool(1)

View File

@ -1,3 +1,4 @@
import myhdl
from myhdl import *
def latch(q, d, g):
@ -33,6 +34,7 @@ def simulate(timesteps):
tb = traceSignals(test_latch)
sim = Simulation(tb)
sim.run(timesteps)
sim.quit()
simulate(20000)

View File

@ -1,5 +1,6 @@
from math import atan, sqrt, ceil, floor, pi
import myhdl
from myhdl import *
t_State = enum("WAITING", "CALCULATING")

View File

@ -1,6 +1,7 @@
from math import pi, sin, cos, log
import random
import myhdl
from myhdl import *
from SineComputer import SineComputer, SineComputer_v

View File

@ -1,3 +1,4 @@
import myhdl
from myhdl import *
from TimeCount import TimeCount

View File

@ -1,3 +1,4 @@
import myhdl
from myhdl import *
def TimeCount(tens, ones, tenths, startstop, reset, clock):

View File

@ -1,5 +1,6 @@
import seven_segment
import myhdl
from myhdl import *
code = [None] * 10

View File

@ -1,5 +1,6 @@
from random import randrange
import myhdl
from myhdl import *
from TimeCount import TimeCount

View File

@ -1,5 +1,6 @@
from random import randrange
import seven_segment
import myhdl
from myhdl import *
from bcd2led import bcd2led

View File

@ -0,0 +1,18 @@
from myhdl import block, delay, instance
@block
def ClkDriver(clk, period=20):
lowTime = int(period / 2)
highTime = period - lowTime
@instance
def drive_clk():
while True:
yield delay(lowTime)
clk.next = 1
yield delay(highTime)
clk.next = 0
return drive_clk

View File

@ -1,6 +1,6 @@
// File: FramerCtrl.v
// Generated by MyHDL 0.8dev
// Date: Fri Dec 21 15:02:39 2012
// Generated by MyHDL 1.0dev
// Date: Mon Feb 15 21:03:52 2016
`timescale 1ns/10ps
@ -35,7 +35,7 @@ reg [7:0] index;
always @(posedge clk, negedge reset_n) begin: FRAMERCTRL_FSM
if ((reset_n == 0)) begin
if ((reset_n == 1'b0)) begin
SOF <= 0;
index <= 0;
state <= 3'b001;
@ -66,7 +66,7 @@ always @(posedge clk, negedge reset_n) begin: FRAMERCTRL_FSM
state <= 3'b001;
end
end
SOF <= (index == (8 - 1));
SOF <= ($signed({1'b0, index}) == (8 - 1));
end
default: begin
$finish;

View File

@ -1,11 +1,13 @@
-- File: FramerCtrl.vhd
-- Generated by MyHDL 0.8dev
-- Date: Fri Dec 21 15:02:39 2012
-- Generated by MyHDL 1.0dev
-- Date: Mon Feb 15 21:03:52 2016
package pck_FramerCtrl is
attribute enum_encoding: string;
type t_enum_t_State_1 is (
SEARCH,
CONFIRM,
@ -20,7 +22,7 @@ use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
use std.textio.all;
use work.pck_myhdl_08.all;
use work.pck_myhdl_10.all;
use work.pck_FramerCtrl.all;
@ -43,6 +45,8 @@ end entity FramerCtrl;
architecture MyHDL of FramerCtrl is
signal index: unsigned(7 downto 0);
begin
@ -50,18 +54,19 @@ begin
FRAMERCTRL_FSM: process (clk, reset_n) is
begin
if (reset_n = '0') then
SOF <= '0';
index <= "00000000";
index <= to_unsigned(0, 8);
state <= SEARCH;
elsif rising_edge(clk) then
index <= ((index + 1) mod 8);
SOF <= '0';
case state is
when SEARCH =>
index <= "00000001";
index <= to_unsigned(1, 8);
if bool(syncFlag) then
state <= CONFIRM;
end if;

View File

@ -1,3 +1,4 @@
import myhdl
from myhdl import *
from bin2gray2 import bin2gray

View File

@ -1,56 +0,0 @@
// File: GrayIncReg.v
// Generated by MyHDL 0.8dev
// Date: Fri Dec 21 15:02:38 2012
`timescale 1ns/10ps
module GrayIncReg (
graycnt,
enable,
clock,
reset
);
output [7:0] graycnt;
reg [7:0] graycnt;
input enable;
input clock;
input reset;
reg [7:0] graycnt_comb;
reg [7:0] gray_inc_1_bincnt;
always @(posedge clock, negedge reset) begin: GRAYINCREG_GRAY_INC_1_INC_1_INCLOGIC
if (reset == 0) begin
gray_inc_1_bincnt <= 0;
end
else begin
if (enable) begin
gray_inc_1_bincnt <= (gray_inc_1_bincnt + 1);
end
end
end
always @(gray_inc_1_bincnt) begin: GRAYINCREG_GRAY_INC_1_BIN2GRAY_1_LOGIC
integer i;
reg [9-1:0] Bext;
Bext = 9'h0;
Bext = gray_inc_1_bincnt;
for (i=0; i<8; i=i+1) begin
graycnt_comb[i] = (Bext[(i + 1)] ^ Bext[i]);
end
end
always @(posedge clock) begin: GRAYINCREG_REG_1
graycnt <= graycnt_comb;
end
endmodule

View File

@ -1,63 +0,0 @@
-- File: GrayIncReg.vhd
-- Generated by MyHDL 0.8dev
-- Date: Fri Dec 21 15:02:38 2012
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
use std.textio.all;
use work.pck_myhdl_08.all;
entity GrayIncReg is
port (
graycnt: out unsigned(7 downto 0);
enable: in std_logic;
clock: in std_logic;
reset: in std_logic
);
end entity GrayIncReg;
architecture MyHDL of GrayIncReg is
signal graycnt_comb: unsigned(7 downto 0);
signal gray_inc_1_bincnt: unsigned(7 downto 0);
begin
GRAYINCREG_GRAY_INC_1_INC_1_INCLOGIC: process (clock, reset) is
begin
if (reset = '0') then
gray_inc_1_bincnt <= (others => '0');
elsif rising_edge(clock) then
if bool(enable) then
gray_inc_1_bincnt <= (gray_inc_1_bincnt + 1);
end if;
end if;
end process GRAYINCREG_GRAY_INC_1_INC_1_INCLOGIC;
GRAYINCREG_GRAY_INC_1_BIN2GRAY_1_LOGIC: process (gray_inc_1_bincnt) is
variable Bext: unsigned(8 downto 0);
begin
Bext := to_unsigned(0, 9);
Bext := resize(gray_inc_1_bincnt, 9);
for i in 0 to 8-1 loop
graycnt_comb(i) <= (Bext((i + 1)) xor Bext(i));
end loop;
end process GRAYINCREG_GRAY_INC_1_BIN2GRAY_1_LOGIC;
GRAYINCREG_REG_1: process (clock) is
begin
if rising_edge(clock) then
graycnt <= graycnt_comb;
end if;
end process GRAYINCREG_REG_1;
end architecture MyHDL;

11
example/manual/Hello.py Normal file
View File

@ -0,0 +1,11 @@
from myhdl import block, always, now
@block
def Hello(clk, to="World!"):
@always(clk.posedge)
def say_hello():
print("%s Hello %s" % (now(), to))
return say_hello

View File

@ -1,43 +1,16 @@
from myhdl import Signal, delay, Simulation, always_comb, instance, intbv, bin, traceSignals
from myhdl import block, always_comb
def bin2gray(B, G, width):
@block
def bin2gray(B, G):
""" Gray encoder.
B -- input intbv signal, binary encoded
G -- output intbv signal, gray encoded
width -- bit width
B -- binary input
G -- Gray encoded output
"""
@always_comb
def logic():
for i in range(width):
G.next[i] = B[i+1] ^ B[i]
G.next = (B>>1) ^ B
return logic
def testBench(width):
B = Signal(intbv(0))
G = Signal(intbv(0))
dut = traceSignals(bin2gray, B, G, width)
@instance
def stimulus():
for i in range(2**width):
B.next = intbv(i)
yield delay(10)
print "B: " + bin(B, width) + "| G: " + bin(G, width)
return dut, stimulus
def main():
sim = Simulation(testBench(width=3))
sim.run()
if __name__ == '__main__':
main()

View File

@ -1,6 +1,6 @@
// File: bin2gray.v
// Generated by MyHDL 0.8dev
// Date: Fri Dec 21 15:02:38 2012
// Generated by MyHDL 1.0dev
// Date: Mon May 23 16:09:27 2016
`timescale 1ns/10ps
@ -11,27 +11,16 @@ module bin2gray (
);
// Gray encoder.
//
// B -- input intbv signal, binary encoded
// G -- output intbv signal, gray encoded
// width -- bit width
// B -- binary input
// G -- Gray encoded output
input [7:0] B;
output [7:0] G;
reg [7:0] G;
wire [7:0] G;
always @(B) begin: BIN2GRAY_LOGIC
integer i;
reg [9-1:0] Bext;
Bext = 9'h0;
Bext = B;
for (i=0; i<8; i=i+1) begin
G[i] = (Bext[(i + 1)] ^ Bext[i]);
end
end
assign G = ((B >>> 1) ^ B);
endmodule

View File

@ -1,6 +1,6 @@
-- File: bin2gray.vhd
-- Generated by MyHDL 0.8dev
-- Date: Fri Dec 21 15:02:38 2012
-- Generated by MyHDL 1.0dev
-- Date: Mon May 23 16:09:27 2016
library IEEE;
@ -8,7 +8,7 @@ use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
use std.textio.all;
use work.pck_myhdl_08.all;
use work.pck_myhdl_10.all;
entity bin2gray is
port (
@ -18,26 +18,19 @@ entity bin2gray is
end entity bin2gray;
-- Gray encoder.
--
-- B -- input intbv signal, binary encoded
-- G -- output intbv signal, gray encoded
-- width -- bit width
-- B -- binary input
-- G -- Gray encoded output
architecture MyHDL of bin2gray is
begin
BIN2GRAY_LOGIC: process (B) is
variable Bext: unsigned(8 downto 0);
begin
Bext := to_unsigned(0, 9);
Bext := resize(B, 9);
for i in 0 to 8-1 loop
G(i) <= (Bext((i + 1)) xor Bext(i));
end loop;
end process BIN2GRAY_LOGIC;
G <= (shift_right(B, 1) xor B);
end architecture MyHDL;

View File

@ -1,3 +1,4 @@
import myhdl
from myhdl import *
def bin2gray(B, G, width):

View File

@ -0,0 +1,11 @@
from myhdl import block
@block
def bin2gray(B, G):
# DUMMY PLACEHOLDER
""" Gray encoder.
B -- binary input
G -- Gray encoded output
"""
pass

View File

@ -0,0 +1,16 @@
from myhdl import block, always_comb
@block
def bin2gray(B, G):
# INCORRECT IMPLEMENTATION
""" Gray encoder.
B -- binary input
G -- Gray encoded output
"""
@always_comb
def logic():
G.next = B[0]
return logic

View File

@ -0,0 +1,17 @@
from myhdl import toVerilog, toVHDL, Signal, ResetSignal, modbv
from inc import inc
ACTIVE_LOW, INACTIVE_HIGH = 0, 1
# conversion
m = 8
count = Signal(modbv(0)[m:])
enable = Signal(bool(0))
clock = Signal(bool(0))
reset = ResetSignal(0, active=0, async=True)
inc_inst = inc(count, enable, clock, reset)
inc_inst = toVerilog(inc, count, enable, clock, reset)
inc_inst = toVHDL(inc, count, enable, clock, reset)

View File

@ -0,0 +1,15 @@
from myhdl import Signal, intbv
from bin2gray import bin2gray
def convert(hdl, width=8):
B = Signal(intbv(0)[width:])
G = Signal(intbv(0)[width:])
inst = bin2gray(B, G)
inst.convert(hdl=hdl)
convert(hdl='Verilog')
convert(hdl='VHDL')

View File

@ -0,0 +1,15 @@
from myhdl import Signal, ResetSignal, modbv
from gray_inc_reg import gray_inc_reg
def convert_gray_inc_reg(hdl, width=8):
graycnt = Signal(modbv(0)[width:])
enable = Signal(bool())
clock = Signal(bool())
reset = ResetSignal(0, active=0, async=True)
inst = gray_inc_reg(graycnt, enable, clock, reset, width)
inst.convert(hdl)
convert_gray_inc_reg(hdl='Verilog')
convert_gray_inc_reg(hdl='VHDL')

View File

@ -0,0 +1,21 @@
from myhdl import Signal, ResetSignal, modbv
from inc import inc
def convert_inc(hdl):
"""Convert inc block to Verilog or VHDL."""
m = 8
count = Signal(modbv(0)[m:])
enable = Signal(bool(0))
clock = Signal(bool(0))
reset = ResetSignal(0, active=0, async=True)
inc_1 = inc(count, enable, clock, reset)
inc_1.convert(hdl=hdl)
convert_inc(hdl='Verilog')
convert_inc(hdl='VHDL')

View File

@ -1,3 +1,4 @@
import myhdl
from myhdl import *
def inc_comb(nextCount, count, n):

View File

@ -1,6 +1,7 @@
import sys
import traceback
import myhdl
from myhdl import *
class Error(Exception):

View File

@ -1,91 +1,54 @@
from myhdl import *
from myhdl import block, always_seq, Signal, intbv, enum
ACTIVE_LOW = 0
FRAME_SIZE = 8
t_State = enum('SEARCH', 'CONFIRM', 'SYNC')
t_state = enum('SEARCH', 'CONFIRM', 'SYNC')
@block
def framer_ctrl(sof, state, sync_flag, clk, reset_n):
def FramerCtrl(SOF, state, syncFlag, clk, reset_n):
""" Framing control FSM.
SOF -- start-of-frame output bit
sof -- start-of-frame output bit
state -- FramerState output
syncFlag -- sync pattern found indication input
sync_flag -- sync pattern found indication input
clk -- clock input
reset_n -- active low reset
"""
index = Signal(0) # position in frame
@always(clk.posedge, reset_n.negedge)
"""
index = Signal(intbv(0, min=0, max=FRAME_SIZE)) # position in frame
@always_seq(clk.posedge, reset=reset_n)
def FSM():
if reset_n == ACTIVE_LOW:
SOF.next = 0
sof.next = 0
index.next = 0
state.next = t_State.SEARCH
state.next = t_state.SEARCH
else:
index.next = (index + 1) % FRAME_SIZE
SOF.next = 0
sof.next = 0
if state == t_State.SEARCH:
if state == t_state.SEARCH:
index.next = 1
if syncFlag:
state.next = t_State.CONFIRM
if sync_flag:
state.next = t_state.CONFIRM
elif state == t_State.CONFIRM:
elif state == t_state.CONFIRM:
if index == 0:
if syncFlag:
state.next = t_State.SYNC
if sync_flag:
state.next = t_state.SYNC
else:
state.next = t_State.SEARCH
state.next = t_state.SEARCH
elif state == t_State.SYNC:
elif state == t_state.SYNC:
if index == 0:
if not syncFlag:
state.next = t_State.SEARCH
SOF.next = (index == FRAME_SIZE-1)
if not sync_flag:
state.next = t_state.SEARCH
sof.next = (index == FRAME_SIZE-1)
else:
raise ValueError("Undefined state")
return FSM
def testbench():
SOF = Signal(bool(0))
syncFlag = Signal(bool(0))
clk = Signal(bool(0))
reset_n = Signal(bool(1))
state = Signal(t_State.SEARCH)
framectrl = FramerCtrl(SOF, state, syncFlag, clk, reset_n)
@always(delay(10))
def clkgen():
clk.next = not clk
@instance
def stimulus():
for i in range(3):
yield clk.posedge
for n in (12, 8, 8, 4):
syncFlag.next = 1
yield clk.posedge
syncFlag.next = 0
for i in range(n-1):
yield clk.posedge
raise StopSimulation
return framectrl, clkgen, stimulus
def main():
tb_fsm = traceSignals(testbench)
sim = Simulation(tb_fsm)
sim.run()
if __name__ == '__main__':
main()

View File

@ -1,3 +1,4 @@
import myhdl
from myhdl import *
# SEARCH, CONFIRM, SYNC = range(3)

View File

@ -1,6 +1,7 @@
import os
path = os.path
import myhdl
from myhdl import *
# SEARCH, CONFIRM, SYNC = range(3)
@ -9,6 +10,7 @@ ACTIVE_LOW = bool(0)
FRAME_SIZE = 8
t_State = enum('SEARCH', 'CONFIRM', 'SYNC', encoding="one_hot")
@block
def FramerCtrl(SOF, state, syncFlag, clk, reset_n):
""" Framing control FSM.
@ -62,8 +64,8 @@ def main():
reset_n = Signal(bool(1))
state = Signal(t_State.SEARCH)
toVerilog(FramerCtrl, SOF, state, syncFlag, clk, reset_n)
toVHDL(FramerCtrl, SOF, state, syncFlag, clk, reset_n)
toVerilog(FramerCtrl(SOF, state, syncFlag, clk, reset_n))
toVHDL(FramerCtrl(SOF, state, syncFlag, clk, reset_n))
if __name__ == '__main__':

View File

@ -0,0 +1,15 @@
from myhdl import block, Signal, modbv
from bin2gray import bin2gray
from inc import inc
@block
def gray_inc(graycnt, enable, clock, reset, width):
bincnt = Signal(modbv(0)[width:])
inc_0 = inc(bincnt, enable, clock, reset)
bin2gray_0 = bin2gray(B=bincnt, G=graycnt)
return inc_0, bin2gray_0

View File

@ -0,0 +1,17 @@
from myhdl import block, always_seq, Signal, modbv
from gray_inc import gray_inc
@block
def gray_inc_reg(graycnt, enable, clock, reset, width):
graycnt_comb = Signal(modbv(0)[width:])
gray_inc_0 = gray_inc(graycnt_comb, enable, clock, reset, width)
@always_seq(clock.posedge, reset=reset)
def reg_0():
graycnt.next = graycnt_comb
return gray_inc_0, reg_0

View File

@ -0,0 +1,52 @@
// File: gray_inc_reg.v
// Generated by MyHDL 1.0dev
// Date: Thu Jun 23 19:06:43 2016
`timescale 1ns/10ps
module gray_inc_reg (
graycnt,
enable,
clock,
reset
);
output [7:0] graycnt;
reg [7:0] graycnt;
input enable;
input clock;
input reset;
wire [7:0] graycnt_comb;
reg [7:0] gray_inc_1_bincnt;
always @(posedge clock, negedge reset) begin: GRAY_INC_REG_GRAY_INC_1_INC_1_SEQ
if (reset == 0) begin
gray_inc_1_bincnt <= 0;
end
else begin
if (enable) begin
gray_inc_1_bincnt <= (gray_inc_1_bincnt + 1);
end
end
end
assign graycnt_comb = ((gray_inc_1_bincnt >>> 1) ^ gray_inc_1_bincnt);
always @(posedge clock, negedge reset) begin: GRAY_INC_REG_REG_0
if (reset == 0) begin
graycnt <= 0;
end
else begin
graycnt <= graycnt_comb;
end
end
endmodule

Some files were not shown because too many files have changed in this diff Show More