Pasar de "C" a "Verilog"

Foro dedicado a la programación en todo tipo de sistemas clásicos.
jepalza

Pasar de "C" a "Verilog"

Mensajepor jepalza » 19 Feb 2013, 06:36

He encontrado un traductor de lenguaje "C" a "Lenguaje" ( :twisted: ) Verilog, con la pega de que no hay programa para descargar, sino que se hace desde su página, pero es un mal menor.
He probado a convertir una cosa compleja, como un emulador que tenía de hace años (mio propio) de una máquina arcade, y se vuelve loco (quizás depurando lo haga mejor), pero para convertir cosas sencillas, como ua rutina de lectura desde una SD, es suficiente.

Se puede probar AQUI

Para los "puristas" , decir que Verilog es un Lenguaje, es un sacrilegio , pero actualmente, está dividido el tema de como se llama a esto del Verilog. Casualmente, buscando info, dí con una página en la que se discutía sobre la forma de llamar a esto del verilog, y la cosa, quedó en que cada uno lo llama como quiera, con tal de que el resultado se entienda. Unos decían que era programar, y otros sintetizar/diseñar. Para mi sigue siendo programar, aunque sea a nivel electrónico y no de programa.

Avatar de Usuario
DistWave
Atari 1040 STf
Atari 1040 STf
Mensajes: 750
Registrado: 15 Ene 2011, 09:08
Sistema Favorito: PC
primer_sistema: PC
consola_favorita: Nintendo SNES
Primera consola: Atari 2600
Ubicación: Zaragoza
Gracias dadas: 3 veces
Gracias recibidas: 58 veces

Re: Pasar de "C" a "Verilog"

Mensajepor DistWave » 19 Feb 2013, 09:52

Como programador que soy, no entiendo ni el propósito ni el funcionamiento de ese "traductor"... :?

Cuando programas a bajo nivel, diseñas algoritmos que son interpretados por una CPU. Esa CPU está bien definida, tiene sus registros, operaciones, modos de direccionamiento, etc que debes conocer a la perfección para poder utilizarlos correctamente. Conforme vas "subiendo de nivel" esta información deja de ser necesaria porque es abstraída por el compilador/interprete y se reduce a unas rutinas genéricas, llegando a casos extremos como los frameworks web modernos tipo Rails, que te generan en tiempo de ejecución la mitad de las funciones que utilizas.

En cambio cuando diseñas un circuito, lo que haces es conectar puertas lógicas. Es cierto que combinando puertas lógicas terminas por construir una función lógica y asignando variables de entrada y salida puede asemejarse a un algoritmo por su comportamiento. Pero de ahí a coger una aplicación en C y convertirla en un circuito... magia negra!

Avatar de Usuario
jotego
Atari 1040 STf
Atari 1040 STf
Mensajes: 657
Registrado: 16 Ene 2013, 23:25
Sistema Favorito: Atari ST
primer_sistema: Amstrad CPC
consola_favorita: Sony PlayStation 2
Primera consola: Atari Lynx
Ubicación: Valencia (España)
Gracias dadas: 27 veces
Gracias recibidas: 44 veces
Contactar:

Re: Pasar de "C" a "Verilog"

Mensajepor jotego » 19 Feb 2013, 10:59

Verilog tiene una vertiente de modelado y simulación para la que el conversor podría funcionar bien.

Avatar de Usuario
mcleod_ideafix
Amiga 2500
Amiga 2500
Mensajes: 5316
Registrado: 06 Oct 2009, 04:12
Sistema Favorito: Spectrum 16Kb/48Kb
primer_sistema: Spectrum 16Kb/48Kb
consola_favorita: Vectrex
Primera consola: TV Games/Pong Clone
Ubicación: Jerez de la Frontera
Gracias dadas: 12 veces
Gracias recibidas: 54 veces
Contactar:

Re: Pasar de "C" a "Verilog"

Mensajepor mcleod_ideafix » 19 Feb 2013, 14:18

A ver, que esto ya toca el tema de mi tesis, así que algo puedo aportar.

