MICROPROCESADORES PU1232Características GeneralesEl uP1232 es un procesador de propósito general de 8 bits con arquitectura CISC. En su diseño se ha buscado simultáneamente reducir el tamaño del procesador y aportar la flexibilidad suficiente para facilitar la programación y el desarrollo rápido de aplicaciones. La velocidad de ejecución, en cambio, no ha sido una prioridad, ni a nuestro juicio lo es en las aplicaciones hacia las que está orientado.
Las principales características del procesador son las siguientes:
· Contiene 32 registros internos de 8 bits, actuando todos ellos como acumuladores.
· Su código ejecutable, dependiendo de la versión, varía entre 4 KB y 64 KB.
· Accede a 64 KB de memoria externa (datos, código ejecutable y puertos de E/S).
· Dispone internamente de hasta 256 bytes de RAM, con un mínimo de 32 bytes.
· La pila también es interna, tiene sólo 32 palabras, pero es ampliable.
· Su código de instrucciones dispone de 33 operaciones distintas.
· Las instrucciones requieren sólo uno o dos bytes en su codificación.
· Su ALU de 8 bits puede realizar 16 operaciones distintas sobre cualquier registro.
· Responde a cuatro flags: cero, acarreo, signo y paridad.
· Atiende tres interrupciones priorizadas y enmascarables individualmente.
· En su momento, dispondrá de 15 puertos de entrada/salida.
· Ocupa unas 200 CLBs en una XC4000E (unas 5000 puertas equivalentes).
Comparado con otros procesadores, el uP1232 dispone de 32 registros internos en vez de 8, y todos ellos actúan como acumuladores, y no sólo uno.
Arquitectura ExternaEl uP1232 será implantado, inicialmente, sobre una FPGA XC4000E de Xilinx, aunque previsiblemente su diseño también pueda ser utilizado sobre los dispositivos de Atmel y Lucent sin apenas modificaciones. Difícilmente se podrá exportar el diseño a las FPGAs de Altera, pues se utilizan algunas características específicas de Xilinx (en particular, sus memorias síncronas de tamaño 32x1).
Externamente a la FPGA se dispondrá de una memoria EEPROM o EPROM de 32 KB y, opcionalmente, otros 32 KB de memoria SRAM o EEPROM. En la primera memoria residirá tanto la secuencia de bits que configurará a la FPGA en la puesta bajo tensión (usando de 12 a 22 KB) como el código ejecutable y datos que requiera el microprocesador para su funcionamiento. Ambos bloques de memoria pueden ser de tipo SRAM en un "emulador".
Para conectar el módulo microprocesador con el exterior de la FPGA se necesitan normalmente 28 pines: el bus de datos bidireccional DATA[7..0] requiere 8 pines, mientras el de direcciones ADDR[15..0] usará 16. Los cuatro restantes son para las señales de lectura (/RD) y escritura (/WR), ambas activas a nivel bajo, y las otras de siempre: CLK que sincroniza el funcionamiento interno a 4~12 MHz y /RESET que, activa también a nivel bajo, inicializa el circuito.
![](//photos1.blogger.com/blogger/1253/3707/320/111.0.jpg)
Adicionalmente a estas señales se pueden incorporar otras ocho: seis para generar y atender las interrupciones (/IRQ[3..1] y /IACK[3..1]) y dos para permitir accesos directos a memoria (/DMA y /DACK). Estas últimas son habitualmente activas a nivel bajo, para anularlas fácilmente con pull-ups cuando los circuitos están en alta impedancia.
Código de Instrucciones
Las 33 instrucciones del uP1232 se organizan alrededor de 16 instrucciones básicas, las cuales se identifican a través de cuatro bits del código de instrucción:
![](//photos1.blogger.com/blogger/1253/3707/320/222.0.jpg)
Las instrucciones de la primera columna (00xx) requieren dos ciclos de reloj para su ejecución, uno dedicado a leer el código de instrucción y otro a ejecutarlo. Las instrucciones de la cuarta columna, dedicadas al movimiento de datos entre los registros y/o la memoria externa, son más complejas y requieren cuatro ciclos o cinco ciclos. Las demás instrucciones emplean tres ciclos de reloj.
En la notación seguida, "Rm" y "Sm" indican cualquiera de los 32 registros internos (R0 a R31), mientras "Rn", "Sn" y "Tn" indican únicamente uno de los 16 primeros (R0 a R15). Como se puede observar, las operaciones aritméticas y lógicas se pueden efectuar directamente sobre cualquier registro interno, sin las limitaciones que introducen otros procesadores al emplear para esta tarea un único registro acumulador.
Veamos a continuación las instrucciones de forma más detallada:
![](//photos1.blogger.com/blogger/1253/3707/320/333.0.jpg)
![](//photos1.blogger.com/blogger/1253/3707/320/444.jpg)
![](//photos1.blogger.com/blogger/1253/3707/320/555.jpg)
![](//photos1.blogger.com/blogger/1253/3707/320/666.jpg)
Como se puede observar, en las instrucciones de salto absoluto se emplean sólo 12 bits para indicar la dirección de destino ("GOTO nnn" y "CALL nnn"). Esto es característico de este procesador y limitaría, en principio, el tamaño del código ejecutable a 4 KB: con 12 bits no se pueden direccionar más de 4.096 posiciones de memoria. Para evitar esta limitación se crean varias versiones del uP1232: el más pequeño, denominado uP1232a, salta a cualquier dirección entre 0x0000 y 0x0FFF (es decir, hasta 4 KB de código); el siguiente, el uP1232b, sólo salta a las posiciones pares entre 0x0000 y 0x1FFF, por lo que consigue extender el código ejecutable a 8 KB; el uP1232c salta a una de cada cuatro posiciones, ejecutando hasta 16 KB de programa; el uP1232d ejecuta hasta 32 KB mientras el mayor de todos, el uP1232e, ejecuta hasta 64 KB, pero sólo puede saltar a una de cada 16 posiciones de memoria. Por defecto, se considera que el procesador es el uP1232a, salvo que la orden "MODEL {A,B,C,D,E}" ejecutada como primera instrucción indique lo contrario.
Las instruciones de salto condicional ("JP flag, nn") se limitan, como es habitual, a saltos cercanos. Dedicando 8 bits para señalar la dirección de destino se pueden producir saltos en un entorno de -128 a +127 posiciones de memoria cercanas, lo cual es más que suficiente. Las comparaciones que puede efectuar, y que definen los cuatro bits restantes de la instrucción, son las siguientes: Z (0000) y NZ (0001) que evalúan el flag "Cero", el cual se activa si el resultado de una operación es nulo; C (0010) y NC (0011) que mira el flag de "Acarreo"; NEG (0100) y POS (0101) usan el bit de "Signo" mientras IMPAR u ODD (0110) y PAR o EVEN (0111) usan el bit de "Paridad". Las ocho combinaciones restantes (1xxx) serán usadas por los periféricos.
Al igual que se observa una elevada flexibilidad en las operaciones aritméticas y lógicas, pues se puede emplear directamente cualquiera de los 32 registros internos de ocho bits, también se dispone de suficientes modos de direccionamiento:
· Inmediato: "LD Rn, nn". Asigna cualquier número de 0 a 255. · Directo: "ADD Rm, Sm". Opera directamente con hasta 32 registros. · Indirecto a Registro: "LDI Rn, (Sn + n)" Puede usar hasta 256 registros internos. · Indirecto a Memoria: "LDI Rn, (Sn, Tn)" Puede usar hasta 64 KB de memoria externa.
Aunque sus operaciones se limiten a 8 bits (el Z80, por ejemplo, opera con 8 y con 16 bits), el uP1232 no tiene nada que envidiar a otros procesadores, pues al usar el acarreo puede extender su aritmética a números con 16, 24, 32 ó más bits de precisión (por ejemplo, mientras "ADD R0,R10" podría sumar los 8 bits menos significativos, "ADC R1,R11" sumaría los ocho bits siguientes usando el acarreo producido en la suma anterior, y así sucesivamente).
En las instrucciones PUSH y POP se ponen y retiran, respectivamente, datos de la pila. Como es habitual, estas operaciones se realizan con frecuencia en las subrutinas, para preservar el valor de los registros intermedios que se utilizan y restaurarlos antes de volver al programa principal. Una característica añadida en este procesador es que en todas las instrucciones PUSH y POP se guardan y recuperan, respectivamente, el valor de los "flags": esto es especialmente importante, y de hecho imprescindible, en las rutinas de atención a las interrupciones, pues pueden ser llamadas en cualquier punto de la ejecución de un programa.
La última instrucción que comentaremos, posiblemente la más llamativa por no estar presente (o documentada) en la mayoría de los procesadores conocidos, es la orden "BREAK". Hace lo mismo que "NOP", es decir, no hace nada, pero en el caso de una puesta a punto puede ser empleada tanto por el simulador como el emulador. El primero puede utilizarla como punto de parada en la ejecución simulada del programa, para visualizar el estado interno del procesador; el emulador, en cambio, puede habilitar señales externas que permitan interrumpir temporalmente la ejecución.
Arquitectura Interna
El diseño interno del uP1232 se basa en una estructura de dos buses (implementados internamente con multiplexores), un Banco de Registros, una Pila y una ALU. También tiene diversos registros especiales.
![](//photos1.blogger.com/blogger/1253/3707/320/888.jpg)
El Banco de Registros, donde se almacenan los valores de R0 a R31, es una memoria SRAM de tamaño 32x8 con escritura síncrona (con el flanco de subida del reloj) y lectura asíncrona (inmediata a la presentación de cada dirección). Tanto Xilinx como Atmel y Lucent implementan de forma muy eficiente este tipo de memorias, lo cual es básico en el diseño del procesador.
La Pila, de 32 posiciones ampliables, es otra memoria síncrona de tamaño 32x12 en el uP1232a y de tamaño 32x16 en el uP1232e. Su anchura de palabra permite tanto el almacenamiento de direcciones de retorno (para CALL y RET) como el almacenamiento de datos (para PUSH y POP). En este último caso, siempre quedan al menos 4 bits libres que permiten retener el estado de los FLAGs, lo cual es imprescindible para poder atender las interrupciones.
La ALU (Unidad Aritmético-Lógica) es la encargada de efectuar las operaciones. Como se podrá apreciar, su diseño está directamente vinculado a las instrucciones de la tercera columna (10xx). De hecho, la ALU efectúa hasta 16 operaciones distintas, que se corresponden biunívocamente con las 16 instrucciones de la citada tercera columna.
![](//photos1.blogger.com/blogger/1253/3707/320/999.jpg)
Sus entradas son dos valores de 8 bits, una procedente del Banco de Registros y otra de un registros intermedio denominado Acumulador (ACC). También recibe otros cuatro bits de entrada, procedentes de los registros de instrucciones IR e IRb, los cuales le indican directamente qué operación debe realizar. La salida es puramente combinacional y depende de las entradas y de la operación solicitada.
Los registros especiales son los siguientes:
· PC: El Contador de Programa se usa para leer las instrucciones de la memoria externa. · SP: El Puntero de Pila controla la ubicación del último valor puesto en la Pila. · IR e IRb: Los Registros de Instrucciones retienen el código de la instrucción que se ejecuta. · ACC: El Acumulador es un registro intermedio usado, principalmente, en la ALU. · AUX: Junto con el Acumulador se utiliza para efectuar accesos a la memoria externa. · FLAGs: Retienen valores característicos de los resultados de las operaciones (cero, acarreo, ...).
Programa Interno de Control
El "Programa de Control" es el que se encarga de que el microprocesador realice las tareas necesarias para que sea operativo, y consiste en un circuito algorítmico que, usando la arquitectura anterior, lee e interpreta secuencialmente las instrucciones para ejecutarlas. Evoluciona por tanto a través de diversos estados, pero su funcionamiento es completamente cíclico: lee de la memoria externa el primer byte de una instrucción, dedicando para ello un ciclo de reloj; si la instrucción es de dos bytes, dedica otro ciclo a leer la segunda palabra; seguidamente lee los registros necesarios, opera con ellos y guarda el resultado, quedando preparado para ejecutar la siguiente instrucción. El programa de control, al fin y al cabo, define casi por completo la arquitectura interna del microprocesador.
Una versión simple del programa de control, el cual interpreta y ejecuta todas las instrucciones del uP1232a empleando la arquitectura interna descrita anteriormente, pero que no atiende de momento las interrupciones, podría ser el siguiente:
![](//photos1.blogger.com/blogger/1253/3707/320/10.jpg)
El procesador siempre parte del estado '0', en donde lee el primer byte de la instrucción sobre el registro especial IR, de ocho bits, y pasa sin más al estado '1'. Allí se ejecutan las instrucciones sencillas (las del grupo 00xx), pero las demás son más complejas, por lo que requieren ciclos adicionales: unas siguen la secuencia '0'-'1'-'3', las que usan la ALU evolucionan según '0'-'1'-'5', mientras las últimas hacen '0'-'1'-'7'-'6' ó '0'-'1'-'7'-'6'-'4'. El estado '2' queda, de momento, reservado.
Una instrucción como "GOTO nnn", que efectúa un salto en la secuencia del programa modificando el contador de programa PC con un nuevo valor de doce bits, se realiza en tres ciclos de reloj:
1) IR(7..0) = Memo[PC]; PC = PC + 1; -- Lee el primer byte de la instrucción en '0'.
2) IR = IR; IRb(7..0) = Memo[PC]; PC = PC + 1; -- Lee el segundo byte, manteniendo IR, en '1'.
3) PC(11..8) = IR(3..0); PC(7..0) = IRb(7..0); -- Efectúa el salto modificando PC en '3'.
Posiblemente esta instrucción se podría completar en tan sólo dos ciclos (IR = Memo[PC++] y PC(11..0) = IR(3..0) Memo[PC]), pero entonces el diseño no tendría tanta simetría como la que se ha conseguido, y se complicaría notablemente la Unidad de Control. También se podría evitar el incremento del contador de programa del segundo ciclo, pero de nuevo se ha hecho así por simetría, en este caso con la instrucción CALL.
Las operaciones aritméticas y lógicas también necesitan tres ciclos de reloj, y todas ellas son iguales para el programa de control: la distinción entre unas operaciones y otras se realiza directamente en la ALU, que usando bits específicos de los registros de instrucciones decide qué resultado mostrar.
1) IR(7..0) = Memo[PC++]; -- Carga la instrucción sobre IR en '0'.
2) IR = IR; IRb(7..0) = Memo[PC++]; ACC = Reg[IR(4..0)]; -- Carga un operando sobre ACC en '1'.
3) Reg[IRb(4..0)] = Reg[IRb(4..0)] ALU ACC; -- Opera: Rm = Rm ALU Sm en '5'.
En este punto se observa cómo el código de instrucciones, la arquitectura interna del procesador y el programa de control están estrechamente relacionados. De hecho, los tres han sido diseñados y optimizados de forma conjunta y partiendo de cero (from scratch), lo que nos ha permitido adaptarnos a la estructura interna de las FPGAs mejor que otros diseños basados en procesadores ya existentes.
Controlador de Interrupciones y de DMA
El controlador de interrupciones del uP1232 está integrado en el programa interno de control, y permite atender hasta tres peticiones de interrupción independientes, es decir, puede ejecutar hasta tres subrutinas distintas en respuesta a la activación de señales externas. El controlador de DMA atiende un único canal, manteniendo los pines de dirección y datos en alta impedancia durante tres ciclos de reloj para que un circuito externo pueda acceder a la memoria EEPROM y/o SRAM. Ambos elementos son imprescindibles para el funcionamiento del emulador (que se describe más adelante).
Las interrupciones del uP1232 tienen las siguientes características:
· Son tres, solicitadas a través de los pines de entrada /IRQ1, /IRQ2 y /IRQ3, y reconocidas con las señales de salida /IACK1, /IACK2 y /IACK3, respectivamente.
· Están priorizadas (IRQ1 > IRQ2 > IRQ3), de modo que IRQ2 puede interrumpir a IRQ3 pero no a IRQ1 ni a sí misma.· Se pueden habilitar e inhabilitar desde programa, a través de la instrucción IMASK. Por ejemplo, "IMASK 6" habilita las interrupciones IRQ3 e IRQ2, pero deshabilita IRQ1 (6 es 110 en binario).
·Están "autovectorizadas", es decir, que cuando se atienden efectúan saltos a posiciones predefinidas. Saltan a 0x0010 (IRQ1), a 0x0020 (IRQ2) y a 0x0030 (IRQ3).
Para atender las interrupciones se ha de modificar el programa interno de control, añadiendo el estado '2' que hasta ahora no tenía ninguna función:
![](//photos1.blogger.com/blogger/1253/3707/320/11.jpg)
Por su parte, una máquina de control específica registra qué interrupciones se han atendido y cuáles se pueden atender, de modo que se tengan en cuenta las prioridades. Sus propios bits (negados) son empleados para responder por los pines /IACKn a las peticiones de interrupción.
![](//photos1.blogger.com/blogger/1253/3707/320/12.jpg)
El controlador de DMA otorga a un circuito externo, durante tres ciclos de reloj, el control sobre los buses de acceso a la memoria. En este tiempo el microprocesador no hace nada, pues no puede leer nuevas instrucciones para ejecutarlas.
Esto permitirá al futuro emulador del microprocesador precargar la memoria con nuevos códigos ejecutables, y también leer en la memoria valores que allí haya puesto el programa del usuario, todo ello sin necesidad de detener el micro, que puede estar ejecutando tareas críticas en tiempo.
Herramientas de Desarrollo
Para desarrollar aplicaciones basadas en este procesador se necesitan, al menos, tres herramientas: un ensamblador, un simulador y un emulador. Adicionalmente se podría generar un compilador de algún lenguaje de alto nivel, generalmente C.
El "ensamblador" lee los programas en formato ASM (ficheros de texto con secuencias de instrucciones descritas con un lenguaje más o menos rígido, pero comprensible) y los traduce al formato binario que, en último término, es el único que entiende el procesador. La salida es en general en formato HEX, que describe en hexadecimal el contenido de la memoria que ha de asociarse al procesador para que éste funcione. Cada instrucción se traduce por uno o dos bytes, según le corresponda, y se calculan las representaciones binarias de cada uno de los saltos que se indiquen el el programa.
El "simulador" es otro programa, que lee los ficheros HEX que describen la memoria accesible por el procesador y permite simular su comportamiento de forma controlada. En nuestro caso el simulador incorpora internamente el código del ensamblador, de modo que si se le suministra un fichero ASM en lugar de uno HEX, lo ensambla antes de comenzar la simulación.
El "emulador", cuando esté disponible, se encargará de dos tareas: configurará la FPGA para que se comporte como microprocesador y transferirá a su memoria externa el programa que ha de ejecutar. Ambas tareas se reducen a una, que consiste en leer y escribir en las memorias EEPROM y SRAM asociadas a la FPGA. En una zona de la EEPROM reside la secuencia de bits que configurará la FPGA cuando se le ordene a través de la señal de inicialización apropiada. En otra parte de la misma EEPROM se podrá cargar el programa ejecutable por el micro, quedando el resto disponible como memoria para datos.