Micro Motorola MC68000
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 Eleectronica Digital. Voy a intentar enfocarlo para que cualquiera pueda empezar en este tema. No obstante, dare 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
- Indice
- Propiedades hardware
- Modelo de programación
- La Memoria
- Modos de Direccionamiento
- Juego de instrucciones
- Subrutinas
- Excepciones
- Interrupciones
- Ejemplo práctico
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.
Ej: MOVE $23345,CCR
- Direccionamiento Inmediato:
Se expresa la dirección explicitamente en la operación. Se utiliza el caracter # antes de la dirección.
Ej: 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.
Ej: ADDQ #6,A0
- Direccionamiento Absoluto Largo:
El argumento es la dirección efectiva a la que se accede.
Ej: 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.
Ej: EORI.B #$FF,$8000
- Direccionamiento directo a registro:
El operando es un registro interno, D* o A*
Ej: 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.
Ej: 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*)+
Ej: 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.
Ej: 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.
Ej: 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)
Ej: DIVU 8(A3,D7.L),D5
- Direccionamiento Relativo con Desplazamiento:
Igual que el de desplazamiento pero con el contador de programa.
Ej: LEA $200(PC),A3
- Direccionamiento Relativo con Indice y Desplazamiento
Igual que el de indice y desplazamiento pero con el PC
Ej: MOVE $B(PC,D1.L),D5
6. El juego de instrucciones
Aquí va un extracto del juego de instrucciones. Es un juego 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.
JUEGO DE INSTRUCCIONES DEL MC68000
[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)
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.
Ej: ORG $25000
END
Debe aparecer al final del programa. El código escrito a continuación se ignorará.
DC
DC.B expresión,expresóon,…
DC.W expresión,expresión,…
DC.L expresión,expresión,…
Inicializa espacio en memoria.
Ej: DC.W $25000
DC.L ‘HOLA’,$00
DS
DS.B|W|L expresión
Reserva tantos bytes|words|longword como se ponga en expresión.
Ej: DS.W 2 —-> DC.W 0,0
EQU
etiqueta EQU expresión
Asigna el valor de la expresión a una etiqueta.
Ej: NUMERO EQU $400
Existen más, pero las omito.
- Instrucciones de transferencia de datos
MOVE
MOVE.B|W|L origen, destino
Transfiere datos del origen al destino.
Ej: MOVE #$12,D3
MOVEA
MOVEA origen,A*
Transfiere una dirección.
Ej: MOVEA $27,A2
MOVEM
MOVEM.W|L lista de registros,destino
o
MOVEM.W|L origen,lista de registros
Transfiere multiples 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*
o
MOVEP.W|L D*,O(A2)
Transferencia a periféricos.
- Instrucciones de intercamibo
EXG (Exchange)
EXG expresión, expresión
Permite intercambiar dos registros (de direcciones, de datos o uno con otro)
SWAP
SWAP D*
Intercambia las dos mitades de un registro de datos.
- Instrucciones de manejo de direcciones efectivas
LEA (Load Effective Address)
LEA fuente,A*
Carga en un registro de direcciones la direccion efectiva del operando.
PEA (Push Effective Address)
Igual que el anterior, pero guarda la direccion efectiva en la pila.
- Instrucciones de suma
ADD
ADD.B|W|L origen,destino
Suma binaria. Uno de los dos operandos ha de ser un registro de datos.
Ej: ADD #$4F,D3
ADDA
ADDA.B|W|L fuente,A*
Suma de dirección.
Ej: 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
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
NEG
NEG.B|W|L operando
Niega el operando.
NEGX
NEGX.B|W|L operando
Negacion con extensión.
- Instrucciones de multiplicación
MULS
MULS.W operando,D*
Multiplicacion 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
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
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
EXT
EXT.W|L D*
Extiende el bit de signo del operando.
- Instrucción de puesta a cero
CLR (Clear)
CLR.B|W|L operando
Pone a 0 el operando.
- Testeo de operandos
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
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
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
BTST
BTST #n,destino
o
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
o
BCLR D*,destino
Comprueba el bit indicado y refleja el contenido en Z. Despues pone a 0 ese bit.
BSET
BSET #n,destino
o
BSET D*,destino
Comprueba, actualiza Z y pone a 1 el bit.
BCHG
BCHG #n,destino
o
BCHG D*,destino
Comprueba, actualiza Z e invierte el valor del bit.
- Instrucciones de desplazamiento y rotació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 aritmético 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 aritmético 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
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 dir. 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
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
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:
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 SR y PC
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 (Check)
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 (Trampa)
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
Numero vector Direccion 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 Violacion 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 interrupcion
[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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | **** 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 |

Este es el weblog personal de Antonio Rodríguez (aka MoebiuZ).