Primero: Verilog sí es un lenguaje. Jepalza, ¿qué purista dice que no lo es? Si la cosa va por mi, te r epito que lo que yo digo es que Verilog no es un lenguaje para programar, sino uno lenguaje para describir. Se enmarca en eso que llamamos HDL (Hardware Language Description).
Segundo: sobre qué sentido tiene un traductor de C a Verilog.... pues lo tiene. De hecho no es el único tipo de traducción que hay. También existen traductores de Python a VHDL/Verilog. Estos traductores son basicamente de dos tipos:

- Traductores que cogen una descripción hecha en C y la pasan a VHDL/Verilog. Esto es, se define un subconjunto del lenguaje C suficiente para que permita describir hardware, y se usa para eso, para describir hardware. El traductor coge esa descripción y la convierte en otra equivalente en VHDL/Verilog, porque son esos lenguajes los que entiende el sintetizador. Estos traductores están pensados para que el ingeniero que viene del mundo C pueda introducirse mejor en esto de la descripción de hardware ya que estarán acostumbrados a expresar comportamiento usando la sintaxis del C. Dado que Verilog en concreto se parece un poco a C, las descripciones que se hagan en C quedarán muy similares en Verilog. Algo así:

Código: Seleccionar todo

char Multiplexor (bit s, char a, char b)
{
  if (!s)
    return a;
  else
    return b;
}


Que se convierte en:

Código: Seleccionar todo

module Multiplexor (
  input s,
  input[7:0] a,
  input[7:0] b,
  output reg [7:0] returnvalue
);
  always @(*) begin
    if (!s)
      returnvalue = a;
    else
      returnvalue = b;
  end
endmodule


- Traductores que cogen un código C (o cualquier otro lenguaje de programación) en el que se expresa un programa, un algoritmo, y traducen ese algoritmo (ya no es un subconjunto de C) a una descripción de un hardware que implementa ese algoritmo.
Esto es precisamente una de las cosas que estoy haciendo para la tesis. Consiste en que tú puedas escribir un programa que haga "algo" (que ejecute un algoritmo) y eso que has escrito, convertirlo a una pieza de hardware que realiza la misma función. Es la base de lo que se denomina "codiseño" que consiste en dado un programa de ordenador, y dado un sistema que contiene un procesador convencional y una FPGA, el ingeniero (o el compilador) elige qué partes del programa se ejecutan en el procesador, y qué partes se convierten en módulos hardware (se dice que "se ejecutan en silicio"). El código sintetizable generado de esta forma suele ser una máquina de estados finita que implementa los pasos del algoritmo. Algo así:

Código: Seleccionar todo

short Checksum (char v[1024])
{
  short suma=0;
  short i;
  for (i=0;i<1024;i++)
    suma = suma + v[i];
  return suma;
}

Esta sencilla función realiza un checksum de un bloque de memoria de 1024 bytes (por ejemplo, con vistas a comprobar que el bloque es correcto). Si se está en un ambiente de codiseño y este módulo se requiere que funcione a muy alta velocidad, o se requiere que funcione de forma simultánea en varios flujos de datos, el compilador puede optar a convertirlo en un módulo hardware, que se comunicaría con el procesador bien por puertos de E/S, o bien en forma de nuevas instrucciones añadidas al procesador. En Verilog, el módulo podría quedar más o menos así (según el traductor que estoy haciendo ;) )

Código: Seleccionar todo

module Checksum (
  input clk,  // reloj del FSM
  input startf,  // señal para comenzar la funcion
  output reg endf,  // señal que indica que el valor de retorno es valido
  output reg[9:0] addr_v, // bus de direcciones para V
  output reg read_v,  // señal de lectura para V
  input[7:0] datain_v, // dato de entrada de V
  output reg[15:0] returnvalue   // valor de retorno
);
  reg [15:0] i;      // indice del bucle
  reg [15:0] suma;   // checksum
  reg estado_fsm;    // estado del autómata

  initial begin
    suma = 0;
    estado_fsm = 0;
    endf = 0;
    read_v = 0;
  end

  always @(posedge clk) begin
    case (estado_fsm)
      0 : begin
            if (startf)       // solo pasamos de estado si pedimos que comience
              estado_fsm <= 1;
              endf <= 0;
              i <= 0;         // inicializacion del FOR
          end
      1 : begin
            if (i==1024)     // condicion de parada del FOR
              estado <= 4
            else
              estado <= 2;
          end
      2 : begin
            addr_v <= i[9:0];  // preparamos a la memoria para
            read_v <= 1;       // ser leida en la direccion i
            estado_fsm <= 3;
          end
      3 : begin
            suma <= suma + {8{datain_v[7]},datain_v};  // leemos memoria y
            read_v <= 0;  // sumamos su contenido, extendido en signo, a "suma"
            i <= i + 1;         // siguiente vuelta del FOR
            estado_fsm <= 1;    // vamos a ella
         end
     4 : begin
           returnvalue <= suma;  // actualizamos salida del circuito
           endf <= 1;    // señalamos que la salida es correcta
           if (!startf)     // handshake: solo salimos de aqui cuando
             estado <= 0;   // no esté activa startf
        end
    endcase
  end
