Print
Category: DE0-NANO
Hits: 4212

Escrito por Fabio Andres


En este proyecto se utilizan las herramientas la De0-nano (FPGA, Procesador NIOS II, Memoria y pines) en conjunto con una pantalla touch para lograr la visualizacion de un fractal Mandelbrot, y lograr ver las ventajas que tiene poner Hardware en paralelo con Software para realizar procesos matemáticos complejos como los utilizados en la realización de fractales.
El procesador se programa en lenguaje C y la FPGA en el lenguaje de descripción de Hardware Verilog en Quartus II, se utilizan módulos realizados por el docente Holguer Becerra y librerias ya hechas con el fin de apoyar el diseño modular,  y optimizar tiempo y recursos.
 
El touch de la pantalla se utiliza para acercar y alejar la imagen sin necesidad de botones externos, con el fin de ver que mirando de cerca la imagen esta, está compuesta de la misma figura repetidamente, ademas tendra un boton para seleccionar una carga de imagen sin aceleración de hardware y otra implementando aceleracion de hardware para observar las diferencias de estos metodos.
 
Este proyecto esta basado en el capitulo 22  del libro de Pong Chu.
 
Los sources y el Software se puede encontrar en esta página.

 
Es importante saber que la base de este proyecto usa los conceptos aprendidos en las siguientes practicas:
5 de mayo de 2014
 
Documentación sobre los fractales de mandelbroot:

                           "Un fractal es un objeto semigeométrico cuya estructura básica, fragmentada o irregular, se repite a diferentes escalas."

Benoit Mandelbrot


