I take Computer Architecture course this semester and study basic VHDL for digital design. The instructor recommends ModelSim with both Windows and Linux versions. But unfortunately, ModelSim for Linux can only be installed on RH Linux. I tried to install it on Ubuntu but obviously it didn’t work. It turned out that the only solution would be using ModelSim for Windows in our computer lab. But as a dead-head Linux fan, I simply want to find alternative software to get things done on Linux platform. After some googling and asking help from friends, I found two handy software packages that form a tool chain to do VHDL simulation on Linux: GHDL and GTKWave.
What
GHDL is an amazing package that it employ gcc and compile VHDL code to objective code. It can’t translate your design into a netlist but it’s sufficient for us to do the simulation.
GTKwave is another tool which can help you view the wave form dumped by GHDL simulation. There two, in principle, can help you handle all the VHDL simulation tasks involved in a one-semester-course like computer architecture.
How
Build the tool chain
If you are using a Debian family (Debian/Ubuntu, etc) Linux, an apt-get will save your life. Try:
apt-get install ghdl
and
apt-get install gtkwave.
[You might need sudo or run it as root.]
If you not, try to download the package and read the README. It’s easy. If you want to install it on Mac as what I’ve done, remember to install X11. The whole procedure should take you less than five minutes.
How to use it
It’s very simple. GHDL will compile the VHDL code for you to object code and convert it to executable. For example, if I have CPU.vhdl which is a simple computer description. Try to type:
ghdl -a cpu.vhdl
to compile it, and
ghdl -e cpu
to make executable file (do linking).
Finally you can use
./cpu --help
to see how to run it.
Some tips:
If you include ieee package, add this option: –ieee=synopsys
If you want to let the simulation run certain amount of time, use something like
<br />
./cpu --stop-time=100ns
If you want to dump a signal wave format for gtkwave, just add –vcd=vcd.file
After that, you can use
gtkwave vcd.file to see the wave. You might need to add all the signals to the wave window via “Search->Signal Search Tree”.
Why
You might ask why it’s handy than ModelSim. It’s obvious. For example, if you write a shell script that can issue all the compiling/dumping/viewing command in the right order, you only need two keyboard stoke to run a test, in comparing with in ModelSim, where you need to do at least 10 mouse click and maybe type these commands:
``I take Computer Architecture course this semester and study basic VHDL for digital design. The instructor recommends ModelSim with both Windows and Linux versions. But unfortunately, ModelSim for Linux can only be installed on RH Linux. I tried to install it on Ubuntu but obviously it didn’t work. It turned out that the only solution would be using ModelSim for Windows in our computer lab. But as a dead-head Linux fan, I simply want to find alternative software to get things done on Linux platform. After some googling and asking help from friends, I found two handy software packages that form a tool chain to do VHDL simulation on Linux: GHDL and GTKWave.
What
GHDL is an amazing package that it employ gcc and compile VHDL code to objective code. It can’t translate your design into a netlist but it’s sufficient for us to do the simulation.
GTKwave is another tool which can help you view the wave form dumped by GHDL simulation. There two, in principle, can help you handle all the VHDL simulation tasks involved in a one-semester-course like computer architecture.
How
Build the tool chain
If you are using a Debian family (Debian/Ubuntu, etc) Linux, an apt-get will save your life. Try:
apt-get install ghdl
and
apt-get install gtkwave.
[You might need sudo or run it as root.]
If you not, try to download the package and read the README. It’s easy. If you want to install it on Mac as what I’ve done, remember to install X11. The whole procedure should take you less than five minutes.
How to use it
It’s very simple. GHDL will compile the VHDL code for you to object code and convert it to executable. For example, if I have CPU.vhdl which is a simple computer description. Try to type:
ghdl -a cpu.vhdl
to compile it, and
ghdl -e cpu
to make executable file (do linking).
Finally you can use
./cpu --help
to see how to run it.
Some tips:
If you include ieee package, add this option: –ieee=synopsys
If you want to let the simulation run certain amount of time, use something like
<br />
./cpu --stop-time=100ns
If you want to dump a signal wave format for gtkwave, just add –vcd=vcd.file
After that, you can use
gtkwave vcd.file to see the wave. You might need to add all the signals to the wave window via “Search->Signal Search Tree”.
Why
You might ask why it’s handy than ModelSim. It’s obvious. For example, if you write a shell script that can issue all the compiling/dumping/viewing command in the right order, you only need two keyboard stoke to run a test, in comparing with in ModelSim, where you need to do at least 10 mouse click and maybe type these commands:
``
Finally, you can use GHDL as your VHDL code formatter and get a very nice HTML format for your neat code. You can now make it even neater, why not :)
Some really missing features for these small tools.
- Non-standard signal watch.
If you have a signal which is an array, it’s not handy to view the wave as ghdl doesn’t actually output the signal changing information for this signal.
- Automatic dependency solving.
Currently GHDL will complain about the dependency, but it doesn’t actually handle this like GNU make. Therefore, you have to either write your own makefile to use make to manage your code dependency, or recompile all the code every time.
My example code of a silly CPU:
1 -- CSE 560 Homework, a simple CPU 2 -- Eric You XU 3 --- version 0.05 4 5 library ieee; 6 use ieee.std_logic_arith.all; 7 use ieee.std_logic_signed.all; 8 use ieee.std_logic_1164.all; 9 10 entity CPU is 11 port ( IR : in std_logic_vector (31 downto 0); 12 READY : in bit; 13 CLK : in bit 14 ); 15 end entity CPU; 16 17 architecture behav of CPU is 18 type reg_type is array(0 to 255) of std_logic_vector(31 downto 0); 19 signal storage: reg_type; 20 21 signal d1, d2: std_logic_vector(31 downto 0); 22 signal raw1, raw2: std_logic_vector(31 downto 0); 23 signal s1_int, s2_int: integer; 24 signal prod: std_logic_vector(63 downto 0); 25 signal status: std_logic_vector(1 downto 0); 26 signal phase: bit; 27 signal index: integer; 28 signal opcode: std_logic_vector(2 downto 0); 29 signal needd2: bit; 30 31 begin 32 33 34 35 process(clk) 36 begin 37 if (ready='0') then 38 phase <= '0'; 39 -- For test 40 storage(0) <= X"00000004"; 41 storage(1) <= X"FFFFFFFD"; 42 storage(2) <= X"01010103"; 43 storage(3) <= X"0F0F0F08"; 44 storage(4) <= X"F0F0F0F0"; 45 storage(5) <= X"FFFFFFFF"; 46 storage(6) <= X"00000000"; 47 storage(7) <= X"0000000E"; 48 storage(8) <= X"00000004"; 49 storage(9) <= X"DEADBEEF"; 50 51 else 52 if(clk'event) then 53 if(clk = '1') then -- CLK _| 54 if(phase = '0') then -- state 1, read instructions 55 56 opcode <= IR(26 downto 24); 57 -- 31 30 29 28 27 26 25 24: Lower 3 bit 58 raw1 <= storage(ieee.std_logic_unsigned.conv_integer( IR(23 downto 16) )); 59 raw2 <= storage(ieee.std_logic_unsigned.conv_integer( IR(15 downto 8) )); 60 -- RAW Hazard 61 --avoid to use s1_int = con_int(raw1) 62 s1_int <= ieee.std_logic_signed.conv_integer(storage(ieee.std_logic_unsigned.conv_integer( IR(23 downto 16) ))); 63 s2_int <= ieee.std_logic_signed.conv_integer(storage(ieee.std_logic_unsigned.conv_integer( IR(15 downto 8) ))); 64 index <= ieee.std_logic_unsigned.conv_integer(IR(7 downto 0)); 65 66 else -- state 3, write register files 67 case opcode is 68 when "000" => -- ADD 69 storage(index) <= d1; 70 when "001" => -- SUB 71 storage(index) <= d1; 72 when "011" => 73 storage(index) <= d1; 74 when "100" => -- INC 75 storage(index) <= d1; 76 when "101" => -- DEC 77 storage(index) <= d1; 78 when "010" => -- MULT 79 storage(index) <= prod(31 downto 0); 80 d2 <= prod(63 downto 32); 81 d1 <= prod(31 downto 0); 82 if (index = 255) then 83 storage(0) <= prod(63 downto 32); 84 else 85 storage(index+1) <= prod(63 downto 32); 86 end if; 87 when "110" => -- DIV 88 storage(index) <= d1; 89 if (index = 255) then 90 storage(0) <= d2; 91 else 92 storage(index+1) <= d2; 93 end if; 94 when others => 95 report "Invalid OpCode." severity FAILURE; 96 end case; 97 end if; 98 99 else -- CLK |_ 100 if(phase = '0') then -- state 2, ALU step 101 102 case opcode is 103 when "000" => -- ADD 104 d1 <= conv_std_logic_vector((s1_int + s2_int), 32); 105 needd2 <= '0'; 106 when "001" => -- SUB 107 d1 <= conv_std_logic_vector((s1_int - s2_int), 32); 108 needd2 <= '0'; 109 when "011" => -- COMP 110 d1 <= conv_std_logic_vector((-s1_int - 1), 32); 111 needd2 <= '0'; 112 when "100" => -- INC 113 d1 <= conv_std_logic_vector((s1_int + 1), 32); 114 needd2 <= '0'; 115 when "101" => -- DEC 116 d1 <= conv_std_logic_vector((s1_int - 1), 32); 117 needd2 <= '0'; 118 when "010" => -- MULT 119 -- If I assign the prod value to d1 and d2 here, a RAW hazard will occur. 120 prod <= raw1 * raw2; 121 needd2 <= '1'; 122 when "110" => -- DIV 123 d1 <= conv_std_logic_vector((s1_int/s2_int), 32); 124 d2 <= conv_std_logic_vector((s1_int rem s2_int), 32); 125 needd2 <= '1'; 126 when others => 127 report "Invalid OpCode." severity FAILURE; 128 end case; 129 130 131 phase <= '1'; 132 else -- state 4: NOP, Increase PC, etc. 133 134 -- Set STATUS --- 135 status <= "00"; 136 if(needd2 = '0') then -- only look at d1 137 if d1 = X"00000000" then 138 status <= "01"; 139 end if; 140 if d1(31) = '1' then 141 status <= "10"; 142 end if; 143 if d1 = X"FFFFFFFF" then 144 status <= "11"; 145 end if; 146 else -- needd2 = 1 147 if d1 = X"00000000" and d2 = X"00000000" then 148 status <= "01"; 149 end if; 150 if d2(31) = '1' and opcode = "010" then -- high order bit of mult is 1 151 status <= "10"; 152 else 153 if d1(31) = '1' and opcode = "110" then -- high order bit of div is 1 154 status <= "10"; 155 end if; 156 end if; 157 if d1 = X"FFFFFFFF" and d2 = X"FFFFFFFF" then 158 status <= "11"; 159 end if; 160 end if; 161 ------------------ 162 163 phase <= '0'; 164 end if; 165 end if; 166 end if; 167 end if; 168 169 end process; 170 end architecture behav;