Giter Club home page Giter Club logo

myhdl's Introduction

MyHDL 0.11

Documentation Status Documentation Status

Join the chat at https://gitter.im/myhdl/myhdl

Visit MyHDL at Discourse


What is MyHDL?

MyHDL is a free, open-source package for using Python as a hardware description and verification language.

To find out whether MyHDL can be useful to you, please read:

License

MyHDL is available under the LGPL license. See LICENSE.txt.

Website

The project website is located at http://www.myhdl.org

Documentation

The manual is available on-line:

What's new

To find out what's new in this release, please read:

Installation

It is recommended to install MyHDL (and your project's other dependencies) in a virtualenv.

Installing the latest stable release:

pip install myhdl

Unfortunately the version on PyPI is quite behind the current development status, so you are better off installing the stable master branch directly from this GitHub repository:

pip install git+https://github.com/myhdl/myhdl.git@master

To install a local clone of the repository:

pip install -e path/to/dir

To install a specific commit hash, tag or branch from git:

pip install git+https://github.com/myhdl/myhdl@f696b8

You can test the proper installation as follows:

cd myhdl/test/core
py.test

To install co-simulation support:

Go to the directory cosimulation/<platform> for your target platform and following the instructions in the README.txt file.

myhdl's People

Contributors

alexforencich avatar arcanenibble avatar atharvaw avatar cfelton avatar clade avatar dargor0 avatar davekeeshan avatar dsp77 avatar gcc42 avatar gitter-badger avatar hgomersall avatar hugovk avatar iamsrinivas avatar jandecaluwe avatar javvalverde avatar jck avatar jdavidberger avatar jmgc avatar josyb avatar mrcanadianmenace avatar nicopy avatar nturley avatar rafaelcorsi avatar richmorj avatar rubund avatar srivatsan-ramesh avatar thomashornschuh avatar tobygomersall avatar udara28 avatar vikram9866 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

myhdl's Issues

Python 2 <-> 3 difference: Signal in multiple list is not supported

The code in https://gist.github.com/ThorimMB/00a3a5e51d97ea980015 raises a "Signal in multiple lists" conversion error on Python 3. It converts perfectly with Python 2.7 and compiles in Quartus:

File "bitonic.py", line 151, in convert: toVHDL(array8sorter, *sigs)
File "myhdl/conversion/_toVHDL.py", line 170, in call: siglist, memlist = _analyzeSigs(h.hierarchy, hdl='VHDL')
File "myhdl/myhdl/conversion/_analyze.py", line 128, in _analyzeSigs: raise ConversionError(_error.SignalInMultipleLists, s._name)
myhdl.ConversionError: Signal in multiple list is not supported: sort_merge_hi_merge_list_a(0)

I think it is not good if some parts of code only convert in a special Python version ;)

test_numass fails for VHDL on python3

--- env/py27-dev-upstream/tmp/NumassBench.vhd   2015-07-25 09:34:51.443378663 -0400
+++ env/py34-dev-upstream/tmp/NumassBench.vhd   2015-07-25 09:34:52.500068840 -0400
@@ -1,6 +1,6 @@
 -- File: NumassBench.vhd
 -- Generated by MyHDL 1.0dev
--- Date: Sat Jul 25 09:34:51 2015
+-- Date: Sat Jul 25 09:34:52 2015
@@ -62,8 +62,8 @@
     writeline(output, L);
     p <= to_unsigned(2, 8);
     q <= to_unsigned(2, 40);