-Definición: Los fractales de mandelbroot como todo fractal es un conjunto de figuras conformadas por sucesiones de figuras geométricas, en este caso sucesion por recursion.
                   Estos conjuntos deben su nombre al matemático  Benoit Mandelbrot y se definen así:

                 \left \{ \begin{matrix}   z_0     & = & 0 \qquad \ & \mbox{(término inicial)} \qquad  \\   z_{n+1} & = & z_n^2 + c  & \mbox{(relación de inducción)} \end{matrix} \right.
                  
                  donde C es un numero complejo, con condición de que este numero debe hacer la sucesion convergente para que pertenezca al conjunto del fractal.
                  
                 La conocida representación de este conjunto en el plano complejo es la siguiente:
                
                
 
                  Los fractales tienen actualmente un gran interes en varias ramas de la ciencia ya que estas figuras representan en parte el comportamiento de la naturaleza y es                          aplicable en la optimizacion de muchos procesos actuales.
 
 
- Código en Matlab para obtener un fractal:
 
 
            Código simple:
                
puntos=200;
puntosx=linspace(-2.1,0.9,puntos);
puntosy=linspace(-1.5,1.5,puntos);
[X,Y]=meshgrid(puntosx,puntosy);
C=X+Y*i;
Z=zeros(puntos);
iteraciones=20;
for k=1:iteraciones

Z=Z.^2+C;
W=exp(-abs(Z));
end
pcolor(W);

 

               Resultado:
                 

Código con gráfica mejorada:
 


col=20;
m=400;
cx=-.6;
cy=0;
l=1.5;
x=linspace(cx-l,cx+l,m);
y=linspace(cy-l,cy+l,m);
[X,Y]=meshgrid(x,y);
Z=zeros(m);
C=X+i*Y;
for k=1:col;
Z=Z.^2+C;
W=exp(-abs(Z));
end
colormap copper(256);
pcolor(W);
shading flat;
axis('square','equal','off');​

Resultado:

 
 
Conclusión: Se observó que a mayor cantidad de iteraciones es mejor el resultado pero se tarda mas la GPU en procesar los datos para elaborar la imagen,
cuando se llevo la cantidad de iteraciones a un número muy alto, el programa se bloqueo totalmente lo que demuestra que elaborar estas gráficas requieren 
bastante cantidad de procesamiento.
 
 
_______________________________________________________________________________________________________________________________________________________
 
                     
6 de mayo de 2014


¿ Cómo hacer Zoom en el fractal ?

El algoritmo mas facil de emplear, es hacer que en el display se muestren las coordenadas especificas dentro de un fractal, no expandiendo la imagen, por ejemplo si se tienen las coordenadas de las esquinas de la imagen como 1,1,-1,-1 y la gráfico en cierta resolución, ejemplo 800x600, y quiero hacerle zoom a la esquina superior izquierda, ahora debo visualizar las coordenadas 1,0.5,0.5,0.5 en la misma resolucion lo que dara como resultado hacerle un zoom a la imagen. Lo anterior nos demuestra que entre mas dentro vaya del fractal, las coordenadas deben ser mas exactas y con mas decimales por lo que va a requerir mas procesamiento de datos.


Un código que implementa esto en matlab es el siguiente:
clear all
figure(1); clf;

termination = 1000;
x = linspace(-2,1,640); % si se quiere hacer zoom se debe modificar el -2,1 y -1,1 que son los limites del gráfico.
y = linspace(-1,1,480);
x_index = 1:length(x) ;
y_index = 1:length(y) ;
img = zeros(length(y),length(x));


for k=x_index
    for j=y_index
        z = 0;
        n = 0;
        c = x(k)+ y(j)*i ;%complex number
        while (abs(z)<2 && n<termination)
            z = z^2 + c;
            n = n + 1;
        end
        img(j,k) = n;
    end
end

imagesc(img)
colormap(summer)
 
 

 


8 de mayo de 2014



Resultado zoom in matlab, y generación de fractal en C.


Resultado:

Se ejecuto el código descrito en el dia 6 de mayo y se obtuvieron los siguientes resultados en matlab:
 
 
 
GRÁFICA SIN ZOOM
 
 
 
 
GRÁFICA CON 
x = linspace(-1,1,640); 
y = linspace(-0-5,1,480);
GRÁFICA CON 
x = linspace(-0.2,0.5,640); y = linspace(-0.1,0.5,480);
 
 
 






Código fractal en C

A continuación se tiene un ejemplo de una sub-función que genera el fractal y lo proyecta en un display, este código fue suministrado por el Docente Ing.Holguer Becerra y se tratara de ir explicando que trata cada linea.
 
 
 
 
void generate_fractal(void){             // da nombre y tipo a la sub-función


    int XXX=800; //establece el ancho de la resolución de la pantalla
    int YYY=600; // establece el alto de la resolución de la pantalla
    float Maxx=1;             // Define 1 como el punto más a la derecha de la pantalla.
    float Minx=-1;            //  Define -1 como el punto más a la izquierda de la pantalla
    float Maxy=1;             //  Define 1 como el punto más arriba en la pantalla
    float Miny=-1;            //  Define -1 como el punto más abajo de la pantalla
    float initer=100;          // Establece el número de iteraciones de la funcion(Como en el código Matlab).

    float pixcorx=(Maxx-Minx)/XXX;            //  cada cuanto esta desplazado un pixel verticalmente, la respuesta es 2.5x10^-3 esto quiere decir que despues de -1 el siguiente es -1+2.5+10^-3
    float pixcory=(Maxy-Miny)/YYY;            //igualmente horizontalmente

    image1=create_surface(800,600); // 

    int j=0;

    do                                     //Start vertical loop

    {

        int i=0;

        do

        {

            float x=0;
            float y=0;s
            float xnew=0;
            float ynew=0;
            int k;

            for(k=0;k<=initer;k++)  // Se repite la función tanto, como el número de iteraciones
            {
             //The Mandelbrot Function Z=Z*Z+c into x and y parts   

             xnew=x*x-y*y + i*pixcorx+Minx;  // estableciendo direccion del punto vertical segun la funcion de mandelbroot vista anteriormente
             ynew=2*x*y   + Maxy-j*pixcory;  // estableciondo direccion del punto horizontal 
             x=xnew;
             y=ynew;
             if ( (x*x+y*y)>4 ){break; } // Criterio de permanencia en la función
            }

               int color = k;            // estableciendo color
               if (color>color/2){
                   color=color%0xffffff;
               }
               else{

               }
               if (k>=initer){

               }
               else{
                   set_pixel(i,j,colors[color%10],image1);  // envia las direcciones y el porcentaje de brillo del punto a dibujar.
               }

             i++;

        }while ( (i<XXX));  //Finaliza ciclo horizontal

        j++;

    }while ( (j<YYY));        //Finaliza ciclo vertical

}​
 

 

 
Nota: Esta sub-función en conjunto con otro código, generará el fractal mediante software (sin aceleración hardware) en el display cuando se seleccione el boton de mostrar sin aceleración hardware.
 
 
Conclusión gráfico Matlab: Se comprobó que el codigo funciona, ademas se observó que entre mas se hace zoom, mas se demora el computador en arrojar la gráfica, y que si se quiere mas detalle en el zoom es necesario hacer mas iteraciones por lo que esta acción (hacer zoom) requiere aun mas procesamiento que obtener la gráfica del fractal normalmente.
 
Conclusión código: Se afianza el concepto de que el número de iteraciones juega un papel muy importante en el código ya que de estas dependen la calidad y precisión del gráfico, pero esto tiene un costo en el consumo de recursos, que se va a poder mitigar en un futuro con ayuda de hardware.
 
 
 
______________________________________________________________________________________________________________________________________________________________________
 
 
10 de Mayo de 2014

Empezando con el capitulo 22 del libro EMBEDDED SoPC DESIGN WITH NIOS II PROCESSOR  AND VERILOG EXAMPLES de PONG CHU


En este capitulo CHU implementa el mismo algoritmo usando una rutina software y un acelerador de Hardware para generar un fractal, hacer zoom y visualizarlo en una pantalla con VGA.
 
 
Explicación del algoritmo:
 
 en algoritmo de CHU no se usa la ecuación matemática con números complejos:
 
Si no que hace una conversión de esta ecuación en coordenadas cartesianas de la siguiente manera:
 
 
Para determinar el valor de las constantes Cx y Cy no existe una fórmula para saberlo, y se necesitaría realizar un número infinito de iteraciones. Por ello en el algoritmo se usa una restricción, cuando alguno de los dos Xn y Yn sea mayor a cuatro se dirá que el punto no esta en el conjunto, y ello depende del número de iteraciones a realizar, ya que si por ejemplo se realizan 100 iteraciones y el numero es superior en la iteracion número 98, se dirá que el punto no esta en el conjunto, pero si se tiene con esos mismos valores 50 iteraciones se dirá que si esta en el conjunto ya que no alcanza a la iteracion número 98.
 
Sub-función Calc_frac_point:
 
 
 
    
calc_frac_point(cx, cy, max_itr){
    x = cx;
    y = cy;
    itr=0;
    do {
            xx = x * x;
            yy = y * y;
            xy = x * y;
            y = x2 - y2 + cx;
            x = xy*2 + cy;
            itr + + ;
          } while ((xx+yy)<4.0 && i t r < m a x _ i t r ) ;
    r e t u m (itr ) ;
    }​
 

 
Esquema de color:

Para hacer mas interesante la gráfica, se realizan escalas de color de acuerdo al resultado de la ecuación, si se tiene:
 
 Con M=max iteraciónes y n= al numero de return(itr)
 
El gráfico obtenido seria el siguiente:
 
 
Se pueden añadir mas colores para un mejor efecto del gráfico del fractal, por ejemplo:
 
 Donde K=número de colores soportados por la pantalla.
 
Y se obtendría un gráfico como el siguiente:
 
 
 
Generación de una imagen fractal


Para obtener la imagen en el display, es necesario, ademas de obtener los valores Cx y Cy ubicarlos en un plano y poner un color de acuerdo al numero de la iteración en el pixel indicado, la distancia entre cada pixel esta dado por:
 
 
Un código que genera esto puede ser el siguiente:
 
 
Cy = Cy0;
for(j=0; j<HPIX; j++){
    Cx = cxO;
    for(i=0; i<VPIX; i++){
        itr = calc_f rac_point (ex , cy, max_i.tr);
        color = assign.color(itr);
        display.pix (i, j, color);
       Cx = Cx + delta;
        }
cy = cy + delta;
}​
 
 

 
 
 
______________________________________________________________________________________________________________________________________________________________________
 

12 de mayo de 2014(Ya le envié un correo, corregir..)
 
implantación del código en NIOS II
 
Se harán uso de los drivers de VGA usados en el laboratorio cuatro de la materia para visualizar el fractal en el display, el main principal de todo el proyecto queda algo como lo siguiente:
 
 
sub-funcion para generar el color del pixel:
 
unsigned int colors[10]={GREEN_24,AQUAMARINE_16,BROWN_16,BLUEVIOLET_16,INDIGO_16, LEMONCHIFFON_16,OLIVE_16,SILVER_16, DIMGRAY_24,GOLD_24};
 
 
 
int color(iter,max_iter )
{
int p;
int color;

if(iter==max_iter)
{
color=0x0000;
}
else
{
p=iter%10;
color=p;

}


return(color);
}
 ​
 
 
 
 
sub-funcion para generar el fractal
 
 
 
 
int calc_frac_point(cx, cy, max_itr){
int xx;
int x;
int y;
int yy;
int xy;
int x2;
int y2;
int itr;

x = cx;
    y = cy;
    itr=0;
    do {
            xx = x * x;
            yy = y * y;
            xy = x * y;
            y = x2 - y2 + cx;
            x = xy*2 + cy;
            itr ++ ;
          } while ((xx +yy)< 4 && (itr<max _itr));
    return (itr) ;
    }​
 
 

 

programa principal:
 
 
 
int cy;
  int cy0;
  int cx0;
  int cx;
  int j;
  int i;
  int HPIX;
  int VPIX;
  int delta;
  int itr;
  int max_itr;

  int xn;
  int yn;
  // resolución de la pantalla
  HPIX=480;
  VPIX=272;
  delta=99;
  // Area de dibujo del fractal
  cx0=0;
  cy0=0;
  xn=480;
  yn=272;
  // cálculo de delta

  delta= xn-cx0/HPIX; // delta= 1




   while(1){

   cy = cy0;
   for(j=0; j<HPIX; j++){
   cx = cx0;
   for(i=0; i<VPIX; i++){
   itr = calc_frac_point (cx , cy, max_itr);
   color = color(itr,max_itr);
    vid_set_pixel(j,i,color,pReader);
   cx = cx + delta;
   }
   cy = cy + delta;
   }

   }
   return 0;
   }​
 
