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

Merge branch 'master' into initial_value_support

This commit is contained in:
Henry Gomersall 2016-02-26 15:42:33 +00:00
commit c8b1b285ca
No known key found for this signature in database
GPG Key ID: 67F4313D73CED5A6
138 changed files with 3431 additions and 2168 deletions

1
.gitignore vendored
View File

@ -22,6 +22,7 @@ modelsim.ini
transcript
*.log
work/
work_nvc/
work_vlog/
work_vcom/
*.wlf

View File

@ -7,6 +7,7 @@ python:
- "2.7"
- "pypy"
- "3.4"
- "3.5"
addons:
apt:
@ -21,15 +22,19 @@ install:
env:
- CI_TARGET=core
- CI_TARGET=icarus
- CI_TARGET=iverilog
- CI_TARGET=ghdl
matrix:
allow_failures:
- python: "3.4"
env: CI_TARGET=icarus
- python: "3.4"
env: CI_TARGET=ghdl
# matrix:
# allow_failures:
# - python: "3.4"
# env: CI_TARGET=iverilog
# - python: "3.4"
# env: CI_TARGET=ghdl
# - python: "3.5"
# env: CI_TARGET=iverilog
# - python: "3.5"
# env: CI_TARGET=ghdl
script: ./scripts/ci.sh

View File

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

View File