-    r <= to_signed(-2, 9);
-    s <= to_signed(-2, 41);
+    r <= to_signed((-2), 9);
+    s <= to_signed((-2), 41);
     wait for 10 * 1 ns;
     write(L, to_integer(p));
     write(L, string'(" "));
@@ -76,7 +76,7 @@
     p <= to_unsigned(255, 8);
     q <= unsigned'("0011100101111000100101110011010111011101");
     r <= to_signed(255, 9);
-    s <= signed'("11100011010000111011010001100101000100011");
+    s <= to_signed((-246836311517), 41);
     wait for 10 * 1 ns;
     write(L, to_integer(p));
     write(L, string'(" "));
@@ -91,9 +91,9 @@
     write(L, to_integer(unsigned(s(20-1 downto 0))));
     writeline(output, L);
     p <= to_unsigned(254, 8);
-    q <= unsigned'("0110000110010100000101111111011100100101");
-    r <= to_signed(-256, 9);
-    s <= signed'("10110101110100100001001001101001001111011");
+    q <= unsigned'("1110111011010010111010000111100100001001");
+    r <= to_signed((-256), 9);
+    s <= signed'("11101001110111100011010101000101101110101");
     wait for 10 * 1 ns;
     write(L, to_integer(p));
     write(L, string'(" "));

The root cause of the problem:

-2.7.10 (default, May 26 2015, 04:16:29) 
+3.4.3 (default, Mar 25 2015, 17:13:50) 
 a=-10
-Module(body=[Assign(targets=[Name(id='a', ctx=Store())], value=Num(n=-10))])
+Module(body=[Assign(targets=[Name(id='a', ctx=Store())], value=UnaryOp(op=USub(), operand=Num(n=10)))])

[enhancement] Top-Level Conversion of Structured Types and a case for SystemVerilog (and VHDL-2008)

Top-Level Conversion of Structured Types

and a case for SystemVerilog (and VHDL-2008)

Preface

Hoegaarden, August 22st, 2015.
I decided to write this proposition/text after a good night's sleep over an IRC discussion I had with Christopher Felton, @cfelton, our number one MyHDL advocate, chatting about Arrays and Conversion of ListOfSignals arguments to the Top-Level module. And the best thing to organise ideas is to put them on paper and disseminate them!.
This enhancement certainly has a low priority, as most of us are tied up with other MyHDL improvements.
But your comments are welcome!

Introduction

Currently MyHDL does not support conversion of a List of Signals on the Top Level of the design. There is the solution for the Interface object ( AKA record in VHDL and struct in SystemVerilog) that enumerates the members and declares a port for each member. Which is fine as long as that member isn't a structured type itself ...

The actual limitation is a consequence of maintaining (equal) conversion to Verilog which doesn't allow arrays in port declarations, and hasn't got support for structured types other than a multi-dimensional arrays.

MyHDL users very often use List Of Signals in their designs. While simulation of a Top-Level LoS in a module works perfectly, direct conversion is now impossible and the user has to write a top-level wrapper where the LoS is handed over to a lower level module. An example by @cfelton shows that the wrapper could be sometimes more work than the function.

As some of you are aware, I have been working on implementing multi-dimensional type in MyHDL (see my MyHDL branch m1D and my MEP112_ndarray branch - remarks and ideas are welcome!). And yes I had to write a wrapper every time to be able to inspect the conversion.
Now if we want to synthesise such a converted module, we'll need a wrapper anyway because (in the case of Quartus II) the Pin Planner (probably, I haven tried this yet) doesn't handle a structured type either. And quite often no physical FPGA device has enough pins, too!

VHDL

Now for VHDL the conversion of a (single-dimensional) LoS, multi-dimensional list, or the proposed Array type is rather easy. Basically all we have to do is to make the type declarations in a VHDL Package:

Library ieee;
    use ieee.std_logic_1164.all ;
    use IEEE.numeric_std.all;

Package ModuleName_TypeDefs_Pkg is
`
    type a8_s1 is array (0 to 8 - 1) of std_logic;
    type a3_s1 is array (0 to 3 - 1) of std_logic;
    type a1024_u10 is array (0 to 1024 - 1) of unsigned(9 downto 0);
    type a16_u10 is array (0 to 16 - 1) of unsigned(9 downto 0);

End ModuleName_TypeDefs_Pkg ;

We then include this Package before the entity

Library ieee;
    use ieee.std_logic_1164.all ;
    use IEEE.numeric_std.all;

    use work. ModuleName_TypeDefs_Pkg.all;


Entity ModuleName is
    port (
        ...

        ) ;
End Entity ;

    ....

The Package and the Entity reside in the same file (with obviously the Package before the Entity), which saves the user from separately having to specify the location of the package in the synthesis tool of choice.

Verilog

Using the New Verilog-2001 Standard - Sutherland HDL, Inc.

Verilog is problematic, as it doesn't allow structured types in port declarations. Period.
Also Vendor support for multi-dimensional arrays is not clear to me.
Which makes the case for ...

SystemVerilog

SystemVerilog is already quite some time in the making and is currently well supported by the FPGA Vendors, maybe even better than VHDL-2008.
It has full support for structured types.
Support for multi-dimensional arrays is quite simple, as in contrast with VHDL, we don't need an extra package as we simply enumerate the dimensions in the port declaration.

Here are some links to support why we should extend the toVerilog() conversion to SystemVerilog.

Synthesizing SystemVerilog - Sutherland HDL, Inc.

Is SystemVerilog Useful for FPGA Design? - Sutherland HDL, Inc.

Observations

Conversion of Top-Level Structured Types is a requirement / prerequisite / part of MEP-110: Keep hierarchy in conversion

Converting List of Interfaces needs an in-depth study how this would interact with the current implementation of Interfaces.

I haven't addressed Cosimulation or Simulation of the converted code in the standard simulators (iverilog, GHDL, ModelSim, Active-HDL, ...). Basically because I trust the MyHDL simulator and secondly because the free commercial Simulators supplied by the FPGA vendors fully support VHDL and SystemVerilog (beyond what the Vendors synthesise).

A Personal Note

I strongly believe that a high quality conversion is a necessity to further the adoption of MyHDL. Every V* user will judge on the result of the conversion. The better, dare I say more beautiful, it is, the faster she/he will be convinced. Extending the convertible set of Python constructs is a key element in this.

conversion error when tristate signal is not read in the module.

Below is a modified version of a tristate signal example from https://gist.github.com/cfelton/6119313/download#

from myhdl import *

def top(sda, scl, sda_i, sda_o, scl_i, scl_o):
     """Simple I2C bi-dir converter.
     This example will break the I2C bi-directional signals into
     uni-dir explicit signals.
     """
     sda_d = sda.driver()
     scl_d = scl.driver()

     @always_comb
     def hdl():
         #sda_i.next = sda
         sda_d.next = False if not sda_o else None

         scl_i.next = scl
         scl_d.next = False if not scl_o else None

     return hdl


def convert():
     clk = Signal(False)
     rst = Signal(False)
     sda = TristateSignal(True)
     scl = TristateSignal(True)
     sda_i = Signal(False)
     sda_o = Signal(False)
     scl_i = Signal(False)
     scl_o = Signal(False)

     toVerilog(top, sda, scl, sda_i, sda_o, scl_i, scl_o)
     toVHDL(top, sda, scl, sda_i, sda_o, scl_i, scl_o)

if __name__ == '__main__':
     convert()

If I comment the line sda_i.next = sda, the conversion result becomes incorrect.
The sda port is reported as not used, and mistakenly converted to input port.
The assignment statement for sda is also missing.

module top (
    sda,
    scl,
    sda_i,
    sda_o,
    scl_i,
    scl_o
);
// Simple I2C bi-dir converter.
// This example will break the I2C bi-directional signals into
// uni-dir explicit signals.

input sda;
output scl;
wire scl;
input sda_i;
input sda_o;
output scl_i;
wire scl_i;
input scl_o;

wire scl_d;
wire sda_d;

assign scl = scl_d;

assign sda_d = (!sda_o) ? 1'b0 : 'bz;
assign scl_i = scl;
assign scl_d = (!scl_o) ? 1'b0 : 'bz;

endmodule

The test case "general/test_ShadowSignal.py" does not capture this problem because there is not port in that testbench.

[RFC] Use extended/escaped identifiers naming attribute references?

We're currently replacing periods with underscores and performing rudimentary collision detection. However, I don't think this technique is very robust and wont scale well when we start to support crazier things (like dicts).

I think we should use escaped identifiers for verilog[1] and extended identifiers for VHDL[2] to simplify the conversion logic.

It would also prevent bugs like #33 in the future.

[1] http://verilog.renerta.com/source/vrg00018.htm
[2] http://www.seas.upenn.edu/~ese171/vhdl/vhdl_primer.html#_Toc526061347

Co-simulation does not handle signal value type properly

Symptom

If a signal has boolean initial value, and during co-simulation, external simulator sets its value to 'X', the simulation fails with

ERROR: testCoSimStatic (__main__.TestTop)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "testbench.py", line 185, in testCoSimStatic
    sim.run()
  File "/home/hash/src/HISEE_Test/myhdl/venv/local/lib/python2.7/site-packages/myhdl/_Simulation.py", line 126, in run
    _extend(s._update())
  File "/home/hash/src/HISEE_Test/myhdl/venv/local/lib/python2.7/site-packages/myhdl/_Signal.py", line 191, in _update
    self._val._val = next._val
AttributeError: 'int' object has no attribute '_val'

----------------------------------------------------------------------

Root cause:

In Cosimulation._get(), _Cosimulation.py:134, we have

            s, v = self._toSigDict[e[i]], e[i+1]
            try:
                next = int(v, 16)
                if s._nrbits and s._min is not None and s._min < 0:
                    if next >= (1 << (s._nrbits-1)):
                        next |= (-1 << s._nrbits)
            except ValueError:
                next = intbv(0)
            s.next = next

If external simulator returns anything that does not converts to integer, intbv(0) is assigned to s.next.

In _Signal._update(), we have

            if next is None:
                self._val = None
            elif isinstance(val, intbv):
                self._val._val = next._val
            elif isinstance(val, (int, long, EnumItemType)):
                self._val = next
            else:
                self._val = deepcopy(next)

Since the signal has boolean initial value, the else clause is picked, and the type of self._val changed from bool to intbv.

Some time later, when the external simulator returns a valid integer value, Cosimulation._get() assigns next the integer. Now we encounter the problem in _Signal._update(): we enter the intbv clause, but next is an integer instead of intbv.

Possible fix:

I added the following clause before the intbv clause in _Signal._update().

            elif isinstance(val, bool):
                self._val = bool(next)
            elif isinstance(val, intbv):
                self._val._val = next._val

It worked for me. However, we can also fix it in Cosimulation._get().

The type handling in Signal assignment is a bit confusing, I'm not sure if this fix is correct.

Clarifications on ConcatSignal()

The reference says:

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 leaves room for interpretation. E.g. if we want to concatenate a series of Signal(intbv(0)[WIDTH:]) this works fine. But if we try this for elements like Signal(intbv(0, min = -2WIDTH, max = 2WIDTH)) the simulation goes wrong as soon as we have negative values.
If we look at the _init function:

class ConcatSignal(_ShadowSignal):

    __slots__ = ('_args',)

    def __init__(self, *args):
        assert len(args) >= 2
        self._args = args
        ### XXX error checks
        nrbits = 0
        for a in args:
            nrbits += len(a)
        ini = intbv(0)[nrbits:]
        hi = nrbits
        for a in args:
            lo = hi - len(a)
            ini[hi:lo] = a
            hi = lo
        _ShadowSignal.__init__(self, ini)
        gen = self.genfunc()
        self._waiter = _SignalTupleWaiter(gen)

The line ini = intbv(0)[nrbits:] is declaring an (unsigned) intbv having the width of the sum of the bits in the elements Later the line ini[hi:lo] = a assigns the values of the elements to a corresponding slice of this intbv. If there are elements with a negative value we get an exception:

  File "C:\qdesigns\MyHDL\Source\misc\ev2.py", line 123, in stimulus
    yc = ConcatSignal( *reversed(aa) )
  File "C:\Python27\lib\site-packages\myhdl\_ShadowSignal.py", line 146, in __init__
    ini[hi:lo] = a 
  File "C:\Python27\lib\site-packages\myhdl\_intbv.py", line 185, in __setitem__
    self._handleBounds()
  File "C:\Python27\lib\site-packages\myhdl\_intbv.py", line 85, in _handleBounds
    (self._val, self._min))
ValueError: intbv value -543822107497910413242085675106304 < minimum 0

A fix could be:

            ini[hi:lo] = a if a >= 0 else 2**len(a) + a #! a is negative in the else case

This would present the 2's complement representation of the negative value in the desired bit-width.

Using parameters for delays doesn't work with simulator vsim

I'm new at myhdl so most probably I'm doing something wrong but from the rs232_tx example I think what I'm trying should be possible.

I have defined a constant with an integer value. Then, I use this constant for the delay function.

HALF_PERIOD = 5

@instance
def clockGen():
    yield delay(HALF_PERIOD)
    ...

Everything seems to work fine with the testbench in python, but when I try to test the vhdl, using the vcom simulator (documentation says vsim but in mine _verify module it's defined as vcom) I get the following error:

** Error: testResetValues.vhd(53): near "ns": expecting ';'

The reasons is that the resulting vhdl has the following code:

constant HALF_PERIOD: integer := 5;
...
    wait for HALF_PERIOD ns;

As far as I known this is not supported for vhdl. Either the constant should be of type time instead of integer and the time unit inserted at the definition or the value should be directly replaced after the wait for.

Extraneous copies of top-level signals in lower-level blocks in vcd-file

The .vcd ouput of the simulation of the module described in issue #12 shows the effect:
e.g. the signals in bold for module ao2 are superfluous
$scope module test_sim_intbv_width_1 $end
$var reg 2 ! A $end
$var reg 1 " Reset $end
$var reg 32 # WD $end
$var reg 32 $ RQ $end
$var reg 1 % Clk $end
$var reg 2 & TestVector $end
$var reg 1 ' Rd $end
$var reg 1 ( TestBit $end
$var reg 1 ) Wr $end
$var reg 32 * ClkCount $end
$scope module hw_inst $end
$var reg 2 ! A $end
$var reg 1 " Reset $end
$var reg 32 # WD $end
$var reg 32 $ RQ $end
$var reg 1 % Clk $end
$var reg 2 & TestVector $end
$var reg 1 + lq1 $end
$var reg 2 , lq2 $end
$var reg 1 ' Rd $end
$var reg 1 ( TestBit $end
$var reg 1 ) Wr $end
$var reg 3 - rbd $end
$scope module ao2 $end
$var reg 2 ! A $end
$var reg 1 " Reset $end
$var reg 32 # WD $end
$var reg 32 $ RQ $end
$var reg 1 % Clk $end
$var reg 2 & TestVector $end
$var reg 1 ' Rd $end
$var reg 1 ( TestBit $end
$var reg 2 & Q $end
$var reg 1 ) Wr $end
$var reg 2 , D $end
$upscope $end
$scope module ao1 $end
$var reg 2 ! A $end
$var reg 1 " Reset $end
$var reg 32 # WD $end
$var reg 32 $ RQ $end
$var reg 1 % Clk $end
$var reg 2 & TestVector $end
$var reg 1 ' Rd $end
$var reg 1 ( TestBit $end
$var reg 1 ( Q $end
$var reg 1 ) Wr $end
$var reg 1 + D $end
$upscope $end
$scope module reg2 $end
$var reg 2 ! A $end
$var reg 1 " Reset $end
$var reg 32 # WD $end
$var reg 32 $ RQ $end
$var reg 1 % Clk $end
$var reg 2 & TestVector $end
$var reg 1 ' Rd $end
$var reg 1 ( TestBit $end
$var reg 2 , Q $end
$var reg 1 ) Wr $end
$upscope $end
$scope module reg1 $end
$var reg 2 ! A $end
$var reg 1 " Reset $end
$var reg 32 # WD $end
$var reg 32 $ RQ $end
$var reg 1 % Clk $end
$var reg 2 & TestVector $end
$var reg 1 ' Rd $end
$var reg 1 ( TestBit $end
$var reg 1 + Q $end
$var reg 1 ) Wr $end
$upscope $end
$upscope $end
$upscope $end

where as the correct set is:
```text
$scope module test_sim_intbv_width_1 $end
$var reg 2 ! A $end
$var reg 1 " Reset $end
$var reg 32 # WD $end
$var reg 32 $ RQ $end
$var reg 1 % Clk $end
$var reg 2 & TestVector $end
$var reg 1 ' Rd $end
$var reg 1 ( TestBit $end
$var reg 1 ) Wr $end
$var reg 32 * ClkCount $end
$scope module hw_inst $end
$var reg 2 ! A $end
$var reg 1 " Reset $end
$var reg 32 # WD $end
$var reg 32 $ RQ $end
$var reg 1 % Clk $end
$var reg 2 & TestVector $end
$var reg 1 + lq1 $end
$var reg 2 , lq2 $end
$var reg 1 ' Rd $end
$var reg 1 ( TestBit $end
$var reg 1 ) Wr $end
$var reg 3 - rbd $end
$scope module ao2 $end
$var reg 2 & Q $end
$var reg 2 , D $end
$upscope $end
$scope module ao1 $end
$var reg 1 ( Q $end
$var reg 1 + D $end
$upscope $end
$scope module reg2 $end
$var reg 2 ! A $end
$var reg 1 " Reset $end
$var reg 32 # WD $end
$var reg 1 % Clk $end
$var reg 2 , Q $end
$var reg 1 ) Wr $end
$upscope $end
$scope module reg1 $end
$var reg 2 ! A $end
$var reg 1 " Reset $end
$var reg 32 # WD $end
$var reg 1 % Clk $end
$var reg 1 + Q $end
$var reg 1 ) Wr $end
$upscope $end
$upscope $end
$upscope $end

shadow-of-shadows and user defined code conversion

A possible error was reported on the mailing-list where a shadow-of-shadow was used and passed to user defined code. The following is the example provided:

import myhdl
print(myhdl.__version__)
from myhdl import *

def add_example(CLK, IN_1, IN_2, SUM_OUT):

     SUM_OUT.driven = 'reg'
     IN_1.read = True
     IN_2.read = True

     in1_part = IN_1(10,0)
     in2_part = IN_2(10,0)

     part_of_in1_part = in1_part(5,2)
     part_of_in2_part = in2_part(5,2)

     #This always block isn't exactly like the verilog code.
     @always(CLK.posedge)
     def adding():
         SUM_OUT.next = IN_1 + IN_2

     return adding

add_example.verilog_code = \
"""
 always @(posedge $CLK) begin:
     $SUM_OUT[11-1:0] <= $in1_part + $in2_part;
     $SUM_OUT[32:28] <= $part_of_in1_part + $part_of_in2_part
 end
 """

clk = Signal(bool(0))
in1 = Signal(intbv(0)[32:])
in2 = Signal(intbv(0)[32:])
sum_out = Signal(intbv(0)[32:])
toVerilog(add_example, clk, in1, in2, sum_out)

https://gist.github.com/cfelton/7bb0cbd1657f5c49d2f2

The above example converts unexpectedly:

 always @(posedge CLK) begin:
     SUM_OUT[11-1:0] <= in1[10-1:0] + in2[10-1:0];
     SUM_OUT[32:28] <= 0 + 0
 end

Missing signal in generated VHDL

MyHDL code below:

#!/usr/bin/env python
from myhdl import *

MAX = 16

def myhdl_b1(i, o):

  c = intbv(4,min=0,max=MAX)

  @always_comb
  def rtl():
    o.next = i + c

  return rtl

i, o = [Signal(modbv(min=0,max=MAX)) for i in range(2)]

toVHDL(myhdl_b1, i, o)

I expected this to get compiled into a VHDL module where c is declared between the component declaration and architecture section. However, what ends up happening is c is never declared.

See here for VHDL output:

-- File: myhdl_b1.vhd
-- Generated by MyHDL 0.9dev
-- Date: Fri Feb 13 13:15:38 2015


library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
use std.textio.all;

use work.pck_myhdl_09.all;

entity myhdl_b1 is
    port (
        i: in unsigned(3 downto 0);
        o: out unsigned(3 downto 0)
    );
end entity myhdl_b1;


architecture MyHDL of myhdl_b1 is






begin





o <= (i + c);

end architecture MyHDL;

The workarounds for this seem to be either declaring constants as integers, in which case they get used as literals in the generated VHDL, or declaring them as signals and assigning them values in a generator. It might be workable for the former to be the only supported way of doing it, but toVHDL should to throw an error rather than compiling broken VHDL.

toVHDL.numeric_ports

toVHDL() has an undocumented experimental feature to disable numeric_ports (signed, unsigned).

This was an experimental hack that I needed in a project. It was never documented because it was never thoroughly tested and finished. I am not even sure it is a good idea.

However, people started using it, see issues #14 and #15. With git and hidden local branches, I will keep such "features" for myself from now on :-)

Is anyone interested in investigating/fixing this? I have zero time to do so myself.

Creation of constants during conversion.

This is intended to be a feature enhancement request (MEP lite).

A common issue experienced by many new MyHDL users is how constants are converted. More commonly than not, these constants are contained in a structure and managed in elaboration code versus literals used directly in the MyHDL generators.

The below is a variation of an example that was presented on the mailing-list:

The user was expecting (hoping) that coef[0] would be replaced with the constant value contained in coef[0]. Since the coef is constant at conversion and the index is constant it is reasonable that coef[constant_index] be replaced in the converted code with a literal.

Although the below example is a toy example it is a common design pattern, where the Python structures are used to manage constants, variables, and signals. There are alternative methods
to achieve the desired effect:

  • locally reference the constants outside of the MyHDL generators.
  • internally reference with a variable (this will generate an embedded case which the synthesizer will optimize away).

In addition, initial value support might also provide a solution but the direct replacement seems ideal. The enhancement request is intended to only address the tuple(int) or tuple(intbv) with a constant index.

code example gist

from __future__ import print_function

from random import randint
from myhdl import *

def m_top_const(clock, reset, x, y, a, b, N=10):
    # a tuple of constant ints
    coef = tuple([(randint(-19,23), randint(0,127),) 
                 for _ in range(N)])

    v = [Signal(x.val) for _ in range(N-1)]
    glist = [None for _ in range(N)]

    # create multiple instances
    glist[0] = m_constants(clock, reset, x, a, b, coef[0])
    for ii in range(1,N):
        # append the constant module to the list of generators
        glist[ii] = m_constants(clock, reset, v[ii-1], a, b, coef[ii])

    # combine all the outputs into one output
    @always_seq(clock.posedge, reset=reset)
    def rtl():
        psum = 0          # sorta declaring the variable
        psum = psum + x   # initial value of the variable
        for ii in range(1,N):
            psum = psum + v[ii-1]
        y.next = psum

    # attach for whitebox testing
    m_top_const.coef = coef

    return glist, rtl


def m_constants(clock, reset, x, a, b, coef):
    # use fixed indexes from the coef
    @always_seq(clock.posedge, reset=reset)
    def rtl():
        x.next = a*coef[0] + b*coef[1]

    return rtl


def test_constant():
    clock = Signal(bool(0))
    reset = ResetSignal(0, active=0, async=True)
    x = Signal(intbv(0, min=-233, max=544))
    y = Signal(intbv(0, min=-2*18, max=1111*13))
    a = Signal(intbv(0, min=-19, max=17))
    b = Signal(intbv(0, min=-3, max=37))

    # a test function
    def _test():
        # instantiate the design under test
        tbdut = m_top_const(clock, reset, x, y, a, b)
        coef = m_top_const.coef

        @always(delay(3))
        def tbclk():
            clock.next = not clock

        @instance
        def tbstim():
            reset.next = reset.active
            yield delay(33)
            reset.next = not reset.active

            yield clock.posedge
            yield clock.posedge

            psum = 0
            for vals in coef:
                psum = psum + (a*vals[0] + b*vals[1]) 

            assert psum == y

            raise StopSimulation

        return tbdut, tbclk, tbstim


    Simulation(_test()).run()
    print("** Simulation Successfull **")
    toVHDL(m_top_const, clock, reset, x, y, a, b)
    toVerilog(m_top_const, clock, reset, x, y, a, b)


if __name__ == '__main__':
    test_constant()

Cosimulation error with python 3.2

MyHDL does not seem to like running with Python 3 earlier than 3.4:

        # 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)
E               AttributeError: 'module' object has no attribute 'set_inheritable'

/usr/local/lib/python3.2/dist-packages/myhdl/_Cosimulation.py:61: AttributeError

Undefined behaviour in test_Signal.py (sorting a list of objects)

In test_Signals.py, waiters and expected are a list of objects. These lists are sorted even though object() does not have cmp defined and are sorted. Due to an implementation detail in python 2, these lists are sorted by memory address[1,2]. These lists cannot be sorted in python 3.

Here is one possible solution (setting sort key as id()) :
jmgc@82a64b9#diff-e87341a754720c5ac5aacd8b55997ebaR198

Is there a better way to solve this?

[1] http://stackoverflow.com/questions/6252758/python-default-comparison
[2] http://stackoverflow.com/questions/4266918/why-is-int50str5-in-python-2-x

[enhancement] Conversion detect ShadowSignals usage in generators

During conversion detect when a ShadowSignal is attempting to be used inside a MyHDL generator (the generator being converted). For new users this can be a source of confusion because there are to methods to access bits (sig[], sig()). The ShadowSignal access (sig()) is only valid outside a
generator (elaboration). The use of ShadowSignal will simulate fine, making it difficult to debug the problem.

[1.0 feature] Fixed point

Task Fixed point type support

Description A proposal for this is in http://dev.myhdl.org/meps/mep-111.html, and there is also a reference implementation. What is not clear to me is how much of the resizing/alignment is automated. I think it is mandatory to automate as much as possible. To be discussed with @cfelton.

Complexity estimation Guru level + @cfelton + @jandecaluwe involvement. We have to carefully decide on and implement the type hierarchy, resizing & alignment issues, conversion support.

Guidelines http://dev.myhdl.org/guide.html

Slices and toVHDL(), possibly toVerilog() too

I had one more error in my conversion of a MyHDL module. I wrote a small test-module to isolate it, and found a work-around, but the same issue also appeared in another place.
This code:

'''
Created on 10 Mar 2015

@author: Josy
'''

import os, random
from myhdl import *

class record(object):
    ''' an interface is kind of a VHDL-record
        and
        a record by any other name will work as sweet ...
    '''
    def __init__(self, WIDTH_A , WIDTH_B, a = 0, b = 0):
        self.WIDTH_A = WIDTH_A
        self.WIDTH_B = WIDTH_B
        self.a = Signal(intbv(a)[WIDTH_A:])
        self.b = Signal(intbv(b)[WIDTH_B:])

    def torecord(self, v):
        ''' split a vector into record-elements'''
        # need an unique name as 'alias' otherwise the 'self.WIDTH_FPN' shows up as a constant in the VHDL :)
        trWIDTH_A = self.WIDTH_A
        if USE_LOCAL_VARIABLE_TO_CANONIZE_SLICED_VECTORS:
            @always_comb
            def tr():
                # need to assign the input vector to a variable to avoid
                # the VHDL conversion indexing a sliced vector like this
                # a <= b(15 downto 8)(3 downto 0)
                # which is an error
                # the variable has a right index of 0
                lv = v
                # now can slice this 'canonical form' vector
                self.a.next = lv[trWIDTH_A:]
                self.b.next = lv[:trWIDTH_A]
        else:
            @always_comb
            def tr():
                self.a.next = v[trWIDTH_A:]
                self.b.next = v[:trWIDTH_A]

        return tr

    def tointbv(self, y):
        ''' build a flattened vector from the record's elements in ascending order'''
        # need an unique name as 'alias' otherwise the 'self.WIDTH_FPN' shows up as a constant in the VHDL :)
        tiWIDTH_A = self.WIDTH_A

        @always_comb
        def ti():
            y.next[tiWIDTH_A:] = self.a
            y.next[:tiWIDTH_A] = self.b

        return ti


def split(a, y1, y2):
    cr = [record(WIDTH_A,WIDTH_B) for _ in range(2)]

    # extract the records from the flattened vector
    ctr1 = record.torecord( cr[0], a( WIDTH_A + WIDTH_B, 0))
    ctr2 = record.torecord( cr[1], a(( WIDTH_A + WIDTH_B) *2, WIDTH_A + WIDTH_B))
    # for the sake of conversion, flatten each record to a vector
    cti1 =  record.tointbv(cr[0], y1)
    cti2 =  record.tointbv(cr[1], y2)

    return ctr1, ctr2, cti1, cti2


def tb_split():
    random.seed('C-Cam') # we want 'repeatable randomness' :)
    tda1 = [ random.randrange(2**WIDTH_A-1) for _ in range(20)]
    tda2 = [ random.randrange(2**WIDTH_A-1) for _ in range(20)]
    tdb1 = [ random.randrange(2**WIDTH_B-1) for _ in range(20)]
    tdb2 = [ random.randrange(2**WIDTH_B-1) for _ in range(20)]

    dut = split(a, y1, y2)

    @instance
    def stimulus():
        for i in range(len(tda1)):
            a.next[                    WIDTH_A :                             ] = tda1[i]
            a.next[          WIDTH_B + WIDTH_A :                      WIDTH_A] = tdb1[i]
            a.next[WIDTH_A + WIDTH_B + WIDTH_A :            WIDTH_B + WIDTH_A] = tda2[i]
            a.next[                            :  WIDTH_A + WIDTH_B + WIDTH_A] = tdb2[i]
            yield delay(10)
            if y1 !=  (tdb1[i] << WIDTH_A) + tda1[i] or y2 !=  (tdb2[i] << WIDTH_A) + tda2[i] :
                print "Failed {}: {} {}" .format( i , y1, y2 )
        raise StopSimulation

    return dut, stimulus

def convert():
    toVHDL( split, a, y1, y2)
    toVerilog( split, a, y1, y2)


if __name__ == '__main__':

    def simulate(timesteps, mainclass):
        """Runs simulation for MyHDL Class"""
        # Remove old vcd File, otherwise we get a list of renamed .vcd files lingering about
        filename = (mainclass.__name__ +".vcd")
        if os.access(filename,  os.F_OK):
            os.unlink(filename)

        # Run Simulation
        tb = traceSignals(mainclass)
        sim = Simulation(tb)
        sim.run(timesteps)



    USE_LOCAL_VARIABLE_TO_CANONIZE_SLICED_VECTORS = False

    WIDTH_A = 8
    WIDTH_B = 8

    # a flattened vector as input
    a = Signal( intbv()[(WIDTH_A + WIDTH_B) * 2 :])
    # ideally I wanted a list of 'records' but that will not convert, so let's use separate vectors
    y1 = Signal( intbv()[(WIDTH_A + WIDTH_B) :])
    y2 = Signal( intbv()[(WIDTH_A + WIDTH_B) :])

    simulate( 300 , tb_split)
    convert()

will convert into this:

-- File: split.vhd
-- Generated by MyHDL 0.9dev
-- Date: Tue Mar 10 11:40:06 2015


library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
use std.textio.all;

use work.pck_myhdl_09.all;

entity split is
    port(
        a  : in  unsigned(31 downto 0);
        y1 : out unsigned(15 downto 0);
        y2 : out unsigned(15 downto 0)
    );
end entity split;

architecture MyHDL of split is
    constant tiWIDTH_A : integer := 8;
    constant trWIDTH_A : integer := 8;

    signal cti2_self_b : unsigned(7 downto 0);
    signal cti2_self_a : unsigned(7 downto 0);
    signal cti1_self_b : unsigned(7 downto 0);
    signal cti1_self_a : unsigned(7 downto 0);

begin
    cti1_self_a <= a(16 - 1 downto 0)(trWIDTH_A - 1 downto 0);
    cti1_self_b <= a(16 - 1 downto 0)(16 - 1 downto trWIDTH_A);

    cti2_self_a <= a(32 - 1 downto 16)(trWIDTH_A - 1 downto 0);
    cti2_self_b <= a(32 - 1 downto 16)(16 - 1 downto trWIDTH_A);

    SPLIT_CTI1_TI : process(cti1_self_b, cti1_self_a) is
    begin
        y1(tiWIDTH_A - 1 downto 0)  <= cti1_self_a;
        y1(16 - 1 downto tiWIDTH_A) <= cti1_self_b;
    end process SPLIT_CTI1_TI;

    SPLIT_CTI2_TI : process(cti2_self_b, cti2_self_a) is
    begin
        y2(tiWIDTH_A - 1 downto 0)  <= cti2_self_a;
        y2(16 - 1 downto tiWIDTH_A) <= cti2_self_b;
    end process SPLIT_CTI2_TI;

end architecture MyHDL;

The lines:

    cti2_self_a <= a(32 - 1 downto 16)(trWIDTH_A - 1 downto 0);
    cti2_self_b <= a(32 - 1 downto 16)(16 - 1 downto trWIDTH_A);

are flagged with this error:

Multiple markers at this line
- Vcom: (vcom-1167) Index value 0 (of type ieee.NUMERIC_STD.UNSIGNED)
   is out of range 31 downto 16.
- Vcom: (vcom-1167) Index value 7 (of type ieee.NUMERIC_STD.UNSIGNED)
   is out of range 31 downto 16.

and in Verilog:

// File: split.v
// Generated by MyHDL 0.9dev
// Date: Tue Mar 10 11:40:07 2015


`timescale 1ns/10ps

module split (
    a,
    y1,
    y2
);

input [31:0] a;
output [15:0] y1;
reg [15:0] y1;
output [15:0] y2;
reg [15:0] y2;

wire [7:0] cti2_self_b;
wire [7:0] cti2_self_a;
wire [7:0] cti1_self_b;
wire [7:0] cti1_self_a;


assign cti1_self_a = a[16-1:0][8-1:0];
assign cti1_self_b = a[16-1:0][16-1:8];

assign cti2_self_a = a[32-1:16][8-1:0];
assign cti2_self_b = a[32-1:16][16-1:8];

always @(cti1_self_b, cti1_self_a) begin: SPLIT_CTI1_TI
    y1[8-1:0] = cti1_self_a;
    y1[16-1:8] = cti1_self_b;
end

always @(cti2_self_b, cti2_self_a) begin: SPLIT_CTI2_TI
    y2[8-1:0] = cti2_self_a;
    y2[16-1:8] = cti2_self_b;
end

endmodule

I hardly know Verilog, so I'm not sure whether this is an error:

assign cti2_self_a = a[32-1:16][8-1:0];
assign cti2_self_b = a[32-1:16][16-1:8];

If I set USE_LOCAL_VARIABLE_TO_CANONIZE_SLICED_VECTORS to True, I introduce a local variable and the converted code changes to:

    constant trWIDTH_A : integer := 8;
. . .
    SPLIT_CTR2_TR : process(a) is
        variable lv : unsigned(15 downto 0);
    begin
        lv          := a(32 - 1 downto 16);
        cti2_self_a <= lv(trWIDTH_A - 1 downto 0);
        cti2_self_b <= lv(16 - 1 downto trWIDTH_A);
    end process SPLIT_CTR2_TR;

and

always @(a[32-1:16]) begin: SPLIT_CTR2_TR
    reg [16-1:0] lv;
    lv = a[32-1:16];
    cti2_self_a = lv[8-1:0];
    cti2_self_b = lv[16-1:8];
end

The workaround of introducing a local variable to canonize the input, works but looks clumsy to me.
As the simulation has no problem, because Python canonizes slices, I feel that we should rework toVHDL (and possibly toVerilog) to address this.

[1.0 feature] Initial values

Task Enable initial values for signals and variables

Description It's time to enable initial value support, as by now all tools should support them and some synthesis tools make good use of them. Use no_initial_values as a parameter to toVHDL() and toVerilog() to disable/enable this. Default should be enabled.

Guideline This is best done in atomic well-defined subtasks. Start with a PR for the simplest case of non-composite VHDL signals & Verilog regs.

See also http://dev.myhdl.org/tasks/initial-values-support.html

Complexity estimation Medium

Guidelines http://dev.myhdl.org/guide.html

Usability of Interfaces

Yesterday I decided to try using an Interface.
I am currently experimenting with a StructType object to mimic the VHDL record / SystemVerilog struct, and wanted to get a feel for the 'how and what' of the Interface.
Some background: I use MyHDL to develop re-usable modules for use with Altera's Qsys. Qsys has two main interfaces, the Memory Mapped (MM) and the Streaming (ST) types. All of the modules have (at least) one input and (at least) one output ST-interface. So the ST was a good candidate for my first try.
I also have a utility to generate the necessary _hw.tcl file for Qsys to be able to recognise/parametrise the module. This utility also steers the conversion.
I added some code to generate the members for the ST-interfaces on demand.

I was kindly surprised, because it looked good. The ports were all there and had the correct names matching the advertised names in the corresponding _hw.tcl file.

So today I decided I thus had to upgrade all my existing modules to conform to my latest changes in the Qsys utility, not necessarily because of the interfaces but in anticipating using interfaces I had already changed some port naming rules.
The first module mentioned above was a rather simple one and only had one level of functions, better said the top function was the only RTL function.
Now when trying/ working on a larger module where the top function only collects the RTL from lower modules I find that the names are 'mangled'.
This MyHDL code

import myhdl

class fi( object ):
    ''' a simple interface '''
    def __init__(self):
        self.Data = myhdl.Signal( myhdl.intbv()[8:])
        self.Ready = myhdl.Signal( bool(0) )
        self.Valid = myhdl.Signal( bool(0) )


def mangler( Clk, Reset, D, Q):
    ''' a silly module to mangle the input data '''
    @myhdl.always_comb
    def mangler():
        Q.Data.next[:4] = D.Data[4:]
        Q.Data.next[4:] = D.Data[:4]
        Q.Valid.next = D.Valid
        D.Ready.next = Q.Ready


    return mangler


def topfi(Clk, Reset, D, Q):
    ''' the top level '''

    mnglr = mangler(Clk, Reset, D, Q)

    return mnglr


def convert():

    Clk = myhdl.Signal( bool(0) )
    Reset = myhdl.ResetSignal(0, active=1, async=True)
    D = fi()
    Q = fi()

    myhdl.toVHDL( topfi, Clk, Reset, D, Q)


if __name__ == '__main__':
    ''' '''
    convert()

produces the following VHDL:

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
use std.textio.all;

use work.pck_myhdl_10.all;

entity topfi is
    port(
        Clk           : in  std_logic;
        Reset         : in  std_logic;
        mnglr_Q_Ready : in  std_logic;
        mnglr_Q_Valid : out std_logic;
        mnglr_Q_Data  : out unsigned(7 downto 0);
        mnglr_D_Ready : out std_logic;
        mnglr_D_Valid : in  std_logic;
        mnglr_D_Data  : in  unsigned(7 downto 0)
    );
end entity topfi;
-- the top level 

architecture MyHDL of topfi is
begin
    TOPFI_MNGLR_MANGLER : process(mnglr_D_Valid, mnglr_D_Data, mnglr_Q_Ready) is
    begin
        mnglr_Q_Data(8 - 1 downto 4) <= mnglr_D_Data(4 - 1 downto 0);
        mnglr_Q_Data(4 - 1 downto 0) <= mnglr_D_Data(8 - 1 downto 4);
        mnglr_Q_Valid                <= mnglr_D_Valid;
        mnglr_D_Ready                <= mnglr_Q_Ready;
    end process TOPFI_MNGLR_MANGLER;

end architecture MyHDL;

where I expected / need this:

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
use std.textio.all;

use work.pck_myhdl_10.all;

entity topfi is
    port(
        Clk           : in  std_logic;
        Reset         : in  std_logic;
        Q_Ready : in  std_logic;
        Q_Valid : out std_logic;
        Q_Data  : out unsigned(7 downto 0);
        D_Ready : out std_logic;
        D_Valid : in  std_logic;
        D_Data  : in  unsigned(7 downto 0)
    );
end entity topfi;
-- the top level 

architecture MyHDL of topfi is
begin
    TOPFI_MNGLR_MANGLER : process(D_Valid, D_Data, Q_Ready) is
    begin
        Q_Data(8 - 1 downto 4) <= D_Data(4 - 1 downto 0);
        Q_Data(4 - 1 downto 0) <= D_Data(8 - 1 downto 4);
        Q_Valid                <= D_Valid;
        D_Ready                <= Q_Ready;
    end process TOPFI_MNGLR_MANGLER;

end architecture MyHDL;

I used the current 1.0-dev master branch to check this (not my experimental code).
Your thoughts?

Interface conversion broken in the master branch

I have a project that fails with the latest code on the master branch. According to git bisect the bug was introduced in 08519b4 rename attribute ref in the AST before analysis.

Warning: this issue simply describes an observed failure. Other than using git bisect to determine when the bug was introduced, no additional debugging as been completed or a standalone test case created. Also, the code linked above passes travis-ci because it clones a previous version of the master branch (i.e. before 08519b4, it clones 88cb76b).

[bug] Verilog conversion error when concatenating with a bool constant

The following example illustrates a Verilog conversion error when concatenating with a bool constant.

def concat_bug(clk, sdi, pdo):
    NOP_C = bool(0)
    delay_reg = Signal(intbv(0)[8:])
    @always(clk.posedge)
    def rtl():
        delay_reg.next = concat(NOP_C, delay_reg[6:1], sdi)
        pdo.next = delay_reg
    return rtl

clk, sdi = [Signal(bool(0)) for _ in range(2)]
pdo = Signal(intbv(0)[8:])
toVerilog(concat_bug, clk, sdi, pdo)

The bool is converted to an integer literal without a bitwidth and the verilog compilers error on the concatenation.

always @(posedge clk) begin: CONCAT_BUG_RTL
    delay_reg <= {0, delay_reg[6-1:1], sdi};
    pdo <= delay_reg;
end

A bit-width needs to be included with the bool conversion. This is not an issue with VHDL as the bool is converted to a string literal (bit-string) and a length is part of the literal. Verilog uses a default width of 32 for the 0 literal.

Make simulation instances standalone (or... multiple simulation instances).

An issue that keeps coming up in various guises, and is the root cause of this PR, is the problem of global state in simulation instances.

It has been suggested that it is desirable to have multiple simulation instances. Personally I am fairly agnostic on this specific issue, but the removal of global state would allow this.

This issue is to discuss the problem of global state in simulation and collect opinion.

toVHDL() doesn't assign a driver to a tristate output

I'm trying to drive the reset and halt lines on a m68k processor. These lines are bi-directional so I only want to have Z or 0 on my pin from the FPGA. I don't care about them if the m68k does ever drive them.

I thought something like this should work:

from myhdl import *

input = Signal(bool(False))
tsoutput = TristateSignal(bool(None))


def TristateTest(input, tsoutput):
    tsoutputdriver = tsoutput.driver()

    @always_comb
    def logic():
        if (input == False):
            tsoutputdriver.next = False
        else:
            tsoutputdriver.next = None

    return logic


tstest = toVHDL(TristateTest, input, tsoutput)

Input being a signal from a counter that generates the reset signals and tsoutput being either of the lines I want to drive.
The VHDL generated doesn't actually assign anything to the output though:

-- File: TristateTest.vhd
-- Generated by MyHDL 0.9.dev0
-- Date: Sun May 31 00:44:30 2015


library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
use std.textio.all;

use work.pck_myhdl_090.all;

entity TristateTest is
    port (
        input: in std_logic;
        tsoutput: out std_logic
    );
end entity TristateTest;


architecture MyHDL of TristateTest is





signal tsoutputdriver: std_logic;

begin





TRISTATETEST_LOGIC: process (input) is
begin
    if (input = '0') then
        tsoutputdriver <= '0';
    else
        tsoutputdriver <= 'Z';
    end if;
end process TRISTATETEST_LOGIC;

end architecture MyHDL;

If I set tsoutput.read to True the signal is assigned but then the port becomes inout which I don't really want.

[1.0 feature] Support for nonlocal variables

Task Support for nonlocal variables

Description To realize the vision behind MyHDL, support for the nonlocal variables is mandatory. It makes it possible to assign to variables within generators and still let those variables keep global state. In HDL terms, it enables register inferencing from variables - the ultimate semantic power in synthesizable modeling. One way to implement this would be to support the nonlocal declaration. Unfortunately, the nonlocal declaration is only available in Python 3K. Another way would be to access nonlocal variables using attribute access in generators. One advantage of the latter solution is that it can be supported in Python 2K also.

Complexity estimation Guru level for several reasons. One reason is that the best strategy is still to be investigated, another is the potential Python 3K dependency.

Guidelines http://dev.myhdl.org/guide.html

[1.0 feature] Better support of the ternary operator in VHDL

Task Support Python's ternary operator in a better way in VHDL.

Description Verilog has a direct equivalent for the ternary operator, but for VHDL it depends on the version and the context. As a consequence, current VHDL support is fragile and unverfiable with the current test infrastructure. In this task, investigate whether it is possible to support the ternary operator using a function, so that it works for all VHDL versions in all contexts. The idea would be to put an overloaded function in the pck_myhdl package, and used that to compile IfExp nodes.

Complexity estimation Medium

Guidelines http://dev.myhdl.org/guide.html

Constant values inside recursive functions do not work in VHDL conversion

Applies to MyHDL 0.9.
If a constant value is given as an argument that is then assigned to a signal in an enclosed process, conversion to VHDL will generate a VHDL constant for that variable. If this function is recursive, the same name should be bound to different values, but the generated VHDL code will use the same name with one single value for all generated processes.

Here's an MWE:

inp = Signal(intbv(0,0,2**8))
nz = Signal(False)
idx = Signal(intbv(0,0,8))

def toplevel(inp,nz,idx,n):
    if not n:
        @always_comb
        def p():
            nz.next = inp[0]
            idx.next = 0
        return p
    inz = Signal(False)
    iidx = Signal(intbv(0,0,n+1))
    ret = toplevel(inp,inz,iidx,n-1)
    @always_comb
    def p():
        if inp[n]:
            nz.next = True
            idx.next = n
        else:
            nz.next = inz
            idx.next = iidx
    return ret,p

toVHDL(toplevel,inp,nz,idx)

Here, n is the constant that has a different value on each recursive level.
Note that when idx.next = n is replaced by idx.next = n-1. then the name n will not be used, but replaced by it's value in the generated VHDL.

TristateSignal Conversion Error and Verilog missing inout

When TristateSignals are used as top-level ports the signal is not converted to an inout when the target is Verilog. This appears to work in VHDL but not in Verilog.

In addition PR #74 appeared to break code that use to convert. I used bisect to verify the revision where the code stopped converting f965132.

Failing code snip:

def top(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 = False if not sda_o else None 
         scl_i.next = scl
         scl_d.next = False if not scl_o else None
     return hdl

It is not clear (at this point) why the conversion is failing. The conversion for the code snip only fails for VHDL conversion.

[RFC] enhancement verilog testbench without cosim

Hello

Problem:
I target a design for FPGA. I have know a couple of verilog module, build on a bottom-up approach.
I face strange behaviour when running the application : sound synthesizer . And I was not able to find the issue with directed testbench. So I want convert my existing verilog code to myhdl.
This will allow me drive the dut with more realistic case. To solve timing issue I make effort to pipe-line my design and manage to use FPGA primitive :

def mul_reg(clk,a,b,p):
    a_q = Signal(intbv(min=0,max=2**16))
    b_q = Signal(intbv(min=0,max=2**16))

    @always(clk.posedge)
    def logic():
        a_q.next = a
        b_q.next = b
        p.next = a_q * b_q
    return logic

mul_reg.verilog_code = \
"""
MULT18X18SIO #(
   .AREG(1),
   .BREG(1),
   .PREG(1),
   .B_INPUT("DIRECT")
) mul_reg_inst (
.A({2'b00,$a}),
.B({2'b00,$b}),
.CEA(1'b1),
.CEB(1'b1),
.CEP(1'b1),
.CLK($clk),
.RSTA(1'b0),
.RSTB(1'b0),
.RSTP(1'b0),
.BCIN(18'h00000),
.BCOUT(),
.P($p)
);
"""

The primary objective is to validate the myhdl model against the vendor primitive. But the simulator vendor does not provide vpi interface for co-simulation.
I understand that that people having access to Mentor or Cadence simulator have capability to generate vendor primitive library will use vpi/cosim.

An initial attempt to work-arround the simulator vendor limitation is to generate VCD trace at testbench level, post-process the trace to create to rebuild a testbench. However the current solution is far to be automatic : The dut still need to be instantiate. In the VCD, there is not anymore port direction so statement need to remove : the dut and the testbench should not drive the same wire ... So this task is quite boring and need to be perform each time I change my test-bench.

Solution:
The VCD spec is part of verilog spec. Myhdl implement it's traceSignal feature by instrumenting the simulator in order to print the update signal value for all signal monitored into the VCD file.
Same idea can be apply to a verilog test bench. The tool could generate testbench file similar to the one create for the cosim when running the function toVerilog(). But instead of calling vpi function the initial begin / end statement, will have a calendar of value generated from the myhdl simulation :

initial begin
  clk = 1'b1;
  #185
  clk = 1'b0;
  #190
  clk = 1'b1;
  #195
  clk = 1'b0;
  #200
  clk = 1'b1;
  a = 16'b100000000000000000;
  b = 16'b10000000000;
  result = 16'b1000000000;
  #205
  clk = 1'b0;
  a = 16'b100000000000;
  #210
  clk = 1'b1;
  result = 16'b10000000000;
  #215
  clk = 1'b0;
  b = 16'b1000000000000;
  #220
  clk = 1'b1;
  result = 16'b100000000000;
  #225
  clk = 1'b0;
  a = 16'b10000000000000;
  #230
  clk = 1'b1;
end

In details
A copy of traceSignal class can be use as a template.
In Signal class similar to printVCD a printVerilog need to be implemented.
Difficult part is how can to generate dut instantiation code...
I do not understand very well why traceSignal() and toVerilog() are exclusive function...

Thomas

[bug] Inconsistent Hierarchy returning list of generators

A subtle error occurs, in some scenarios, when a list of generators is returned. The following captures the slight differences

def mod1():
    # ...
    return gen1

def mod2():
    # ...
    return [gen2]

def top():
    mod_insts = []
    mod_insts += [mod1()]   # this works
    mod_insts += mod2()     # this doesn't work 

This appears to only occur when a single generator is being returned. This test demonstrates the error.

[1.0 fixes] How to fix issues for 1.0

Goal Minimize the open issues in the Issue Tracker.

  • Pick an issue you would like to fix. Check if it really refers to an issue, and suggest how to deal with it otherwise.
  • Decide whether it is an issue of the 0.9 release, or ask help to do so. In that case, fix it in the 0.9-maintenance branch. (The repo maintenainer will merge to master later.)
  • If it is a real issue, design a test that should work but fails. Tests should be as simple as possible.
  • Add it to myhdl/test/bugs. Use existing tests there as a template for the details.
  • If you don't plan to fix it yourself, that is OK. Mark the expect failure to travis by adding a @pytest.mark.xfail decorator to the test. (You have to add import pytest in your test module for this to work.) Raise a PR that references the issue number, so people see the test was added.
  • Otherwise, fix the issue and raise a PR when completed, again referencing the issue number.
  • Thanks!

Guidelines http://dev.myhdl.org/guide/guide.html

Installing with pip for python 3 problem

Presumably the problem is that pip isn't grabbing the correct code.
Quite possibly this is something I'm doing wrong on my end but I thought I'd post just in case, since probably most people aren't using it with python3 yet.

ben@limner:~/Code/communityshare$ sudo pip3 install myhdl
[sudo] password for ben: 
Downloading/unpacking myhdl
  Downloading myhdl-0.8.1.tar.gz (579kB): 579kB downloaded
  Running setup.py (path:/tmp/pip_build_root/myhdl/setup.py) egg_info for package myhdl
    Traceback (most recent call last):
      File "<string>", line 17, in <module>
      File "/tmp/pip_build_root/myhdl/setup.py", line 15
        print versionError
                         ^
    SyntaxError: invalid syntax
    Complete output from command python setup.py egg_info:
    Traceback (most recent call last):

Conversion failure if integer comparison used in if-else

The following failing code example was presented on the mailing-list by @geschema.

from myhdl import *

def mpegChannel(clk, rst):

    s_tx_data_xor_mask_r = Signal(intbv(0)[1 + 31:])

    @always_seq(clk.posedge, rst)
    def fsm_seq():
        for i in range(4):
            if i == 0:
                s_tx_data_xor_mask_r.next[1 + 7:0] = 0
            elif i == 1:
                s_tx_data_xor_mask_r.next[1 + 15:8] = 1
            elif i == 2:
                s_tx_data_xor_mask_r.next[1 + 23:16] = 2
            else:
                s_tx_data_xor_mask_r.next[1 + 31:24] = 3

    return instances()

clk = Signal(bool(0))
rst = ResetSignal(0, active=1, async=True)
mpegChannelInst = toVerilog(mpegChannel, clk, rst)

The above code gives a type error in during analysis.

myhdl\conversion\_analyze.pyc in visit_If(self, node)
    747         node.caseVar = var1
    748         node.caseItem = item1
--> 749         if (len(choices) == _getNritems(var1.obj)) or node.else_:
    750             node.isFullCase = True

myhdl\conversion\_analyze.pyc in _getNritems(obj)
    401         return len(obj._type)
    402     else:
--> 403         raise TypeError("Unexpected type")
    404 
    405 

TypeError: Unexpected type

A solution was proposed by @josyb . The solution is two parts, first to short-circuit on the else and
then to identify the int,long in the VHDL conversion.

Release 0.9

There are no outstanding bugs related to interface conversion, and the documentation has been updated. Can we release 0.9?

toVHDL(): Possibly incorrect order of casting and slicing when numeric_ports == False

The following code:

@always_seq( Clk.posedge, reset = Reset)
def ccregrw():
    if Wr and (A == OFFSET):
        Q.next = WD[WIDTH+START:START]

gets converted to:

TCSR_CONTROL_CC_0_CCREGRW: process (Clk, Reset) is
begin
    if (Reset = '1') then
        control_ccassigns_6_D <= to_unsigned(0, 24);
    elsif rising_edge(Clk) then
        if ((Wr = '1') and (unsigned(A) = OFFSET)) then
            control_ccassigns_6_D <= unsigned(WD)((WIDTH + START)-1 downto START);
        end if;
    end if;
end process TCSR_CONTROL_CC_0_CCREGRW;

ModelSim (launched by the Sigasi editor) flags unsigned(WD)((WIDTH + START)-1 downto START) as an error:

Vcom: Prefix of slice name cannot be type conversion (UNSIGNED)  expression.

Quartus and ISE (so I have been told) have no issue and compile this without a blink.
If I change it to : unsigned(WD((WIDTH + START)-1 downto START)); ModelSim shuts up.

[1.0 feature] General support for indexed constants

Task General support for indexed constants.

Description http://dev.myhdl.org/tasks/indexed-constants.html

Complexity estimation This is probably a hard task. It has multiple facets, as it involves knowledge about VHDL/Verilog synthesis and access to synthesis tools. The task may depend on prior improvements of the conversion code to be done right. Don't let this be your first task, be sure you are familiar with the conversion code first.

Guidelines http://dev.myhdl.org/guide.html

[enhancement] toVHDL name collision checks

Users often run into the scenario when the converted VHDL is invalid because of name collisions. This typically occurs because VHDL is not case sensitive and Python is. The toVHDL converter should produce warnings for signal, variable, and port names that conflict, identifiers that are invalid (e.g. dash in the name '-' or starting with an underscore '_'), and/or reserved word conflicts.

Example of an incorrect conversion:

def pipe(xi, xo, clock, reset, N=8):
    # note buffer is a reserved VHDL word
    buffer = [Signal(xi.val) for _ in range(N)]

    @always_seq(clock.posedge, reset=reset)
    def rtl():
        buffer[0].next = xi
        for n in range(1, N):
            buffer[n].next = buffer[n-1]
        xo.next = buffer[N-1]

    return rtl

complete code example

Shadow Signals don't work with a list of signals

This is issue #32 from sourceforge being forwarded here.

When constructing slice signals from a list of signals, the conversion doesn't work properly.

The following is an example that exposes the issue. In this case the shadow signal is converted as a constant.

def m_shadow_bittest(clock, sdi, sdo):
    """
    This module demostrates a ShadowSignal (slice) of an element
    in a list-of-signals is converted as a constant
    """
    a = [Signal(intbv(0)[8:]),Signal(intbv(0)[8:])]
    b = Signal(intbv(0)[8:])

    bittest = a[0](0)

    @always(clock.posedge)
    def rtl_in():
        a.next = concat(a[0][7:], sdi)
        sdo.next = b[7]

    @always(clock.posedge)
    def rtl():
        if bittest:
            b.next = 1
        else:
            b.next = 0

    return rtl_in, rtl
clock = Signal(bool(0))
sdi,sdo = Signal(bool(0)),Signal(bool(0))
toVerilog(m_shadow_bittest, clock, sdi, sdo)

The Verilog converted code (related section only)

always @(posedge clock) begin: M_SHADOW_BITTEST_RTL
    if (False) begin
        b <= 1;
    end
    else begin
        b <= 0;
    end
end

Problem simulating process with intbv signals of width 1

In my registerfile module I have these processes:

import os
from myhdl import *
import hdlutils, SimulateAvalon

def regrw(OFFSET, LENGTH, START, WIDTH, Clk, Reset, A, WD, Wr, Q, Pulse = None):
    ''' the WriteRead register '''

    @always_seq( Clk.posedge, reset = Reset)
    def ccregrw():
        if Wr and (A == OFFSET):
            Q.next = WD[WIDTH+START:START]

    return ccregrw

def ccassign( D, Q):
    ''' to assign the output ports from internal signals '''
    @always_comb
    def cca():
        Q.next = D

    return cca

def sim_intbv_width_1(Clk, Reset, A, WD, Wr, Rd, RQ, TestBit, TestVector):
    """   """
    lq1 = Signal(intbv(0)[1:])
    lq2 = Signal(intbv(0)[2:])
    reg1 = regrw(0,1,0,1, Clk, Reset, A, WD, Wr, lq1)
    reg2 = regrw(1,1,0,2, Clk, Reset, A, WD, Wr, lq2)
    ao1 = ccassign( lq1 , TestBit )
    ao2 = ccassign( lq2 , TestVector )

    rbd = ConcatSignal( lq2, lq1)

    @always_seq(Clk.posedge, reset = Reset)
    def mmrdr():
        if Rd:
            RQ.next = 0
            if A == 0 :
                RQ.next = rbd[1:]
            elif A == 1:
                RQ.next = rbd[:1]

    return instances()


def test_sim_intbv_width_1():

    hw_inst = sim_intbv_width_1(Clk, Reset, A, WD, Wr, Rd, RQ, TestBit, TestVector)

    ClkCount = Signal( intbv( 0 )[32:])
    tCK = 20

    @instance
    def clkgen():
        yield hdlutils.genClk(Clk, tCK, ClkCount)


    @instance
    def resetgen():
        yield hdlutils.genReset(Clk, tCK, Reset)

    @instance
    def stimulus():
        yield hdlutils.delayclks(Clk, tCK, 10)
        for i in range(2):
            yield SimulateAvalon.MMread(Clk, tCK, A, Rd, RQ, 1, i, None, None)

        # write a few things
        yield SimulateAvalon.MMwrite(Clk, tCK, A, WD, Wr, 0, 1)
        yield hdlutils.delayclks(Clk, tCK, 2)
        yield SimulateAvalon.MMwrite(Clk, tCK, A, WD, Wr, 0, 0)
        yield SimulateAvalon.MMwrite(Clk, tCK, A, WD, Wr, 1, 0x1)
        yield SimulateAvalon.MMwrite(Clk, tCK, A, WD, Wr, 1, 0x2)

        # read it all back
        for i in range(2):
            yield SimulateAvalon.MMread(Clk, tCK, A, Rd, RQ, 1, i, None, None)

        raise StopSimulation

    return instances()


def convert():
    # force std_logic_vectors instead of unsigned in Interface
    toVHDL.numeric_ports = False
    # Convert
    toVHDL(sim_intbv_width_1, Clk, Reset, A, WD, Wr, Rd, RQ, TestBit, TestVector)


if __name__ == '__main__':
    Clk = Signal(bool(0))
    Reset = ResetSignal(0, active=1, async=True)
    A = Signal(intbv(0)[2:])
    WD, RQ = [Signal(intbv(0)[32:]) for _ in range(2)]
    Wr , Rd = [ Signal(bool(0)) for _ in range(2) ]
    TestBit  = Signal(bool(0))
    TestVector = Signal(intbv(0)[2:])

    hdlutils.simulate(3000, test_sim_intbv_width_1)
    convert()

The output of the first process goes to an intermediate intbv signal so we can read the value back. The second process routes the intermediate signal to the output.
This works OK for bitwidths > 1 so TestVector goes from 0 to 1 to 2.
But Testbit should go from 0 to 1 to 0, but stays 1 forever as can be seen in the vcd waveform:
image
The problem seems to be in the simulation of the ccassign function, in the case of being handed Signals containing an intbv of width 1.

toVHDL(): superfluous cast when indexing a port and numeric_ports == False

The following code:

if A[LWIDTHA_RAM]:

gets converted into:

if bool(unsigned(A)(LWIDTHA_RAM)) then

The cast unsigned( ) is unnecessary as an index operation on either an unsigned or a std_logic_vector both return a std_logic
Apart from that, ModelSim flags this as an error:

Vcom: Prefix of indexed name cannot be a type conversion (UNSIGNED) expression.

Define a numeric default value for tristate signals

When converting a tristate signal to an hdl, if it's numeric value is requested, for example using int, an error is generated as the default value is None. To avoid this problem, a metavalue warning could be generated, and a default value of 0 could be provided. This can be done in the _Signal class modifying the int(), long(), float() and float() functions to take care of this case.

Problem with slicing of a slice signal

Hi,

I encounter a problem while trying to use a slice of a slice signal, or any other shadow signal.
The following python code generates a buggy verilog:

def add_example(CLK, IN_1, IN_2, SUM_OUT):

SUM_OUT.driven = 'reg'
IN_1.read = True
IN_2.read = True

in1_part = IN_1(10,0)
in2_part = IN_2(10,0)

part_of_in1_part = in1(5,2)
part_of_in2_part = in2(5,2)

#This always block isn't exactly like the verilog code.
@always(CLK.posedge)
def adding():
  SUM_OUT.next = IN_1 + IN_2

add_example.verilog_code = \
"""
always @(posedge $CLK) begin:
    $SUM_OUT[11-1:0] <= $in1_part + $in2_part;
    $SUM_OUT[32:28] <= $part_of_in1_part + $part_of_in2_part
end
"""

return adding

I get the following buggy always block in the verilog code:

always @(posedge CLK) begin
    SUM_OUT[11-1:0] <= IN_1[10-1:0] + IN_2[10-1:0];
    SUM_OUT[32:28] <= 0 + 0;
end

[Enhancement] 'Open' Signals

When creating re-usable modules we create output signals, which quite often are not all used in an instantiation, and cause undesirable warnings.
In VHDL we have the open keyword to tell the compiler about our intention. Of course in Python we would use None to achieve the same. But the None is propagated and we end up assigning something to None which results in an Attribute Exception.
The following code illustrates this:

def addresscounter( clk, reset, startValue, Length , initP, cntEn, 
                                 isStart, isEnd, Q, WRAP_AROUND = False ):

    lq = Signal(intbv(0)[len(Q):])

    @always_seq(clk.posedge, reset=reset)
    def counter():
        endval = int(startValue) + int(Length)
        if initP or cntEn:
            if initP :
                lq.next = startValue
                isStart.next = 1
                isEnd.next = 0
            else:
                if lq < (endval - 1):
                    lq.next = lq + 1
                    isStart.next = 0
                else:
                    lq.next = startValue
                    isStart.next = 1

                if lq == (endval - 2):
                    isEnd.next = 1
                else:
                    isEnd.next = 0

    @always_comb
    def assignoutputs():
        Q.next = lq

When we instantiate the module as follows:

wraddresscounter = addresscounter.addresscounter(Clk, Reset, 0, DEPTH, wraddresscounterinitP, 
                                                 wraddresscountercntEn, None, None, 
                                                 wraddresscounter_Q, WRAP_AROUND= True)

We will get:

AttributeError: 'NoneType' object has no attribute 'next'

There are two workarounds:

  1. declare two (in this case) SIgnals and add them to the instantiation
wraddresscounter = addresscounter.addresscounter(Clk, Reset, 0, DEPTH, wraddresscounterinitP, 
                                                 wraddresscountercntEn,  dummysig1, dummysig2, 
                                                 wraddresscounter_Q, WRAP_AROUND= True)
  1. declare local Signals in the re-usable module and selectively assign them to the outputs
def addresscounter( clk, reset, startValue, Length , initP, cntEn, 
                                 isStart, isEnd, Q, WRAP_AROUND = False ):

    lq = Signal(intbv(0)[len(Q):])
    lisstart = Signal(bool(0))
    lisend = Signal(bool(0))

    @always_seq(clk.posedge, reset=reset)
    def counter():
        endval = int(startValue) + int(Length)
        if initP or cntEn:
            if initP :
                lq.next = startValue
                lisstart .next = 1
                lisend.next = 0
            else:
                if lq < (endval - 1):
                    lq.next = lq + 1
                    lisstart .next = 0
                else:
                    lq.next = startValue
                    lisstart .next = 1

                if lq == (endval - 2):
                    lisend.next = 1
                else:
                    lisend.next = 0

    @always_comb
    def assignoutputs():
        Q.next = lq

    if IsStart is not None:
        @always_comb
        def assignis():
            IsStart.next = lisstart

    if IsEnd is not None:
        @always_comb
        def assignie():
            IsEnd.next = lisend

    return instances()

Both workarounds are equivalent (with 2. being preferred), but both will end up with warning(s):

** ToVerilogWarning: Signal is driven but not read: lisstart
** ToVerilogWarning: Signal is driven but not read: lisend

I would like to get rid of the warning(s). I discovered _/markRead() in _Signal.py: if I change the code as follows:

    if IsStart is None:
        lisstart._markRead()
    else:
        @always_comb
        def assignis():
            IsStart.next = lisstart

the warnings are gone.
There are two caveat:

  1. The _markRead() method is not documented.
  2. The _open_Signals are still in the converted code, so later on the Synthesiser will complain anyway.
    text Warning (10036): Verilog HDL or VHDL warning at scfifo.vhd(68): object "wraddresscounter_lisend" assigned a value but never read

So ideally the lines assigning to open Signals should be removed from the converted code.

Simulation failures after simulation suspend

Currently there are two ways to run a simulation: run to completion or run a certain duration:

Run to completion

sim = Simulation(top())
sim.run()

In the above example, the simulation will run until no more events or StopSimulation is raised (or an error occurs).

When the simulator runs to completion it does a finalize and resets all the Signals under simulation control back to the initial value. The user state is the same as it entered. New simulation instances can be created and additional simulations can be run.

Run for a duration

sim = Simulation(top())
sim.run(100)
# the simulator is paused/suspended

# resume and run some more
sim.run(100)  

Running for a duration allows a user to run a number of simulation steps, pause, and resume.

There is a bug when the simulator is paused and a new simulation instance is created with reused signals, e.g. signals that are in a global state in the user space.

There were two proposed solutions:

  1. Always initialize when a new instance is created. The
    initialize would be similar to finalize in that the
    simulator guarantees all user Signals are in an initial
    state (will be redundant if the user has no global signals).
  2. Add a quit method to the simulator to end simulations
    that have been suspended (vs. stopped). And don't allow
    new simulation instances if the simulator is in a run
    or suspend state (new instances only valid if none exist
    or stopped).

The second solution was preferred as discussed in #67.

A previous example demonstrates when user global signals are used and the simulator is suspended subsequent simulation instances and runs can cause unexpected (incorrect) results.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.