endmodule

Esto que se ve aquí es una descripción de un FSM que a su vez ejecuta el equivalente al código C que hace el checksum. Como "pieza hardware" que es, puede replicarse tantas veces como quepa en la FPGA para realizar checksums en paralelo (en bloques de memoria distintos, claro), o bien se puede usar como una función para hacer checksum muy rápida: el cuerpo del bucle FOR está implementado en tres estados del FSM, y estos estados se suceden 1024 veces, más el estado inicial y final, pues nos dan: 1+1+1024*3=3074 ciclos de reloj para esta implementación.

A modo de comparación, he escrito la misma rutina en lenguaje ensamblador del Z80 (no es precisamente un ARM ni va a 1GHz, pero a efectos de comparación vale). La rutina (seguramente mejorable) es ésta:

Código: Seleccionar todo

V               equ 0 ;por ponerlo en algun sitio...

Start           ld ix,V      ; Vector V
                ld hl,0      ; el checksum
                ld bc,1024

VueltaBucle     ld e,(ix+0)  ; Leemos valor del vector
                ld a,e       ;
                rlca         ; Extensión de signo
                sbc a,a      ;
                ld d,a       ;
                add hl,de    ; sumamos a checksum
                inc hl
                dec bc
                ld a,b
                or c
                jr nz,VueltaBucle
           ret

Este algoritmo tarda 34 ciclos en la inicialización (las tres instrucciones desde Start). El bucle da 1024 vueltas, de las cuales 1023 tardan lo mismo (78 ciclos). La última vuelta tarda un poco menos porque el salto condicional, cuando no se cumple, usa menos ciclos (7 en lugar de 12), así que esta última vuelta tarda 73 ciclos. El total de ciclos consumidos es de 34+1023*78+73=79901.

Esto es, la implementación hardware del algoritmo tarda 3074 ciclos de reloj frente a los 79901 que tarda la versión para procesador. Es decir, la versión hardware es casi casi 26 veces más rápida (usando la misma frecuencia de reloj) que la versión del Z80.

Si alguien piensa que comparar una FPGA con un humilde Z80 es una comparación injusta, allá va el mismo código escrito para x86 (IA32) subconjunto RISC:

Código: Seleccionar todo

Start                    mov esi,V
                         mov ecx,0
                         mov edx,0

BucleChecksum            movsx eax,byte ptr [esi+ecx]
                         add edx,eax
                         inc ecx
                         cmp ecx,1024
                         jnz BucleChecksum

                         ret

Voy a suponer que todas las instrucciones duran 1 ciclo de reloj, lo cual no es en absoluto cierto. De hecho ni siquiera el pipeline aquí puede comenzar una nueva instrucción en el siguiente ciclo de reloj porque hay dependencia real entre muchas de ellas dentro del bucle. Probablemente pueda haber bypass entre INC y CMP, pero definitivamente ADD tendrá que esperar a que MOVSX termine de leer la memoria.

Aun con esta simplificación, el algoritmo tarda 3+1024*5 = 5123 ciclos de reloj , 1.66 veces más lento (a la misma frecuencia de reloj) que la implementación en silicio.

PD: mi traductor no optimiza la FSM generada... si la hiciera a mano, podría meter el contenido del estado 2 en una de las ramas del IF del estado 1, con lo que tendría no 3 ciclos por vuelta, sino 2, aumentando dramáticamente la velocidad de ejecución en silicio, que pasaría de 3074 ciclos a 1+1+2*1024=2050 ciclos. Los números anteriores se transforman en: casi 39 veces más rápido el FSM que el Z80, y 2.5 veces más lento el x86 que el FSM.
Recuerda: cada vez que se implementa un sistema clásico en FPGA, Dios mata a un purista

