miércoles, 20 de noviembre de 2013

Contador de "UNOS" de un registro de 8 bits con VHDL

Se trata de implementar un contador que detecte el número de bits en nivel alto presentes en un registro, para implementar con la FPGA de la tarjeta Digilent Basys 2.

Se hace uso del método de Máquina de Estado Algorítmico ASM.

El ejercicio se plantea y resuelve en el libro Fundamentos de Lógica Digital con diseño VHDL de Stephen Brown y Zvonko Vranesic.

Una máquina ASM dispone de una Unidad de Control y de un procesador de datos.

En el procesador de datos se dispone de un registro A que carga en paralelo los 8 bits Data y además puede desplazar los bits de izquierda a derecha (del más al menos significativo). Con la compuerta NOR de 8 entradas se detecta si A = 0, haciendo Z = 1 cuando ello ocurra. Si el bit menos significativo de A (A0 = 1), un contador B que inicia reseteado al cargar sus 8 bits en cero incrementa. Si Z = 1, quiere decir que A =0, y B indicará el número de "Unos" presentes en el registro A. Un led denominado "Done" indicará que ha finalizado el conteo de bits en nivel alto presentes en A.
El registro A  esquemáticamente es similar a la siguiente figura
 Si L = 1, se carga en los flip-flops los datos R, paralelamente, sin importar el enable E.
Si L = 0, y, E=1, hay corrimiento en este caso desde la entrada serial W a Q0, de Q0 a Q1, de Q1 a Q2, etc.
Si L=0, E=0, las salidas Q de los flip-flops no cambian
aunque se presente el flanco de subida del reloj.

La carta o diagrama ASM es tal como se muestra
S responde a un pulso de inicio (start) para que se inicie el proceso de conteo de los bits en nivel alto presentes en el registro A. Mientras S no sea 1 no comienza el conteo de bits.

La unidad de control sigue un diagrama similar a la carta ASM anterior
Si los enables EA y EB estan en nivel alto A desplaza y B incrementa, siempre y cuando las entradas de carga LA y LB esten en nivel bajo. Z=1 si el registro A tiene sus 8 bits en cero, y la bandera "Done" avisa que el conteo de "unos" ha finalizado.

El libro de Brown muestra el código VHDL para el contador de bits y la siguiente simulación realizada en Altera
Para que Xilinx sintetize el código VHDL del contador de bits completo hay que sintetizar previamente el registro A de desplazamiento a la derecha el cual debe ser empaquetado en la librería de Work para que el código de contador de bits lo pueda llamar y ejecutar.
Veamos el código VHDL del registro llamado reg_derecha  con su empaquetamiento:

--Registro de desplazamiento a la derecha,con carga ---paralela y enable (habilitación)

library IEEE; 
use IEEE.STD_LOGIC_1164.ALL;

entity reg_derecha is
    Port ( R : in  STD_LOGIC_VECTOR (7 downto 0);
           L,E,W : in  STD_LOGIC;
           Clock : in  STD_LOGIC;
               Q : buffer  STD_LOGIC_VECTOR (7 downto 0));
end reg_derecha;

architecture Behavioral of reg_derecha is

begin
  Process
  Begin
   wait until Clock'event and Clock = '1';
   If E = '1' then 
     If L = '1' then Q <= R;
     else
      For i IN 0 to 6 LOOP
      Q(i) <= Q(i+1);
      END LOOP;
      Q(7) <= W;
     END if;
   END if;
 END Process;
end Behavioral;

library IEEE; 
use IEEE.STD_LOGIC_1164.ALL;

PACKAGE reg_derecha_PACKAGE IS
 Component reg_derecha
   Port ( R : in  STD_LOGIC_VECTOR (7 downto 0);
           L,E,W : in  STD_LOGIC;
           Clock : in  STD_LOGIC;
               Q : buffer  STD_LOGIC_VECTOR (7 downto 0));
 END component;
END  reg_derecha_PACKAGE;

Chequeamos sintaxis y sintetizamos, y luego procedemos a elaborar el código VHDL del contador de bits completo así:

--Contador de UNOS para registro de 8 bits
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use work.reg_derecha_PACKAGE.all;

entity bitcount is
    Port ( Clock, Resetn : in  STD_LOGIC;
           LA, S : in  STD_LOGIC;
           Data :  in  STD_LOGIC_VECTOR (7 downto 0);
           B    :  BUFFER   INTEGER RANGE 0 TO 8;
           Done :  out  STD_LOGIC);
end bitcount;

architecture Behavioral of bitcount is
TYPE estado IS (S1,S2,S3);
SIGNAL y: estado;
SIGNAL A: STD_LOGIC_VECTOR (7 downto 0);
SIGNAL  Z,EA,LB,EB,LOW: STD_LOGIC;
begin

CONTROL: PROCESS(Clock, Resetn)
  BEGIN
    IF Resetn = '1' THEN y <= S1;
elsif (Clock'EVENT and Clock = '1') THEN
 CASE y is
  WHEN S1 =>
 if S = '0' then y <= S1; else y <= S2;
                  end if;
WHEN S2 =>
 if Z = '0' then y <= S2; else y <= S3; 
                  end if;
WHEN S3 =>
 if S = '1' then y <= S3; else y <= S1;
                  end if;  
End CASE;
  End if;
End Process;

SALIDAS: PROCESS(y,A(0))
begin
EA <= '0'; LB <= '0'; EB <= '0'; Done <= '0';
CASE y IS
  WHEN S1 => 
   LB <= '1'; 
WHEN S2 => 
   EA <= '1'; 
IF A(0) ='1' THEN EB <= '1'; else EB <= '0'; END IF;
WHEN S3 => 
   Done <= '1'; 
 END CASE;
END PROCESS;

upcount: PROCESS(Resetn, Clock)
begin
 if Resetn = '1' THEN
   B <= 0;
 ELSIF (Clock'EVENT and Clock = '1') THEN
   IF LB = '1' THEN B <= 0;
   ELSIF EB = '1' then B <= B + 1;
   END IF;
 END IF;
END PROCESS;

 LOW <= '0';
 SHIFTA:reg_derecha  
PORT MAP(Data,LA,EA,LOW,Clock,A);
 Z <= '1' when A ="00000000" else '0';

end Behavioral;

El código VHDL completo se sintetiza satisfactoriamente

Desde luego hay que adicionar el divisor de frecuencia de 50 Mhz a 1 hz para poder visualizar en la tarjeta Basys2.