Descripción Comportamental del Microcontrolador 8051 mediante Lenguaje VHDL
Los modelos más populares de microcontroladores de INTEL son los 8XX1 y más concretamente los 80X51, que han dado nombre a la familia. El 8051 es un microcontrolador cuyas características generales son:
CPU de 8 bits.
Procesador booleano (operación sobre bits).
4 puertos de 8 bits con pines bidireccionables.
128 bytes de memoria interna útiles para el usuario y 256 bytes incluyendo los registros especiales (SFR) en el caso del 8051.
4KB de ROM o EPROM.
Espacio de memoria de 64 KB para programa externo.
Espacio de memoria de 64 KB para datos externos.
Contiene 2 contadores-temporizadores.
Comunicación asíncrona full-duplex.
5 fuentes de interrupción con niveles de prioridad.
Este dispositivo puede ser empleado propiamente como microcontrolador o como microprocesador.[[1]]
Un diagramas a bloques de este dispositivo es mostrado en la Figura 1. Es posible observar que el 8051 cuenta con una CPU, un oscilador, un control de interrupción, su correspondiente control de bus, cuatro puertos con pines bidireccionales individualmente, memoria RAM, memoria ROM, dos Timers, y una UART. Los espacios de dirección separados para la memoria de datos y para la memoria de programas permiten que la memoria interna de datos sea direccionable con solo 8 bits.
La memoria de programa (ROM o EPROM) solamente puede ser leída pero no es posible escribir en ella. Esta memoria puede tener hasta un total de 64 KB repartidos entre la memoria interna y la memoria externa. En el caso particular del 80C51, este cuenta con 4 kB de memoria de programa on-chip. En cuanto a este aspecto, el diseño que se propone no tiene mas limitante que los 64 KB para implementar una memoria on-chip de esa capacidad; además, presenta la ventaja de emplear únicamente la cantidad de memoria requerida por el programa del cliente. Así, por ejemplo, si el programa desarrollado consta de 500 bytes, entonces solamente se declararían 500 localidades de memoria para el programa.
La memoria de datos ocupa un espacio diferente al de la memoria de programas. En algunas series de la familia 8051, los 128 bytes mas bajos de la memoria de datos son on-chip. De nuevo, la ventaja de realizar el diseño del 8051 mediante el empleo de lenguaje VHDL es la posibilidad de definir la cantidad de memoria de datos on-chip de acuerdo con las necesidades de programación. Es decir, es posible declarar una memoria de datos mas pequeña y así ahorrar espacio o, por el contrario, implementar una memoria de datos con una mayor cantidad de bytes (con las adecuadas correcciones al acceso de la máxima dirección de memoria interna de datos).
La figura 2 muestra la arquitectura que se va a implementar en este trabajo.
El objetivo del trabajo presentado es lograr la descripción completa del comportamiento de un dispositivo 8051 mediante el lenguaje VHDL, y en base a esta descripción lograr su implementación (síntesis) en dispositivos programables tales como FPGAs o PLCs. Es decir, obtener un replica exacta del 8051 en cuanto a funcionamiento y lo más cercanamente s su arquitectura.
Bloque ROM
Dado que vamos a emular el 8051 en un dispositivo programable, el bloque ROM será implementado mediante un bloque RAM , emulando un bloque EEPROM. En la figura 3 se muestra al bloque ROM con las señales de control, el bus de direcciones y el BUS de datos.
Figura 3. Bloque para la memoria de programa
Solamente se requieren dos señales: La dirección del dato, y una señal de habilitación para generar el dato de salida controlar el acceso al bus de datos del sistema. De acuerdo con algunos autores existen dos maneras de implementar este bloque: usando un arreglo constante o instanciando una ROM de tecnología específica. [ ]La manera mas conveniente es declarar un arreglo con lo datos del programa como constantes y únicamente hacer un llamado mediante el índice adecuado del arreglo, que en este caso correspondería a la dirección dada.
De manera general, el bus de direcciones es conectado directamente con una señal llamada PC_aux, la cual contiene el valor de dirección del la localidad de memoria de programa que se desea leer, el bus de dato es conectado a una señal llamada data_ROM que se encarga de comunicar el valor sacado de la ROM con el registro de instrucciones pmem_s1_byte o pmem_s4_byte, siempre y cuando la señal Enable reciba el adecuado nivel lógico a través del pin EA_n, el cual permite elegir entre la ROM interna y una ROM externa. La Figura 4 muestra estas relaciones.
Figura 4. Interconexión de la ROM interna con las señales auxiliares del sistema del 8051.
En lenguaje VHDL esta descripción se llevo a cabo como se muestra en la Figura 5
ENTITY ROM_interna IS
GENERIC(MSB : integer:=15);
PORT( addr_ROM : IN unsigned(MSB downto 0);
data_ROM : OUT unsigned(7 downto 0);
enable : IN std_logic );
END ENTITY;
ARCHITECTURE BHV OF ROM_interna IS
CONSTANT localidades_1:INTEGER :=31;
type ROM_TYPE is array (0 to localidades_1) of UNSIGNED(7 downto 0);
constant PROGRAM : ROM_TYPE := (
'01110100', -- MOV A, #12
'00010010',
'11111011', -- MOV R3, A
'11111001', -- MOV R1, A
'10001001', -- MOV_9
'00010100',
'10001101', -- MOV_9
'00010101',
'11100100', -- CLR_1
'11111111', -- MOV_5
'11101111', -- MOV_1
'11000011', -- CLR_2
'10010101', -- SUBB_2
'00010101',
'01010000', -- JNC
'01000110',
'10101110', -- MOV_6
'00000111',
'11101110', -- MOV_1
'11000011', -- CLR_2
'10010101', -- SUBB_2
'00010101',
'01010000', -- JNC
'00111011',
'10101011', -- MOV_6
'00010010',
'10101010', -- MOV_6
'00010011',
'10101001', -- MOV_6
'10101001', -- MOV_6
'10101001', -- MOV_6
'10101001' -- MOV_6 );
BEGIN
PROCESS(addr_ROM, enable)
BEGIN
IF enable='1' THEN
data_ROM <= PROGRAM(conv_integer(addr_ROM));
ELSE data_ROM <= (others => 'Z');
END IF;
END PROCESS;
END BHV;
Figura 5. Descripción de la ROM interna
La prueba para este bloque se llevó a cabo empleando el simulador ModelSim SE/EE PLUS 5.4 [[3]]. La figura 6 muestra la descripción de módulo creado para la prueba el cual ha sido llamado CTR_uno. La figura 7 muestra un diagrama a bloques representando lo descrito en la Figura 6, en la cual es posible observar el empleo de registros auxiliares como es el caso de addr y data. Esto es así para poder llevar a cabo la conexión entre las señales de los diversos módulos pues el lenguaje VHDL no permite la conexión directa entre módulos de señales de entrada y salida sino es a través de una señal auxiliar.
ENTITY ctr_uno IS
--GENERIC(MSB : integer := 5);
PORT(
clk : IN std_logic;
rst : IN std_logic;
resul : OUT unsigned(7 downto 0)
);
END ctr_uno;
ARCHITECTURE BHV OF ctr_uno IS
CONSTANT MSB : integer := 5;
SIGNAL pc : integer range 0 to 32;
SIGNAL addr : unsigned(MSB downto 0);
SIGNAL data : unsigned(7 downto 0);
SIGNAL ENA : std_logic;
BEGIN
PROCESS(clk, rst)
BEGIN
IF rst='1' THEN
resul <= 'ZZZZZZZZ';
pc <= 0;
addr <= (others => 'Z');
ELSIF clk'event AND clk ='1' THEN
addr <= conv_unsigned(PC,MSB+1); -- CONVERSION DE ENTERO A UNSIGNED.
pc <= pc+1;
END IF;
IF rst = '1' THEN
ENA <='0';
ELSE ENA <= '1';
END IF;
END PROCESS;
U1: ENTITY work.ROM_interna(BHV)
PORT MAP(addr,
data,
ENA );
process(data)
begin
resul <= data;
end process;
END BHV;
cuando la asignación resul <= data está dentro del process, esta se realiza después del flanco de subida del reloj. y como para el caso de dato el valor No ha cambiado aún, entonces se asigna el dato anterior. Con otro process para detectar el cambio de data, esta asignación se hace sin requerir del flanco del reloj.
Figura 6. Descripción del módulo creado para probar la ROM interna
Figura 7. Representación a bloques del módulo de prueba para la ROM
Los resultados de esta prueba fueron satisfactorios. Los estímulos aplicados correspondieron únicamente a la señal de reloj (clk) y reset (rst). El frecuencia de reloj no fue de mucha importancia pues solamente se efectuó la simulación para verificar el buen funcionamiento del bloque ROM mas no la velocidad.
El siguiente paso fue la síntesis de este bloque. Ésta no representó mayor problema. Cabe comentar que por como fue descrito este bloque, el área ocupada es muy grande pero es independiente de la tecnología usada[2].
Bloque RAM
El siguiente bloque a considerar es la memoria RAM. Justo como con la ROM, existen dos maneras de declarar una memoria RAM: empleando registros o instanciandola a partir de cierta tecnología. Se ha elegido un bloque formado por 256 registros los cuales han sido declarados como un arreglo que pertenece al módulo de control. La Figura 8 muestra la descripción comportamental mediante VHDL y la Figura 9 representa su conexión dentro del bloque. Es fácil notar que como los registros están dentro de la unidad de control no es necesaria ninguna señal intermedia para la lectura y escritura de los datos a este bloque de registros y basta con indicar el índice la localidad para tener acceso a ella sin necesidad de mandar alguna dirección ni señales de control. Este bloque contiene todos los registros de funciones especiales (SFR). Para cada una de las localidades fue declarado un alias con el correspondiente nombre del registro para facilitar la escritura y seguimiento de la descripción.
type data_lowRAM_T is array (0 to MAX_ADDR-1) of UNSIGNED (7 downto 0);
type data_hiRAM_T is array (MAX_ADDR to 2*MAX_ADDR-1) of UNSIGNED (7 downto 0);
subtype bvec is unsigned(7 downto 0) ;
SIGNAL lo_dmem : data_lowRAM_T; -- parte baja de la RAM
SIGNAL direct_hi_dmem : data_hiRAM_T; -- Espacio de meoria RAM para los SFR
SIGNAL indirect_hi_dmem : data_hiRAM_T; -- parte akta de memoria RAM
ALIAS acc : bvec IS direct_hi_dmem(16#E0#); -- accumulaDor
ALIAS b : bvec IS direct_hi_dmem(16#F0#); -- Registro B
ALIAS psw : bvec IS direct_hi_dmem(16#D0#); -- PSW
ALIAS cy : std_logic IS psw(7); -- Bandera de acarreo total
ALIAS ac : std_logic IS psw(6); -- Bandera de acarreo intermedio
ALIAS f0 : std_logic IS psw(5); -- flag 0
ALIAS rs : unsigned(1 DOWNTO 0) IS psw(4 DOWNTO 3); -- Selector del banco de Registros
ALIAS ov : std_logic IS psw(2); -- Bandera de Sobreflujo
ALIAS p : std_logic IS psw(0); -- BIT DE PARIDAD
ALIAS sp : bvec IS direct_hi_dmem(16#81#); -- Stack Pointer
ALIAS dpl : bvec IS direct_hi_dmem(16#82#); -- Data Pointer Low
ALIAS dph : bvec IS direct_hi_dmem(16#83#); -- Data Pointer High
ALIAS p0_latch : bvec IS direct_hi_dmem(16#80#); -- Lacth del puerto 0
ALIAS p1_latch : bvec IS direct_hi_dmem(16#90#); -- Lacth del puerto 1
ALIAS p2_latch : bvec IS direct_hi_dmem(16#A0#); -- Lacth del puerto 2
ALIAS p3_latch : bvec IS direct_hi_dmem(16#B0#); -- Lacth del puerto 3
ALIAS scon : bvec IS direct_hi_dmem(16#98#); -- serial control reg.
ALIAS sm : unsigned(2 DOWNTO 0) IS scon(7 DOWNTO 5);
Figura 8. Declaración de la memoria RAM junto con algunos de los alias empleados.
La prueba de la memoria RAM se efectúo de manera similar a la de la ROM, es decir se creo un módulo que controlara la escritura y lectura en el arreglo, y que mostrara el resultado en un puerto. El módulo fue llamado prueba_RAM. La descripción de este módulo se muestra en la Figura 9. Como la memoria RAM es un bloque declarado dentro de la unidad de control, entonces no es necesario crear señales para su interconexión con otros módulos como en el caso de la ROM.
ENTITY prueba_RAM IS
GENERIC(MSB : integer := 7; MAX_ADDR : integer := 128);
PORT(
addr : IN unsigned(MSB downto 0);
data : INOUT unsigned(MSB downto 0);
modo : IN std_logic;
enable : IN std_logic;
Figura 9. Descripción del módulo de prueba de la RAM
W_R : IN std_logic;
sbuf_dup : IN unsigned(MSB downto 0);
scon_out : IN unsigned(MSB downto 0);
timer1H : OUT unsigned(7 DOWNTO 0)
);
END ENTITY;
ARCHITECTURE BHV OF prueba_RAM IS
type data_lowRAM_T is array (0 to MAX_ADDR-1) of UNSIGNED (7 downto 0);
type data_hiRAM_T is array (MAX_ADDR to 2*MAX_ADDR-1) of UNSIGNED (7 downto 0);
subtype bvec is unsigned(7 downto 0) ;
SIGNAL lo_dmem : data_lowRAM_T; -- parte baja de la RAM
SIGNAL direct_hi_dmem : data_hiRAM_T; -- Espacio de meoria RAM para los SFR
SIGNAL indirect_hi_dmem : data_hiRAM_T; -- parte alta de memoria RAM
ALIAS acc : bvec IS direct_hi_dmem(16#E0#); -- accumulaDor
ALIAS en_x1 : std_logic IS ie(2);
.
.
.
ALIAS en_t0 : std_logic IS ie(1);
ALIAS en_x0 : std_logic IS ie(0);
ALIAS ip : bvec IS direct_hi_dmem(16#B8#); -- Interrupt Priority
BEGIN
PROCESS(addr, W_R, modo)
variable aux : unsigned(data'range);
variable addr_int : integer;
IMPURE FUNCTION get_byte_dmem(
CONSTANT addr : IN bvec;
CONSTANT modo1 : IN std_logic
) RETURN bvec IS
VARIABLE addr_int : INTEGER;
VARIABLE byte_slice : bVec;
BEGIN
addr_int := conv_integer(addr);
IF addr_int < 128 THEN
byte_slice := lo_dmem(addr_int);
ELSIF modo1 = '1' THEN
byte_slice := indirect_hi_dmem(addr_int);
ELSIF (addr_int=16#80#) THEN -- read the port itself
byte_slice := unsigned(acc);
ELSIF (addr_int=16#90#) THEN -- read the port itself
byte_slice := unsigned(acc);
ELSIF (addr_int=16#A0#) THEN -- read the port itself
byte_slice := unsigned(acc);
ELSIF (addr_int=16#B0#) THEN -- read the port itself
byte_slice := unsigned(acc);
ELSIF addr_int = 16#99# THEN
byte_slice := sbuf_dup;
ELSIF addr_int = 16#98# THEN
byte_slice := scon_out;
ELSE
byte_slice := direct_hi_dmem(addr_int);
END IF;
RETURN(byte_slice);
END FUNCTION get_byte_dmem;
PROCEDURE set_byte_dmem(
CONSTANT addr : IN bvec;
CONSTANT val : IN bVec;
CONSTANT mode : IN std_logic
) IS
VARIABLE addr_int : INTEGER;
BEGIN
addr_int := conv_integer(addr);
IF addr_int < 128 THEN
lo_dmem(addr_int) <= val;
Figura 9. Continuación.
ELSIF mode = '1' THEN
indirect_hi_dmem(addr_int) <= val;
-- write to timer1H
ELSIF addr_int = 16#8D# THEN
timer1H <= val;
direct_hi_dmem(addr_int) <= val;
ELSE
direct_hi_dmem(addr_int) <= val;
END IF;
END PROCEDURE set_byte_dmem;
BEGIN
IF enable = '1' THEN --new1
IF W_R= '0' THEN
data <= get_byte_dmem(addr, modo);
ELSE set_byte_dmem(addr, data, modo); --lo_dmem(addr_int)<=data;
END IF;
ELSE data <= (others => 'Z');
END IF;
END PROCESS;
END BHV;
Figura 9. Continuación
Bloque de control
Este bloque esta formado por varios procesos, cada uno de ellos se encarga de una función en especial: generación de los correspondientes estados y ciclos del sistema. Generación del reset del sistema, Obtener bytes de la memoria de programa, la lectura y escritura a la RAM, la ejecución de las instrucciones y.
Generación de los estados del sistema y reset interno.
Este bloque es muy sencillo pues únicamente requiere cambiar el estado con cada ciclo de reloj y repetir estos estados cada 12 ciclos de reloj.
oscillator : PROCESS (CLK1)
BEGIN
IF falling_edge(CLK1) THEN --DEJAR LIBRE LA CORRIDA DE RELOJ Y PROCURAR PONER UN RESET DE MAS DE 24 CICLOS
--POR EJEMPLO 30 CICLOS LIBRES
CASE estado IS
WHEN init => estado <= s1p1;
WHEN s1p1 => estado <= s1p2;
WHEN s1p2 => estado <= s2p1;
WHEN s2p1 => estado <= s2p2;
WHEN s2p2 => estado <= s3p1;
WHEN s3p1 => estado <= s3p2;
WHEN s3p2 => estado <= s4p1;
WHEN s4p1 => estado <= s4p2;
WHEN s4p2 => estado <= s5p1;
WHEN s5p1 => estado <= s5p2;
WHEN s5p2 => estado <= s6p1;
WHEN s6p1 => estado <= s6p2;
WHEN s6p2 => estado <= s1p1;
END CASE;
END IF;
END PROCESS oscillator;
inicio: PROCESS(estado, rst)
BEGIN
IF rst = '0' THEN
ciclo <= edo0;
ELSIF estado = s5p2 THEN
CASE ciclo IS
Figura 9. descripción de los proceso para la generación de los estados y del reset interno
WHEN edo0 =>
ciclo <= edo1;
WHEN edo1 =>
ciclo <= edo2;
WHEN edo2 =>
ciclo <= edo2;
END CASE;
END IF;
end process inicio;
ciclo_inicio: process(ciclo)
begin
CASE ciclo IS
WHEN edo0 => rst_int <= '0';
WHEN edo2 => rst_int <= rst;
WHEN OTHERS => NULL;
END CASE;
END PROCESS ciclo_inicio;
Figura 10. Continuación
Figura 11. Representación de la generación del los estados del sistema y del reset interno.
Obtención de bytes de la memoria de programa
Este proceso es el encargado de realizar la lectura de los datos grabados en la ROM interna o ROM externa, el caso de esta última, generar las señales de control adecuadas para la correcta lectura de los datos de acuerdo con el diagrama de tiempo mostrado en la Figura 12. La descripción se muestra en la figura 13 y la Figura 14 nos da una idea de los bloque empleados.
Figura 12. Diagrama de tiempo para la lectura de la memoria de programa
get_pmem : PROCESS(cycle_state, pc) IS --siempre que haya un cambio en PC habrá un posible nuevo opcode
VARIABLE addr : INTEGER ; --:= 0;
VARIABLE resync : BOOLEAN; --:= FALSE; -- set true when pc changes
BEGIN
IF p0_reset_ack <= '1' THEN
p0_reset <= '0';
END IF;
-- If there has been a transaction on pc, and it is
-- not the initial start-up state, then flag the
-- resync variable
--IF pc'ACTIVE THEN se han comentado para ver si asi sintetiza
-- resync := TRUE;
--END IF;
-- If the process main is trying to read a data byte from external mem, yield to it by putting ctrl's to high impedance
IF port_req = '1' THEN
p0_ctrl <= 'Z';
p2_ctrl <= 'Z';
p0_addr <= 'ZZZZZZZZ';
p2_addr <= 'ZZZZZZZZ';
ale_pm <= '0';
psen_n <= '1';
ELSIF reset_pmem = '1' THEN -- SIENTO QUE ESTA ASIGNSCION DEBERIA HACRESE FUERA Y CUANDO SE DE EL RESET ADECUADO
resync := TRUE;
PC_aux <= X'0000';
addr := 0;
ELSE
--ELSIF cycle_state ;entonces esta activo
CASE cycle_state IS
WHEN init =>
NULL;
WHEN s1p1 =>
IF ( addr > 16#0FFF#) OR (ea_n = '0') OR (ea_n = 'L') THEN
pmem_s1_byte <= unsigned(p0);
ELSE
pmem_s1_byte <= data_ROM;
END IF;
WHEN s4p1 =>
-- read in the current byte from pmem
IF ( addr >= 16#0FFF#) OR (ea_n = '0') OR (ea_n = 'L') THEN
pmem_s4_byte <= unsigned(p0);
ELSE
pmem_s4_byte <= data_ROM;
END IF;
WHEN s1p2 | s4p2 =>
IF resync THEN
addr := conv_integer(pc);
resync := FALSE;
PC_aux <= PC;
ELSE
addr := addr + 1;
--PC_aux <= PC_aux + 1;
END IF;
-- strobe ale if next addr is external
-- rewrite p0_latch to all 1's
IF ( addr >= 16#0FFF#) OR (ea_n = '0') OR (ea_n = 'L') THEN
ale_pm <= '1';
psen_n <= '1';
p0_reset <= '1';
END IF;
WHEN s2p1 | s5p1 =>
-- drive puerto 0 y puerto 2 si addr es externo
IF ( addr >= 16#0FFF#) OR (ea_n = '0') OR (ea_n = 'L') THEN
Figura 13. Descripción del proceso de extracción de los códigos de instrucciones de la memoria de datos ya sea interna o externa.
p0_addr <= conv_unsigned(addr MOD 256, 8);
p2_addr <= conv_unsigned(addr / 256, 8); ---ya esta compuesto chercar el archivo correspondiente
p0_ctrl <= '1';
p2_ctrl <= '1';
ELSE
p0_ctrl <= '0';
p2_ctrl <= '0';
END IF;
WHEN s2p2 | s5p2 => -- drive ale a cero
IF ( addr >= 16#0FFF#) OR (ea_n = '0') OR (ea_n = 'L') THEN
ale_pm <= '0';
END IF;
WHEN s3p1 | s6p1 => -- drive psen cero
IF ( addr >= 16#0FFF#) OR (ea_n = '0') OR (ea_n = 'L') THEN
psen_n <= '0';
p0_ctrl<='0'; --cuidado pues se puede quedar asi y luego causar conflictos con otro
END IF; --p0_ctrl.
WHEN s3p2 | s6p2 =>
NULL;
END CASE;
END IF;
END PROCESS get_pmem;
Figura 13. Continuación
Figura 14. Representación de la descripción del proceso para el fetch de datos de la memoria de programa y generación de la señales de control necesarias para el caso de una memoria externa.
La Figura 15 muestra las señeles obtenida a partir de la simulación de unidad de control completa. En ella se observan las diferentes instrucciones y la manera en que se han descrito. Es de notar que para cada una de las instrucciones se procesan los datos de acuerdo con lo que esta indique, por lo que un bloque propiamente decodificadora de instrucciones no se ha descrito.
Si a la unidad de control se le agregan la ROM interna, se tendrá el sistema completo, restando únicamente la descripción de los temporizadores y del UART. Para probar este bloque completo, se hizo uso de un una memoria de datos externa cuyo contenido es idéntico al de la ROM mostrada en la Figura 5.
Problemas encontrados durante la síntesis de los diversos bloques
- Alias no sintetizables
En el bloque de la RAM fue imposible la síntesis mediante el uso de alias para cada registro. El error generado fue Esto tuve que ser resuelto declarando constantes enteras de acuerdo con las localidades del registro, y para resolver el detalle de las manipulaciones bit a bit de los registros, se recurrió al acceso por índice como si se tratara de un arreglo bidimensional:
RAM(ACC)(bit0)
donde previamente ACC fue declarada como una constante entera cuyo valor corresponde a la localidad que ocupa el registro ACC y bit0 fue declarada como una constante con valor entero igual a cero.
Esto condujo a la corrección de las instrucciones de asignación de todas las instrucciones que manipulaban algún registro de memoria así como registros especiales y sobre todo en las que se efectúan manipulaciones de un solo bit, así como también de la funciones que controlan la escritura y lectura de la memoria RAM.
- Sentencias Wait
El proceso principal, llamado main, hace uso de sentencias wait. Esta sentencia espera por algún cambio en la señal que se indica y entonces procede a ejecutar las asignaciones. El detalle es que el proceso principal basa la ejecución de las instrucciones en varias sentencias WAIT que se activan en diferentes estados del sistema (s1p1, s1p2, etc.) y la herramienta solamente permite la síntesis mediante la activación por una sola señal, es decir que todas las sentencias wait dentro de un proceso deberán ser activadas por el mismo estado.
- Empleo de diferentes flancos en una asignación concurrente.
Cuando el código efectúa la asignación de la interrupción interna generada por el pin 1 del puerto 3, se checa si ha ocurrido un flanco ascendente o descendente para generar la interrupción de manera adecuada. A continuación se muestra la parte de este código.
int1_n_internal <= '0' WHEN falling_edge(p3(3)) ELSE
'1' WHEN rising_edge(p3)(3) AND direct_hi_dmem(tcon)(it1) = '0' ELSE
'1' WHEN interrupt_ack = '1' AND direct_hi_dmem(tcon)(it1) = '1' ELSE
int1_n_internal;
La herramienta de síntesis no permite el uso de diferentes flancos de reloj para llevar a cabo la asignación a un señal. En este caso hay que replantear la descripción de activación de las interrupciones del sistema.
-Las funciones del tipo impure.
Cuando se requiere que una función pueda tener efecto sobre variables o señales que no son declaradas dentro de su cuerpo, es posible utilizar las funciones del tipo impure. Sin embargo, este tipo de funciones no son reconocidas por la herramienta de síntesis, por lo que hubo que optar por convertirlas a procedure. Esto conllevó a declarar nuevas variables así como rescribir las asignaciones correspondientes en cada instrucción.
-Puertos del sistema.
El lenguaje de descripción VHDL permite el uso de señales bidireccionales. Sin embargo en este punto, el planteamiento o duda existente es sobre como se hará esta implementaron pues al momento de la simulación se tuvo que recurrir a la descripción de buffers tri-estado para evitar los conflictos de asignación concurrente.
Figura 15. Resultado de la simulación de la descripción en VHDL del 8051.
Figura 15. Continuación.
Figura 15. Continuación.
|