jepalza

Re: Pasar de "C" a "Verilog"

Mensajepor jepalza » 19 Feb 2013, 14:20

A mi forma de entender, sirve para no "programar" en Verilog, en caso de hacerse engorroso. Por ejemplo, un simple "flip-flop", si eres conocedor del C lo haces en un plis-plas. Si no tienes conocimientos de Verilog, tardas mas.

Para algo servirá ese traductor, cuando existen versiones comerciales que vale 1000€, para pasar de C a Verilog. Algo tendrá de bueno. (esa que comento, es gratuíta)

Avatar de Usuario
mcleod_ideafix
Amiga 2500
Amiga 2500
Mensajes: 5316
Registrado: 06 Oct 2009, 04:12
Sistema Favorito: Spectrum 16Kb/48Kb
primer_sistema: Spectrum 16Kb/48Kb
consola_favorita: Vectrex
Primera consola: TV Games/Pong Clone
Ubicación: Jerez de la Frontera
Gracias dadas: 12 veces
Gracias recibidas: 54 veces
Contactar:

Re: Pasar de "C" a "Verilog"

Mensajepor mcleod_ideafix » 19 Feb 2013, 15:01

jepalza escribió:Para algo servirá ese traductor, cuando existen versiones comerciales que vale 1000€, para pasar de C a Verilog. Algo tendrá de bueno. (esa que comento, es gratuíta)

El que has encontrado pertenece al segundo tipo de traductores que he explicado, los que pueden coger un algoritmo y convertirlo a una máquina de estados. Cuando empecé en esto, fue el primero que encontré :D
Xilinx incorpora ahora, en su ISE versión "cañera", algo parecido, pero sólamente vale para trabajar con Virtex.

Si usas la función Checksum de mi ejemplo con el traductor que has encontrado, verás que genera un código en el que puedes encontrar esto:

Código: Seleccionar todo

// Control
case (eip)
entry0:
begin
   eip <= entry1;
end
entry1:
begin
   mem_v_mode0 <= 0;
   mem_v_addr0 <= (p_v + (i_incrementVal));
   eip <= entry2;
end
entry2:
begin
   i_tmp6____1___ <= mem_v_out0;
   eip <= entry3;
end
entry3:
begin
   eip <= entry4;
end
...
...


Este traductor llama "eip" al estado del autómata. Es un nombre curioso, ya que está sugiriendo que efectivamente, cada estado del autómata es una instrucción a ejecutar, y "eip" sería el índice a dicha instrucción (para los que no lo sepan, EIP es el nombre del registro de puntero de instrucciones del x86). Por lo que leo, parece ser que la variable "i" del código original se ha transformado en "mem_v_addr0". El FSM que ha generado es incluso peor que el mío (hay estados que no hacen nada, con lambda-transiciones y ya está).
Recuerda: cada vez que se implementa un sistema clásico en FPGA, Dios mata a un purista

jepalza

Re: Pasar de "C" a "Verilog"

Mensajepor jepalza » 19 Feb 2013, 18:06

Acabo de hacer unas pruebillas con el conversor. Sale un poco enrevesado, y no me gusta que meta "____" a patadas, pero bueno, hace su función.

Por la semi-coña de lo de "programación" ,no iba por ti, era en plan genérico, de broma. Y como ya he comentado, encontré un hilo en inglés, en el que quedaba empate el tema de si llamarlo programar o sintetizar/diseñar. Mientras cada uno lo entienda, ya vale.

Si no sería complicado, me haría un conversor de Basic a Verilog. Cosas mas raras he hecho, y no sería esta la mas rara.

Avatar de Usuario
Joss
Atari 1040 STf
Atari 1040 STf
Mensajes: 930
Registrado: 17 Jul 2012, 20:07
Gracias dadas: 14 veces
Gracias recibidas: 2 veces

Re: Pasar de "C" a "Verilog"

Mensajepor Joss » 19 Feb 2013, 22:53

Está bien la página. Para aprender Verilog puede venir muy bien. Te tecleas ejemplos sencillos en C y miras como se haría en Verilog.

