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:
commit
d726752437
9
.gitignore
vendored
9
.gitignore
vendored
@ -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/
|
||||
|
24
.travis.yml
24
.travis.yml
@ -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
|
||||
|
@ -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
|
||||
-------------------------
|
||||
|
||||
|
6
Makefile
6
Makefile
@ -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
|
||||
|
28
README.md
28
README.md
@ -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.
|
||||
|
@ -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
|
||||
|
@ -1,2 +0,0 @@
|
||||
all:
|
||||
python test_all.py
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
21
cosimulation/modelsim-win/Makefile
Normal file
21
cosimulation/modelsim-win/Makefile
Normal 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 ||:
|
532
cosimulation/modelsim-win/myhdl_vpi.c
Normal file
532
cosimulation/modelsim-win/myhdl_vpi.c
Normal 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]();
|
||||
}
|
||||
}
|
11
cosimulation/modelsim-win/test/bin2gray.py
Normal file
11
cosimulation/modelsim-win/test/bin2gray.py
Normal 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)
|
2
cosimulation/modelsim-win/test/cosim.do
Normal file
2
cosimulation/modelsim-win/test/cosim.do
Normal file
@ -0,0 +1,2 @@
|
||||
run -all
|
||||
quit
|
11
cosimulation/modelsim-win/test/dff.py
Normal file
11
cosimulation/modelsim-win/test/dff.py
Normal 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())
|
11
cosimulation/modelsim-win/test/dff_clkout.py
Normal file
11
cosimulation/modelsim-win/test/dff_clkout.py
Normal 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())
|
11
cosimulation/modelsim-win/test/inc.py
Normal file
11
cosimulation/modelsim-win/test/inc.py
Normal 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())
|
47
cosimulation/modelsim-win/test/test_all.py
Normal file
47
cosimulation/modelsim-win/test/test_all.py
Normal 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()
|
@ -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
|
||||
|
@ -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]();
|
||||
}
|
||||
}
|
||||
|
@ -1,2 +0,0 @@
|
||||
all:
|
||||
python test_all.py
|
@ -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))
|
||||
|
@ -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')
|
||||
|
@ -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')
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
import myhdl
|
||||
from myhdl import *
|
||||
|
||||
ACTIVE_LOW, INACTIVE_HIGH = 0, 1
|
||||
|
@ -1,3 +1,4 @@
|
||||
import myhdl
|
||||
from myhdl import *
|
||||
|
||||
from dff import dff
|
||||
|
@ -1,3 +1,4 @@
|
||||
import myhdl
|
||||
from myhdl import *
|
||||
|
||||
ACTIVE_LOW, INACTIVE_HIGH = 0, 1
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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::).
|
||||
|
@ -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`
|
||||
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
||||
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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*
|
||||
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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.
|
||||
|
||||
|
||||
|
@ -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 |
@ -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
|
||||
|
35
doc/source/myhdldoctools.py
Normal file
35
doc/source/myhdldoctools.py
Normal 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
8
doc/source/python3.rst
Normal 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
398
doc/source/whatsnew/0.3.rst
Normal file
@ -0,0 +1,398 @@
|
||||
=======================
|
||||
What’s 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 doesn’t 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 25–35%
|
||||
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
796
doc/source/whatsnew/0.4.rst
Normal 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 interpreter’s 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: Python’s 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 it’s so useful
|
||||
for debugging, even though it’s 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
|
||||
doesn’t attempt to detect a lot of errors beyond syntax errors, which
|
||||
given Python’s 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 doesn’t 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, 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.)
|
||||
|
||||
::
|
||||
|
||||
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 doesn’t 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)
|
||||
doesn’t 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 don’t work.
|
||||
I didn’t get non-blocking (signal) assignments to task arguments to
|
||||
work. I don’t know yet whether the issue is my own, a Verilog issue,
|
||||
or an issue with my Verilog simulator Icarus. I’ll need to check
|
||||
this further.
|
587
doc/source/whatsnew/0.5.rst
Normal file
587
doc/source/whatsnew/0.5.rst
Normal 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
|
@ -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
|
||||
|
||||
|
||||
|
14
doc/source/whatsnew/1.0.rst
Normal file
14
doc/source/whatsnew/1.0.rst
Normal 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
|
@ -1,3 +1,4 @@
|
||||
import myhdl
|
||||
from myhdl import *
|
||||
from arith_utils import BEHAVIOR
|
||||
from PrefixAnd import PrefixAnd
|
||||
|
@ -1,3 +1,4 @@
|
||||
import myhdl
|
||||
from myhdl import *
|
||||
from arith_utils import BEHAVIOR
|
||||
from PrefixAnd import PrefixAnd
|
||||
|
@ -1,3 +1,4 @@
|
||||
import myhdl
|
||||
from myhdl import *
|
||||
|
||||
from arith_utils import log2ceil
|
||||
|
@ -1,6 +1,7 @@
|
||||
import unittest
|
||||
from unittest import TestCase
|
||||
|
||||
import myhdl
|
||||
from myhdl import *
|
||||
|
||||
from arith_utils import BEHAVIOR, STRUCTURE
|
||||
|
@ -1,6 +1,7 @@
|
||||
import unittest
|
||||
from unittest import TestCase
|
||||
|
||||
import myhdl
|
||||
from myhdl import *
|
||||
|
||||
from arith_utils import BEHAVIOR, STRUCTURE
|
||||
|
497
example/cookbook/bitonic/Array8Sorter.v
Normal file
497
example/cookbook/bitonic/Array8Sorter.v
Normal 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
|
@ -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())
|
||||
|
||||
|
||||
|
497
example/cookbook/bitonic/ori.v
Normal file
497
example/cookbook/bitonic/ori.v
Normal 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
|
62
example/cookbook/bitonic/tb_Array8Sorter.v
Normal file
62
example/cookbook/bitonic/tb_Array8Sorter.v
Normal 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
|
@ -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()
|
||||
|
||||
|
||||
|
||||
|
497
example/cookbook/bitonic/tmp.v
Normal file
497
example/cookbook/bitonic/tmp.v
Normal 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
|
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
import myhdl
|
||||
from myhdl import *
|
||||
|
||||
ACTIVE = 0
|
||||
|
@ -1,3 +1,4 @@
|
||||
import myhdl
|
||||
from myhdl import *
|
||||
|
||||
ACTIVE = 0
|
||||
|
@ -1,3 +1,4 @@
|
||||
import myhdl
|
||||
from myhdl import *
|
||||
|
||||
ACTIVE, INACTIVE = bool(0), bool(1)
|
||||
|
@ -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)
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
from math import atan, sqrt, ceil, floor, pi
|
||||
|
||||
import myhdl
|
||||
from myhdl import *
|
||||
|
||||
t_State = enum("WAITING", "CALCULATING")
|
||||
|
@ -1,6 +1,7 @@
|
||||
from math import pi, sin, cos, log
|
||||
import random
|
||||
|
||||
import myhdl
|
||||
from myhdl import *
|
||||
|
||||
from SineComputer import SineComputer, SineComputer_v
|
||||
|
@ -1,3 +1,4 @@
|
||||
import myhdl
|
||||
from myhdl import *
|
||||
|
||||
from TimeCount import TimeCount
|
||||
|
@ -1,3 +1,4 @@
|
||||
import myhdl
|
||||
from myhdl import *
|
||||
|
||||
def TimeCount(tens, ones, tenths, startstop, reset, clock):
|
||||
|
@ -1,5 +1,6 @@
|
||||
import seven_segment
|
||||
|
||||
import myhdl
|
||||
from myhdl import *
|
||||
|
||||
code = [None] * 10
|
||||
|
@ -1,5 +1,6 @@
|
||||
from random import randrange
|
||||
|
||||
import myhdl
|
||||
from myhdl import *
|
||||
|
||||
from TimeCount import TimeCount
|
||||
|
@ -1,5 +1,6 @@
|
||||
from random import randrange
|
||||
import seven_segment
|
||||
import myhdl
|
||||
from myhdl import *
|
||||
from bcd2led import bcd2led
|
||||
|
||||
|
18
example/manual/ClkDriver.py
Normal file
18
example/manual/ClkDriver.py
Normal 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
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -1,3 +1,4 @@
|
||||
import myhdl
|
||||
from myhdl import *
|
||||
|
||||
from bin2gray2 import bin2gray
|
||||
|
@ -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
|
@ -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
11
example/manual/Hello.py
Normal 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
|
@ -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()
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -1,3 +1,4 @@
|
||||
import myhdl
|
||||
from myhdl import *
|
||||
|
||||
def bin2gray(B, G, width):
|
||||
|
11
example/manual/bin2gray_dummy.py
Normal file
11
example/manual/bin2gray_dummy.py
Normal 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
|
16
example/manual/bin2gray_wrong.py
Normal file
16
example/manual/bin2gray_wrong.py
Normal 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
|
17
example/manual/conv_inc.py
Normal file
17
example/manual/conv_inc.py
Normal 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)
|
15
example/manual/convert_bin2gray.py
Normal file
15
example/manual/convert_bin2gray.py
Normal 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')
|
15
example/manual/convert_gray_inc_reg.py
Normal file
15
example/manual/convert_gray_inc_reg.py
Normal 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')
|
21
example/manual/convert_inc.py
Normal file
21
example/manual/convert_inc.py
Normal 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')
|
@ -1,3 +1,4 @@
|
||||
import myhdl
|
||||
from myhdl import *
|
||||
|
||||
def inc_comb(nextCount, count, n):
|
||||
|
@ -1,6 +1,7 @@
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
import myhdl
|
||||
from myhdl import *
|
||||
|
||||
class Error(Exception):
|
||||
|
@ -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()
|
||||
|
@ -1,3 +1,4 @@
|
||||
import myhdl
|
||||
from myhdl import *
|
||||
|
||||
# SEARCH, CONFIRM, SYNC = range(3)
|
||||
|
@ -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__':
|
||||
|
15
example/manual/gray_inc.py
Normal file
15
example/manual/gray_inc.py
Normal 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
|
||||
|
17
example/manual/gray_inc_reg.py
Normal file
17
example/manual/gray_inc_reg.py
Normal 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
|
||||
|
52
example/manual/gray_inc_reg.v
Normal file
52
example/manual/gray_inc_reg.v
Normal 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
Loading…
x
Reference in New Issue
Block a user