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;