______________________________________________________________________________________________________________________________________________________________________
 
 
 
13 de mayo de 2014


Corrección del código del día de ayer y resultados.

El código mostrado en la fecha del 12 de mayo posee ciertos errores, como este código es sacado directamente del libro de PONG CHU, significa que en el libro se presentan estos mismos errores, por lo que se mandó un correo para que corrigieran dicho error.
 
El código corregido es el siguiente:
 
 
 
- Sub-función que cálcula el fractal:

 

int calc_frac_point(float cx, float cy, float max_itr){
float xx;
float x;
float y;
float yy;
float xy;
float x2;
float y2;
float itr;

x = cx;
    y = cy;
    itr=0;
    do {
            xx = x * x;
            yy = y * y;
            xy = x * y;
            x = xx - yy + cx;
            y = xy*2.0 + cy;
            itr ++ ;
          } while (xx+yy<4.0 && (itr<max_itr));
    return (itr) ;
    }
 


- Sub-función para obtener colores:


 
 
int assign_color(int iter,int max_iter )
{
int p;
int color;

if(iter==max_iter)
{
color=0x0000;
}
else
{
p=iter%10;
color=colors[p];

}


return(color);

}​
 
 
 
 
- Programa principal:
 

 
 
int main(){


//***** INICIALIZANDO DRIVERS ****//


// init Touch
int result;
int event=0;
int pos_x,pos_y;
alt_touchscreen touchscreen_global;


result=alt_touchscreen_init(
   &touchscreen_global,
   TOUCH_PANEL_SPI_BASE,
   TOUCH_PANEL_SPI_IRQ,
   TOUCH_PANEL_PENIRQ_N_BASE,
   60,
   ALT_TOUCHSCREEN_SWAP_XY);

if(result==0){
printf("Touch Inicializado\n");

alt_touchscreen_calibrate_upper_right (&touchscreen_global,
3975,   4032,    // ADC readings
 479,      0  ); // pixel coords
alt_touchscreen_calibrate_lower_left  (&touchscreen_global,
112,    110,     // ADC readings
  0,    271  );  // pixel coords
}
else{

printf("Touch Fallo\n");
return 0;
}

// init video

 VIP_FRAME_READER *pReader;

   ////////Se inicializa el HW del sistema//////////////
   // frame reader

   pReader =  VIPFR_Init(ALT_VIP_VFR_0_BASE, (void *)FR_FRAME_0, (void *)FR_FRAME_0, FRAME_WIDTH, FRAME_HEIGHT);

  // se activa el frame de video
   VIPFR_ActiveDrawFrame(pReader);



   // clean screen
   vid_clean_screen(pReader, BLACK_24);



   printf("Video Inicializado\n");


   //***** PROGRAMA PRINCIPAL ****//
  float cy;
  float cy0;
  float cx0;
  float cx;
  int j;
  int i;
  int HPIX;
  int VPIX;
  float deltax;
  float deltay;
  int itr;
  int max_itr;
  int color;
  float xn;
  float yn;
  // resolución de la pantalla
  HPIX=480;
  VPIX=272;
  // Area de dibujo del fractal
  cx0=-2;
  cy0=-1;
  xn=1;
  yn=1;
  // cálculo de delta

  deltax=(float)(xn-cx0)/(float)HPIX;
  deltay=(float)(yn-cy0)/(float)VPIX;
  max_itr=200;



    while(1){

cy = cy0;
for(j=0; j<VPIX; j++){
cx = cx0;
for(i=0; i<HPIX; i++){
itr = calc_frac_point (cx , cy, max_itr);
color = assign_color(itr,max_itr);
vid_set_pixel(i,j,color,pReader);
cx = cx + deltax;
}
cy = cy + deltay;
}
}


return 0;
}
​
 
 
 
 
RESULTADOS:


