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 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 Source code repository.
To demonstrate the capabilities of MyHDL, we made a number of design decisions that are different from the original:
row
variable to make the intention clearer.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
The MyHDL code can be converted to VHDL and Verilog as follows:
### 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 )
-- 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;
// 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