GHDL ( http://ghdl.free.fr/ ) es un simulador open-source para VHDL, que permite la compilación y ejecución del código VHDL directamente en PC. Otra característica avanzada es la capacidad de utilizar funciones C desde el código VHDL.

Si no tenemos instalado GHDL en nuestro sistema, procedemos a ello:

apt-get install ghdl

Ejemplo

El ejemplo que vamos a realizar va a consistir en una implementación de un sumador en hardware (VHDL) y en software (ansi C), y se va a comparar su funcionalidad.

Empecemos con el componente hardware. La implementación consiste en una suma de dos enteros a la que se le ha introducido un error; cuando el operando A es 10 el resultado de la suma va a ser 5.

sumador.vhdl
library ieee;
use ieee.std_logic_1164.all;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use ieee.std_logic_arith.all;
use std.textio.all;

entity sumador is
  port( clk : in  std_logic;
        a   : in  integer;
        b   : in  integer;
        c   : out integer
   );
end sumador;

architecture behaviour of sumador is
  signal c_out : integer := 0;
begin
  c <= c_out;
  process (clk)
    --synopsys translate off
    variable msg_line: line;
    --synopsys translate on
  begin
    if clk'event and clk='1' then
      if a=10 then
        --synopsys translate off
        write(msg_line, string'("Introduciendo error en la suma"));
        writeline(output, msg_line);
        --synopsys translate on
        c_out <= 5;
      else
        c_out <= a + b;
      end if;
    end if;
  end process;
end behaviour;

El componente software devuelve el resultado correcto de la suma de dos enteros.

suma_software.c

int sim_suma_software(int a,int b){
  return a+b;
}

Con el objetivo de poder utilizar la función software desde el código VHDL vamos a utilizar la función de GHDL VHPIDIRECT (un equivalente a los ficheros de cabecera en ansi C). Para ello se ha de definir un paquete:

sumaC.vhdl

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

package sumaC is
	function suma_software(a: integer; b: integer) return integer;

	function sim_suma_software(a: integer; b: integer) return integer;
	attribute foreign of sim_suma_software :
		function is "VHPIDIRECT sim_suma_software";
end package;

package body sumaC is
	function suma_software(a: integer; b: integer) return integer is begin
		return sim_suma_software(a,b);
	end suma_software;

	function sim_suma_software(a: integer; b: integer) return integer is begin
		assert false report "VHPI" severity failure;
	end sim_suma_software;
end package body;

Por último creamos el banco de prueba, encargado de aportar la señales de entrada a los componentes y comparar su salida.

sumador_tb.vhdl

library ieee;
use ieee.std_logic_1164.all;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use ieee.std_logic_arith.all;
use std.textio.all;
library work;
use work.sumaC.all;

entity sumador_tb is  end sumador_tb;

architecture behaviour of sumador_tb is
  signal clk : std_logic := '0';
  signal a   : integer := 0; -- Operando a
  signal b   : integer := 0; -- Operando b
  signal c_h : integer := 0; -- Suma hardware
  signal c_s : integer := 0; -- Suma software

  component sumador is
    port( clk : in  std_logic;
          a   : in  integer;
          b   : in  integer;
          c   : out integer
    );
  end component;

begin

  inst_sumador : sumador
    port map (
      clk => clk,
      a   => a,
      b   => b,
      c   => c_h
    );

  process
  begin
    wait for 10 ns;
    clk <= not clk;
  end process;

  process (clk)
    variable msg_line: line;
  begin
    if clk'event and clk='1' then
      a <= a + 1;
      b <= b + 1;
      c_s <= suma_software(a,b);

      if ( c_s /= c_h) then
        write(msg_line, string'("Error en la suma"));
        write(msg_line, string'("  -a: "));
        write(msg_line, a-1);
        write(msg_line, string'("  -b: "));
        write(msg_line, b-1);
        write(msg_line, string'("  -salida soft: "));
        write(msg_line, c_s);
        write(msg_line, string'("  -salida hard: "));
        write(msg_line, c_h);
        writeline(output, msg_line);
      end if;
    end if;
  end process;
end behaviour;

Compilación

Una vez que tenemos todos los ingredientes pasamos a la compilación. Para simplificar el proceso se aporta el siguiente Makefile:

VHDLFILES = sumador.vhdl sumaC.vhdl sumador_tb.vhdl
CSRCS = suma_software.c
DUTIES = sumador_tb
CFLAGS = -g -Wall

LDFLAGS = -Wl,-L. -Wl,-lmysim -Wl,-lpthread
OBJS = $(CSRCS:%.c=%.o)

all: $(DUTIES)

libmysim.a: $(OBJS)
	$(AR) ruv $@ $(OBJS)

work-obj93.cf: $(VHDLFILES)
	ghdl -a --ieee=synopsys  -fexplicit $(GHDLFLAGS) $(VHDLFILES)

sumador_tb : work-obj93.cf libmysim.a
	ghdl -e  --ieee=synopsys -fexplicit $(GHDLFLAGS) $(LDFLAGS) $@

clean:
	rm *.o *.cf *.a sumador_tb

Con un simple make obtendremos nuestro fichero binario sumador_tb que lo podremos ejecutar normalmente.

Ejecución

Una de las ventajas de GHDL es que permite crear fichero ejecutables que no requieren ningún simulador extra. Así que procedemos a ejecutar sumador_tb:

./sumador_tb
  Introduciendo error en la suma
  Error en la suma  -a: 10  -b: 10  -salida soft: 20  -salida hard: 5

Como se observa en el ejemplo, el programa se ejecuta y aparece como detecta el error introducido. Si además de la salida estandar se desea obtener el fichero de ondas, basta con ejecutar sumador_tb con la opción —vcd=onda.vcd. El resultado lo podremos observar con gtkwave onda.vcd.

Saludos.



blog comments powered by Disqus