EJERCICIOS DE SISTEMAS ELECTRÓNICOS DIGITALES: HOJA 1

Anuncio
EJERCICIOS DE SISTEMAS ELECTRÓNICOS DIGITALES: HOJA 1
2o CURSO DE INGENIERÍA TÉCNICA INDUSTRIAL.
ESPECIALIDAD EN ELECTRÓNICA INDUSTRIAL
LENGUAJES DE ALTO NIVEL
1.- Determina la funcionalidad del siguiente código VHDL.
LIBRARY ieee;
USE ieee.std_logic_1164.all;
ENTITY mux IS
PORT (
a,b,c,d: IN STD_LOGIC_VECTOR (2 DOWNTO 0);
seleccio: IN INTEGER RANGE 0 TO 3;
enable: IN STD_LOGIC;
e: OUT STD_LOGIC_VECTOR (2 DOWNTO 0));
END mux;
ARCHITECTURE comportament OF mux IS
BEGIN
PROCESS (a,b,seleccio,enable)
BEGIN
IF enable=’1’ THEN
CASE seleccio IS
WHEN 0 =>
e <= a;
WHEN 1=>
e <= b;
WHEN 2=>
e <= c;
WHEN 3=>
e <= d;
END CASE;
ELSE
e <= "ZZZ";
END IF;
END PROCESS;
END comportament;
2.- Describe el anterior código funcional en forma concurrente o RTL.
3.- Implementa en VHDL una unidad aritmética de forma que sobre dos palabras ‘a’ y ‘b’
de 4 bits realice las funciones suma, resta, incremento de ‘a’ en una unidad, y decremento
de ‘a’ una unidad en función de una variable de selección. Una vez implementada haz la
simulación con MAX+PLUS II
4.- Implementa en VHDL una unidad lógica de forma que sobre dos palabras ‘a’ y ‘b’ de 4
bits realice las funciones AND, OR, XOR y NOT ‘a’ en función de una variable de
selección. Una vez implementada haz la simulación con MAX+PLUS II
5.- Implementa una ALU de cuatro bits que realice las ocho funciones anteriores (a+b, a-b,
a+1, a-1, a AND b, a OR b, a XOR b, NOT a) en función de una variable de selección.
Realiza su simulación con el MAX+PLUSII.
6.- Indica la funcionalidad del siguiente código VHDL.
LIBRARY ieee;
USE ieee.std_logic_1164.all;
ENTITY entity IS
PORT
(
A
: IN STD_LOGIC;
B
: IN STD_LOGIC;
C
: OUT STD_LOGIC
);
END entity;
ARCHITECTURE arch OF entity IS
BEGIN
PROCESS (A, B)
BEGIN
IF A = '0' THEN
C <= 'Z';
ELSE
C <= B;
END IF;
END PROCESS;
END arch;
7.- Indica la funcionalidad
del siguiente código VHDL.
LIBRARY ieee;
USE ieee.std_logic_1164.all;
ENTITY ent IS
PORT
(
A
: IN INTEGER RANGE 0 TO N;
CLK
: IN STD_LOGIC;
CLR
: IN STD_LOGIC;
EN
: IN STD_LOGIC;
LD
: IN STD_LOGIC;
SORTIDA
: OUT INTEGER RANGE 0 TO N
);
END ent;
ARCHITECTURE arch OF ent IS
SIGNAL
S
: INTEGER RANGE 0 TO N;
BEGIN
PROCESS (CLK, CLR)
BEGIN
IF CLR = '0' THEN
S <= 0;
ELSIF (CLK’EVENT AND CLK = ’1’) THEN
IF LD = ’1’ THEN
S <= A;
ELSE
IF EN = ’1’ THEN
S <= S + 1;
ELSE
S <= S;
END IF;
END IF;
END IF;
END PROCESS;
SORTIDA <= S;
END arch;
8.- Analiza el diseño en VHDL de un procesador sencillo de 16 bits. El procesador es
capaz de ejecutar un número reducido de instrucciones que serán almacenadas en una
RAM (incorporada en una librería de altera). La descripción del circuito es funcional
y cada punto esta comentado detalladamente. El alumno ha de ser capaz de entender
cada línea de código del diseño e implementarlo en el programa MAX+PLUSII de
ALTERA. Así mismo ha de ser capaz de utilizar dicho código para incluirlo en un
diseño que realice las especificaciones que se indican:
a) El primer paso a realizar es la comprensión de cada línea de código que describe el
procesador (para eso consulta las anotaciones de VHDL impartidas en clase).
b) Una vez entendido el funcionamiento realiza un esquema de la arquitectura a nivel de
bloques y describe las instrucciones que hay pre-programadas así como su correspondiente
código de instrucción.
c) Implementa el programa de la RAM que hay indicado en el fichero .mif y compila el
diseño con el programa MAX+PLUSII. Realiza una simulación del funcionamiento del
procesador y calcula la frecuencia máxima a la cual puede operar. Finalmente calcula el
número de puertas lógicas que son usadas en la implementación del diseño a partir de los
resultados de la compilación (que son guardados en el fichero .rpt).
Código del Microprocesador sencillo en VHDL
A continuación detallamos el código VHDL del microprocesador.
-- Microprocesador sencillo
--Esta linea habilita la libreria IEEE, de la cual usamos los "package"
del std_logic_1164,
--IEEE.STD_LOGIC_ARITH y IEEE.STD_LOGIC_UNSIGNED, que me permiten operar
con variables del
--tipo standard_logic
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
-- Abrimos la libreria lpm, en la que tenemos distintos componentes de
libreria (ver ayuda
-- para conocer los distintos componentes que disponemos
LIBRARY lpm;
USE lpm.lpm_components.ALL;
--Definición de las entradas y las salidas del microprocesador
ENTITY microsencill IS
PORT(clock, reset :
IN STD_LOGIC;
register_input :
IN STD_LOGIC_VECTOR(7 DOWNTO 0);
register_output :
OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
program_counter_out :
OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
register_A_out, memory_data_register_out : OUT STD_LOGIC_VECTOR(15
DOWNTO 0));
END microsencill;
--Arquitectura interna del mircoprocesador, consta de una unidad de
control con
--descrita en modo comportamental y de una memoria RAM de la libreria lpm
ARCHITECTURE a OF microsencill IS
-- Definimos un tipo de variable STATE_TYPE que me indica los posibles
estados en los que
-- puede estar el microprocesador
TYPE STATE_TYPE IS (reset_pc, fetch, decode, execute_add, execute_load,
execute_store,
execute_store3, execute_store2, execute_jump, execute_jneg,
execute_sub, execute_xor, execute_or, execute_and, execute_jpos,
execute_jzero, execute_addi, execute_in, execute_out);
--Definición de señales, la variable state me indica el estado del
procesador
SIGNAL state : STATE_TYPE;
SIGNAL instruction_register, memory_data_register, register_A :
STD_LOGIC_VECTOR(15 DOWNTO 0);
SIGNAL program_counter, memory_address_register : STD_LOGIC_VECTOR(7
DOWNTO 0);
-- Si memory_write=1 entonces escribiremos en memoria, si memory_write=0
lo que hacemos es leer
SIGNAL memory_write : STD_LOGIC;
BEGIN
-- Usamos la memoria lpm_ram_dq (ver ayuda para descripción de esta
memória)
memory: lpm_ram_dq
GENERIC MAP (lpm_widthad => 8,
-- aqui definimos la longitud del bus de direcciones (8bits)
lpm_outdata => "UNREGISTERED",
lpm_indata => "REGISTERED",
lpm_address_control => "UNREGISTERED",
-- Definimos si el acceso, los datos de entrada y la salida son síncronos
o asíncronos,
-- como la salida la definimos como asíncrona no hace falta definir clock
de salida (clock_out),
-- (ver instrucciones de la ram en la ayuda)
-- El fichero "program6.mif" me introduce los datos del programa que
deseo me haga el procesador
lpm_file => "program6.mif",
lpm_width => 16)
-- lpm_width me indica la anchura del bus de datos (16 bits)
-- Definición de interconexión entre la memoria y las señales (que me
definen la conexión con
--la unidad de control
PORT MAP (data => Register_A, address => memory_address_register,
we => memory_write, inclock => clock,
q => memory_data_register);
-- Relación entre señales internas y la salida del micro (registre_A_out
me muestra el contenido
-- del acumulador, memory_data_register_out me muestra la salida de la
memoria, program_counter_out
-- indica el punto del programa en el que me encuentro
program_counter_out <= program_counter;
register_A_out <= register_A;
memory_data_register_out <= memory_data_register;
--A continuación detallo el comportamiento de la unidad de control
PROCESS (CLOCK, RESET)
BEGIN
IF reset = '1' THEN
state <= reset_pc;
-- La unidad de control me ejecuta una instruccion a partir de cada
flanco de subida.
ELSIF clock'EVENT AND clock = '1' THEN
CASE state IS
-- dependiendo del estado hacemos una u otra operación,
reset_pc me pone los registros a 0
WHEN reset_pc =>
program_counter <= "00000000";
memory_address_register <= "00000000";
register_A <= "0000000000000000";
memory_write <= '0';
state <= fetch;
-- El estado "fetch" es el estado de búsqueda de
instrucciones, carga la salida de la memoria
--al registro de instrucciones e incrementa el contador de
programa en 1
WHEN fetch =>
instruction_register <= memory_data_register;
program_counter <= program_counter + 1;
memory_write <= '0';
state <= decode;
-- Segidamente se pasaria al estado de decodificación
(fijaros que esto pasaría en el siguiente
-- ciclo de reloj.
WHEN decode =>
--Cargamos el contenido del registro de instrucciones
(últimos 8 bits)
-- en el registro de direcciones de la memoria (por si
se ha de hacer algún acceso
-- al decodificar luego una instrucción
memory_address_register <= instruction_register(7
Downto 0);
CASE instruction_register(15 downto 8) IS
WHEN "00000000" =>
-Cuando los 8 primeros bits del registro de
state <= execute_add;
-instrucciones son 0 ejecutamos la función add
WHEN "00000001" =>
-(suma acumulador a contenido memoria)
state <= execute_store;
-- Si el
"upcode" es 01 entonces función store
WHEN "00000010" =>
-(carga contenido del acc. en la memoria)
state <= execute_load;
-- Si el
"upcode" es 02 ejecuta función load
WHEN "00000011" =>
-Si el "upcode" es 03 ejecuta función jump
state <= execute_jump;
WHEN "00000100" =>
-Si el "upcode" es 04 ejecuta función jneg
state <= execute_jneg;
WHEN "00000101" =>
-Si el "upcode" es 05 ejecuta función sub
state <= execute_sub;
WHEN "00000110" =>
-Si el "upcode" es 06 ejecuta función xor
state <= execute_xor;
WHEN "00000111" =>
-Si el "upcode" es 07 ejecuta función or
state <= execute_or;
WHEN "00001000" =>
-Si el "upcode" es 08 ejecuta función and
state <= execute_and;
WHEN "00001001" =>
-Si el "upcode" es 09 ejecuta función jpos
state <= execute_jpos;
WHEN "00001010" =>
-Si el "upcode" es 0A ejecuta función jzero
state <= execute_jzero;
WHEN "00001011" =>
-Si el "upcode" es 0B ejecuta función addi
state <= execute_addi;
WHEN "00001100" =>
-Si el "upcode" es 0C ejecuta función in
state <= execute_in;
WHEN "00001101" =>
-Si el "upcode" es 0D ejecuta función out
state <= execute_out;
WHEN OTHERS =>
-Cualquier otro código pasa a búsqueda
state <= fetch;
END CASE;
-- Ejecuta la función add
WHEN execute_add =>
register_a <= register_a + memory_data_register;
memory_address_register <= program_counter;
state <= fetch;
-- Ejecuta la función store (en tres ciclos para escribir en
memória)
WHEN execute_store =>
-- write register_A to memory
memory_write <= '1';
state <= execute_store2;
-- Este estado se asegura que la dirección de la memoria es
válido hasta que acaba el ciclo
-- de escritura
WHEN execute_store2 =>
memory_write <= '0';
state <= execute_store3;
WHEN execute_store3 =>
memory_address_register <= program_counter;
state <= fetch;
-- Ejecuta la instrucción load en donde se carga el contenido
de la memoria
-- en el acumulador.
WHEN execute_load =>
register_a <= memory_data_register;
memory_address_register <= program_counter;
state <= fetch;
-- Ejecuta la instrucción JUMP incrementando el contador de
programa
-- hasta donde diga el registro de instrucciones
WHEN execute_jump =>
memory_address_register <= instruction_register(7
Downto 0);
program_counter <= instruction_register(7 Downto 0);
state <= fetch;
-- Ejecuta la instrucción JNEG (salta si el acumulador es
negativo)
WHEN execute_jneg =>
IF register_A(15) = '1' THEN
memory_address_register <= instruction_register(7
Downto 0);
program_counter <= instruction_register(7 Downto
0);
ELSE
memory_address_register <= program_counter;
END IF;
state <= fetch;
-- Ejecuta la función sub (resta del registro el contenido de
la memoria
WHEN execute_sub =>
register_a <= register_a - memory_data_register;
memory_address_register <= program_counter;
state <= fetch;
-- Ejecuta la función XOR
WHEN execute_xor =>
register_a <= register_a XOR memory_data_register;
memory_address_register <= program_counter;
state <= fetch;
-- Ejecuta la función OR
WHEN execute_or =>
register_a <= register_a OR memory_data_register;
memory_address_register <= program_counter;
state <= fetch;
-- Ejecuta la función AND
WHEN execute_and =>
register_a <= register_a AND memory_data_register;
memory_address_register <= program_counter;
state <= fetch;
-- Ejecuta la función jpos (salta si el acumulador es
positivo)
WHEN execute_jpos =>
IF register_A(15) = '0' THEN
IF NOT (register_A = "0000000000000000") THEN
memory_address_register <=
instruction_register(7 DOWNTO 0);
program_counter <= instruction_register(7
DOWNTO 0);
ELSE
memory_address_register <= program_counter;
END IF;
ELSE
memory_address_register <= program_counter;
END IF;
state <= fetch;
-- Ejecuta la función jzero (salta si el acumulador es cero)
WHEN execute_jzero =>
IF register_A = "0000000000000000" THEN
memory_address_register <= instruction_register(7
Downto 0);
program_counter <= instruction_register(7 Downto
0);
ELSE
memory_address_register <= program_counter;
END IF;
state <= fetch;
-- Ejecuta la función addi, suma al acumulador el
número inmediato
-- del registro de instrucciones
WHEN execute_addi =>
IF(instruction_register(7) = '1') THEN
register_a <= register_a+ ("11111111" &
instruction_register(7 DOWNTO 0));
ELSE
register_a <= register_a+ ("00000000" &
instruction_register(7 DOWNTO 0));
END IF;
memory_address_register <= program_counter;
state <= fetch;
-- Ejecuta la función in (carga en el acumulador el valor que
tenemos en la entrada
-- exterior
WHEN execute_in =>
register_a(7 DOWNTO 0) <= register_input;
memory_address_register <= program_counter;
state <= fetch;
-- Saca en el pin de salida el contenido del acumulador
(últimos 8 bits)
WHEN execute_out =>
register_output <= register_a(7 DOWNTO 0);
memory_address_register <= program_counter;
state <= fetch;
WHEN OTHERS =>
memory_address_register <= program_counter;
state <= fetch;
END CASE;
END IF;
END PROCESS;
END a;
Fichero de configuración de la memoria (.mif)
A continuación mostramos un ejemplo de fichero de configuración de la memoria que sirve
para programar la memoria RAM del microprocesador.
-- program6.mif
Depth = 256;
Width = 16;
Address_radix = HEX;
Data_radix = HEX;
Content
Begin
[00..FF]: 00000000; -- nop
00: 0C02; -- Entrada de un número
01: 0B01; -- Añade 1 a la entrada
02: 0D02; -- Pasa el resultado a la salida
03: 0300; -- Vuelve a empezar
End;
Descargar