Skip to content

Commit

Permalink
helloworld
Browse files Browse the repository at this point in the history
  • Loading branch information
jandecaluwe committed Feb 28, 2014
1 parent 005f6f8 commit fa0d5c4
Show file tree
Hide file tree
Showing 12 changed files with 1,676 additions and 23 deletions.
518 changes: 518 additions & 0 deletions _build/examples/helloworld.html

Large diffs are not rendered by default.

372 changes: 372 additions & 0 deletions _build/examples/helloworld.txt
@@ -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>

0 comments on commit fa0d5c4

Please sign in to comment.