10 iteraciones:

 
100 iteraciones 
 
 
 
 
 
1000 iteraciones
 
 
 
 
 
vídeo que muestra los resultados finales:
 
 
 
 
 
______________________________________________________________________________________________________________________________________________________________________
 
15 de mayo de 2014

PASANDO DE FORMATO IEEE FLOTANTE A FORMATO q4.28.


El código mostrado anteriormente utiliza el formato estándar IEEE para manejar flotantes, se pasará ahora a utilizar a un nuevo format con el fin de optimizar recursos y hacer la implementacion de un acelerador de hardware mas fácil y una alternativa son los formatos de punto fijo.

Estos formatos constan de un entero y factor de escala que no varia, por ejemplo si se tiene cinco decimales y un factor de escala de 10^-3 el valor 12.345 puede ser representado como 12345*10^-3
el 10^-3 a diferencia del punto flotante no varia.

Estos tipos de notaciones se representan como de tipo Qm.f donde m es el número de dígitos enteros y f el factor de escala, el ejemplo anterior es de tipo Q2.3.

Para sumar o restar dos números de estos formatos solo hay que sumar o restar los números enteros y dejar el factor de escala intacto, produciendo el resultado en el mismo formato excepto cuando hay desbordamiento.
 
Para multiplicar números se multiplican los enteros y el factor de escala es el doble de los factores de escala, es decir un producto de dos Qm,f da como resultado en número en formato Q2m,2f si se quiere obtener el mismo formato, se debe hacer un recorte de los digitos mas o menos significativos aunque esto nos hace perder precisión que es la principal desventaja de este tipo de formatos.
 
