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.

  1. 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.

  1. 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;