Avatar de Usuario
javu61
Atari 1040 STf
Atari 1040 STf
Mensajes: 981
Registrado: 08 Abr 2010, 21:30
Sistema Favorito: Spectrum 16Kb/48Kb
primer_sistema: Spectrum 16Kb/48Kb
consola_favorita: Nintendo SNES
Primera consola: TV Games/Pong Clone
Gracias recibidas: 3 veces

Re: Pasar de "C" a "Verilog"

Mensajepor javu61 » 20 Feb 2013, 09:12

Hola:

Los lenguajes HDL (Hardware Description Languaje) de descripción de circuitos no se comportan como los lenguajes de programación convencionales, y el principal ejemplo es que las variables son señales y no posiciones de memoria, todo se ejecuta simultáneamente como se hace en el hard, no siguiendo los pasos de un programa convencional. El típico ejemplo es este:

c <= 1
a <= c
c <= 0
b <= c

En un lenguaje convencional "a" valdría 1 y "b" valdría 0, pero en un HDL, como todo se ejecuta a la vez, "a" y "b" valdrán 0, ya que no son variables que se refieren a posiciones de memoria, sino que son señales eléctricas, al cambiar una cambian todas a la vez.

Ante esto, pretender pasar de C a Verilog de forma sencilla no es posible, solo se usa la misma sintaxis como hace el Java, pero el concepto es muy diferente. Por eso yo prefiero usar VHDL, ya que la sintaxis es la del ADA y así no me lio tanto, y cuesta lo mismo de aprender que cualquier otro lenguaje HDL. Los tres mas usados son VHDL, Verilog y ABEL, aunque este es un poco mas reducido de funcionalidades.

Saludos
Imagen
old8bits.blogspot.com __ Va-de-retro.com __ Mis películas en webs.ono.com/javu61

Avatar de Usuario
mcleod_ideafix
Amiga 2500
Amiga 2500
Mensajes: 5316
Registrado: 06 Oct 2009, 04:12
Sistema Favorito: Spectrum 16Kb/48Kb
primer_sistema: Spectrum 16Kb/48Kb
consola_favorita: Vectrex
Primera consola: TV Games/Pong Clone
Ubicación: Jerez de la Frontera
Gracias dadas: 12 veces
Gracias recibidas: 54 veces
Contactar:

Re: Pasar de "C" a "Verilog"

Mensajepor mcleod_ideafix » 20 Feb 2013, 13:16

javu61 escribió:El típico ejemplo es este:

c <= 1
a <= c
c <= 0
b <= c

En un lenguaje convencional "a" valdría 1 y "b" valdría 0, pero en un HDL, como todo se ejecuta a la vez, "a" y "b" valdrán 0, ya que no son variables que se refieren a posiciones de memoria, sino que son señales eléctricas, al cambiar una cambian todas a la vez.

En este ejemplo, si estamos hablando de Verilog, a y b tendrán como valor lo que valiera c en el instante antes de producirse estas asignaciones. Si c no tiene valor definido, los valores de a y b serían "X" (no definido). Por otra parte, en el mismo instante de tiempo se intenta asignar 0 y 1 a c. No sé si lo permitiría Verilog, pero de hacerlo, lo más probable es que en este caso se mantenga la última asignación escrita en orden.

Estas cuatro líneas (tres en realidad porque quedaría sólo el c <= 0) se corresponden en realidad al siguiente circuito:
asignacion_registros.png
asignacion_registros.png (17.01 KiB) Visto 11060 veces


En el que se ve que lo que valen a y b es lo que valiera inicialmente c (cosa que no sabemos).

Si a,b,c son señales y no registros, entonces en Verilog lo que tienes son asignaciones continuas, tal que así:

Código: Seleccionar todo

assign c = 1;
assign a = c;
assign c = 0;  /* ERROR! O se asigna 1 o 0, pero no ambas cosas a la vez */
assign b = c;


Y si lo que se queda es que c vale 1, entonces automaticamente a y b valen 1 (en cualquier caso, serían cables conectados a la señal c)
Recuerda: cada vez que se implementa un sistema clásico en FPGA, Dios mata a un purista


Volver a “Programación”

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 2 invitados