Es importante escoger un rango de operaciones para que las operaciones no den desbordamiento.
 
Se observa que la principal ventaja de este formato es que se pueden usar las mismas operaciones de los números enteros con desplazamiento de números.
 
 
______________________________________________________________________________________________________________________________________________________________________
 
19 de mayo de 2014


Código implementando el sistema decimal  y resultados


Debido a que el lenguaje C no tiene soporte para tipo de datos de punto fijo, estos se deben manipular manualmente para su buen funcionamiento, como el NIOS II es de 32 bits, escojeremos este tamaño para el número de punto fijo, luego mirando el rango de datos en los ejes del fractal de mandelbrot que van de (-2,2) se selecciona el formato de punto fijo Q4.28  (cuatro bits enteros y 28 bits como fracción).
 
 
Explicación del formato Q 4.28:
 
En este formato los primeros 4 bits osea el primer nibble esta dedicado a representar el entero en complemento a dos, y los siguientes 28 bits o 7 nibbles a representar la fracción del número.
 
 
ejemplos:
 
1)
 por ejemplo si se quiere representar el número 2,5:
 
 
 
 
Se debe poner en el primer nibble el número dos que es 0010 y en la parte decimal el número 0,5, sabiendo que el peso de los números van a ser 2^-1-->2^-2-->2^-3, se debe poner el número ocho en binario 1000 ya que 1*2^-1=0,5. Reuniendo ambos componentes el número 2,5 en formado Q.4.28 es:
 
 
0010-1000-0000-0000-0000-0000-0000-0000
0x280000000 (en hexadecimal cada nibble binario representa un número que va de 0 a F)
2)
El número 1,7 tendria:
 
parte entera--> 0001
 
parte decimal ---> una aproximación cercana puede ser 1011001 que representa 0,6953125 si se múltiplica por su respectivo peso como se explico anteriormente.
 
