Nota preliminar: Este artículo fue publicado en el número #6 de NetSearch Ezine, en 2001.
Esto pretende ser el primero de una serie de artículos (si es que veo interés y tengo tiempo) sobre Electrónica Digital. Voy a intentar enfocarlo para que cualquiera pueda empezar en este tema. No obstante, daré por hecho ciertos conocimientos básicos sobre informática (numeración hexadecimal, binaria,...).
La electronica digital es un tema muy amplio, por tanto esto será algo así como una guía básica a partir de la cual podreis investigar vosotros mismos y profundizar. Existen multitud de microprocesadores; yo voy a escribir sobre el MC68000 de Motorola, ya que es el que conozco y es un buen micro con el que aprender. Esta claro que despues utilizareis otros, pero sabiendo uno no tendreis problemas en aprender otros.
Estoy hablando de micros, ya que en este artículo voy a empezar con la estructura y la programación del micro. Decidí empezar por aquí porque creo que es lo más interesante para empezar en electrónica, ademas será una buena guía de iniciación a lenguaje ensamblador para la gente que no sabe utilizarlo. Si veo que interesa, en otros artículos escribiré sobre mapeo de memorias, circuiteria de selección,...
En la web podreis encontrar un simulador del MC68000 y un manual de funcionamiento con el que podreis compilar y simular los programas que hagais.
Puede que os esteis preguntando cual es la aplicación de todo el royo que vais a leer, sobre todo aplicado a los temas que os interesan. Programando un micro (en la práctica, lo más seguro es que programeis un PIC, que es un poco más limitado que un micro, pero os llegará de sobra) y creando un circuito digital controlado por el, podeis hacer desde una calculadora hasta un selector entre multiples tarjetas SIM segun el PIN introducido, cerraduras controladas por una tarjeta EPROM, emuladores de cualquier circuito que conozcais.
Bueno, sin más preambulos empiezo.
1. Indice
2. Propiedades hardware
- Bus interno: 16 bits
- Unidad Aritmetico Lógica (ALU) puede operar sobre 16 bits directamente
- Registros internos de 32 bits (Datos y Direcciones)
- La Entrada/Salida esta mapeada en memoria (Intel utiliza buses diferentes para entrada/salida)
- Bus de datos: 16 bits
- Bus de direcciones: 32 bits (pero solo utiliza las 24 líneas menos significativas)
* Físicamente solo hay 23 lineas de dirección. A0 se sustituye por UDS y LDS de una forma especial.
[Nota:] Las líneas negadas (con una línea por encima) quieren decir que esa línea se activa con un 0 lógico, en lugar de un 1.
- GND (Ground): Masa.
- CLK (Clock): Señal de reloj.
- D0-D13 (Data): Bus de datos.
- A1-A23 (Address): Bus de direcciones.
- AS# (Address Strobe): Validación de dirección.
- R/W# (Read/Write): Control Lectura/Escritura.
- UDS# (Upper Data Strobe): Transferencia por los 8 bits altos del bus de datos.
- LDS# (Lower Data Strobe): Transferencia por los 8 bits bajos del bus de datos.
- DTACK# (Data Transfer Acknowledge): Indicador de transferencia completa. (la recibe del subsistema de memoria)
- IPL*# (Interrupt Priority Level): Entradas de peticion de interrupción. Codifican un número de 3 bits con el nivel de interrupción.
- BERR# (Bus Error): Error en el subsistema de memoria o en E/S.
- RESET#: Es una linea bidireccional: De forma entrante inicializa el micro. De forma saliente fuerza la inicializacion del entorno.
- HALT#: Es bidireccional: Como entrada detiene la CPU. Como salida indica al subsistema que la CPU se ha detenido.
- BR# (Bus Request): Peticion de bus para DMA.
- BG# (Bus Grant): Concesion de bus.
- BGACK# (Bus Acknowledge): Reconocimiento de concesión.
- E: Salida de reloj para perifericos de la familia 68000. Frecuencia de 1/10 CLK
- VMA# (Valid Memory Address): Indica que el bus de direcciones contiene una direccion válida.
- VPA# (Valid Peripherial Address): Indica que la dirección pertenece a un periférico síncrono.
- FC* (Function Codes): Señales de status.
3. El Modelo de Programación
El MC68000 tiene dos modos de funcionamiento:
- Modo Usuario: No se pueden ejecutar ciertas instrucciones y solo se accede al byte bajo del registro de estado.
- 8 registros de Datos de 32 bits (D0-D7)
- 7 registros de direcciones de 32 bits (A0-A6)
- PC (Contador de programa) de 32 bits
- SP (Stack Pointer o Puntero de Pila de Usuario) de 32 bits (A7)
- SR (Registro de estado) 8 bits
- Modo Supervisor: Se accede a todo el juego de instrucciones y a todos los registros.
- 8 registros de Datos de 32 bits (D0-D7)
- 7 registros de direcciones de 32 bits (A0-A6)
- PC (Contador de programa) de 32 bits
- SSP (Stack Pointer o Puntero de Pila de Usuario) de 32 bits (A7)
- SR (Registro de estado) 16 bits
[Nota:] Los registros de datos, direcciones y contador de programa son físicamente los mismos para los dos modos.
Los punteros de pila hay uno físicamente para cada modo.
El Registro de estado es físicamente el mismo: El usuario solo utiliza el byte menos significativo, y el supervisor el registro entero.
[Nota:] Los registros que almacenan direcciones (A*, Sp, CP) son de 32 bits pero solo utilizan los 24 bits menos significativos.
[Nota:] Cuando vallamos a utilizar la pila en un programa (ya sea de usuario, para las subrutinas, o de supervisor para las interrupciones) es necesario inicializarla, sino el micro generará un error.
La de usuario la podemos inicializar así:
MOVE #$40000,A7
La de supervisor:
ORG $00000
DC.L $40000
Registro de Estados (SR):
bit 15 14 13 12 11 10 9 8 | 7 6 5 4 3 2 1 0
flag T # S # # I2 I1 I0 | # # # X N Z V C
[Nota:] El byte más significativo no es accesible por el modo usuario
- T (Trace): Si está a "1" el micro funciona en modo traza (Paso a paso)
- S (Status): Si está a "1" estamos en modo Supervisor Si esta a "0" estamos en modo Usuario
- I2 I1 I0 (Máscara de interrupción): Si un periférico solicita una interrupción, el nivel de prioridad debe ser superior al codificado por la máscara.
- X (Bit de Extension): Indica el acarreo en operaciones BCD
- N (Flag de Signo): Nos indica si la ultima operacion genero un numero negativo.
- Z (Flag de Zero): Indica que en la ultima operacion se obtuvo un 0.
- V (Flag de Overflow): Cuando esta a "1" indica que la ultima operacion genero un desbordamiento.
- C (Flag de Carry): Indica ke en la ultima operacion se genero un acarreo
4. La Memoria
El 68000 utiliza el formato Big Endian para el almacenamiento de datos superiores al byte en memoria. Esto quiere decir que el byte más significativo se almacena en posiciones de memoria bajas (cercanas al $00000).
$00000
.
.
byte alto
byte bajo
.
.
$FFFFF
La señal R/W# nos indica si vamos a leer o a escribir en memoria:
R/W# | Acción |
---|---|
0 | Escribir |
1 | Leer |
La señal AS# se envia al sistema de memoria para decir si la dirección que se ha puesto en el bus de direcciones es válida.
AS# | Indicación |
---|---|
0 | Dirección válida |
1 | Dirección no válida |
UDS# y LDS#
UDS# | LDS# | Acceso |
---|---|---|
0 | 0 | Tamaño palabra (16 bits) |
0 | 1 | Byte bajo |
1 | 0 | Byte alto |
1 | 1 | No hay acceso a memoria |
La señal DTACK# viene del sistema de memoria, e indica si se ha conseguido acceder con exito
DTACK# | Indicación | ||
---|---|---|
0 | Se ha accedido | |
1 | No se ha accedido |
5. Modos de direccionamiento
Los modos de direccionamiento son los formas de indicar al micro donde encontrar un dato determinado, es decir, cual es su dirección efectiva (direccion física del dato). En el 68000 tenemos 13 modos de direccionamiento:
Direccionamiento Implícito
No se necesita operando. Se refiere a un registro definido en la operación.
MOVE $23345,CCR
Direccionamiento Inmediato
Se expresa la dirección explicitamente en la operación. Se utiliza el caracter # antes de la dirección.
MOVE #$9F,D5
Direccionamiento Inmediato Rápido
Igual que antes, pero el valor es:
Número entre 1 y 8 para suma y resta.
Número entre -128 y 127 en instrucciones de movimiento de datos.
Se añade el caracter Q al mnemónico y el # antes del número.
ADDQ #6,A0
Direccionamiento Absoluto Largo
El argumento es la dirección efectiva a la que se accede.
MULS $25022,D2
Direccionamiento Absoluto Corto
El argumento es una dirección de tamaño palabra (Word, 2 bytes)
Si el valor está entre $0000-$7FFF accedemos a los 32k mas bajos de memoria.
Si el valor está entre $8000-$FFFF accedemos a los 32k mas altos de memoria.
EORI.B #$FF,$8000
Direccionamiento directo a registro
El operando es un registro interno, D* o A*
SUB D1,A2
Direccionamiento Indirecto
El operando es una dirección de memoria intermedia, donde está contenida la dirección efectiva.
Esta dirección de memoria esta contenida en un registro de dirección.
ASL.W (A3)
Direccionamiento Indirecto con Postincremento
Igual que el anterior, pero despues de obtener el argumento el registro de direcciones se incrementa en un valor, segun el tamaño:
.B (Byte): Se incrementa en 1
.W (Word): Se incrementa en 2
.L (LongWord): Se incrementa en 4
Se utiliza la representacion (A*)+
CMPM (A0)+,(A4)+
Esto es muy útil para recorrer arrays y para actualizar el puntero de pila al sacar datos (El 68000 no tiene instrucción para eso)
Direccionamiento Indirecto con Predecremento
Primero se decrementa el valor del registro de direcciones y luego se accede al dato.
OR.B D3,-(A0)
Se utiliza para introducir datos en pila.
Direccionamiento Indirecto con Desplazamiento
La dirección efectiva se obtiene sumando un valor al contenido del registro de direcciones.
El desplazamiento es un numero con signo de 16 bits.
CHR $24(A4),D3
Direccionamiento Indirecto con Indice y Desplazamiento
La dirección efectiva se halla sumando 3 valores:
- El contenido de un registro de direcciones.
- Un desplazamiento de 8 bits.
- Un registro de datos.
Formato: desplazamiento(A*,D*.B|W|L)
DIVU 8(A3,D7.L),D5
Direccionamiento Relativo con Desplazamiento
Igual que el de desplazamiento pero con el contador de programa.
LEA $200(PC),A3
Direccionamiento Relativo con Indice y Desplazamiento
Igual que el de indice y desplazamiento pero con el PC
MOVE $B(PC,D1.L),D5
6. El juego de instrucciones de MC68000
Aquí va un extracto del juego de instrucciones. Es sencillo, pero suficiente.
[Nota:] Omitiré ciertas instrucciones, puesto que este artículo está pensado para aprender a programar un micro, no para profundizar en el 68000. Si estás interesado puedes buscar en la web el juego completo.
[Nota:] Este juego esta escrito resumidamente, y tiene el único fin de aprender un poco a programar el micro. Si se quiere utilizar con fines mas complejos, recomiendo que se busque las especificaciones completas de este código, ya que vendrán más extensamente comentadas.
Comentarios
Los comentarios comienzan por * o por ' y el ensamblador los ignora al generar el código.
Representacion de datos
Dato | Prefijo | Ejemplo |
---|---|---|
Decimal | Sin prefijo | 63 |
Binario | % | %111111 |
Hexadecimal | $ | $3F |
ASCII | ' ' | 'NETSEARCH' |
Operaciones
Estas operaciones pueden realizarse entre registros dentro de una instrucción.
Por ejemplo:
NETSEARCH EQU 20
EZINE EQU 30
MOVE #(NETSEARCH + EZINE / 2),D2
sería lo mismo que
MOVE #25,D2
- | OR lógico
- ^ OR Exclusivo (aka XOR)
- & AND lógico
- Suma de enteros
- Resta de enteros
- Multiplicación de enteros
- / División entera de enteros
- > Desplazamiento lógico hacia la derecha
- < Desplazamiento lógico hacia la izquierda
- (prefijo) Signo positivo
- (prefijo) Signo negativo
- ! Negacion lógica
- ( ) Parentesis sin límite de nivel
- Etiquetas: Se utilizan para demarcar determinada posicion, y se emplean sobretodo para las subrutinas.
- Extensiones: Se colocan en ciertas instrucciones.
En instrucciones de manejo de datos:
.B | El operando es un byte |
.W | El operando es una palabra (Por defecto para datos) |
.L | El operando es una palabra larga (Por defecto para direcciones) |
En instrucciones de tipo branch (ramificación):
.S | Desplazamiento corto (8 bits) |
.L | Desplazamiento largo (16 bits) |
Directivas o pseudoinstrucciones
(Se ponen en el código fuente, pero solo los emplea el compilador, no generan código)
Directiva | Uso | Descripción |
---|---|---|
ABSOLUTE | Indica que el código que se generará es absoluto (las referencias a posiciones de memoria). El código absoluto solo se ejecutará correctamente si se encuentra en las posiciones de memoria para las que ha sido ensamblado. | |
RELATIVE | Modo por defecto. Las referencias a posiciones de memoria seran relativas al Contador de programa (PC) |
|
ORG* (ORIGIN) | 'ORG expresión' | Indica la posición de memoria a partir de la cual se coloca el código que se genere a continuación. En código absoluto puede aparecer 20 veces, y en relativo solo 1. ORG $25000
|
END | Debe aparecer al final del programa. El código escrito a continuación se ignorará. | |
DC | DC DC.L expr, expr,... DC.B expr, expr,... |
Inicializa espacio en memoria. DC.W $2500
DC.L 'HOLA',$00
|
DS | DS.B|W|L expresión | Reserva tantos bytes|words|longword como se ponga en expresión. DS.W 2 -> DC.W 0,0
|
EQU | etiqueta EQU expresión | Asigna el valor de la expresión a una etiqueta. NUMERO EQU $400
|
Existen más, pero las omito.
Instrucciones de transferencia de datos
Instrucción | Uso | Descripción |
---|---|---|
MOVE | MOVE.B|W|L origen, destino | Transfiere datos del origen al destino. MOVE #$12,D3
|
MOVEA | MOVEA origen,A* | Transfiere una dirección. MOVEA $27,A2
|
MOVEM | MOVEM.W|L lista_reg,destino MOVEM.W|L origen,lista_reg |
Transfiere múltiples registros |
MOVEQ | MOVEQ #n,D* | Transferencia rapida a registro de datos n es un numero de 8 bits en complemento a 2. |
MOVEP | MOVEP.W|L O(A2),D* MOVEP.W|L D*,O(A2) |
Transferencia a perifericos. |
Instrucciones de intercambio
Instrucción | Uso | Descripción |
---|---|---|
EXG (Exchange) | EXG expresión, expresión | Permite intercambiar dos registros (de direcciones, de datos o uno con otro) |
SWAP | SWAP D* registro de datos. | Intercambia las dos mitades de un |
Instrucciones de manejo de direcciones efectivas
Instrucción | Uso | Descripción |
---|---|---|
LEA (Load Effective Address) | LEA fuente,A* | Carga en un registro de direcciones la direccion efectiva del operando. |
PEA (Push Effective Address) | PEA fuente,A* | Igual que el anterior, pero guarda la direccion efectiva en la pila. |
Instrucciones de suma
Instrucción | Uso | Descripción |
---|---|---|
ADD | ADD.B|W|L origen,destino | Suma binaria. Uno de los dos operandos ha de ser un registro de datos. ADD #$4F,D3
|
ADDA | ADDA.B|W|L fuente,A* | Suma de dirección. ADDA.W #$5,A2
|
ADDI | ADDI.B|W|L #n,destino | Suma inmediata. |
ADDQ | ADDQ.B|W|L #n,destino | Suma rápida. 1 <= n <= 8 |
ADDX | ADDX.B|W|L origen,destino | Suma extendida. origen + destino + X = destino X es el flag extendido del registro de estados |
Instrucciones de Resta
Instrucción | Uso | Descripción |
---|---|---|
SUB | SUB.B|W|L origen,destino | Resta binaria. |
SUBA | SUB.B|W|L origen,A* | Resta de direcciones. |
SUBI | SUBI.B|W|L #n,destino | Resta inmediata. |
SUBQ | SUBQ.B|W|L #n,destino | Resta rapida. |
SUBX | SUBX.B|W|L origen,destino | Resta extendida. |
Instrucciones de negación
Instrucción | Uso | Descripción |
---|---|---|
NEG | NEG.B|W|L operando | Niega el operando. |
NEGX | NEGX.B|W|L operando | Negacion con extensión. |
Instrucciones de multiplicación
Instrucción | Uso | Descripción |
---|---|---|
MULS | MULS.W operando,D* | Multplicación con signo. Los operandos son de 16 bits y el resultado de 32 bits. |
MULU | MULU.W operando,D* | Multiplicación sin signo. El resultado es de 32 bits. |
Instrucciones de división
Instrucción | Uso | Descripción |
---|---|---|
DIVS | DIVS.W operando,D* | División con signo. El la palabra más significativa del resultado es el resto, y la menos significativa el cociente. |
DIVU | DIVU.W operando,D* | División sin signo. |
Instrucciones de comparación
Instrucción | Uso | Descripción |
---|---|---|
CMP | CMP.B|W|L operando,D* | Compara registros de datos. |
CMPA | CMPA.B|W|L operando,D* | Comparacion inmediata. |
CMPM | CMPM.B|W|L (A*)+,(A*)+ | Comparacion de posiciones de memoria. |
Instrucciones de extensión de signo
Instrucción | Uso | Descripción |
---|---|---|
EXT | EXT.W|L D* | Extiende el bit de signo del operando. |
Instrucción de puesta a cero
Instrucción | Uso | Descripción |
---|---|---|
CLR | CLR.B|W|L operando | Pone a 0 el operando. |
Testeo de operandos
Instrucción | Uso | Descripción |
---|---|---|
TST | TST.B|W|L operando | Compara 0 con el operando. |
TAS | TAS.B operando | Comprueba operando y pone a 1 su bit de signo. |
Instrucciones de aritmética BCD
Instrucción | Uso | Descripción |
---|---|---|
ABCD | ABCD.B|W|L fuente,destino | Suma en código BCD con extensión. |
SBCD | SBCD.B|W|L fuente,destino | Resta BCD con extensión. |
NBCD | NBCD.B|W|L operando | Negacion en BCD con extensión. |
Instrucciones lógicas
Instrucción | Uso | Descripción |
---|---|---|
AND | AND.B|W|L fuente,destino | Realiza un Y lógico entre los operandos. |
ANDI | ANDI.B|W|L #n,operando | Y logico inmediato. #n es un número decimal entre 1 y 8. |
OR | OR.B|W|L origen,destino | Realiza un O lógico. |
ORI | ORI.B|W|L #n,destino | O lógico inmediato. |
NOT | NOT.B|W|L operando | Negación lógica. |
EOR | EOR.B|W|L D*,destino | Realiza un O exclusivo (aka XOR) |
EORI | EORI.B|W|L #n,destino | O exclusivo inmediato. |
Instrucciones de chequeo de bits
Instrucción | Uso | Descripción |
---|---|---|
BTST | BTST #n,destino BTST D*,destino |
Comprobamos un bit y reflejamos el estado de ese bit en el flag Z del registro de estados. #n es el bit a comprobar. |
BCLR | BCLR #n,destino BCLR D*,destino |
Comprueba el bit indicado y refleja el contenido en Z. Despues pone a 0 ese bit. |
BSET | BSET #n,destino BSET D*,destino |
Comprueba, actualiza Z y pone a 1 el bit. |
BCHG | BCHG #n,destino BCHG D*,destino |
Comprueba, actualiza Z e invierte el valor del bit. |
Instrucciones de desplazamiento y rotación
Instrucción | Uso | Descripción |
---|---|---|
LSL | LSL.B|W|L Di,Dj desp = Di mod 64 LSL.B|W|L #n,D* desp = #n LSL destino desp = 1 |
Desplaza hacia la izquierda los bits tantas veces como desp. C <- bit|bit|bit|...|bit|bit|bit <- 0 | X <- |
LSR | LSR.B|W|L Di,Dj desp = Di mod 64 LSR.B|W|L #n,D* desp = #n LSR destino desp = 1 |
Desplaza hacia la derecha los bits tantas veces como desp. 0 -> bit|bit|bit|...|bit|bit|bit -> C | -> X |
ASL | ASL.B|W|L Di,Dj desp = Di mod 64 ASL.B|W|L #n,D* desp = #n ASL destino desp = 1 |
Desplazamiento aritmetico hacia la izquierda El flag V (overflow) se pone a 1 si el bit más significativo cambia en algún momento. |
ASR | ASR.B|W|L Di,Dj desp = Di mod 64 ASR.B|W|L #n,D* desp = #n ASR destino desp = 1 |
Desplazamiento aritmetico hacia la derecha El flag V (overflow) se pone a 1 si el bit menos significativo cambia en algún momento. |
ROL | ROL.B|W|L Di,Dj desp = Di mod 64 ROL.B|W|L #n,D* desp = #n ROL destino desp = 1 |
Rotación hacia la izquierda | | C <- bit|bit|bit|...|bit|bit|bit <- |
ROR | ROR.B|W|L Di,Dj desp = Di mod 64 ROR.B|W|L #n,D* desp = #n ROR destino desp = 1 |
Rotación hacia la derecha. | | -> bit|bit|bit|...|bit|bit|bit -> C |
ROXL | ROXL.B|W|L Di,Dj desp = Di mod 64 ROXL.B|W|L #n,D* desp = #n ROXL destino desp = 1 |
Rotación a izquierda con extensión. | | C <- bit|bit|bit|...|bit|bit|bit <- X <- |
ROXR | ROXR.B|W|L Di,Dj desp = Di mod 64 ROXR.B|W|L #n,D* desp = #n ROXR destino desp = 1 |
Rotación a derecha con extensión | | - X -> bit|bit|bit|...|bit|bit|bit -> C |
Instrucciones de control de programa (Saltos) incondicionales
Instrucción | Uso | Descripción |
---|---|---|
BRA (Branch) | BRA etiqueta | Ramificación incondicional (Salto de 8 o 16 bits relativo a PC) El PC apunta ahora a la dirección de etiqueta |
BSR (Branch SubRoutine) | BSR etiqueta | Ramificación a subrutina. (Llamada a subrutina con esa etiqueta) Guarda el PC en la pila y cambia el PC a la dirección de etiqueta. 8 o 16 bits relativo a PC |
JMP (Jump) | JMP destino | Salto. (Direccionamiento absoluto) El PC se pone la dir. de etiqueta. |
JSR (Jump SubRoutine) | JSR destino | Salto a subrutina. Guarda el PC en pila y cambia PC por la dir. destino. Direccionamiento absoluto. |
RTS (Return SubRoutine) | RTS | Retorno de subrutina. Recupera el PC de la pila (Volvemos al punto donde se llamo la subrutina) |
RTR | RTR | Retorno de subrutina y reposición de los códigos de condición. |
Saltos condicionales
cc: Condiciones base. Se colocan como sufijo a la instruccion condicional.
Aritmética con signo
- GT (Greater Than) si >
- LS (Less Than) si <
- GE (Greater or Equal) si >=
- LE (Less or Equal) si =<
- VS (Overflow) si overflow
- VC (No overflow) si no overflow
- PL (Plus) si positivo
- MI (Minus) si negativo
Aritmetica sin signo
- HI (Higher) si mayor
- CS (Carry Set) si menor
- CC (Carry Clear) si mayor o igual
- LS (Low or Same) si menor o igual
- EQ (Equal) si igual
- NE (Not Equal) si distinto
- T (True) si cierto
- F (False) si falso
Instrucción | Uso | Descripción |
---|---|---|
Bcc (Branch if) | Bcc etiqueta | Si se cumple cc salta a etiqueta (etiqueta -> PC) Dirección relativa a PC (8 o 16 bits) |
DBcc | DBcc D*,etiqueta | Decrementar y ramificar. Mientras cc se cumple no se hace nada. Si cc no se cumple, se decrementa el registro D*. Mientras D* es distinto de -1, se salta a etiqueta. |
Scc (Set) | Scc destino | Pone destino a 1 si la condicion se cumple o a 0 si no. El destino sera un byte. |
Instrucción de no operación
Instrucción | Uso | Descripción |
---|---|---|
NOP | NOP | No hace nada. Solo consume tiempo de reloj (4 ciclos). Es útil para generar retrasos, reservas de espacio para futuras instrucciones o para substituir instrucciones sobrantes sin tener que modificar el resto del programa. |
INSTRUCCIONES PRIVILEGIADAS
Las instrucciones privilegiadas solo son accesibles en modo supervisor.
Estas instrucciones son muchas de las anteriores pero aplicadas a los registros SR (Registro de estado), CCR (Registro de Códigos de Condición) y USP (Puntero de Pila de Usuario). Ademas, tenemos estas otras:
Instrucción | Uso | Descripción |
---|---|---|
RESET | RESET | Activa la linea de reset o produce una excepción (el micro no se reinicializa). |
RTE (Return of Exception) | RTE | Retorna de una interrupción, restaurando |
STOP | STOP #n | Se pone #n en SR y se para la ejecución. Para reanudar la ejecución es necesaria una interrupción. |
CHK | CHK origen,D* | Compara un registro con unos limites. D* < 0 o D* > origen Si fuera de esos limites, se genera una interrupción 6 (Tipo trampa) |
TRAP | TRAP #n | Se genera una interrupción trampa. #n esta entre 0 y 15, segun la prioridad. |
TRAPV | TRAPV | Se genera una excepción de tipo trampa de orden 7 si el flag V (Overflow) esta a 1. |
7. Subrutinas
A veces hay operaciones que se repiten durante un programa, y habría que reescribir todo el código de nuevo, con el consiguiente gasto de memoria y el engorro de reescribirlo. Para evitar esto se crean subrutinas, que son pedazos de código que podemos llamar mediante instrucciones de salto o ramificación. Físicamente, en memoria solo está una vez, pero puede utilizarse cuantas veces sea necesario. El funcionamiento básico de una subrutina es el siguiente:
Al llegar a una llamada a subrutina, se guarda en la pila la dirección a la que apunta ese momento el PC (Contador de programa). Entonces actualizamos el PC con la dirección de comienzo de la subrutina. Una vez termina la subrutina (Con la instruccion RTS o RTR), se recupera de la pila la direccion del PC y continuaremos en la siguiente instrucción a la llamada de la subrutina.
8. Excepciones
Las excepciones son acontecimientos, internos o externos al micro, que hacen que se interrumpa la ejecución para realizar una subrutina de atencion a esa excepción. Estas excepciones pueden ser:
- Errores hardware
- Errores intenos
- Reset
- Ejecución paso a paso
- Interrupciones hardware
- Interrupciones software
Cada excepcion tiene asociada una dirección de memoria donde se encuentra su vector de excepción. Ese vector contiene la dirección de comienzo de la rutina de excepción.
TABLA DE LOS VECTORES DE EXCEPCION DEL MC68000
[Nota:] El reset ocupa 2 vectores de excepcion
Nº vector | Dirección | Asignación |
---|---|---|
0 | $000 | Reset: SSP (Punt. de pila supervisor) inicial. |
- | $004 | Reset: PC inicial. |
2 | $008 | Error de bus. |
3 | $00C | Error de dirección. |
4 | $010 | Instrucción ilegal. |
5 | $014 | División por cero. |
6 | $018 | Instrucción CHK. |
7 | $01C | Instrucción TRAP. |
8 | $020 | Violación de privilegio. |
9 | $024 | Traza. |
10 | $028 | Instrucción emulada 1010. |
11 | $02C | Instrucción emulada 1111. |
12 | $030 | No asignado. Reservado. |
13 | $034 | No asignado. Reservado. |
14 | $038 | No asignado. Reservado. |
15 | $03C | Vector de interrupción no inicializado. |
6-23 | $044-$05C | No asignado. Reservado. |
24 | $060 | Interrupción espúrea (Especie de timeout). |
25 | $064 | Autovector de Interrupción de nivel 1 (IRQ1). |
26 | $068 | Autovector de Interrupción de nivel 2 (IRQ2). |
27 | $06C | Autovector de Interrupción de nivel 3 (IRQ3). |
28 | $070 | Autovector de Interrupción de nivel 4 (IRQ4). |
29 | $074 | Autovector de Interrupción de nivel 5 (IRQ5). |
30 | $078 | Autovector de Interrupción de nivel 6 (IRQ6). |
31 | $07C | Autovector de Interrupción de nivel 7 (IRQ7). |
32-47 | $080-$0BC | Vectores de la instrucción TRAP (1-15). |
48-63 | $0C0-$0FC | No asignado. Reservado. |
64-255 | $100-$3FC | Vectores de interrupción de usuario. |
Dirección de excepción = Número de vector x 4
9. Interrupciones
Las interrupciones son el mecanismo básico de sincronización del micro con dispositivos externos. Quizá sean una de las cosas mas importantes en un micro.
Pueden ser generadas por hardware, a traves de las lineas IPL2 IPL1 e IPL0 o por software, mediante las instrucciones TRAP.
Existe tambien una interrupción especial llamada Interrupción Espúrea, que sirve para evitar esperas infinitas cuando el micro lleva mucho tiempo esperando (por ejemplo, se activa una IRQ por ruido, pero realmente nadie pide la interrupción).
Una interrupción funciona básicamente igual que una subrutina, con la diferencia de que se trabaja en modo supervisor (y por tanto, tambien utilizamos la pila de supervisor (SSP). ?Mecanismo de solicitud
En las líneas de interrupción se codifica el nivel de prioridad de la interrupción. Se utilizan los 7 Autovectores (ya que estamos hablando de una interrupción generada externamente, por un periférico, por ejemplo).
IPL2 | IPL1 | IPL0 | Nivel de prioridad |
---|---|---|---|
0 | 0 | 0 | 7 (Máxima, no enmascarable) |
0 | 0 | 1 | 6 |
0 | 1 | 0 | 5 |
0 | 1 | 1 | 4 |
1 | 0 | 0 | 3 |
1 | 0 | 1 | 2 |
1 | 1 | 0 | 1 (Mínima) |
1 | 1 | 1 | No se solicita interrupción |
[Nota:] Como vemos, son lineas que se activan a nivel bajo (es decir, con un 0).
Se suele utilizar un codificador para generar estos códigos a partir de las 7 IRQ, pero eso ya lo veremos en próximos artículos.
Enmascaramiento
El enmascaramiento nos sirve para controlar si cuando se activa una interrupción y ya esta otra en ejecución se debe parar la primera o no. Esto se hace con la máscara de interrupción, codificada en el byte alto del registro de estado, como hemos visto anteriormente. Esta máscara se actualiza cuando se genera una interrupción, y si se genera otra, el nivel de prioridad de esta interrupción debe ser superior a la máscara, o se ignorará.
10. Ejemplo práctico
Aquí os dejo un pequeño ejercicio práctico para que veais como funciona el 68000. Tendreis que utilizar el simulador.
No voy a explicar como funciona, porque es bastante intuitivo. Simplemente, teneis que compilar y linkar el código y ejecutarlo en el simulador. Dentro del simulador, antes de ejecutar debereis configurar las posiciones de memoria de los puertos de entrada y de salida que necesiteis (aquí uso como entrada $60000 y como salida $60001) y configurar la ventana para que muestre esos puertos y ver su contenido durante la ejecución. Tambien podeis ejecutar en modo traza.
Bien, el objetivo es el siguiente:
Tenemos un sistema de 8 leds conectados a la posicion de memoria $60000 de un sistema digital con un micro MC68000. Cada uno de esos leds se enciende cuando recibe un "1" lógico, y se apaga al recibir un "0". En el puerto de entrada, situado en la posicion $60001, si se pone un 1 los leds deben parpadear mientras ese 1 siga ahí. Si se pone un 2, los leds deben hacer un efecto estilo el coche fantástico Kit (bueno, los malotes si lo preferis le poneis leds verdes y ya esta :P). Si se pone cualquier otro dato, los leds continuarán apagados.
Tambien tenemos un pulsador conectado a las lineas de interrupción, que genera una interrupción de nivel 2 (IRQ2). Si lo pulsamos, apagamos todos los leds.
[Nota:] Cada led esta conectado a un bit del primer byte del puerto de salida.
**** SIMULACION CON LEDS
ABSOLUTE
ORG $00000
DC.L $40000 * Inicializamos la SSP
DC.L $25000
ORG $68 * Inicializamos la IRQ2 (Su autovector
DC.L $26000 * es el $68) la direccion de comienzo
* de la rutina de interrupcion sera
* la $26000
ORG $25000
MOVE.L #$29000,A7 * Inicializacion de SP
INICIO
CLR.L D0 * Ponemos a 0 D0
MOVE.B $60000,D0 * Leer entrada
CMPI.B #1,D0 * Si es 1...
BEQ PARPADEO * ...saltamos a parpadeo
CMPI.B #2,D0 * Si es 2...
BEQ COCHE * ...saltamos a COCHE
JMP INICIO * Sino, reiniciamos
**** Bucle FOR de $F a $0
WAIT
MOVE.W #$F,D1
ITER
DBF D1,ITER *
RTS
**** Subrutina 1: Parpadeo
PARPADEO
MOVE.B #$FF,$60001 * Escribir 1's en el byte de salida (8 LEDS)
JSR WAIT * Hacemos un retardo (Subrutina Bucle FOR)
MOVE.B #$00,$60001 * Escribir 0's en salida
CMPI.B #1,D0
BNE INICIO
JSR WAIT
JMP PARPADEO
*** Subrutina 2: Coche Fantastico
COCHE
MOVE #1,D2
IZQUIERDA
MOVE.B D2,$60001 * Poner 1 en salida
JSR WAIT
CMPI.B #2,D0 * Comprobar que D0 sigue siendo 2...
BNE INICIO * ...sino volvemos al comienzo
MULU #$2,D2 * Multiplicamos por 2 D2, asi tenemos el siguiente LED
* que serian 1,2,4,8,16,32,64 y 128 en binario
CMP #128,D2 * Se para en el ultimo bit encendido y cambia de
* sentido
BEQ DERECHA
JMP IZQUIERDA
DERECHA
MOVE.B D2,$60001
JSR WAIT
CMPI.B #2,D0
BNE INICIO
DIVU #$2,D2
CMP #1,D2 * Se para en el primer bit encendido y cambia de
* sentido
BEQ IZQUIERDA
JMP DERECHA
ORG $26000 * Direccion del codigo a continuacion
PUESTACERO
MOVE.W #0,D0 * Poner 0 en D0
RTE
END