By default, an
intbv object has an “indefinite” bit width. Although this is a novel concept compared to traditional HDL modeling, it corresponds to the natural way to think about integers and their 2's complement representation. Consider:
>>> from myhdl import intbv >>> a = intbv(5) >>> a = 1 >>> a intbv(37778931862957161709573L) >>> a[77:74] intbv(2L)
This illustrates that you can index and slice an
intbv object with arbitrary indices, without having to declare a bit width at object construction time.
The default is fine for modeling at a very high level. Other applications require a defined bit width, and this is supported by the
intbv class also.
To define the bit width of an
intbv object, you have two options.
The first method is an indirect one that specifies the acceptable value range using the
max parameters. For example:
a = intbv(0, min=-24, max=75)
As always in Python, the minimum value is inclusive, but the maximum value is exclusive. Note how this method stresses the “integer” nature of an
The second method defines the bit width directly, as follows:
a = intbv(0)[8:]
This works because when you take a slice from an intbv, the returned object is a new
intbv with a bit width
w corresponding to the slicing range. The min and max value are set to
2**w respectively. Note that the object returned by a slice is always positive, as in Verilog.
The range of acceptable values of an
intbv object is checked at simulation runtime. This is an interesting application of defining a bit width. Another application is implementation-oriented modeling, such as code that needs to be converted automatically to synthesizable Verilog.
In HDLs such as Verilog and VHDL, the bit vectors have wrap-around behaviour. This means that when the result of a numeric operation would exceed the bit width, the higher order bits are dropped automatically. In effect, the operations are done modulo the power of 2 of the bit width.
intbv object is much like an integer. Therefore, it doesn't have this wrap-around behavior. If needed, it has to be described explicitly.
The most straightforward way to describe wrap-around behavior is with an if-then-else. For example:
if count < N: count.next = count + 1 else: count.next = 0
This may seem a little verbose compared to automatic wrap-around, but in many cases there is no overhead. Often, something else will have to be done depending on the condition (such as setting a control signal) so you can directly add that in the code. Moreover, the wrap-around condition is not limited to powers of 2.
To describe wrap-around behaviour with a one-liner, you can use the modulo operation:
count.next = (count + 1) % N
You can use user-defined code to replace a MyHDL module by a corresponding instantiation.
The converted output is non-hierarchical because conversion works on a design instance elaborated by the Python interpreter. This process flattens out all hierarchy.
You can generate hierarchical designs by some additional work, in particular by converting lower level modules and using user-defined instantiation code at a higher level. This technique is explained here.
The implementation of co-simulation in MyHDL relies on unix-style interprocess communication. Therefore, unlike the rest of MyHDL, you cannot use co-simulation on Windows natively.
To run co-simulation on Windows, use a unix-like environment for Windows, such as cygwin. You will have to compile all co-simulation tools in that environment. This includes Python itself, the HDL simulator, and the PLI module.
Users have reported co-simulation success on Windows using cygwin and the Verilog simulators Icarus and Cver.