@ -1,7 +1,10 @@
MyHDL 0.9
=========
MyHDL 1.0dev
============
[![Documentation Status](https://readthedocs.org/projects/myhdl/badge/?version=master)](http://docs.myhdl.org/en/latest/manual)
[![Join the chat at https://gitter.im/jandecaluwe/myhdl](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/jandecaluwe/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/jandecaluwe/myhdl.svg?branch=master)](https://travis-ci.org/jandecaluwe/myhdl)
What is MyHDL?
@ -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.9.html
- http://docs.myhdl.org/en/stable/whatsnew/0.9.html
Installation
------------

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,33 +1,25 @@
# 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

View File

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

View File

@ -13,10 +13,12 @@
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('../..'))
import myhdl
# -- General configuration -----------------------------------------------------
@ -42,16 +44,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.

View File

@ -19,9 +19,20 @@ Welcome to the MyHDL documentation
manual/index
whatsnew/0.9
python3
Old Whatsnew documents
======================
.. toctree::
:maxdepth: 1
whatsnew/0.8
whatsnew/0.7
whatsnew/0.6
whatsnew/0.5
whatsnew/0.4
whatsnew/0.3
Index
=====
@ -31,4 +42,3 @@ Index
Search
======
* :ref:`search`

View File

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

View File

@ -85,8 +85,13 @@ 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:: 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 +217,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 +234,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 +610,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 +773,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:

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

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

View File

@ -1,6 +1,6 @@
=======================================
New in MyHDL 0.4: Conversion to Verilog
=======================================
==============================================
What's new in MyHDL 0.4: Conversion to Verilog
==============================================
:Author: Jan Decaluwe
@ -187,8 +187,11 @@ 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
@ -200,6 +203,7 @@ The :keyword:`if` statement.
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
@ -210,6 +214,7 @@ The :keyword:`raise` statement.
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

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

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

View File

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

View File

@ -1,3 +1,5 @@
import subprocess
from myhdl import *
from myhdl.conversion import analyze
@ -71,12 +73,15 @@ def Array8Sorter(a0, a1, a2, a3, a4, a5, a6, a7,
def Array8Sorter_v(a0, a1, a2, a3, a4, a5, a6, a7,
z0, z1, z2, z3, z4, z5, z6, z7):
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"
# cmd = "cver -q +loadvpi=../../../cosimulation/cver/myhdl_vpi:vpi_compat_bootstrap " + \
# "Array8Sorter.v tb_Array8Sorter.v"
subprocess.call("iverilog -o Array8Sorter.o Array8Sorter.v tb_Array8Sorter.v", shell=True)
cmd = "vvp -m ../../../cosimulation/icarus/myhdl.vpi Array8Sorter.o"
return Cosimulation(cmd, **locals())

View File

@ -20,17 +20,18 @@
""" Module that provides the Cosimulation class """
from __future__ import absolute_import
import sys
import os
import shlex
import subprocess
from myhdl._intbv import intbv
from myhdl import _simulator, CosimulationError
from myhdl._compat import PY2, string_types, to_bytes, to_str
from myhdl._compat import set_inheritable, string_types, to_bytes, to_str
_MAXLINE = 4096
class _error:
pass
_error.MultipleCosim = "Only a single cosimulator allowed"
@ -41,25 +42,32 @@ _error.NoCommunication = "No signals communicating to myhdl"
_error.SimulationEnd = "Premature simulation end"
_error.OSError = "OSError"
class Cosimulation(object):
""" Cosimulation class. """
def __init__(self, exe="", **kwargs):
""" Construct a cosimulation object. """
if _simulator._cosim:
raise CosimulationError(_error.MultipleCosim)
_simulator._cosim = 1
self._rt, self._wt = rt, wt = os.pipe()
self._rf, self._wf = rf, wf = os.pipe()
# New pipes are not inheritable by default since py 3.4
if not PY2:
for p in rt, wt, rf, wf:
os.set_inheritable(p, True)
rt, wt = os.pipe()
rf, wf = os.pipe()
# Disable inheritance for ends that we don't want the child to have
set_inheritable(rt, False)
set_inheritable(wf, False)
# Enable inheritance for child ends
set_inheritable(wt, True)
set_inheritable(rf, True)
self._rt = rt
self._wf = wf
self._fromSignames = fromSignames = []
self._fromSizes = fromSizes = []
@ -71,20 +79,23 @@ class Cosimulation(object):
self._hasChange = 0
self._getMode = 1
def close_rt_wf():
os.close(rt)
os.close(wf)
env = os.environ.copy()
env['MYHDL_TO_PIPE'] = str(wt)
env['MYHDL_FROM_PIPE'] = str(rf)
# In Windows the FDs aren't inheritable when using Popen,
# only the HANDLEs are
if sys.platform != "win32":
env['MYHDL_TO_PIPE'] = str(wt)
env['MYHDL_FROM_PIPE'] = str(rf)
else:
import msvcrt
env['MYHDL_TO_PIPE'] = str(msvcrt.get_osfhandle(wt))
env['MYHDL_FROM_PIPE'] = str(msvcrt.get_osfhandle(rf))
if isinstance(exe, string_types):
exe = shlex.split(exe)
try:
sp = subprocess.Popen(exe, env=env, close_fds=False,
preexec_fn=close_rt_wf)
sp = subprocess.Popen(exe, env=env, close_fds=False)
except OSError as e:
raise CosimulationError(_error.OSError, str(e))
@ -154,7 +165,7 @@ class Cosimulation(object):
except ValueError:
next = intbv(0)
s.next = next
self._getMode = 0
def _put(self, time):
@ -182,7 +193,7 @@ class Cosimulation(object):
while 1:
yield sigs
self._hasChange = 1
def __del__(self):
""" Clear flag when this object destroyed - to suite unittest. """
_simulator._cosim = 0

View File

@ -1,7 +1,7 @@
# This file is part of the myhdl library, a Python package for using
# Python as a Hardware Description Language.
#
# Copyright (C) 2003-2011 Jan Decaluwe
# Copyright (C) 2003-2015 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
@ -172,8 +172,12 @@ class ConcatSignal(_ShadowSignal):
else:
w = len(a)
lo = hi - w
if a in sigargs:
newval[hi:lo] = a
# note: 'a in sigargs' is equivalence check, not identity
if isinstance(a, _Signal):
if isinstance(a._val, intbv):
newval[hi:lo] = a[w:]
else:
newval[hi:lo] = a
hi = lo
set_next(self, newval)
yield sigargs

View File

@ -29,7 +29,6 @@ negedge -- callable to model a falling edge on a signal in a yield statement
from __future__ import absolute_import
from __future__ import print_function
from inspect import currentframe, getouterframes
from copy import copy, deepcopy
import operator
@ -43,7 +42,7 @@ from myhdl._bin import bin
_schedule = _futureEvents.append
def _isListOfSigs(obj):
""" Check if obj is a non-empty list of signals. """
if isinstance(obj, list) and len(obj) > 0:
@ -53,8 +52,8 @@ def _isListOfSigs(obj):
return True
else:
return False
class _WaiterList(list):
def purge(self):
@ -69,7 +68,7 @@ class _PosedgeWaiterList(_WaiterList):
return "posedge %s" % self.sig._name
def _toVHDL(self):
return "rising_edge(%s)" % self.sig._name
class _NegedgeWaiterList(_WaiterList):
def __init__(self, sig):
self.sig = sig
@ -96,7 +95,7 @@ def Signal(val=None, delay=None):
return _DelayedSignal(val, delay)
else:
return _Signal(val)
class _Signal(object):
""" _Signal class.
@ -109,8 +108,8 @@ class _Signal(object):
__slots__ = ('_next', '_val', '_min', '_max', '_type', '_init',
'_eventWaiters', '_posedgeWaiters', '_negedgeWaiters',
'_code', '_tracing', '_nrbits', '_checkVal',
'_setNextVal', '_copyVal2Next', '_printVcd',
'_code', '_tracing', '_nrbits', '_checkVal',
'_setNextVal', '_copyVal2Next', '_printVcd',
'_driven' ,'_read', '_name', '_used', '_inList',
'_waiter', 'toVHDL', 'toVerilog', '_slicesigs',
'_numeric'
@ -121,7 +120,7 @@ class _Signal(object):
""" Construct a signal.
val -- initial value
"""
self._init = deepcopy(val)
self._val = deepcopy(val)
@ -177,7 +176,7 @@ class _Signal(object):
self._numeric = True
for s in self._slicesigs:
s._clear()
def _update(self):
val, next = self._val, self._next
if val != next:
@ -227,12 +226,12 @@ class _Signal(object):
@property
def posedge(self):
return self._posedgeWaiters
# support for the 'negedge' attribute
@property
def negedge(self):
return self._negedgeWaiters
# support for the 'min' and 'max' attribute
@property
def max(self):
@ -252,7 +251,7 @@ class _Signal(object):
if not val in ("reg", "wire", True):
raise ValueError('Expected value "reg", "wire", or True, got "%s"' % val)
self._driven = val
# support for the 'read' attribute
@property
def read(self):
@ -297,17 +296,17 @@ class _Signal(object):
def _setNextNonmutable(self, val):
if not isinstance(val, self._type):
raise TypeError("Expected %s, got %s" % (self._type, type(val)))
self._next = val
self._next = val
def _setNextMutable(self, val):
if not isinstance(val, self._type):
raise TypeError("Expected %s, got %s" % (self._type, type(val)))
self._next = deepcopy(val)
self._next = deepcopy(val)
# vcd print methods
def _printVcdStr(self):
print("s%s %s" % (str(self._val), self._code), file=sim._tf)
def _printVcdHex(self):
if self._val is None:
print("sz %s" % self._code, file=sim._tf)
@ -334,11 +333,11 @@ class _Signal(object):
### operators for which delegation to current value is appropriate ###
def __hash__(self):
raise TypeError("Signals are unhashable")
def __bool__(self):
return bool(self._val)
@ -353,7 +352,7 @@ class _Signal(object):
def __getitem__(self, key):
return self._val[key]
# integer-like methods
def __add__(self, other):
@ -363,7 +362,7 @@ class _Signal(object):
return self._val + other
def __radd__(self, other):
return other + self._val
def __sub__(self, other):
if isinstance(other, _Signal):
return self._val - other._val
@ -387,7 +386,7 @@ class _Signal(object):
return self._val / other
def __rtruediv__(self, other):
return other / self._val
def __floordiv__(self, other):
if isinstance(other, _Signal):
return self._val // other._val
@ -395,7 +394,7 @@ class _Signal(object):
return self._val // other
def __rfloordiv__(self, other):
return other // self._val
def __mod__(self, other):
if isinstance(other, _Signal):
return self._val % other._val
@ -405,7 +404,7 @@ class _Signal(object):
return other % self._val
# XXX divmod
def __pow__(self, other):
if isinstance(other, _Signal):
return self._val ** other._val
@ -421,7 +420,7 @@ class _Signal(object):
return self._val << other
def __rlshift__(self, other):
return other << self._val
def __rshift__(self, other):
if isinstance(other, _Signal):
return self._val >> other._val
@ -429,7 +428,7 @@ class _Signal(object):
return self._val >> other
def __rrshift__(self, other):
return other >> self._val
def __and__(self, other):
if isinstance(other, _Signal):
return self._val & other._val
@ -445,7 +444,7 @@ class _Signal(object):
return self._val | other
def __ror__(self, other):
return other | self._val
def __xor__(self, other):
if isinstance(other, _Signal):
return self._val ^ other._val
@ -453,7 +452,7 @@ class _Signal(object):
return self._val ^ other
def __rxor__(self, other):
return other ^ self._val
def __neg__(self):
return -self._val
@ -465,33 +464,33 @@ class _Signal(object):
def __invert__(self):
return ~self._val
# conversions
def __int__(self):
return int(self._val)
def __long__(self):
return long(self._val)
def __float__(self):
return float(self._val)
def __oct__(self):
return oct(self._val)
def __hex__(self):
return hex(self._val)
def __index__(self):
return int(self._val)
# comparisons
def __eq__(self, other):
return self.val == other
return self.val == other
def __ne__(self, other):
return self.val != other
return self.val != other
def __lt__(self, other):
return self.val < other
def __le__(self, other):
@ -506,7 +505,7 @@ class _Signal(object):
def __getattr__(self, attr):
return getattr(self._val, attr)
# representation
# representation
def __str__(self):
if self._name:
return self._name
@ -556,7 +555,7 @@ class _Signal(object):
class _DelayedSignal(_Signal):
__slots__ = ('_nextZ', '_delay', '_timeStamp',
)
@ -594,7 +593,7 @@ class _DelayedSignal(_Signal):
self._val = copy(next)
if self._tracing:
self._printVcd()
return waiters
return waiters
else:
return []
@ -607,7 +606,7 @@ class _DelayedSignal(_Signal):
def delay(self, delay):
self._delay = delay
class _SignalWrap(object):
def __init__(self, sig, next, timeStamp):
self.sig = sig

View File

@ -1,7 +1,7 @@
# This file is part of the myhdl library, a Python package for using
# Python as a Hardware Description Language.
#
# Copyright (C) 2003-2013 Jan Decaluwe
# Copyright (C) 2003-2015 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
@ -52,7 +52,7 @@ toVerilog -- function that converts a design to Verilog
from __future__ import absolute_import
from __future__ import print_function
__version__ = "0.9.dev0"
__version__ = "1.0dev"
import sys
import warnings

View File

@ -24,7 +24,7 @@ from __future__ import absolute_import
from types import FunctionType
from myhdl import AlwaysError
from myhdl._util import _isGenFunc
from myhdl._util import _isGenFunc, _makeAST
from myhdl._delay import delay
from myhdl._Signal import _Signal, _WaiterList, posedge, negedge
from myhdl._Waiter import _Waiter, _SignalWaiter, _SignalTupleWaiter, \
@ -58,28 +58,31 @@ def always(*args):
raise AlwaysError(_error.NrOfArgs)
return _Always(func, args)
return _always_decorator
class _Always(_Instantiator):
def __init__(self, func, args):
def __init__(self, func, senslist):
self.func = func
self.senslist = tuple(args)
self.gen = self.genfunc()
self.senslist = tuple(senslist)
super(_Always, self).__init__(self.genfunc)
@property
def funcobj(self):
return self.func
def _waiter(self):
# infer appropriate waiter class
# first infer base type of arguments
for t in (_Signal, _WaiterList, delay):
if isinstance(args[0], t):
if isinstance(self.senslist[0], t):
bt = t
for arg in args[1:]:
if not isinstance(arg, bt):
for s in self.senslist[1:]:
if not isinstance(s, bt):
bt = None
break
# now set waiter class
W = _Waiter
if bt is delay:
W = _DelayWaiter
elif len(self.senslist) == 1:
@ -92,9 +95,7 @@ class _Always(_Instantiator):
W = _SignalTupleWaiter
elif bt is _WaiterList:
W = _EdgeTupleWaiter
self.waiter = W(self.gen)
return W
def genfunc(self):
senslist = self.senslist
@ -104,4 +105,3 @@ class _Always(_Instantiator):
while 1:
yield senslist
func()

View File

@ -29,10 +29,9 @@ import ast
from myhdl import AlwaysCombError
from myhdl._Signal import _Signal, _isListOfSigs
from myhdl._util import _isGenFunc, _dedent
from myhdl._cell_deref import _cell_deref
from myhdl._Waiter import _Waiter, _SignalWaiter, _SignalTupleWaiter
from myhdl._instance import _Instantiator
from myhdl._resolverefs import _AttrRefTransformer
from myhdl._always import _Always
class _error:
pass
@ -50,117 +49,12 @@ def always_comb(func):
raise AlwaysCombError(_error.ArgType)
if func.__code__.co_argcount > 0:
raise AlwaysCombError(_error.NrOfArgs)
varnames = func.__code__.co_varnames
symdict = {}
for n, v in func.__globals__.items():
if n not in varnames:
symdict[n] = v
# handle free variables
if func.__code__.co_freevars:
for n, c in zip(func.__code__.co_freevars, func.__closure__):
try:
obj = _cell_deref(c)
symdict[n] = obj
except NameError:
raise NameError(n)
c = _AlwaysComb(func, symdict)
c = _AlwaysComb(func)
return c
INPUT, OUTPUT, INOUT = range(3)
class _SigNameVisitor(ast.NodeVisitor):
def __init__(self, symdict):
self.inputs = set()
self.outputs = set()
self.toplevel = 1
self.symdict = symdict
self.context = INPUT
def visit_Module(self, node):
inputs = self.inputs
outputs = self.outputs
for n in node.body:
self.visit(n)
for n in inputs:
if n in outputs:
raise AlwaysCombError(_error.SignalAsInout % n)
def visit_FunctionDef(self, node):
if self.toplevel:
self.toplevel = 0 # skip embedded functions
for n in node.body:
self.visit(n)
else:
raise AlwaysCombError(_error.EmbeddedFunction)
def visit_If(self, node):
if not node.orelse:
if isinstance(node.test, ast.Name) and \
node.test.id == '__debug__':
return # skip
self.generic_visit(node)
def visit_Name(self, node):
id = node.id
if id not in self.symdict:
return
s = self.symdict[id]
if isinstance(s, _Signal) or _isListOfSigs(s):
if self.context == INPUT:
self.inputs.add(id)
elif self.context == OUTPUT:
self.outputs.add(id)
elif self.context == INOUT:
raise AlwaysCombError(_error.SignalAsInout % id)
else:
raise AssertionError("bug in always_comb")
def visit_Assign(self, node):
self.context = OUTPUT
for n in node.targets:
self.visit(n)
self.context = INPUT
self.visit(node.value)
def visit_Attribute(self, node):
self.visit(node.value)
def visit_Call(self, node):
fn = None
if isinstance(node.func, ast.Name):
fn = node.func.id
if fn == "len":
pass
else:
self.generic_visit(node)
def visit_Subscript(self, node, access=INPUT):
self.visit(node.value)
self.context = INPUT
self.visit(node.slice)
def visit_AugAssign(self, node, access=INPUT):
self.context = INOUT
self.visit(node.target)
self.context = INPUT
self.visit(node.value)
def visit_ClassDef(self, node):
pass # skip
def visit_Exec(self, node):
pass # skip
def visit_Print(self, node):
pass # skip
class _AlwaysComb(_Instantiator):
# class _AlwaysComb(_Instantiator):
class _AlwaysComb(_Always):
# def __init__(self, func, symdict):
# self.func = func
@ -191,37 +85,26 @@ class _AlwaysComb(_Instantiator):
# W = _SignalTupleWaiter
# self.waiter = W(self.gen)
def __init__(self, func, symdict):
self.func = func
self.symdict = symdict
s = inspect.getsource(func)
s = _dedent(s)
tree = ast.parse(s)
# print ast.dump(tree)
v = _AttrRefTransformer(self)
v.visit(tree)
v = _SigNameVisitor(self.symdict)
v.visit(tree)
self.inputs = v.inputs
self.outputs = v.outputs
def __init__(self, func):
senslist = []
super(_AlwaysComb, self).__init__(func, senslist)
inouts = self.inouts | self.inputs.intersection(self.outputs)
if inouts:
raise AlwaysCombError(_error.SignalAsInout % inouts)
if self.embedded_func:
raise AlwaysCombError(_error.EmbeddedFunction)
for n in self.inputs:
s = self.symdict[n]
if isinstance(s, _Signal):
senslist.append(s)
else: # list of sigs
elif _isListOfSigs(s):
senslist.extend(s)
self.senslist = tuple(senslist)
self.gen = self.genfunc()
if len(self.senslist) == 0:
raise AlwaysCombError(_error.EmptySensitivityList)
if len(self.senslist) == 1:
W = _SignalWaiter
else:
W = _SignalTupleWaiter
self.waiter = W(self.gen)
def genfunc(self):
senslist = self.senslist
@ -231,7 +114,3 @@ class _AlwaysComb(_Instantiator):
while 1:
func()
yield senslist

View File

@ -28,12 +28,10 @@ import ast
from myhdl import AlwaysError, intbv
from myhdl._util import _isGenFunc, _dedent
from myhdl._cell_deref import _cell_deref
from myhdl._delay import delay
from myhdl._Signal import _Signal, _WaiterList,_isListOfSigs
from myhdl._Waiter import _Waiter, _EdgeWaiter, _EdgeTupleWaiter
from myhdl._instance import _Instantiator
from myhdl._resolverefs import _AttrRefTransformer
from myhdl._always import _Always
# evacuate this later
AlwaysSeqError = AlwaysError
@ -82,13 +80,13 @@ def always_seq(edge, reset):
return _always_seq_decorator
class _AlwaysSeq(_Instantiator):
class _AlwaysSeq(_Always):
def __init__(self, func, edge, reset):
self.func = func
self.senslist = senslist = [edge]
senslist = [edge]
self.reset = reset
if reset is not None:
self.genfunc = self.genfunc_reset
active = self.reset.active
async = self.reset.async
if async:
@ -96,44 +94,20 @@ class _AlwaysSeq(_Instantiator):
senslist.append(reset.posedge)
else:
senslist.append(reset.negedge)
self.gen = self.genfunc()
else:
self.gen = self.genfunc_no_reset()
if len(self.senslist) == 1:
W = _EdgeWaiter
else:
W = _EdgeTupleWaiter
self.waiter = W(self.gen)
self.genfunc = self.genfunc_no_reset
# find symdict
# similar to always_comb, but in class constructor
varnames = func.__code__.co_varnames
symdict = {}
for n, v in func.__globals__.items():
if n not in varnames:
symdict[n] = v
# handle free variables
if func.__code__.co_freevars:
for n, c in zip(func.__code__.co_freevars, func.__closure__):
try:
obj = _cell_deref(c)
symdict[n] = obj
except NameError:
raise NameError(n)
self.symdict = symdict
super(_AlwaysSeq, self).__init__(func, senslist)
if self.inouts:
raise AlwaysSeqError(_error.SigAugAssign, v.inouts)
if self.embedded_func:
raise AlwaysSeqError(_error.EmbeddedFunction)
# now infer outputs to be reset
s = inspect.getsource(func)
s = _dedent(s)
tree = ast.parse(s)
# print ast.dump(tree)
v = _AttrRefTransformer(self)
v.visit(tree)
v = _SigNameVisitor(self.symdict)
v.visit(tree)
sigregs = self.sigregs = []
varregs = self.varregs = []
for n in v.outputs:
for n in self.outputs:
reg = self.symdict[n]
if isinstance(reg, _Signal):
sigregs.append(reg)
@ -144,7 +118,6 @@ class _AlwaysSeq(_Instantiator):
for e in reg:
sigregs.append(e)
def reset_sigs(self):
for s in self.sigregs:
s.next = s._init
@ -155,7 +128,7 @@ class _AlwaysSeq(_Instantiator):
n, reg, init = v
reg._val = init
def genfunc(self):
def genfunc_reset(self):
senslist = self.senslist
if len(senslist) == 1:
senslist = senslist[0]
@ -178,88 +151,3 @@ class _AlwaysSeq(_Instantiator):
while 1:
yield senslist
func()
# similar to always_comb, calls for refactoring
# note: make a difference between augmented assign and inout signals
INPUT, OUTPUT, INOUT = range(3)
class _SigNameVisitor(ast.NodeVisitor):
def __init__(self, symdict):
self.inputs = set()
self.outputs = set()
self.toplevel = 1
self.symdict = symdict
self.context = INPUT
def visit_Module(self, node):
for n in node.body:
self.visit(n)
def visit_FunctionDef(self, node):
if self.toplevel:
self.toplevel = 0 # skip embedded functions
for n in node.body:
self.visit(n)
else:
raise AlwaysSeqError(_error.EmbeddedFunction)
def visit_If(self, node):
if not node.orelse:
if isinstance(node.test, ast.Name) and \
node.test.id == '__debug__':
return # skip
self.generic_visit(node)
def visit_Name(self, node):
id = node.id
if id not in self.symdict:
return
s = self.symdict[id]
if isinstance(s, (_Signal, intbv)) or _isListOfSigs(s):
if self.context == INPUT:
self.inputs.add(id)
elif self.context == OUTPUT:
self.outputs.add(id)
elif self.context == INOUT:
raise AlwaysSeqError(_error.SigAugAssign, id)
else:
raise AssertionError("bug in always_seq")
def visit_Assign(self, node):
self.context = OUTPUT
for n in node.targets:
self.visit(n)
self.context = INPUT
self.visit(node.value)
def visit_Attribute(self, node):
self.visit(node.value)
def visit_Subscript(self, node, access=INPUT):
self.visit(node.value)
self.context = INPUT
self.visit(node.slice)
def visit_AugAssign(self, node, access=INPUT):
self.context = INOUT
self.visit(node.target)
self.context = INPUT
self.visit(node.value)
def visit_ClassDef(self, node):
pass # skip
def visit_Exec(self, node):
pass # skip
def visit_Print(self, node):
pass # skip

View File

@ -1,22 +0,0 @@
# cell dereferencing hack, thanks to Samuele Pedroni
from types import FunctionType
def _proto_acc(v=None):
def acc():
return v
return acc
_acc0 = _proto_acc()
_make_acc = lambda cell: (FunctionType(_acc0.__code__,
_acc0.__globals__,
'#cell_acc',
_acc0.__defaults__,
(cell,)
)
)
def _cell_deref(cell):
return _make_acc(cell)()

View File

@ -13,6 +13,7 @@ if not PY2:
class_types = (type,)
from io import StringIO
from os import set_inheritable
import builtins
def to_bytes(s):
@ -20,6 +21,7 @@ if not PY2:
def to_str(b):
return b.decode()
else:
string_types = (str, unicode)
integer_types = (int, long)
@ -31,3 +33,30 @@ else:
to_bytes = _identity
to_str = _identity
def set_inheritable(fd, inheritable):
# This implementation of set_inheritable is based on a code sample in
# [PEP 0446](https://www.python.org/dev/peps/pep-0446/) and on the
# CPython implementation of that proposal which can be browsed [here]
# (hg.python.org/releasing/3.4/file/8671f89107c8/Modules/posixmodule.c#l11130)
if sys.platform == "win32":
import msvcrt
import ctypes.windll.kernel32 as kernel32
HANDLE_FLAG_INHERIT = 1
if kernel32.SetHandleInformation(msvcrt.get_osfhandle(fd),
HANDLE_FLAG_INHERIT,
1 if inheritable else 0) == 0:
raise IOError("Failed on HANDLE_FLAG_INHERIT")
else:
import fcntl
fd_flags = fcntl.fcntl(fd, fcntl.F_GETFD)
if inheritable:
fd_flags &= ~fcntl.FD_CLOEXEC
else:
fd_flags |= fcntl.FD_CLOEXEC
fcntl.fcntl(fd, fcntl.F_SETFD, fd_flags)

View File

@ -85,6 +85,9 @@ def enum(*names, **kwargs):
__str__ = __repr__
def __int__(self):
return int(self._val, 2)
def __hex__(self):
return hex(int(self._val, 2))

View File

@ -25,7 +25,6 @@ from __future__ import absolute_import
import sys
import inspect
from inspect import currentframe, getframeinfo, getouterframes
import re
import string
from types import GeneratorType
@ -36,6 +35,7 @@ from myhdl._Signal import _Signal, _isListOfSigs
from myhdl._util import _isGenFunc, _flatten, _genfunc
from myhdl._misc import _isGenSeq
from myhdl._resolverefs import _resolveRefs
from myhdl._getcellvars import _getCellVars
_profileFunc = None
@ -48,18 +48,14 @@ _error.InconsistentToplevel = "Inconsistent top level %s for %s - should be 1"
class _Instance(object):
__slots__ = ['level', 'obj', 'subs', 'sigdict', 'memdict', 'name', 'func', 'argdict', 'objdict']
def __init__(self, level, obj, subs, sigdict, memdict, func, argdict, objdict=None):
__slots__ = ['level', 'obj', 'subs', 'sigdict', 'memdict', 'name']
def __init__(self, level, obj, subs, sigdict, memdict):
self.level = level
self.obj = obj
self.subs = subs
self.sigdict = sigdict
self.memdict = memdict
self.func = func
self.argdict = argdict
if objdict:
self.objdict = objdict
self.name = None
_memInfoMap = {}
@ -308,17 +304,11 @@ class _HierExtr(object):
if isGenSeq and arg:
sigdict = {}
memdict = {}
argdict = {}
if func:
arglist = inspect.getargspec(func).args
else:
arglist = []
symdict = frame.f_globals.copy()
symdict.update(frame.f_locals)
cellvars = []
cellvars.extend(frame.f_code.co_cellvars)
#All nested functions will be in co_consts
# All nested functions will be in co_consts
if func:
local_gens = []
consts = func.__code__.co_consts
@ -327,6 +317,8 @@ class _HierExtr(object):
if genfunc.__code__ in consts:
local_gens.append(item)
if local_gens:
cellvarlist = _getCellVars(symdict, local_gens)
cellvars.extend(cellvarlist)
objlist = _resolveRefs(symdict, local_gens)
cellvars.extend(objlist)
#for dict in (frame.f_globals, frame.f_locals):
@ -345,9 +337,6 @@ class _HierExtr(object):
memdict[n] = m
if n in cellvars:
m._used = True
# save any other variable in argdict
if (n in arglist) and (n not in sigdict) and (n not in memdict):
argdict[n] = v
subs = []
for n, sub in frame.f_locals.items():
@ -355,8 +344,7 @@ class _HierExtr(object):
if elt is sub:
subs.append((n, sub))
inst = _Instance(self.level, arg, subs, sigdict, memdict, func, argdict)
inst = _Instance(self.level, arg, subs, sigdict, memdict)
self.hierarchy.append(inst)
self.level -= 1

33
myhdl/_getcellvars.py Normal file
View File

@ -0,0 +1,33 @@
from __future__ import absolute_import
import ast
import itertools
from types import FunctionType
from myhdl._util import _flatten
from myhdl._enum import EnumType
from myhdl._Signal import SignalType
class Data():
pass
def _getCellVars(symdict, arg):
gens = _flatten(arg)
data = Data()
data.symdict = symdict
v = _GetCellVars(data)
for gen in gens:
v.visit(gen.ast)
return list(data.objset)
class _GetCellVars(ast.NodeVisitor):
def __init__(self, data):
self.data = data
self.data.objset = set()
def visit_Name(self, node):
if node.id in self.data.symdict:
self.data.objset.add(node.id)
self.generic_visit(node)

View File

@ -24,8 +24,10 @@ from __future__ import absolute_import
from types import FunctionType
from myhdl import InstanceError
from myhdl._util import _isGenFunc
from myhdl._util import _isGenFunc, _makeAST
from myhdl._Waiter import _inferWaiter
from myhdl._resolverefs import _AttrRefTransformer
from myhdl._visitors import _SigNameVisitor
class _error:
pass
@ -33,19 +35,56 @@ _error.NrOfArgs = "decorated generator function should not have arguments"
_error.ArgType = "decorated object should be a generator function"
def instance(genFunc):
if not isinstance(genFunc, FunctionType):
def instance(genfunc):
if not isinstance(genfunc, FunctionType):
raise InstanceError(_error.ArgType)
if not _isGenFunc(genFunc):
if not _isGenFunc(genfunc):
raise InstanceError(_error.ArgType)
if genFunc.__code__.co_argcount > 0:
if genfunc.__code__.co_argcount > 0:
raise InstanceError(_error.NrOfArgs)
return _Instantiator(genFunc)
return _Instantiator(genfunc)
class _Instantiator(object):
def __init__(self, genFunc):
self.genfunc = genFunc
self.gen = genFunc()
self.waiter = _inferWaiter(self.gen)
def __init__(self, genfunc):
self.genfunc = genfunc
self.gen = genfunc()
# infer symdict
f = self.funcobj
varnames = f.__code__.co_varnames
symdict = {}
for n, v in f.__globals__.items():
if n not in varnames:
symdict[n] = v
# handle free variables
freevars = f.__code__.co_freevars
if freevars:
closure = (c.cell_contents for c in f.__closure__)
symdict.update(zip(freevars, closure))
self.symdict = symdict
tree = self.ast
# print ast.dump(tree)
v = _AttrRefTransformer(self)
v.visit(tree)
v = _SigNameVisitor(self.symdict)
v.visit(tree)
self.inputs = v.inputs
self.outputs = v.outputs
self.inouts = v.inouts
self.embedded_func = v.embedded_func
@property
def funcobj(self):
return self.genfunc
@property
def waiter(self):
return self._waiter()(self.gen)
def _waiter(self):
return _inferWaiter
@property
def ast(self):
return _makeAST(self.funcobj)

View File

@ -1,7 +1,7 @@
# This file is part of the myhdl library, a Python package for using
# Python as a Hardware Description Language.
#
# Copyright (C) 2003-2013 Jan Decaluwe
# Copyright (C) 2003-2015 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
@ -262,35 +262,35 @@ class intbv(object):
def __rshift__(self, other):
if isinstance(other, intbv):
return type(self)(self._val >> other._val)
return intbv(self._val >> other._val)
else:
return type(self)(self._val >> other)
return intbv(self._val >> other)
def __rrshift__(self, other):
return other >> self._val
def __and__(self, other):
if isinstance(other, intbv):
return type(self)(self._val & other._val)
return intbv(self._val & other._val)
else:
return type(self)(self._val & other)
return intbv(self._val & other)
def __rand__(self, other):
return type(self)(other & self._val)
return intbv(other & self._val)
def __or__(self, other):
if isinstance(other, intbv):
return type(self)(self._val | other._val)
return intbv(self._val | other._val)
else:
return type(self)(self._val | other)
return intbv(self._val | other)
def __ror__(self, other):
return type(self)(other | self._val)
return intbv(other | self._val)
def __xor__(self, other):
if isinstance(other, intbv):
return type(self)(self._val ^ other._val)
return intbv(self._val ^ other._val)
else:
return type(self)(self._val ^ other)
return intbv(self._val ^ other)
def __rxor__(self, other):
return type(self)(other ^ self._val)
return intbv(other ^ self._val)
def __iadd__(self, other):
if isinstance(other, intbv):
@ -401,9 +401,9 @@ class intbv(object):
def __invert__(self):
if self._nrbits and self._min >= 0:
return type(self)(~self._val & (long(1) << self._nrbits)-1)
return intbv(~self._val & (long(1) << self._nrbits)-1)
else:
return type(self)(~self._val)
return intbv(~self._val)
def __int__(self):
return int(self._val)

View File

@ -3,7 +3,7 @@ import ast
import itertools
from types import FunctionType
from myhdl._util import _flatten, _makeAST, _genfunc
from myhdl._util import _flatten
from myhdl._enum import EnumType
from myhdl._Signal import SignalType
@ -18,17 +18,16 @@ def _resolveRefs(symdict, arg):
data.symdict = symdict
v = _AttrRefTransformer(data)
for gen in gens:
func = _genfunc(gen)
tree = _makeAST(func)
v.visit(tree)
v.visit(gen.ast)
return data.objlist
#TODO: Refactor this into two separate nodetransformers, since _resolveRefs
#needs only the names, not the objects
def _suffixer(name):
def _suffixer(name, used_names):
suffixed_names = (name+'_renamed{0}'.format(i) for i in itertools.count())
return itertools.chain([name], suffixed_names)
new_names = itertools.chain([name], suffixed_names)
return next(s for s in new_names if s not in used_names)
class _AttrRefTransformer(ast.NodeTransformer):
@ -36,6 +35,7 @@ class _AttrRefTransformer(ast.NodeTransformer):
self.data = data
self.data.objlist = []
self.myhdl_types = (EnumType, SignalType)
self.name_map = {}
def visit_Attribute(self, node):
self.generic_visit(node)
@ -44,12 +44,16 @@ class _AttrRefTransformer(ast.NodeTransformer):
if node.attr in reserved:
return node
#Don't handle subscripts for now.
# Don't handle subscripts for now.
if not isinstance(node.value, ast.Name):
return node
# Don't handle locals
if node.value.id not in self.data.symdict:
return node
obj = self.data.symdict[node.value.id]
#Don't handle enums and functions, handle signals as long as it is a new attribute
# Don't handle enums and functions, handle signals as long as it is a new attribute
if isinstance(obj, (EnumType, FunctionType)):
return node
elif isinstance(obj, SignalType):
@ -58,8 +62,11 @@ class _AttrRefTransformer(ast.NodeTransformer):
attrobj = getattr(obj, node.attr)
name = node.value.id + '_' + node.attr
new_name = next(s for s in _suffixer(name) if s not in self.data.symdict)
orig_name = node.value.id + '.' + node.attr
if orig_name not in self.name_map:
base_name = node.value.id + '_' + node.attr
self.name_map[orig_name] = _suffixer(base_name, self.data.symdict)
new_name = self.name_map[orig_name]
self.data.symdict[new_name] = attrobj
self.data.objlist.append(new_name)

View File

@ -26,7 +26,6 @@ from __future__ import print_function
import sys
from inspect import currentframe, getouterframes
import time
import os
path = os.path
@ -50,12 +49,14 @@ _error.MultipleTraces = "Cannot trace multiple instances simultaneously"
class _TraceSignalsClass(object):
__slot__ = ("name",
"directory",
"timescale",
"tracelists"
)
def __init__(self):
self.name = None
self.directory = None
self.timescale = "1ns"
self.tracelists = True
@ -82,8 +83,14 @@ class _TraceSignalsClass(object):
name = str(self.name)
if name is None:
raise TraceSignalsError(_error.TopLevelName)
if self.directory is None:
directory = ''
else:
directory = self.directory
h = _HierExtr(name, dut, *args, **kwargs)
vcdpath = name + ".vcd"
vcdpath = os.path.join(directory, name + ".vcd")
if path.exists(vcdpath):
backup = vcdpath + '.' + str(path.getmtime(vcdpath))
shutil.copyfile(vcdpath, backup)
@ -111,7 +118,7 @@ def _genNameCode():
while 1:
yield _namecode(n)
n += 1
def _namecode(n):
q, r = divmod(n, _mod)
code = _codechars[r]
@ -175,10 +182,11 @@ def _writeVcdSigs(f, hierarchy, tracelists):
else:
print("$var real 1 %s %s $end" % (s._code, n), file=f)
# Memory dump by Frederik Teichert, http://teichert-ing.de, date: 2011.03.28
# The Value Change Dump standard doesn't support multidimensional arrays so
# The Value Change Dump standard doesn't support multidimensional arrays so
# all memories are flattened and renamed.
if tracelists:
for n in memdict.keys():
print("$scope module {} $end" .format(n), file=f)
memindex = 0
for s in memdict[n].mem:
sval = _getSval(s)
@ -197,6 +205,7 @@ def _writeVcdSigs(f, hierarchy, tracelists):
else:
print("$var real 1 %s %s(%i) $end" % (s._code, n, memindex), file=f)
memindex += 1
print("$upscope $end", file=f)
for i in range(curlevel):
print("$upscope $end", file=f)
print(file=f)
@ -205,16 +214,3 @@ def _writeVcdSigs(f, hierarchy, tracelists):
for s in siglist:
s._printVcd() # initial value
print("$end", file=f)

View File

@ -23,15 +23,16 @@
from __future__ import absolute_import
from __future__ import print_function
import ast
import sys
import os
import inspect
from tokenize import generate_tokens, untokenize, INDENT
from myhdl._compat import integer_types, StringIO
def _printExcInfo():
kind, value = sys.exc_info()[:2]
msg = str(kind)

89
myhdl/_visitors.py Normal file
View File

@ -0,0 +1,89 @@
import ast
from myhdl._intbv import intbv
from myhdl._Signal import _Signal, _isListOfSigs
class _SigNameVisitor(ast.NodeVisitor):
def __init__(self, symdict):
self.toplevel = 1
self.symdict = symdict
self.inputs = set()
self.outputs = set()
self.inouts = set()
self.embedded_func = None
self.context = 'input'
def visit_Module(self, node):
for n in node.body:
self.visit(n)
def visit_FunctionDef(self, node):
if self.toplevel:
self.toplevel = 0 # skip embedded functions
for n in node.body:
self.visit(n)
else:
self.embedded_func = node.name
def visit_If(self, node):
if not node.orelse:
if isinstance(node.test, ast.Name) and \
node.test.id == '__debug__':
return # skip
self.generic_visit(node)
def visit_Name(self, node):
id = node.id
if id not in self.symdict:
return
s = self.symdict[id]
if isinstance(s, (_Signal, intbv)) or _isListOfSigs(s):
if self.context == 'input':
self.inputs.add(id)
elif self.context == 'output':
self.outputs.add(id)
elif self.context == 'inout':
self.inouts.add(id)
else:
print(self.context)
raise AssertionError("bug in _SigNameVisitor")
def visit_Assign(self, node):
self.context = 'output'
for n in node.targets:
self.visit(n)
self.context = 'input'
self.visit(node.value)
def visit_Attribute(self, node):
self.visit(node.value)
def visit_Call(self, node):
fn = None
if isinstance(node.func, ast.Name):
fn = node.func.id
if fn == "len":
pass
else:
self.generic_visit(node)
def visit_Subscript(self, node):
self.visit(node.value)
self.context = 'input'
self.visit(node.slice)
def visit_AugAssign(self, node):
self.context = 'inout'
self.visit(node.target)
self.context = 'input'
self.visit(node.value)
def visit_ClassDef(self, node):
pass # skip
def visit_Exec(self, node):
pass # skip
def visit_Print(self, node):
pass # skip

View File

@ -34,7 +34,6 @@ from collections import defaultdict
import myhdl
from myhdl import *
from myhdl import ConversionError
from myhdl._cell_deref import _cell_deref
from myhdl._always_comb import _AlwaysComb
from myhdl._always_seq import _AlwaysSeq
from myhdl._always import _Always
@ -52,9 +51,6 @@ myhdlObjects = myhdl.__dict__.values()
builtinObjects = builtins.__dict__.values()
_enumTypeSet = set()
_constDict = {}
_extConstDict = {}
def _makeName(n, prefixes, namedict):
# trim empty prefixes
@ -145,14 +141,14 @@ def _analyzeGens(top, absnames):
tree = g
elif isinstance(g, (_AlwaysComb, _AlwaysSeq, _Always)):
f = g.func
tree = _makeAST(f)
tree = g.ast
tree.symdict = f.__globals__.copy()
tree.callstack = []
# handle free variables
tree.nonlocaldict = {}
if f.__code__.co_freevars:
for n, c in zip(f.__code__.co_freevars, f.__closure__):
obj = _cell_deref(c)
obj = c.cell_contents
tree.symdict[n] = obj
# currently, only intbv as automatic nonlocals (until Python 3.0)
if isinstance(obj, intbv):
@ -171,7 +167,7 @@ def _analyzeGens(top, absnames):
v.visit(tree)
else: # @instance
f = g.gen.gi_frame
tree = _makeAST(f)
tree = g.ast
tree.symdict = f.f_globals.copy()
tree.symdict.update(f.f_locals)
tree.nonlocaldict = {}
@ -248,6 +244,12 @@ class _FirstPassVisitor(ast.NodeVisitor, _ConversionMixin):
self.raiseError(node, _error.NotSupported, "list")
def visitSliceObj(self, node):
self.raiseError(node, _error.NotSupported, "slice object")
# All try blocks from python 3.3+
def visit_Try(self, node):
self.raiseError(node, _error.NotSupported, "try statement")
# Legacy try blocks
def visit_TryExcept(self, node):
self.raiseError(node, _error.NotSupported, "try-except statement")
def visit_TryFinally(self, node):
@ -261,11 +263,19 @@ class _FirstPassVisitor(ast.NodeVisitor, _ConversionMixin):
self.visit(node.value)
def visit_Call(self, node):
if node.starargs:
# ast.Call signature changed in python 3.5
# http://greentreesnakes.readthedocs.org/en/latest/nodes.html#Call
if sys.version_info >= (3, 5):
starargs = any(isinstance(arg, ast.Starred) for arg in node.args)
kwargs = any(kw.arg is None for kw in node.keywords)
else:
starargs = node.starargs is not None
kwargs = node.kwargs is not None
if starargs:
self.raiseError(node, _error.NotSupported, "extra positional arguments")
if node.kwargs:
if kwargs:
self.raiseError(node, _error.NotSupported, "extra named arguments")
# f = eval(_unparse(node.node), self.tree.symdict)
self.generic_visit(node)
def visit_Compare(self, node):
@ -517,12 +527,6 @@ class _AnalyzeVisitor(ast.NodeVisitor, _ConversionMixin):
if isinstance(obj, modbv):
if not obj._hasFullRange():
self.raiseError(node, _error.ModbvRange, n)
ws = getattr(obj, 'lenStr', False)
ext = getattr(obj, 'external', False)
if ws and ws in self.tree.symdict:
_constDict[ws] = self.tree.symdict[ws]
if ext:
_extConstDict[ws] = self.tree.symdict[ws]
if n in self.tree.vardict:
curObj = self.tree.vardict[n]
if isinstance(obj, type(curObj)):
@ -601,7 +605,7 @@ class _AnalyzeVisitor(ast.NodeVisitor, _ConversionMixin):
# handle free variables
if f.__code__.co_freevars:
for n, c in zip(f.__code__.co_freevars, f.__closure__):
obj = _cell_deref(c)
obj = c.cell_contents
if not isinstance(obj, (integer_types, _Signal)):
self.raiseError(node, _error.FreeVarTypeError, n)
tree.symdict[n] = obj
@ -817,12 +821,6 @@ class _AnalyzeVisitor(ast.NodeVisitor, _ConversionMixin):
else:
if sig._type is bool:
node.edge = sig.posedge
ws = getattr(sig._val, 'lenStr', False)
ext = getattr(sig._val, 'external', False)
if ws and ws in self.tree.symdict:
_constDict[ws] = self.tree.symdict[ws]
if ext:
_extConstDict[ws] = self.tree.symdict[ws]
if self.access == _access.INPUT:
self.tree.inputs.add(n)
elif self.access == _access.OUTPUT:
@ -859,27 +857,11 @@ class _AnalyzeVisitor(ast.NodeVisitor, _ConversionMixin):
else:
assert False, "unexpected mem access %s %s" % (n, self.access)
self.tree.hasLos = True
ws = getattr(m.elObj._val, 'lenStr', False)
ext = getattr(m.elObj._val, 'external', False)
if ws and ws in self.tree.symdict:
_constDict[ws] = self.tree.symdict[ws]
if ext:
_extConstDict[ws] = self.tree.symdict[ws]
elif isinstance(node.obj, int):
node.value = node.obj
# put VHDL compliant integer constants in global dict
if n not in _constDict and abs(node.obj) < 2**31:
_constDict[n] = node.obj
if n in self.tree.nonlocaldict:
# hack: put nonlocal intbv's in the vardict
self.tree.vardict[n] = v = node.obj
# typedef string for nonlocal intbv's
ws = getattr(v, 'lenStr', False)
ext = getattr(v, 'external', False)
if ws and ws in self.tree.symdict:
_constDict[ws] = self.tree.symdict[ws]
if ext:
_extConstDict[ws] = self.tree.symdict[ws]
elif n in builtins.__dict__:
node.obj = builtins.__dict__[n]
else:
@ -1240,7 +1222,7 @@ def isboundmethod(m):
return ismethod(m) and m.__self__ is not None
def _analyzeTopFunc(top_inst, func, *args, **kwargs):
def _analyzeTopFunc(func, *args, **kwargs):
tree = _makeAST(func)
v = _AnalyzeTopFuncVisitor(func, tree, *args, **kwargs)
v.visit(tree)

View File

@ -48,11 +48,12 @@ from myhdl._instance import _Instantiator
from myhdl.conversion._misc import (_error,_kind,_context,
_ConversionMixin, _Label, _genUniqueSuffix, _isConstant)
from myhdl.conversion._analyze import (_analyzeSigs, _analyzeGens, _analyzeTopFunc,
_Ram, _Rom, _enumTypeSet, _constDict, _extConstDict)
_Ram, _Rom, _enumTypeSet)
from myhdl._Signal import _Signal,_WaiterList
from myhdl.conversion._toVHDLPackage import _package
from myhdl._util import _flatten
from myhdl._compat import integer_types, class_types, StringIO
from myhdl._ShadowSignal import _TristateSignal, _TristateDriver
_version = myhdl.__version__.replace('.','')
@ -162,8 +163,6 @@ class _ToVHDLConvertor(object):
_genUniqueSuffix.reset()
_enumTypeSet.clear()
_enumPortTypeSet.clear()
_constDict.clear()
_extConstDict.clear()
arglist = _flatten(h.top)
_checkArgs(arglist)
@ -173,8 +172,7 @@ class _ToVHDLConvertor(object):
_annotateTypes(genlist)
### infer interface
top_inst = h.hierarchy[0]
intf = _analyzeTopFunc(top_inst, func, *args, **kwargs)
intf = _analyzeTopFunc(func, *args, **kwargs)
intf.name = name
# sanity checks on interface
for portname in intf.argnames:
@ -211,7 +209,6 @@ class _ToVHDLConvertor(object):
_writeCustomPackage(vfile, intf)
_writeModuleHeader(vfile, intf, needPck, lib, arch, useClauses, doc, stdLogicPorts)
_writeFuncDecls(vfile)
_writeConstants(vfile)
_writeTypeDefs(vfile)
_writeSigDecls(vfile, intf, siglist, memlist)
_writeCompDecls(vfile, compDecls)
@ -327,10 +324,11 @@ def _writeModuleHeader(f, intf, needPck, lib, arch, useClauses, doc, stdLogicPor
if convertPort:
pt = "std_logic_vector"
if s._driven:
if s._read:
warnings.warn("%s: %s" % (_error.OutputPortRead, portname),
category=ToVHDLWarning
)
if s._read :
if not isinstance(s, _TristateSignal):
warnings.warn("%s: %s" % (_error.OutputPortRead, portname),
category=ToVHDLWarning
)
f.write("\n %s: inout %s%s" % (portname, pt, r))
else:
f.write("\n %s: out %s%s" % (portname, pt, r))
@ -358,28 +356,6 @@ def _writeFuncDecls(f):
return
# print >> f, package
def _writeConstants(f):
f.write("\n")
# guess nice representation
for c in _constDict:
if c in _extConstDict:
continue
v = _constDict[c]
s = str(int(v))
sign = ''
if v < 0:
sign = '-'
for i in range(4, 31):
if abs(v) == 2**i:
s = "%s2**%s" % (sign, i)
break
if abs(v) == 2**i-1:
s = "%s2**%s-1" % (sign, i)
break
v = _constDict[c]
f.write("constant %s: integer := %s;\n" % (c, s))
f.write("\n")
def _writeTypeDefs(f):
f.write("\n")
sortedList = list(_enumTypeSet)
@ -400,7 +376,7 @@ def _writeSigDecls(f, intf, siglist, memlist):
r = _getRangeString(s)
p = _getTypeString(s)
if s._driven:
if not s._read:
if not s._read and not isinstance(s, _TristateDriver):
warnings.warn("%s: %s" % (_error.UnreadSignal, s._name),
category=ToVHDLWarning
)
@ -461,11 +437,7 @@ def _getRangeString(s):
elif s._type is bool:
return ''
elif s._nrbits is not None:
ls = getattr(s, 'lenStr', False)
if ls:
msb = ls + '-1'
else:
msb = s._nrbits-1
msb = s._nrbits-1
return "(%s downto 0)" % msb
else:
raise AssertionError
@ -516,9 +488,17 @@ def _convertGens(genlist, siglist, memlist, vfile):
w = len(s)
assert w != 0
if s._min < 0:
pre, suf = "to_signed(", ", %s)" % w
if w <= 31:
pre, suf = "to_signed(", ", %s)" % w
else:
pre, suf = "signed'(", ")"
c = '"%s"' % bin(c, w)
else:
pre, suf = "to_unsigned(", ", %s)" % w
if w <= 31:
pre, suf = "to_unsigned(", ", %s)" % w
else:
pre, suf = "unsigned'(", ")"
c = '"%s"' % bin(c, w)
else:
raise ToVHDLError("Unexpected type for constant signal", s._name)
print("%s <= %s%s%s;" % (s._name, pre, c, suf), file=vfile)
@ -791,6 +771,14 @@ class _ConvertVisitor(ast.NodeVisitor, _ConversionMixin):
self.write(")")
def visit_UnaryOp(self, node):
# in python3 a negative Num is represented as an USub of a positive Num
# Fix: restore python2 behavior by a shortcut: invert value of Num, inherit
# vhdl type from UnaryOp node, and visit the modified operand
if isinstance(node.op, ast.USub) and isinstance(node.operand, ast.Num):
node.operand.n = -node.operand.n
node.operand.vhd = node.vhd
self.visit(node.operand)
return
pre, suf = self.inferCast(node.vhd, node.vhdOri)
self.write(pre)
self.write("(")
@ -988,6 +976,7 @@ class _ConvertVisitor(ast.NodeVisitor, _ConversionMixin):
node.args[0].s = ord(node.args[0].s)
elif f in integer_types:
opening, closing = '', ''
pre, suf = self.inferCast(node.vhd, node.vhdOri)
# convert number argument to integer
if isinstance(node.args[0], ast.Num):
node.args[0].n = int(node.args[0].n)
@ -1022,7 +1011,7 @@ class _ConvertVisitor(ast.NodeVisitor, _ConversionMixin):
self.write(f.__name__)
elif f is delay:
self.visit(node.args[0])
self.write(" ns")
self.write(" * 1 ns")
return
elif f is concat:
pre, suf = self.inferCast(node.vhd, node.vhdOri)
@ -1119,17 +1108,16 @@ class _ConvertVisitor(ast.NodeVisitor, _ConversionMixin):
self.write(';')
def visit_IfExp(self, node):
pre, suf = self.inferCast(node.vhd, node.body.vhdOri)
self.write(pre)
self.visit(node.body)
self.write(suf)
self.write(' when ')
# propagate the node's vhd attribute
node.body.vhd = node.orelse.vhd = node.vhd
self.write('tern_op(')
self.write('cond => ')
self.visit(node.test)
self.write(' else ')
pre, suf = self.inferCast(node.vhd, node.orelse.vhdOri)
self.write(pre)
self.write(', if_true => ')
self.visit(node.body)
self.write(', if_false => ')
self.visit(node.orelse)
self.write(suf)
self.write(')')
def visit_For(self, node):
self.labelStack.append(node.breakLabel)
@ -1305,10 +1293,11 @@ class _ConvertVisitor(ast.NodeVisitor, _ConversionMixin):
else:
s = "True"
elif n == 'None':
if node.vhd.size == 1:
if isinstance(node.vhd, vhd_std_logic):
s = "'Z'"
else:
s = "(others => 'Z')"
assert hasattr(node.vhd, 'size')
s = '"%s"' % ('Z' * node.vhd.size)
elif n in self.tree.vardict:
s = n
obj = self.tree.vardict[n]
@ -1328,40 +1317,27 @@ class _ConvertVisitor(ast.NodeVisitor, _ConversionMixin):
obj = self.tree.symdict[n]
s = n
if isinstance(obj, bool):
s = "'%s'" % int(obj)
# print the symbol for a boolean in the global constant dict
if n in _constDict and obj == _constDict[n]:
if isinstance(node.vhd, vhd_boolean):
s = "bool(%s)" % n
elif isinstance(obj, integer_types):
# print the symbol for an integer in the global constant dict
if n in _constDict and obj == _constDict[n]:
assert abs(obj) < 2**31
if isinstance(node.vhd, vhd_int):
s = n
elif isinstance(node.vhd, vhd_boolean):
s = "bool(%s)" % n
elif isinstance(node.vhd, vhd_std_logic):
s = "stdl(%s)" % n
elif isinstance(node.vhd, vhd_unsigned):
s = "to_unsigned(%s, %s)" % (n, node.vhd.size)
elif isinstance(node.vhd, vhd_signed):
s = "to_signed(%s, %s)" % (n, node.vhd.size)
if isinstance(node.vhd, vhd_std_logic):
s = "'%s'" % int(obj)
else:
if isinstance(node.vhd, vhd_int):
s = self.IntRepr(obj)
elif isinstance(node.vhd, vhd_std_logic):
s = "'%s'" % int(obj)
elif isinstance(node.vhd, vhd_unsigned):
if abs(obj) < 2** 31:
s = "to_unsigned(%s, %s)" % (n, node.vhd.size)
else:
s = 'unsigned\'("%s")' % bin(obj, node.vhd.size)
elif isinstance(node.vhd, vhd_signed):
if abs(obj) < 2** 31:
s = "to_signed(%s, %s)" % (n, node.vhd.size)
else:
s = 'signed\'("%s")' % bin(obj, node.vhd.size)
s = "%s" % obj
elif isinstance(obj, integer_types):
if isinstance(node.vhd, vhd_int):
s = self.IntRepr(obj)
elif isinstance(node.vhd, vhd_boolean):
s = "%s" % bool(obj)
elif isinstance(node.vhd, vhd_std_logic):
s = "'%s'" % int(obj)
elif isinstance(node.vhd, vhd_unsigned):
if abs(obj) < 2** 31:
s = "to_unsigned(%s, %s)" % (obj, node.vhd.size)
else:
s = 'unsigned\'("%s")' % bin(obj, node.vhd.size)
elif isinstance(node.vhd, vhd_signed):
if abs(obj) < 2** 31:
s = "to_signed(%s, %s)" % (obj, node.vhd.size)
else:
s = 'signed\'("%s")' % bin(obj, node.vhd.size)
elif isinstance(obj, _Signal):
s = str(obj)
ori = inferVhdlObj(obj)
@ -1948,29 +1924,20 @@ class vhd_boolean(vhd_type):
return 'boolean'
class vhd_vector(vhd_type):
def __init__(self, size=0, lenStr=False):
def __init__(self, size=0):
vhd_type.__init__(self, size)
self.lenStr = lenStr
class vhd_unsigned(vhd_vector):
def toStr(self, constr=True):
if constr:
ls = self.lenStr
if ls:
return "unsigned(%s-1 downto 0)" % ls
else:
return "unsigned(%s downto 0)" % (self.size-1)
return "unsigned(%s downto 0)" % (self.size-1)
else:
return "unsigned"
class vhd_signed(vhd_vector):
def toStr(self, constr=True):
if constr:
ls = self.lenStr
if ls:
return "signed(%s-1 downto 0)" % ls
else:
return "signed(%s downto 0)" % (self.size-1)
return "signed(%s downto 0)" % (self.size-1)
else:
return "signed"
@ -2008,11 +1975,10 @@ def inferVhdlObj(obj):
vhd = None
if (isinstance(obj, _Signal) and obj._type is intbv) or \
isinstance(obj, intbv):
ls = getattr(obj, 'lenStr', False)
if obj.min is None or obj.min < 0:
vhd = vhd_signed(size=len(obj), lenStr=ls)
vhd = vhd_signed(size=len(obj))
else:
vhd = vhd_unsigned(size=len(obj), lenStr=ls)
vhd = vhd_unsigned(size=len(obj))
elif (isinstance(obj, _Signal) and obj._type is bool) or \
isinstance(obj, bool):
vhd = vhd_std_logic()
@ -2306,10 +2272,3 @@ def _annotateTypes(genlist):
continue
v = _AnnotateTypesVisitor(tree)
v.visit(tree)

View File

@ -58,6 +58,12 @@ package pck_myhdl_%(version)s is
function "-" (arg: unsigned) return signed;
function tern_op(cond: boolean; if_true: std_logic; if_false: std_logic) return std_logic;
function tern_op(cond: boolean; if_true: unsigned; if_false: unsigned) return unsigned;
function tern_op(cond: boolean; if_true: signed; if_false: signed) return signed;
end pck_myhdl_%(version)s;
@ -157,6 +163,33 @@ package body pck_myhdl_%(version)s is
return - signed(resize(arg, arg'length+1));
end function "-";
function tern_op(cond: boolean; if_true: std_logic; if_false: std_logic) return std_logic is
begin
if cond then
return if_true;
else
return if_false;
end if;
end function tern_op;
function tern_op(cond: boolean; if_true: unsigned; if_false: unsigned) return unsigned is
begin
if cond then
return if_true;
else
return if_false;
end if;
end function tern_op;
function tern_op(cond: boolean; if_true: signed; if_false: signed) return signed is
begin
if cond then
return if_true;
else
return if_false;
end if;
end function tern_op;
end pck_myhdl_%(version)s;
""" % {'version' : _shortversion}

View File

@ -50,7 +50,7 @@ from myhdl.conversion._misc import (_error, _kind, _context,
from myhdl.conversion._analyze import (_analyzeSigs, _analyzeGens, _analyzeTopFunc,
_Ram, _Rom)
from myhdl._Signal import _Signal
from myhdl._ShadowSignal import _TristateSignal, _TristateDriver
_converting = 0
_profileFunc = None
@ -153,8 +153,8 @@ class _ToVerilogConvertor(object):
genlist = _analyzeGens(arglist, h.absnames)
siglist, memlist = _analyzeSigs(h.hierarchy)
_annotateTypes(genlist)
top_inst = h.hierarchy[0]
intf = _analyzeTopFunc(top_inst, func, *args, **kwargs)
intf = _analyzeTopFunc(func, *args, **kwargs)
intf.name = name
doc = _makeDoc(inspect.getdoc(func))
@ -255,11 +255,15 @@ def _writeModuleHeader(f, intf, doc):
r = _getRangeString(s)
p = _getSignString(s)
if s._driven:
if s._read:
warnings.warn("%s: %s" % (_error.OutputPortRead, portname),
category=ToVerilogWarning
)
print("output %s%s%s;" % (p, r, portname), file=f)
if s._read :
if not isinstance(s, _TristateSignal):
warnings.warn("%s: %s" % (_error.OutputPortRead, portname),
category=ToVerilogWarning
)
if isinstance(s, _TristateSignal):
print("inout %s%s%s;" % (p, r, portname), file=f)
else:
print("output %s%s%s;" % (p, r, portname), file=f)
if s._driven == 'reg':
print("reg %s%s%s;" % (p, r, portname), file=f)
else:
@ -283,7 +287,7 @@ def _writeSigDecls(f, intf, siglist, memlist):
r = _getRangeString(s)
p = _getSignString(s)
if s._driven:
if not s._read:
if not s._read and not isinstance(s, _TristateDriver):
warnings.warn("%s: %s" % (_error.UnreadSignal, s._name),
category=ToVerilogWarning
)
@ -331,7 +335,9 @@ def _writeSigDecls(f, intf, siglist, memlist):
c = int(s.val)
else:
raise ToVerilogError("Unexpected type for constant signal", s._name)
print("assign %s = %s;" % (s._name, c), file=f)
c_len = s._nrbits
c_str = "%s"%c
print("assign %s = %s'd%s;" % (s._name, c_len, c_str), file=f)
print(file=f)
# shadow signal assignments
for s in siglist:
@ -1032,7 +1038,7 @@ class _ConvertVisitor(ast.NodeVisitor, _ConversionMixin):
elif n in self.tree.symdict:
obj = self.tree.symdict[n]
if isinstance(obj, bool):
s = "%s" % int(obj)
s = "1'b%s" % int(obj)
elif isinstance(obj, integer_types):
s = self.IntRepr(obj)
elif isinstance(obj, _Signal):
@ -1573,6 +1579,3 @@ def _annotateTypes(genlist):
continue
v = _AnnotateTypesVisitor(tree)
v.visit(tree)

View File

@ -6,6 +6,8 @@ import tempfile
import subprocess
import difflib
from collections import namedtuple
import myhdl
from myhdl._Simulation import Simulation
from myhdl.conversion._toVHDL import toVHDL
@ -15,14 +17,10 @@ _version = myhdl.__version__.replace('.','')
# strip 'dev' for version
_version = _version.replace('dev','')
_simulators = []
_hdlMap = {}
_analyzeCommands = {}
_elaborateCommands = {}
_simulateCommands = {}
_skiplinesMap = {}
_skipcharsMap = {}
_ignoreMap = {}
_simulators = {}
sim = namedtuple('sim', 'name hdl analyze elaborate simulate skiplines skipchars ignore')
def registerSimulator(name=None, hdl=None, analyze=None, elaborate=None, simulate=None,
skiplines=None, skipchars=None, ignore=None):
@ -38,23 +36,23 @@ def registerSimulator(name=None, hdl=None, analyze=None, elaborate=None, simulat
raise ValueError("Invalid elaborate command")
if not isinstance(simulate, str) or (simulate.strip() == ""):
raise ValueError("Invalid simulator command")
_simulators.append(name)
_hdlMap[name] = hdl
_analyzeCommands[name] = analyze
_elaborateCommands[name] = elaborate
_simulateCommands[name] = simulate
_skiplinesMap[name] = skiplines
_skipcharsMap[name] = skipchars
_ignoreMap[name] = ignore
_simulators[name] = sim(name, hdl, analyze, elaborate, simulate, skiplines, skipchars, ignore)
registerSimulator(
name="GHDL",
name="ghdl",
hdl="VHDL",
analyze="ghdl -a --workdir=work pck_myhdl_%(version)s.vhd %(topname)s.vhd",
elaborate="ghdl -e --workdir=work -o %(unitname)s %(topname)s",
simulate="ghdl -r --workdir=work %(unitname)s"
)
registerSimulator(
name="nvc",
hdl="VHDL",
analyze="nvc --work=work_nvc -a pck_myhdl_%(version)s.vhd %(topname)s.vhd",
elaborate="nvc --work=work_nvc -e %(topname)s",
simulate="nvc --work=work_nvc -r %(topname)s"
)
registerSimulator(
name="vlog",
@ -63,7 +61,7 @@ registerSimulator(
simulate='vsim work_vlog.%(topname)s -quiet -c -do "run -all; quit -f"',
skiplines=6,
skipchars=2,
ignore=("# **", "# run -all")
ignore=("# **", "# //", "# run -all")
)
registerSimulator(
@ -73,12 +71,12 @@ registerSimulator(
simulate='vsim work_vcom.%(topname)s -quiet -c -do "run -all; quit -f"',
skiplines=6,
skipchars=2,
ignore=("# **", "# Time:", "# run -all")
ignore=("# **", "# //", "# Time:", "# run -all")
)
registerSimulator(
name="icarus",
name="iverilog",
hdl="Verilog",
analyze="iverilog -o %(topname)s.o %(topname)s.v",
simulate="vvp %(topname)s.o"
@ -98,31 +96,38 @@ class _VerificationClass(object):
__slots__ = ("simulator", "_analyzeOnly")
def __init__(self, analyzeOnly=False):
self.simulator = "GHDL"
self.simulator = None
self._analyzeOnly = analyzeOnly
def __call__(self, func, *args, **kwargs):
if not self.simulator:
raise ValueError("No simulator specified")
if self.simulator not in _simulators:
raise ValueError("Simulator %s is not registered" % self.simulator)
hdlsim = _simulators[self.simulator]
hdl = hdlsim.hdl
if hdl == 'Verilog' and toVerilog.name is not None:
name = toVerilog.name
elif hdl == 'VHDL' and toVHDL.name is not None:
name = toVHDL.name
else:
name = func.__name__
vals = {}
vals['topname'] = func.__name__
vals['unitname'] = func.__name__.lower()
vals['topname'] = name
vals['unitname'] = name.lower()
vals['version'] = _version
hdlsim = self.simulator
if not hdlsim:
raise ValueError("No simulator specified")
if not hdlsim in _simulators:
raise ValueError("Simulator %s is not registered" % hdlsim)
hdl = _hdlMap[hdlsim]
analyze = _analyzeCommands[hdlsim] % vals
elaborate = _elaborateCommands[hdlsim]
analyze = hdlsim.analyze % vals
elaborate = hdlsim.elaborate
if elaborate is not None:
elaborate = elaborate % vals
simulate = _simulateCommands[hdlsim] % vals
skiplines = _skiplinesMap[hdlsim]
skipchars = _skipcharsMap[hdlsim]
ignore = _ignoreMap[hdlsim]
simulate = hdlsim.simulate % vals
skiplines = hdlsim.skiplines
skipchars = hdlsim.skipchars
ignore = hdlsim.ignore
if hdl == "VHDL":
inst = toVHDL(func, *args, **kwargs)
@ -132,7 +137,7 @@ class _VerificationClass(object):
if hdl == "VHDL":
if not os.path.exists("work"):
os.mkdir("work")
if hdlsim in ('vlog', 'vcom'):
if hdlsim.name in ('vlog', 'vcom'):
if not os.path.exists("work_vsim"):
try:
subprocess.call("vlib work_vlog", shell=True)
@ -194,10 +199,10 @@ class _VerificationClass(object):
glines = [line[skipchars:] for line in glines]
flinesNorm = [line.lower() for line in flines]
glinesNorm = [line.lower() for line in glines]
g = difflib.unified_diff(flinesNorm, glinesNorm, fromfile=hdlsim, tofile=hdl)
g = difflib.unified_diff(flinesNorm, glinesNorm, fromfile=hdlsim.name, tofile=hdl)
MyHDLLog = "MyHDL.log"
HDLLog = hdlsim + ".log"
HDLLog = hdlsim.name + ".log"
try:
os.remove(MyHDLLog)
os.remove(HDLLog)

View File

@ -1 +0,0 @@

View File

@ -1,6 +0,0 @@
from __future__ import absolute_import
from myhdl.conversion import verify
from myhdl.conversion import analyze
verify.simulator = "GHDL"
analyze.simulator = "GHDL"

View File

@ -1,21 +1,24 @@
all: vlog vcom
all: ghdl iverilog
vlog:
py.test vlog.py test_*.py
py.test --sim vlog
vcom:
py.test vcom.py test_*.py
py.test --sim vcom
GHDL:
py.test GHDL.py test_*.py
ghdl:
py.test --sim ghdl
icarus:
py.test icarus.py test_*.py
iverilog:
py.test --sim iverilog
cver:
py.test cver.py test_*.py
py.test --sim cver
clean:
- rm *.o *.out *.v *.vhd *.pyc *~ *.vcd* *.log *_ghdl
gitclean:
git clean -dfx

View File

View File

@ -1,4 +0,0 @@
from __future__ import absolute_import
from myhdl.conversion import verify
verify.simulator = "cver"

View File

@ -1,6 +0,0 @@
from __future__ import absolute_import
from myhdl.conversion import verify
from myhdl.conversion import analyze
verify.simulator = "icarus"
analyze.simulator = "icarus"

View File

@ -0,0 +1,31 @@
"""
When an interface signal gets passed into a function, it
can get renamed to the name of the argument. When the
function is called multiple times, this causes name collisions """
from __future__ import absolute_import
import pytest
from myhdl import *
from myhdl.conversion import analyze
class AB:
def __init__(self):
self.a = Signal(bool(False))
self.b = Signal(bool(False))
def invert(sigin, sigout):
@always_comb
def foo():
sigout.next = not sigin
return foo
def issue_134(ab_in, ab_out):
""" Instantiate an inverter for each signal """
inverta = invert(ab_in.a, ab_out.a)
invertb = invert(ab_in.b, ab_out.b)
return inverta, invertb
@pytest.mark.xfail
def test_issue_134():
""" check for port name collision"""
assert analyze(issue_134, AB(), AB()) == 0

View File

@ -0,0 +1,49 @@
from __future__ import absolute_import
from myhdl import *
from myhdl.conversion import analyze
def issue_117(clk, sdi, pdo, sel, const=False):
assert isinstance(const, (bool, intbv))
delay_reg = Signal(intbv(0)[8:])
rlen = len(pdo)
plen = 1 if isinstance(const, bool) else len(const)
@always(clk.posedge)
def rtl():
if sel == 0:
delay_reg.next = concat(const, delay_reg[rlen-plen-1:1], sdi)
elif sel == 1:
delay_reg.next = concat(delay_reg[rlen-1:plen+1], const, sdi)
elif sel == 2:
delay_reg.next = concat(delay_reg[rlen-1:plen+1], sdi, const)
pdo.next = delay_reg
return rtl
def test_issue_117_1():
clk, sdi = [Signal(bool(0)) for _ in range(2)]
pdo = Signal(intbv(0)[8:])
sel = Signal(intbv(0, min=0, max=3))
toVHDL.name = toVerilog.name = 'issue_117_1'
assert analyze(issue_117, clk, sdi, pdo, sel, const=bool(0))== 0
def test_issue_117_2():
clk, sdi = [Signal(bool(0)) for _ in range(2)]
pdo = Signal(intbv(0)[8:])
sel = Signal(intbv(0, min=0, max=3))
toVHDL.name = toVerilog.name = 'issue_117_2'
assert analyze(issue_117, clk, sdi, pdo, sel, const=False)== 0
def test_issue_117_3():
clk, sdi = [Signal(bool(0)) for _ in range(2)]
pdo = Signal(intbv(0)[8:])
sel = Signal(intbv(0, min=0, max=3))
toVHDL.name = toVerilog.name = 'issue_117_3'
assert analyze(issue_117, clk, sdi, pdo, sel, const=intbv(0)[1:])== 0
if __name__ == '__main__':
analyze.simulator='vlog'
test_issue_117_1()

View File

@ -0,0 +1,30 @@
from __future__ import absolute_import
from myhdl import *
from myhdl.conversion import verify
def issue_122(dout, i):
d = i*10+1
@instance
def write():
# dout[i].next = int(i)
dout[i].next = i
yield delay(d)
print(int(dout[i]))
if i == 0:
return write
else:
inst = issue_122(dout, i-1)
return write, inst
def tb_issue_122():
n = 7
dout = [Signal(intbv(0, min=0, max=n+1)) for i in range(n+1)]
inst = issue_122(dout, n)
return inst
def test_issue_122():
assert verify(tb_issue_122) == 0

View File

@ -0,0 +1,148 @@
''' Bitonic sort '''
# http://www.myhdl.org/examples/bitonic/
from __future__ import absolute_import
import unittest
from random import randrange
from myhdl import Signal, intbv, \
always_comb, instance, \
delay, toVHDL, StopSimulation
ASCENDING = True
DESCENDING = False
# modules
def compare(a_1, a_2, z_1, z_2, direction):
""" Combinatorial circuit with two input and two output signals.
Sorting to 'direction'. """
@always_comb
def logic():
''' Combinatorial logic '''
if direction == (a_1 > a_2):
z_1.next = a_2
z_2.next = a_1
else:
z_1.next = a_1
z_2.next = a_2
return logic
def feedthru(in_a, out_z):
""" Equivalent of 'doing nothing'. """
@always_comb
def logic():
''' Combinatorial logic '''
out_z.next = in_a
return logic
def bitonic_merge(list_a, list_z, direction):
""" bitonicMerge:
Generates the output from the input list of signals.
Recursive. """
len_list = len(list_a)
half_len = len_list//2
width = len(list_a[0])
if len_list > 1:
tmp = [Signal(intbv(0)[width:]) for _ in range(len_list)]
comp = [compare(list_a[i], list_a[i+half_len], tmp[i], tmp[i+half_len], \
direction) for i in range(half_len)]
lo_merge = bitonic_merge( tmp[:half_len], list_z[:half_len], direction )
hi_merge = bitonic_merge( tmp[half_len:], list_z[half_len:], direction )
return comp, lo_merge, hi_merge
else:
feed = feedthru(list_a[0], list_z[0])
return feed
def bitonic_sort(list_a, list_z, direction):
""" bitonicSort:
Produces a bitonic sequence.
Recursive. """
len_list = len(list_a)
half_len = len_list//2
width = len(list_a[0])
if len_list > 1:
tmp = [Signal(intbv(0)[width:]) for _ in range(len_list)]
lo_sort = bitonic_sort( list_a[:half_len], tmp[:half_len], ASCENDING )
hi_sort = bitonic_sort( list_a[half_len:], tmp[half_len:], DESCENDING )
merge = bitonic_merge( tmp, list_z, direction )
return lo_sort, hi_sort, merge
else:
feed = feedthru(list_a[0], list_z[0])
return feed
# tests
def array8sorter(a_0, a_1, a_2, a_3, a_4, a_5, a_6, a_7,
z_0, z_1, z_2, z_3, z_4, z_5, z_6, z_7):
''' Sort Array with 8 values '''
list_a = [a_0, a_1, a_2, a_3, a_4, a_5, a_6, a_7]
list_z = [z_0, z_1, z_2, z_3, z_4, z_5, z_6, z_7]
sort = bitonic_sort(list_a, list_z, ASCENDING)
return sort
class TestBitonicSort(unittest.TestCase):
''' Test class for bitonic sort '''
def test_sort(self):
""" Check the functionality of the bitonic sort """
length = 8
width = 4
def test_impl():
''' test implementation '''
inputs = [ Signal(intbv(0)[width:]) for _ in range(length) ]
outputs = [ Signal(intbv(0)[width:]) for _ in range(length) ]
z_0, z_1, z_2, z_3, z_4, z_5, z_6, z_7 = outputs
a_0, a_1, a_2, a_3, a_4, a_5, a_6, a_7 = inputs
inst = array8sorter(a_0, a_1, a_2, a_3, a_4, a_5, a_6, a_7,
z_0, z_1, z_2, z_3, z_4, z_5, z_6, z_7)
@instance
def check():
''' testbench input and validation '''
for i in range(100):
data = [randrange(2**width) for i in range(length)]
for i in range(length):
inputs[i].next = data[i]
yield delay(10)
data.sort()
self.assertEqual(data, outputs, 'wrong data')
raise StopSimulation
return inst, check
# convert
def test_issue_127():
''' Convert to VHDL '''
length = 8
width = 4
sigs = [Signal(intbv(0)[width:]) for _ in range(2*length)]
toVHDL(array8sorter, *sigs)

View File

@ -0,0 +1,19 @@
from __future__ import absolute_import
from myhdl import *
from myhdl.conversion import verify
def issue_133():
z = Signal(False)
large_signal = Signal(intbv(123456789123456, min=0, max=2**256))
@instance
def check():
z.next = large_signal[10]
yield delay(10)
print (large_signal[31:])
print (large_signal[62:31])
print (large_signal[93:62])
return check
def test_issue_133():
assert verify(issue_133) == 0

View File

@ -1,3 +1,4 @@
from __future__ import absolute_import
from myhdl import *
from myhdl.conversion import analyze
@ -27,5 +28,5 @@ clk = Signal(bool(0))
def test_issue_18():
toVHDL.std_logic_ports = True
analyze(issue_18, dout, din, addr, we, clk) == 0
assert analyze(issue_18, dout, din, addr, we, clk) == 0

View File

@ -0,0 +1,34 @@
from __future__ import absolute_import
from myhdl import *
from myhdl.conversion import analyze
import pytest
def issue_98(sda, scl, sda_i, sda_o, scl_i, scl_o):
sda_d, scl_d = sda.driver(), scl.driver()
@always_comb
def hdl():
sda_i.next = sda
sda_d.next = 0 if not sda_o else None
scl_i.next = scl
scl_d.next = None if not scl_o else 1
return hdl
def test_issue_98_1():
sda_i, sda_o, scl_i, scl_o = [Signal(False) for i in range(4)]
sda, scl = [TristateSignal(False) for i in range(2)]
toVHDL.name = toVerilog.name = 'issue_98_1'
assert analyze(issue_98, sda, scl, sda_i, sda_o, scl_i, scl_o) == 0
def test_issue_98_2():
sda_i, sda_o, scl_i, scl_o = [Signal(intbv(0)[2:0]) for i in range(4)]
sda, scl = [TristateSignal(intbv(0)[2:0]) for i in range(2)]
toVHDL.name = toVerilog.name = 'issue_98_2'
assert analyze(issue_98, sda, scl, sda_i, sda_o, scl_i, scl_o) == 0
def test_issue_98_3():
sda_i, sda_o, scl_i, scl_o = [Signal(intbv(0)[1:0]) for i in range(4)]
sda, scl = [TristateSignal(intbv(0)[1:0]) for i in range(2)]
toVHDL.name = toVerilog.name = 'issue_98_3'
assert analyze(issue_98, sda, scl, sda_i, sda_o, scl_i, scl_o) == 0

View File

@ -1,4 +0,0 @@
from __future__ import absolute_import
from myhdl.conversion import verify, analyze
verify.simulator = analyze.simulator = "vcom"

View File

@ -1,4 +0,0 @@
from __future__ import absolute_import
from myhdl.conversion import verify, analyze
verify.simulator = analyze.simulator = "vlog"

41
myhdl/test/conftest.py Normal file
View File

@ -0,0 +1,41 @@
import sys
import py
import pytest
from myhdl.conversion import analyze, verify
from myhdl.conversion._verify import _simulators
xfail = pytest.mark.xfail
all_sims = list(_simulators)
if sys.version_info[0] > 2:
collect_ignore = ['conversion/toVerilog/test_not_supported_py2.py']
def pytest_addoption(parser):
parser.addoption("--sim", action="store", choices=all_sims,
help="HDL Simulator")
def pytest_configure(config):
sim = config.getoption('sim')
if sim is not None:
verify.simulator = analyze.simulator = sim
def pytest_report_header(config):
sim = config.getoption('sim')
if config.getoption('sim') is not None:
hdr = ['Simulator: {sim}']
if not py.path.local.sysfind(sim):
hdr += ['Warning: {sim} not found in PATH']
return '\n'.join(hdr).format(sim=sim)
def bug(issue_no, hdl='all'):
if hdl == 'all':
sims = all_sims
else:
sims = [k for k, v in _simulators.items() if v.hdl.lower() == hdl]
return xfail(verify.simulator in sims, reason='issue '+issue_no)

View File

@ -3,13 +3,17 @@
all: general toVerilog2 toVHDL toVerilog
general:
cd general; make -k
cd general; py.test --sim ghdl; py.test --sim iverilog
toVerilog2:
cd toVerilog2; make -k
cd toVerilog2; py.test --sim iverilog
toVHDL:
cd toVHDL; make -k
cd toVHDL; py.test --sim ghdl
toVerilog:
cd toVerilog; make -k
cd toVerilog; py.test --sim iverilog
gitclean:
git clean -dfx

View File

@ -1,20 +0,0 @@
from itertools import chain
import pytest
from myhdl.conversion import verify
xfail = pytest.mark.xfail
hdlmap = {
'verilog': ('icarus', 'vlog'),
'vhdl': ('GHDL', 'vcom')
}
def bug(issue_no, hdl='all'):
if hdl == 'all':
sims = list(chain.from_iterable(hdlmap.values()))
else:
sims = hdlmap[hdl]
return xfail(verify.simulator in sims, reason='issue '+issue_no)

View File

@ -1,4 +0,0 @@
from __future__ import absolute_import
from myhdl.conversion import verify, analyze
verify.simulator = analyze.simulator = "GHDL"

View File

@ -1,19 +1,22 @@
all: vlog vcom
GHDL:
py.test GHDL.py test_*.py
ghdl:
py.test --sim ghdl
vlog:
py.test vlog.py test_*.py
py.test --sim vlog
vcom:
py.test vcom.py test_*.py
py.test --sim vcom
icarus:
py.test icarus.py test_*.py
iverilog:
py.test --sim iverilog
cver:
py.test cver.py test_*.py
py.test --sim cver
clean:
- rm *.o *.out *.v *.vhd *.pyc *~ *.vcd* *.log *_ghdl
gitclean:
git clean -dfx

View File

@ -1,4 +0,0 @@
from __future__ import absolute_import
from myhdl.conversion import verify, analyze
verify.simulator = analyze.simulator = "cver"

View File

@ -1,4 +0,0 @@
from __future__ import absolute_import
from myhdl.conversion import verify, analyze
verify.simulator = analyze.simulator = "icarus"

View File

@ -2,8 +2,6 @@ from __future__ import absolute_import
import sys
import pytest
from myhdl import *
from myhdl import ConversionError
from myhdl.conversion._misc import _error
@ -11,10 +9,6 @@ from myhdl.conversion import analyze, verify
from myhdl import *
from myhdl.test.conversion.conftest import bug
from myhdl import *
"""
This set of tests exercies a peculiar scenario where an
expanded interface Signal is flagged as having multiple
@ -110,9 +104,13 @@ def c_testbench_one():
while True:
yield delay(3)
clock.next = not clock
expected = (False, False, False, True, True, True,
False, True, False, True)
# there is an issue when using bools with varialbes and
# VHDL conversion, this might be an expected limitation?
#expected = (False, False, False, True, True, True,
# False, True, False, True)
expected = (0, 0, 0, 1, 1, 1, 0, 1, 0, 1)
ra = reset.active
@instance
def tbstim():
@ -141,7 +139,6 @@ def test_one_testbench():
Simulation(c_testbench_one()).run()
@bug('82')
def test_one_analyze():
clock = Signal(bool(0))
reset = ResetSignal(0, active=1, async=False)
@ -150,11 +147,10 @@ def test_one_analyze():
analyze(m_top, clock, reset, sdi, sdo)
@bug('82')
def test_one_verify():
assert verify(c_testbench_one) == 0
@bug('82')
def test_conversion():
toVerilog(c_testbench_one)
toVHDL(c_testbench_one)
@ -171,4 +167,4 @@ if __name__ == '__main__':
test_conversion()
print("*** verify testbench conversion and execution")
test_one_verify()

View File

@ -66,9 +66,11 @@ def TernaryBench(ternary):
# uncomment when we have a VHDL-2008 compliant simulator
# def test_ternary1():
# assert conversion.verify(TernaryBench, ternary1) == 0
def test_ternary1():
toVHDL.name = 'ternary1'
assert conversion.verify(TernaryBench, ternary1) == 0
def test_ternary2():
toVHDL.name = 'ternary2'
assert conversion.verify(TernaryBench, ternary2) == 0

View File

@ -1,4 +0,0 @@
from __future__ import absolute_import
from myhdl.conversion import verify, analyze
verify.simulator = analyze.simulator = "vcom"

View File

@ -1,4 +0,0 @@
from __future__ import absolute_import
from myhdl.conversion import verify, analyze
verify.simulator = analyze.simulator = "vlog"

View File

@ -1,4 +0,0 @@
from __future__ import absolute_import
from myhdl.conversion import verify
verify.simulator = "GHDL"

View File

@ -1,10 +1,13 @@
all: vcom
vcom:
py.test vcom.py test_*.py
py.test --sim vcom
GHDL:
py.test GHDL.py test_*.py
ghdl:
py.test --sim ghdl
clean:
- rm *.o *.out *.v *.vhd *.pyc *~ *.vcd* *.log *_ghdl
gitclean:
git clean -dfx

View File

View File

@ -74,10 +74,10 @@ def inc(count, enable, clock, reset, n):
__vhdl__ = \
"""
process (%(clock)s, %(reset)s) begin
if (reset = '0') then
if (%(reset)s = '0') then
%(count)s <= (others => '0');
elsif rising_edge(%(clock)s) then
if (enable = '1') then
if (%(enable)s = '1') then
%(count)s <= (%(count)s + 1) mod %(n)s;
end if;
end if;
@ -104,11 +104,11 @@ def incErr(count, enable, clock, reset, n):
__vhdl__ = \
"""
always @(posedge %(clock)s, negedge %(reset)s) begin
if (reset == 0) begin
if (%(reset)s == 0) begin
%(count)s <= 0;
end
else begin
if (enable) begin
if (%(enable)s) begin
%(count)s <= (%(countq)s + 1) %% %(n)s;
end
end
@ -151,10 +151,10 @@ def inc_seq(count, nextCount, enable, clock, reset):
__vhdl__ = \
"""
process (%(clock)s, %(reset)s) begin
if (reset = '0') then
if (%(reset)s = '0') then
%(count)s <= (others => '0');
elsif rising_edge(%(clock)s) then
if (enable = '1') then
if (%(enable)s = '1') then
%(count)s <= %(nextCount)s;
end if;
end if;
@ -215,7 +215,7 @@ def check(count, enable, clock, reset, n):
expect = 0
yield reset.posedge
# assert count == expect
print count
print(count)
while 1:
yield clock.posedge
if enable:
@ -223,7 +223,7 @@ def check(count, enable, clock, reset, n):
yield delay(1)
# print "%d count %s expect %s count_v %s" % (now(), count, expect, count_v)
# assert count == expect
print count
print(count)
return logic

View File

@ -40,23 +40,23 @@ def bench_enum():
a.next = 0xaa
b.next = 0x55
yield clock.posedge
print 'a=%s b=%s' % (a, b)
print('a=%s b=%s' % (a, b))
op.next = bitwise_op.BW_AND
yield clock.posedge
print c
print(c)
op.next = bitwise_op.BW_ANDN
yield clock.posedge
print c
print(c)
op.next = bitwise_op.BW_OR
yield clock.posedge
print c
print(c)
op.next = bitwise_op.BW_XOR
yield clock.posedge
print c
print(c)
raise StopSimulation

View File

@ -34,7 +34,7 @@ def LoopBench(LoopTest):
for i in range(100):
a.next = data[i]
yield delay(10)
print z
print(z)
return stimulus, looptest_inst

View File

@ -74,10 +74,10 @@ def inc(count, enable, clock, reset, n):
inc.vhdl_code = \
"""
process ($clock, $reset) begin
if (reset = '0') then
if ($reset = '0') then
$count <= (others => '0');
elsif rising_edge($clock) then
if (enable = '1') then
if ($enable = '1') then
$count <= ($count + 1) mod $n;
end if;
end if;
@ -104,11 +104,11 @@ def incErr(count, enable, clock, reset, n):
incErr.vhdl_code = \
"""
always @(posedge $clock, negedge $reset) begin
if (reset == 0) begin
if ($reset == 0) begin
$count <= 0;
end
else begin
if (enable) begin
if ($enable) begin
$count <= ($countq + 1) %% $n;
end
end
@ -151,10 +151,10 @@ def inc_seq(count, nextCount, enable, clock, reset):
inc_seq.vhdl_code = \
"""
process ($clock, $reset) begin
if (reset = '0') then
if ($reset = '0') then
$count <= (others => '0');
elsif rising_edge($clock) then
if (enable = '1') then
if ($enable = '1') then
$count <= $nextCount;
end if;
end if;
@ -215,7 +215,7 @@ def check(count, enable, clock, reset, n):
expect = 0
yield reset.posedge
# assert count == expect
print count
print(count)
while 1:
yield clock.posedge
if enable:
@ -223,7 +223,7 @@ def check(count, enable, clock, reset, n):
yield delay(1)
# print "%d count %s expect %s count_v %s" % (now(), count, expect, count_v)
# assert count == expect
print count
print(count)
return logic

View File

@ -145,27 +145,27 @@ def binaryBench(m, n):
yield left, right
yield delay(1)
print Bitand
print Bitor
print Bitxor
print FloorDiv
print LeftShift
print(Bitand)
print(Bitor)
print(Bitxor)
print(FloorDiv)
print(LeftShift)
# print Pow, Pow_v
print Modulo
print RightShift
print Mul
print Sub
print Sum
print int(EQ)
print int(NE)
print int(LT)
print int(GT)
print int(LE)
print int(GE)
print int(Booland)
print int(Boolor)
print(Modulo)
print(RightShift)
print(Mul)
print(Sub)
print(Sum)
print(int(EQ))
print(int(NE))
print(int(LT))
print(int(GT))
print(int(LE))
print(int(GE))
print(int(Booland))
print(int(Boolor))
return binops, stimulus, check
@ -253,11 +253,11 @@ def multiBench(m, n, p):
yield argm, argn, argp
yield delay(1)
print Bitand
print Bitor
print Bitxor
print int(Booland)
print int(Boolor)
print(Bitand)
print(Bitor)
print(Bitxor)
print(int(Booland))
print(int(Boolor))
return multiops, stimulus, check
@ -315,8 +315,8 @@ def unaryBench(m):
while 1:
yield arg
yield delay(1)
print int(Not_kw)
print Invert
print(int(Not_kw))
print(Invert)
# check unary operator support in vhdl
# print UnaryAdd
# print UnarySub
@ -449,16 +449,16 @@ def augmBench(m, n):
while True:
yield left, right
yield delay(1)
print Bitand
print Bitor
print Bitxor
print Sub
print Sum
print FloorDiv
print LeftShift
print Modulo
print Mul
print RightShift
print(Bitand)
print(Bitor)
print(Bitxor)
print(Sub)
print(Sum)
print(FloorDiv)
print(LeftShift)
print(Modulo)
print(Mul)
print(RightShift)
return augmops, stimulus, check

View File

@ -163,24 +163,24 @@ def binaryBench(Ll, Ml, Lr, Mr):
## self.assertEqual(Bitor, Bitor_v)
## self.assertEqual(Bitxor, Bitxor_v)
## ## self.assertEqual(FloorDiv, FloorDiv_v)
print LeftShift
print(LeftShift)
# print Modulo
print Mul
print(Mul)
# self.assertEqual(Pow, Pow_v)
print RightShift
print Sub
print Sum
print Sum1
print Sum2
print Sum3
print int(EQ)
print int(NE)
print int(LT)
print int(GT)
print int(LE)
print int(GE)
print int(BoolAnd)
print int(BoolOr)
print(RightShift)
print(Sub)
print(Sum)
print(Sum1)
print(Sum2)
print(Sum3)
print(int(EQ))
print(int(NE))
print(int(LT))
print(int(GT))
print(int(LE))
print(int(GE))
print(int(BoolAnd))
print(int(BoolOr))
return binops, stimulus, check
@ -255,9 +255,9 @@ def unaryBench( m):
yield arg
yield delay(1)
# print BoolNot
print Invert
print(Invert)
# print UnaryAdd
print UnarySub
print(UnarySub)
return unaryops, stimulus, check
@ -399,12 +399,12 @@ def augmBench( Ll, Ml, Lr, Mr):
## self.assertEqual(Bitor, Bitor_v)
## self.assertEqual(Bitxor, Bitxor_v)
## self.assertEqual(FloorDiv, FloorDiv_v)
print LeftShift
print(LeftShift)
## self.assertEqual(Modulo, Modulo_v)
print Mul
print RightShift
print Sub
print Sum
print(Mul)
print(RightShift)
print(Sub)
print(Sum)
return augmops, stimulus, check
@ -488,8 +488,8 @@ def expressionsBench():
while 1:
yield clk.posedge
yield delay(1)
print int(a)
print int(b)
print(int(a))
print(int(b))
@instance
def clkgen():

View File

@ -1,4 +0,0 @@
from __future__ import absolute_import
from myhdl.conversion import verify, analyze
verify.simulator = analyze.simulator = "vcom"

View File

@ -6,10 +6,10 @@ from random import randrange
from myhdl import *
from test_bin2gray import bin2gray
from test_inc import inc
from .test_bin2gray import bin2gray
from .test_inc import inc
from util import setupCosimulation
from .util import setupCosimulation
ACTIVE_LOW, INACTIVE_HIGH = 0, 1

View File

@ -48,20 +48,6 @@ class TestNotSupported(unittest.TestCase):
return logic
self.check(g, z, a)
def testBackquote(self):
a = Signal(bool())
z = Signal(bool())
def g(z, a):
@instance
def logic():
while 1:
yield a
z.next = 1
`a`
return logic
self.check(g, z, a)
def testClass(self):
a = Signal(bool())
z = Signal(bool())
@ -102,19 +88,6 @@ class TestNotSupported(unittest.TestCase):
return logic
self.check(g, z, a)
def testExec(self):
a = Signal(bool())
z = Signal(bool())
def g(z, a):
@instance
def logic():
while 1:
yield a
z.next = 1
exec "1 + 2" in globals , locals
return logic
self.check(g, z, a)
def testFrom(self):
a = Signal(bool())
z = Signal(bool())

View File

@ -10,7 +10,7 @@ import time
from myhdl import *
from util import setupCosimulation
from .util import setupCosimulation
N = 8
M = 2 ** N
@ -25,7 +25,7 @@ def XorGate(z, a, b, c):
return logic
def randOthers(i, n):
l = range(n)
l = list(range(n))
l.remove(i)
random.shuffle(l)
return l[0], l[1]

View File

@ -32,7 +32,7 @@ from unittest import TestCase
from myhdl import *
from util import setupCosimulation
from .util import setupCosimulation
QUIET = 1

View File

@ -9,7 +9,7 @@ random.seed(2)
from myhdl import *
from util import setupCosimulation
from .util import setupCosimulation
ACTIVE_LOW, INACTIVE_HIGH = 0, 1

View File

@ -6,7 +6,7 @@ from unittest import TestCase
from myhdl import *
from util import setupCosimulation
from .util import setupCosimulation
def bin2gray2(B, G, width):
""" Gray encoder.

View File

@ -1,7 +1,7 @@
from __future__ import absolute_import
from myhdl import *
from util import verilogCompile
from .util import verilogCompile
#############################
# bug report (Tom Dillon)
@ -88,7 +88,7 @@ test()
# case variable name in embedded FSM
####################################
from test_fsm import FramerCtrl
from .test_fsm import FramerCtrl
def mid(SOF, clk, reset_n):
t_State = enum('SEARCH', 'CONFIRM', 'SYNC')

View File

@ -9,7 +9,7 @@ random.seed(2)
from myhdl import *
from util import setupCosimulation
from .util import setupCosimulation
from myhdl import ConversionError
from myhdl.conversion._misc import _error

View File

@ -9,7 +9,7 @@ random.seed(2)
from myhdl import *
from util import setupCosimulation
from .util import setupCosimulation
ACTIVE_LOW, INACTIVE_HIGH = 0, 1

View File

@ -9,7 +9,7 @@ random.seed(2)
from myhdl import *
from util import setupCosimulation
from .util import setupCosimulation
ACTIVE_LOW, INACTIVE_HIGH = 0, 1

View File

@ -1,4 +1,5 @@
from __future__ import absolute_import
from __future__ import print_function
import os
path = os.path
import unittest
@ -154,7 +155,8 @@ def recursion2(count, enable, clock, reset, n):
return logic
def h1(n):
return None
pass
# return None
def functionNoReturnVal(count, enable, clock, reset, n):
@instance
@ -187,34 +189,6 @@ def taskReturnVal(count, enable, clock, reset, n):
return logic
def printnlToFile(count, enable, clock, reset, n):
@instance
def logic():
cnt = intbv(0)[8:]
while 1:
yield clock.posedge, reset.negedge
if reset == ACTIVE_LOW:
count.next = 0
else:
if enable:
print >> f, count
count.next = count + 1
return logic
def printToFile(count, enable, clock, reset, n):
@instance
def logic():
cnt = intbv(0)[8:]
while 1:
yield clock.posedge, reset.negedge
if reset == ACTIVE_LOW:
count.next = 0
else:
if enable:
print >> f, count,
count.next = count + 1
return logic
def listComp1(count, enable, clock, reset, n):
@instance
def logic():
@ -451,22 +425,6 @@ class TestErr(TestCase):
else:
self.fail()
def testPrintnlToFile(self):
try:
self.bench(printnlToFile)
except ConversionError as e:
self.assertEqual(e.kind, _error.NotSupported)
else:
self.fail()
def testPrintToFile(self):
try:
self.bench(printToFile)
except ConversionError as e:
self.assertEqual(e.kind, _error.NotSupported)
else:
self.fail()
def testListComp1(self):
try:
self.bench(listComp1)
@ -556,4 +514,3 @@ if __name__ == '__main__':

View File

@ -6,7 +6,7 @@ from unittest import TestCase
from myhdl import *
from util import setupCosimulation
from .util import setupCosimulation
# SEARCH, CONFIRM, SYNC = range(3)
ACTIVE_LOW = 0

View File

@ -6,7 +6,7 @@ from random import randrange
from myhdl import *
from util import setupCosimulation
from .util import setupCosimulation
COSET = 0x55
@ -128,9 +128,9 @@ def HecCalculator_v(name, hec, header):
headers = [ 0x00000000L,
0x01234567L,
0xbac6f4caL
headers = [ 0x00000000,
0x01234567,
0xbac6f4ca
]
headers.extend([randrange(2**32-1) for i in range(10)])

View File

@ -9,7 +9,7 @@ random.seed(2)
from myhdl import *
from util import setupCosimulation
from .util import setupCosimulation
ACTIVE_LOW, INACTIVE_HIGH = 0, 1

View File

@ -9,7 +9,7 @@ random.seed(2)
from myhdl import *
from util import setupCosimulation
from .util import setupCosimulation
ACTIVE_LOW, INACTIVE_HIGH = 0, 1

View File

@ -8,7 +8,7 @@ from myhdl import *
from myhdl import ConversionError
from myhdl.conversion._misc import _error
from util import setupCosimulation
from .util import setupCosimulation
b = c = 2

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