forked from jandecaluwe/site-myhdl-retired
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
005f6f8
commit fa0d5c4
Showing
12 changed files
with
1,676 additions
and
23 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,372 @@ | ||
====== Hello World ====== | ||
|
||
===== Introduction ===== | ||
|
||
The purpose of this example is to show how a demonstrator design that is | ||
originally coded in VHDL can be done in MyHDL. | ||
|
||
The original design is [[http://hamsterworks.co.nz/mediawiki/index.php/Papilio_Plus/Hello_World|here]]. Basically, it draws the message "Hello World" on a screen. | ||
|
||
We will show how MyHDL can make the design task easier. For example, it is not necessary to worry about VHDL type conversions anymore: the MyHDL type system gives hardware designers exactly the right types for synthesizable code. In particular, MyHDL has integers that "just work" instead of low level ''signed'' and ''unsigned'' types. Furthermore, we will show how MyHDL's embedded scripting capabilities can be used to automate tasks that are traditionally done outside synthesizable code, resulting in a clearer and less error prone design. | ||
|
||
It may be interesting to compare the original VHDL code with the code generated by the MyHDL convertor. Therefore, the generated VHDL and Verilog code is listed also. | ||
|
||
**Note** This example uses the 0.8-dev development version. (It uses the ''modbv'' type introduced in 0.8.) Install from the [[dev:repo]]. | ||
===== Design decisions ===== | ||
|
||
To demonstrate the capabilities of MyHDL, we made a number of design decisions that are different from the original: | ||
|
||
* We start from ascii art generated by a program instead of a table of '0's and '1's as in the original code. This makes it easier to visualize the message right in the code. We use embedded scripting to generate the desired format in-place. | ||
* While we were at it, we used a nicer font :-) | ||
* The whole image is set up as a table so that we can do a one-liner indexing operation in the hardware behavior description. | ||
* We describe the actual hardware behavior in a sequential instead of a combinatorial process. This is a more abstract view that leads to shorter and more robust code. | ||
* We introduced a ''row'' variable to make the intention clearer. | ||
|
||
|
||
===== MyHDL code ===== | ||
<code myhdl> | ||
from myhdl import * | ||
|
||
import re | ||
|
||
def HelloWorld( | ||
pixelClock, | ||
Red, | ||
Green, | ||
Blue, | ||
hSync, | ||
vSync | ||
): | ||
|
||
### Image ### | ||
|
||
# From: figlet -f alphabet " Hello World " | ||
MSG = [ | ||
" H H l l W W l d ", | ||
" H H l l W W l d ", | ||
" HHHH eee l l ooo W W W ooo rrr l ddd ", | ||
" H H e e l l o o W W W o o r l d d ", | ||
" H H ee l l ooo W W ooo r l ddd ", | ||
] | ||
|
||
# Convert spaces, letters to 0, 1 | ||
def to_10(s): | ||
"""Convert letters to 1, then spaces to 0""" | ||
s = re.sub(r'\w', '1', s) | ||
s = re.sub(r'\s', '0', s) | ||
return s | ||
|
||
MSG = [to_10(s) for s in MSG] | ||
assert len(MSG[1]) == 50 | ||
|
||
# Setup image as a concatenation of rows | ||
BORDER = '1' + '0' * 48 + '1' | ||
NULL = '0' * 50 | ||
IMAGE = [BORDER] + [NULL] + MSG + [NULL] * (37-len(MSG)-3) + [BORDER] | ||
assert len(IMAGE) == 37 | ||
|
||
# Convert strings to ints for use in convertible code | ||
TABLE = tuple([int(s, 2) for s in IMAGE]) | ||
|
||
### Hardware behavior ### | ||
|
||
# Timing constants | ||
hMaxCount = 1056-1 | ||
hStartSync = 840 | ||
hEndSync = 968 | ||
vMaxCount = 628-1 | ||
vStartSync = 601 | ||
vEndSync = 605 | ||
|
||
# Signals | ||
hCounter = Signal(intbv(0)[11:]) | ||
vCounter = Signal(intbv(0)[10:]) | ||
shiftReg = Signal(modbv(0)[50:]) | ||
|
||
@always_comb | ||
def assign(): | ||
v = intbv(0)[4:] | ||
v[3] = shiftReg[49] | ||
Red.next = v | ||
Green.next = v | ||
Blue.next = v | ||
|
||
@always(pixelClock.posedge) | ||
def draw(): | ||
row = intbv(0)[6:] | ||
if hCounter == hMaxCount: | ||
hCounter.next = 0 | ||
if vCounter == vMaxCount: | ||
vCounter.next = 0 | ||
else: | ||
row[:] = vCounter[10:4] | ||
shiftReg.next = TABLE[row] | ||
vCounter.next = vCounter + 1 | ||
else: | ||
hCounter.next = hCounter + 1 | ||
if hCounter[4:] == 15: | ||
shiftReg.next = shiftReg << 1 | ||
|
||
hSync.next = hCounter >= hStartSync and hCounter < hEndSync | ||
vSync.next = vCounter >= vStartSync and vCounter < vEndSync | ||
|
||
return assign, draw | ||
|
||
</code> | ||
===== Issues ===== | ||
|
||
* This is a draft version - work in progress | ||
* No simulations done yet, so there will be bugs :-) | ||
* Where is the reset??? | ||
|
||
|
||
===== Conversion to VHDL and Verilog ===== | ||
|
||
The MyHDL code can be converted to VHDL and Verilog | ||
as follows: | ||
|
||
<code myhdl> | ||
### Conversion to VHDL & Verilog | ||
|
||
pixelClock = Signal(bool(0)) | ||
Red = Signal(intbv(0)[4:]) | ||
Green = Signal(intbv(0)[4:]) | ||
Blue = Signal(intbv(0)[4:]) | ||
hSync = Signal(bool(0)) | ||
vsync = Signal(bool(0)) | ||
|
||
for f in (toVHDL, toVerilog): | ||
f(HelloWorld, | ||
pixelClock, | ||
Red, | ||
Green, | ||
Blue, | ||
hSync, | ||
vsync | ||
) | ||
|
||
</code> | ||
|
||
===== Generated VHDL code ===== | ||
|
||
<code vhdl> | ||
-- File: HelloWorld.vhd | ||
-- Generated by MyHDL 0.8dev | ||
-- Date: Thu Aug 16 17:20:37 2012 | ||
|
||
|
||
library IEEE; | ||
use IEEE.std_logic_1164.all; | ||
use IEEE.numeric_std.all; | ||
use std.textio.all; | ||
|
||
use work.pck_myhdl_08.all; | ||
|
||
entity HelloWorld is | ||
port ( | ||
pixelClock: in std_logic; | ||
Red: out unsigned(3 downto 0); | ||
Green: out unsigned(3 downto 0); | ||
Blue: out unsigned(3 downto 0); | ||
hSync: out std_logic; | ||
vSync: out std_logic | ||
); | ||
end entity HelloWorld; | ||
|
||
|
||
architecture MyHDL of HelloWorld is | ||
|
||
signal hCounter: unsigned(10 downto 0); | ||
signal vCounter: unsigned(9 downto 0); | ||
signal shiftReg: unsigned(49 downto 0); | ||
|
||
begin | ||
|
||
|
||
HELLOWORLD_ASSIGN: process (shiftReg) is | ||
variable v: unsigned(3 downto 0); | ||
begin | ||
v := to_unsigned(0, 4); | ||
v(3) := shiftReg(49); | ||
Red <= v; | ||
Green <= v; | ||
Blue <= v; | ||
end process HELLOWORLD_ASSIGN; | ||
|
||
|
||
HELLOWORLD_DRAW: process (pixelClock) is | ||
variable row: unsigned(5 downto 0); | ||
begin | ||
if rising_edge(pixelClock) then | ||
row := to_unsigned(0, 6); | ||
if (hCounter = 1055) then | ||
hCounter <= "00000000000"; | ||
if (vCounter = 627) then | ||
vCounter <= "0000000000"; | ||
else | ||
row := vCounter(10-1 downto 4); | ||
case to_integer(row) is | ||
when 0 => shiftReg <= "10000000000000000000000000000000000000000000000001"; | ||
when 1 => shiftReg <= "00000000000000000000000000000000000000000000000000"; | ||
when 2 => shiftReg <= "00001001000001010000000010000010000000001000010000"; | ||
when 3 => shiftReg <= "00001001000001010000000010000010000000001000010000"; | ||
when 4 => shiftReg <= "00001111011101010111000010010010111011101001110000"; | ||
when 5 => shiftReg <= "00001001010101010101000001010100101010001010010000"; | ||
when 6 => shiftReg <= "00001001011001010111000000101000111010001001110000"; | ||
when 7 => shiftReg <= "00000000000000000000000000000000000000000000000000"; | ||
when 8 => shiftReg <= "00000000000000000000000000000000000000000000000000"; | ||
when 9 => shiftReg <= "00000000000000000000000000000000000000000000000000"; | ||
when 10 => shiftReg <= "00000000000000000000000000000000000000000000000000"; | ||
when 11 => shiftReg <= "00000000000000000000000000000000000000000000000000"; | ||
when 12 => shiftReg <= "00000000000000000000000000000000000000000000000000"; | ||
when 13 => shiftReg <= "00000000000000000000000000000000000000000000000000"; | ||
when 14 => shiftReg <= "00000000000000000000000000000000000000000000000000"; | ||
when 15 => shiftReg <= "00000000000000000000000000000000000000000000000000"; | ||
when 16 => shiftReg <= "00000000000000000000000000000000000000000000000000"; | ||
when 17 => shiftReg <= "00000000000000000000000000000000000000000000000000"; | ||
when 18 => shiftReg <= "00000000000000000000000000000000000000000000000000"; | ||
when 19 => shiftReg <= "00000000000000000000000000000000000000000000000000"; | ||
when 20 => shiftReg <= "00000000000000000000000000000000000000000000000000"; | ||
when 21 => shiftReg <= "00000000000000000000000000000000000000000000000000"; | ||
when 22 => shiftReg <= "00000000000000000000000000000000000000000000000000"; | ||
when 23 => shiftReg <= "00000000000000000000000000000000000000000000000000"; | ||
when 24 => shiftReg <= "00000000000000000000000000000000000000000000000000"; | ||
when 25 => shiftReg <= "00000000000000000000000000000000000000000000000000"; | ||
when 26 => shiftReg <= "00000000000000000000000000000000000000000000000000"; | ||
when 27 => shiftReg <= "00000000000000000000000000000000000000000000000000"; | ||
when 28 => shiftReg <= "00000000000000000000000000000000000000000000000000"; | ||
when 29 => shiftReg <= "00000000000000000000000000000000000000000000000000"; | ||
when 30 => shiftReg <= "00000000000000000000000000000000000000000000000000"; | ||
when 31 => shiftReg <= "00000000000000000000000000000000000000000000000000"; | ||
when 32 => shiftReg <= "00000000000000000000000000000000000000000000000000"; | ||
when 33 => shiftReg <= "00000000000000000000000000000000000000000000000000"; | ||
when 34 => shiftReg <= "00000000000000000000000000000000000000000000000000"; | ||
when 35 => shiftReg <= "00000000000000000000000000000000000000000000000000"; | ||
when others => shiftReg <= "10000000000000000000000000000000000000000000000001"; | ||
end case; | ||
vCounter <= (vCounter + 1); | ||
end if; | ||
else | ||
hCounter <= (hCounter + 1); | ||
if (hCounter(4-1 downto 0) = 15) then | ||
shiftReg <= shift_left(shiftReg, 1); | ||
end if; | ||
end if; | ||
hSync <= stdl((hCounter >= 840) and (hCounter < 968)); | ||
vSync <= stdl((vCounter >= 601) and (vCounter < 605)); | ||
end if; | ||
end process HELLOWORLD_DRAW; | ||
|
||
end architecture MyHDL; | ||
</code> | ||
|
||
|
||
===== Generated Verilog code ===== | ||
|
||
<code verilog> | ||
// File: HelloWorld.v | ||
// Generated by MyHDL 0.8dev | ||
// Date: Thu Aug 16 17:20:37 2012 | ||
|
||
`timescale 1ns/10ps | ||
|
||
module HelloWorld ( | ||
pixelClock, | ||
Red, | ||
Green, | ||
Blue, | ||
hSync, | ||
vSync | ||
); | ||
|
||
input pixelClock; | ||
output [3:0] Red; | ||
reg [3:0] Red; | ||
output [3:0] Green; | ||
reg [3:0] Green; | ||
output [3:0] Blue; | ||
reg [3:0] Blue; | ||
output hSync; | ||
reg hSync; | ||
output vSync; | ||
reg vSync; | ||
|
||
reg [10:0] hCounter; | ||
reg [9:0] vCounter; | ||
reg [49:0] shiftReg; | ||
|
||
|
||
always @(shiftReg) begin: HELLOWORLD_ASSIGN | ||
reg [4-1:0] v; | ||
v = 4'h0; | ||
v[3] = shiftReg[49]; | ||
Red = v; | ||
Green = v; | ||
Blue = v; | ||
end | ||
|
||
|
||
always @(posedge pixelClock) begin: HELLOWORLD_DRAW | ||
reg [6-1:0] row; | ||
row = 6'h0; | ||
if ((hCounter == 1055)) begin | ||
hCounter <= 0; | ||
if ((vCounter == 627)) begin | ||
vCounter <= 0; | ||
end | ||
else begin | ||
row = vCounter[10-1:4]; | ||
case (row) | ||
0: shiftReg <= 51'h2000000000001; | ||
1: shiftReg <= 0; | ||
2: shiftReg <= 47'h241402080210; | ||
3: shiftReg <= 47'h241402080210; | ||
4: shiftReg <= 47'h3dd5c24bba70; | ||
5: shiftReg <= 47'h25554152a290; | ||
6: shiftReg <= 47'h2595c0a3a270; | ||
7: shiftReg <= 0; | ||
8: shiftReg <= 0; | ||
9: shiftReg <= 0; | ||
10: shiftReg <= 0; | ||
11: shiftReg <= 0; | ||
12: shiftReg <= 0; | ||
13: shiftReg <= 0; | ||
14: shiftReg <= 0; | ||
15: shiftReg <= 0; | ||
16: shiftReg <= 0; | ||
17: shiftReg <= 0; | ||
18: shiftReg <= 0; | ||
19: shiftReg <= 0; | ||
20: shiftReg <= 0; | ||
21: shiftReg <= 0; | ||
22: shiftReg <= 0; | ||
23: shiftReg <= 0; | ||
24: shiftReg <= 0; | ||
25: shiftReg <= 0; | ||
26: shiftReg <= 0; | ||
27: shiftReg <= 0; | ||
28: shiftReg <= 0; | ||
29: shiftReg <= 0; | ||
30: shiftReg <= 0; | ||
31: shiftReg <= 0; | ||
32: shiftReg <= 0; | ||
33: shiftReg <= 0; | ||
34: shiftReg <= 0; | ||
35: shiftReg <= 0; | ||
default: shiftReg <= 51'h2000000000001; | ||
endcase | ||
vCounter <= (vCounter + 1); | ||
end | ||
end | ||
else begin | ||
hCounter <= (hCounter + 1); | ||
if ((hCounter[4-1:0] == 15)) begin | ||
shiftReg <= (shiftReg << 1); | ||
end | ||
end | ||
hSync <= ((hCounter >= 840) && (hCounter < 968)); | ||
vSync <= ((vCounter >= 601) && (vCounter < 605)); | ||
end | ||
|
||
endmodule | ||
</code> |
Oops, something went wrong.