Reuniendo 1,7 en fomato Q 4.28 es
 
 
0001-1011-0010-0000-0000-0000-0000
0x1B200000​
 
3)
El número -7.5
 
Parte entera debe usarse con complemento a dos es decir se niega el número 7 y luego se suma uno:
 
  7--> 0111--> 1000+1---> 1001
 
La parte decimal es la mima que la del primer ejemplo, por lo que se tiene que -7,5 en Q 4.28 es:
 
 
1001-1000-0000-0000-0000-0000-0000-0000
0x98000000

4) 
El número 5.025

Parte entera--> 0101
 
Parte decimal --> sabiendo que 2^-2=0.25 se tiene el número 0100
 
en formato Q 4.28
 
 
0101-0100-0000-0000-0000-0000-0000-0000
0x54000000
                                                                                                                                                                                         
 
La implementación de este formato en el código anteriormente descrito se muestra a continuación (sacado del libro de PONG CHU):
 
 
int calc_frac_point_soft( fixed428 cx, fixed428 cy, alt_ul6 max_i.tr)
{
    fixed428 x, y, xx, yy, xy2;
    fixed856 xx_raw, yy.raw, xy.raw;
    int itr;
    x = cx;
    y = cy;
    itr=0;
    do {
            /* Q4.Z8 multiplications */

                xx_raw= (fixed856)(x) * (fixed856)(x);

                xx = (fixed428)(xx_raw » 28);

                yy_raw = (fixed856)(y) * (fixed856)(y);

                yy = (fixed428)(yy_raw >> 28);

                xy_raw=. (fixed856)(x) * (fixed856)(y);

                xy2 = (fixed428)(xy_raw » 27); // 2* is same as «1

                /* iteration equation */

                x = xx - yy + cx;

                y =  xy2 + cy;
        
                itr++;
        
                } while (((xx+yy)<0x40000000) && ( itr < max_itr ) ) ;

       return(itr);
    
       }​

 

 
los codigos .c los encuentran aca:
 
codigo con float
 
Codigo con fixed
 
 
 
Resultados de mejoramiento de tiempo:


tiempo de NIOS IIf con punto flotante: 2 minutos 30 segundos es decir 150 segundos
 
tiempo de NIOS IIf con fixed point: 30 segundos
 
lo que quiere decir que el tiempo se optimizó cinco veces.
 
además de eso el dibujo se muestra mas detallado como se ve en las siguientes figuras:
 
 
punto flotante:
 
 
punto fijo:
 
 
 
 
_________________________________________________________________________________________________________________________________________________________________________
 
23 de mayo de 214

Implementación formato q8.56, en este tipo de formato la parte entera consta de 8 bits y la parte decimal de 56 bits
 
 
 
Conclusión: El sistema Nios II no posee la arquitectura suficiente para hacer este tipo de formato ya que la parte del código en el cual se usa el doble formato para guardar el cuadrado de la variable x no se puede obtener, se necesitaría declarar una variable de 128 bits y esto no es posible tocaria dividirla en dos variables.
 
Se trato de realizar usando el tipo long long pero al ir a la página de altera (ver tabla 1)  se observa que es de 8 bytes por lo tanto es insuficiente para las necesidades que se requiere.
 
Como conclusión se tiene que no se va a implementar este sistema debido a que la única manera de hacerlo es dividiendo los datos y hacer operaciones por partes, por lo que las operaciones en el código aumentarían y consigo el tiempo en que se demoraría en dibujar el fractal entonces este método no estaría optimizando el sistema, que es el objetivo del proyecto. 

 
 
Tabla 1 (fuente: http://www.altera.com/literature/hb/nios2/n2cpu_nii51016.pdf)
 
 
 
 EMPEZANDO IMPLEMENTACIÓN HW:

Despues de realizar el algoritmo para calcular el fractal en lenguaje C, implementarlo en HDL resulta fácil   mediante una maquina de estados finitos, el código HDL se muestra a continuación:
 
 
module Mandelbrot
    #(
        parameter W= 32, // width (# bits) of Qm. 
        parameter M= 4 // # of bits in m
    )
    (
        input wire clk, reset ,
        input wire start,
        input wire [W-1:0] cx, cy,
        input wire [15:0] max_it,
        output reg [15:0] iter,
        output reg idler
		  
    );

    // constant declaration
     localparam F = W - M; // # of bits in fraction

    // symbolic state declaration

    localparam [3:0] idle=4'b0001;
      localparam [3:0] load_data=4'b0010;
		localparam [3:0]  operation1= 4'b0011;
		localparam [3:0]  finish= 4'b0100;
		 localparam [3:0] resetea=   4'b0101;
		 localparam [3:0] finaliza=   4'b0110;
		 
		 localparam [3:0]  operation2= 4'b0111;
		 localparam [3:0]  operation3= 4'b1000;
		 localparam [3:0]  operation4= 4'b1001;
		 localparam [3:0]  operation5= 4'b1010;

		 
		  
		  
		  

    // signal declaration
    reg [3:0] state_reg, state_next;
    reg [15:0] it_reg , it_next;
    reg signed [2*W-1:0] xx_raw, yy_raw, xy_raw;
    reg signed [W-1:0] xx, yy, xy2;
    reg signed [W-1:0] x_reg, x_next, y_reg, y_next;
    reg signed [W-1:0] cx_reg, cx_next, cy_reg, cy_next;
	 wire	reset1;
    wire escape;
    reg frac_ready_i, frac_done;
	 reg reset_reg;
	 reg [31:0] suma;

     // body
    // FSMD state-data registers
    always@(posedge clk)
    begin
        if (reset)
            begin
                    state_reg <= idle;
                    it_reg <= 0;
                    x_reg <= 0;
                    y_reg <= 0;
                    cx_reg <= 0;
                    cy_reg <=0;
              end
        else
				begin
					case (state_reg[3:0])
					
					idle:											
							begin
							
							idler<=1'b1;
							
							if(start==1'b0)
								begin
									state_reg<=idle;
								end
							else
								begin								
									state_reg<=load_data;
								end
								
							end
							
					load_data:
							begin
							
							idler<=1'b0;
							
							x_reg<=cx; //x = cx;
							y_reg<=cy; //y = cy;				
							
							cx_reg<=cx; // nunca se modifican
							cy_reg<=cy; // nunca se modifican
							
							state_reg<=operation1; 
													
							end
					operation1: 
							begin
								state_reg<=operation2;  //while
								idler<=1'b0;
								xx_raw <= x_reg * x_reg; //   xx_raw= (fixed856)(x) * (fixed856)(x);	
							end
						
					operation2:
							begin
								state_reg<=operation3;  //while
								idler<=1'b0;
								xx<= xx_raw[2*W-1:28] ; //  xx = (fixed428)(xx_raw >> 28);
								yy_raw <= y_reg * y_reg; //   yy_raw = (fixed856)(y) * (fixed856)(y);
							end
					operation3:
							begin
								state_reg<=operation4;  //while
								idler<=1'b0;
								yy <=  yy_raw >> 28; //    yy = (fixed428)(yy_raw >> 28);
								xy_raw <= x_reg * y_reg; //  xy_raw=(fixed856)(x) * (fixed856)(y);
							end
					operation4:
							begin
							
								state_reg<=operation5;  //while
								idler<=1'b0;
								
								xy2 <= xy_raw >> 27 ; // xy2 = (fixed428)(xy_raw>>27); // 2* is same as «1															
							  x_reg<= xx-yy+ cx_reg;    //   x = xx - yy + cx; 
							  
							  suma<= xx+yy;
							  
							  end
		
					operation5:
							begin
							  y_next<=  xy2+cy_reg;  //     y =  xy2 + cy;
							  it_reg<=  it_reg +1;  //     itr++;
							  
							  if((suma<32'h40000000) && ( it_reg <  max_it )) //while (((xx+yy)<0x40000000) && ( itr < max_itr ) ) ;
								begin
								state_reg<=operation1;  //while
																		
								end
								else
								state_reg<=finish;
							
								
							end
			
					finish:
						 begin
						  idler<=0;
						  it_reg <= 0;
                    x_reg <= 0;
                    y_reg <= 0;
                    cx_reg <= 0;
                    cy_reg <=0;
						  iter<=it_reg; //return(itr);
						  state_reg<=idle;
						  end
						  
					default:
						begin
							state_reg<=idle;
						end
			endcase
			
			end
		end
		
		

			
endmodule
______________________________________________________________________________________________________________________________________________________________________
 
Explicación de la implementación del psx para mover el fractal:


Para mover el fractal de  derecha a izquierda y de arriba a abajo, el zoom in y el zoom out se hizo uso de un control de play station 2, los sources de la decidificacion y la explicación de como se hace se encuentra en el link: DE0 NANO PlayStation Controller Interface
 
 
En este proyecto se usaron los análogos del control, con el fin de tener algún control sobre la intensidad o velocidad de los movimientos; los controles analogos tienen como resultado en su parte digital dos vectores, uno para el movimiento arriba-abajo y el otro izquierda-derecha,  cada movimiento se representa mediante vectores de _____ bits, donde el cero es el número 124 y varia de acuerdo al movimiento, se usó este numero para multiplicarlo con los margenes del código del fractal en el NIOS II, ademas se utilizaron los botones up-down-left-right digitales para tener mas control de los movimineots y de esta manera tener movimientos bruscos o suaves como se explica a continuación en el siguiente código comentado:
 
 
 
while(1){

    analog1x=IORD( ANALOG1_X_BASE,0); // lee el vector de derecha-izquierda del análogo uno del control psx


    analog1y=IORD( ANALOG1_Y_BASE,0); // lee el vector de arriba a abajo del análogo uno del control psx

    analog2x=IORD( ANALOG2_X_BASE,0); // lee el vector de derecha-izquierda del análogo dos del control psx

    analog2y=IORD( ANALOG2_Y_BASE,0); // lee el vector de arriba a abajo del análogo dos del control psx

    if(IORD(BOTON_UP_BASE,0)==1){   // Si en el control se presiona el boton arriba, el número incd incrementa
    incd++;
    }
    else if(IORD(BOTON_DOWN_BASE,0)==1){  // Si en el control se presiona el boton abajo, el número incd decrementa
    incd--;
    }


  
    if(analog1y>128){  //  si se mueve el analogo1 hacia arriba los margenes del fractal aumentan en y  es decir la                                                      //   imagen se mueve hacia arriba con la sensibilidad dada por (analog1y/incd)
    cy0=cy0+(0x1<<(analog1y/incd));
    yn=yn+(0x1<<(analog1y/incd));

    draw++;

    }
    else if(analog1y<128){//  si se mueve el analogo1 hacia abajo los margenes del fractal disminuyen en y es decir                                                     //la    imagen se mueve hacia abajo con la sensibilidad dada por (analog1y/incd)
    cy0=cy0-(0x1<<((255-analog1y)/incd));
yn=yn-(0x1<<((255-analog1y)/incd));
draw++;
    }

    if(analog1x>128){//  si se mueve el analogo1 hacia la derecha los margenes del fractal aumentan en x es decir                                                     //la    imagen se mueve hacia la derecha con la sensibilidad dada por (analog1y/incd)
    cx0=cx0+(0x1<<(analog1x/incd));
    xn=xn+(0x1<<(analog1x/incd));
    draw++;

    }
    else if(analog1x<128){//  si se mueve el analogo1 hacia la izquierda los margenes del fractal disminuyen en x es decir                                                     //la    imagen se mueve hacia la izquierda con la sensibilidad dada por (analog1y/incd)
    cx0=cx0-(0x1<<((255-analog1x)/incd));
xn=xn-(0x1<<((255-analog1x)/incd));
draw++;
    }


    if(analog2y<128){ //  si se mueve el analogo2 hacia la arriba los margenes del fractal iniciales Cx0 y Cy0 aumentan y 
                                        // los finales disminuyen  esto tiene el efecto de alejar la imagen.

    cx0=cx0+((255-analog2y)<<2);
xn=xn-((255-analog2y)<<2);
cy0=cy0+((255-analog2y)<<2);
yn=yn-((255-analog2y)<<2);
draw++;
    }
    else if(analog2y>128){//  si se mueve el analogo2 hacia la abajo los margenes del fractal iniciales Cx0 y Cy0 disminuyen y 
                                        // los finales aumentan  esto tiene el efecto de acercar la imagen.
    cx0=cx0-(0x1<<((analog2y)/incd));
xn=xn+(0x1<<((analog2y)/incd));
cy0=cy0-(0x1<<((analog2y)/incd));
yn=yn+(0x1<<((analog2y)/incd));
draw++;
    }​
 
 
 
 
 
 
______________________________________________________________________________________________________________________________________________________________________
Sources:  Los sources se pueden encontrar en el link aqui
 
Gracias por su visita :)


Vídeo del resultado final: