Commodore manía
Commodore 64 => Desarrollo => Mensaje iniciado por: Dr.Fred en Marzo 08, 2011, 23:09:42
-
Hola!
Hacía mucho que no escribía, aunque os leo muy a menudo y me alegra ver que paso a paso se van gestando cosas por aquí. Un saludo a todos.
Este año he empezado un ciclo de electrónica y para mi sorpresa, en la asignatura de Electrónica Digital, nos estamos centrando en el procesador 6502 (Imaginaos el subidón que me dio al saberlo), así que estoy aprendiendo ensamblador y disfrutando como un enano.
Por mi cuenta he empezado a ver el tema de interrupciones y he leído algunos libros respecto al tema, pero hay cosas que no me quedan claras.
Si no he entendido mal, a grandes rasgos, consiste en dos bytes que contienen el puntero a la dirección de memoria que se ejecutará cuando se realice la interrución. Cuando salte una interrupcion, el sistema irá a esta zona y ejecutará lo que haya de modo similar a si fuera una subrutina.
Mi primera pregunta es: ¿Cuando y cómo se llama a una interrupción?
También he leído que el sistema utiliza las interrupciones 60 veces por segundo (controlar el reloj, controlar la entrada de teclado, flasheo del cursor, etc...) Entonces supongo que esos dos bytes de puntero cambian en la memoria muchísimas veces ( de ahí la necesidad de usar la instrucción SEI) La cuestión es: cuando yo le meta a esas direcciones una dirección de mi rutina, entiendo que se machacará seguidamente por la que quiera usar el sistema. Entonces, si yo quisiera ejecutar esa rutina varias veces, ¿qué tendría que hacer?
A ver si alguien me puede aclarar un poco este tema, que en los libros no lo veo muy claro y tampoco encuentro muchos ejemplos que lo expliquen.
Os pongo un ejemplo de una interrupción que lee el teclado y escribe en pantalla. Lo que no consigo entender es en qué parte se llama a la interrupción en el programa... o simplemente poniendo la dirección en los dos bytes, ejecutaría mi interrupción... pero sólo lo haría una vez, porque se queda en un bucle infinito en la etiqueta HERE... No sé... hay algo que no termino de ver.
Bueno, muchas gracias por adelantado.
[code]
MAIN SEI
LDA #00
STA USRVTR
LDA #$C1
STA USRVTR+1
CLI
HERE JMP HERE
EQU $C100
IRQ JSR SCNKEY
LDX +$C6
BEQ OUT
DEX
STX +$C6
LDA $0277
JSR CHROUT
OUT LDA IRQCTL
PLA
TAY
PLA
TAX
PLA
RTI
[/quote]
-
Pásate por RetroEncounter y te lo explico :wink:
PD: Cuando tenga un rato también te lo intento explicar por el foro.
-
Que me voy a pasar por ahí es un hecho... sería pecado perderselo. Pero... aun queda mucho tiempo y mi hambre de ensamblador es insaciable!! Jeje, no, fuera coña. Te agradecería mucho si pudieras darme alguna pista cuando tengas tiempo. Un saludo!
-
Por mi cuenta he empezado a ver el tema de interrupciones y he leído algunos libros respecto al tema, pero hay cosas que no me quedan claras.
Te lo intentaré ir respondiendo en píldoras por falta de tiempo...
Si no he entendido mal, a grandes rasgos, consiste en dos bytes que contienen el puntero a la dirección de memoria que se ejecutará cuando se realice la interrución. Cuando salte una interrupcion, el sistema irá a esta zona y ejecutará lo que haya de modo similar a si fuera una subrutina.
Antes de nada aclarar que tipos de interrupciones hay varios: raster, NMI, las producidas por las CIAs, y no sé si alguna mas.
Básicamente el funcionamiento es el que dices (al menos en el caso de las interrupciones raster que son las que conozco), digamos que se interrumpe el flujo de instrucciones normal del procesador para 'saltar' a esa dirección donde está el código que se ejecuta.
Mi primera pregunta es: ¿Cuando y cómo se llama a una interrupción?
En el caso de las raster (repito que es el caso que conozco) se llama cuando nosotros se lo indicamos, es decir, en cada refresco de pantalla (que se hace 50 veces por segundo = 50 Hz en sistemas PAL) nosotros le podemos indicar al procesador que se ejecute una interrupción en una o varias de las diferentes líneas (o rasters) de la pantalla.
Esto lo haríamos modificando el registro $d012, el valor que pongamos en él indicará en que número de línea de pantalla 'saltará' la próxima interrupción raster.
-
Dr.Fred: que bueno!!
-
Mi primera pregunta es: ¿Cuando y cómo se llama a una interrupción?
También he leído que el sistema utiliza las interrupciones 60 veces por segundo (controlar el reloj, controlar la entrada de teclado, flasheo del cursor, etc...) Entonces supongo que esos dos bytes de puntero cambian en la memoria muchísimas veces ( de ahí la necesidad de usar la instrucción SEI) La cuestión es: cuando yo le meta a esas direcciones una dirección de mi rutina, entiendo que se machacará seguidamente por la que quiera usar el sistema. Entonces, si yo quisiera ejecutar esa rutina varias veces, ¿qué tendría que hacer?
Empiezo por el final (como los japoneses que leen desde la ultima página hacia la primera jaja):
Cuando quieras usar tu propia rutina, es buena idea devolver el control a la rutina que se ejecutaba antes de modificar el vector, simplemente con un JMP al final de la tuya.
Las interrupciones no las llama un programa, las llama continuamente la CPU, y como bien dice Carlos, hay varios tipos de interrupciones. Unas (las raster por ejemplo) las llama el chip Vic-II (el encargado del apartado gráficos).
Cada cierto tiempo (60 veces por segundo en sistemas NTSC o 50 en PAL) la cpu salta al fragmento de código especificado en su correspondiente "vector de interrupcion" (ese par de bytes que indican una direccion de los que hablabas)
y lo ejecuta. Pero antes guarda el estado de todos los registros en la pila incluyendo la direccion del PC(puntero de programa) actual antes de iniciar la interrupción, para cuando regrese al programa que se estaba ejecutando, todo este proceso haya sido totalmente "transparente". Es importantísimo saber que las rutinas que se ejecuten por la interrupcion de cada tipo de interrupcion son responsables de recuperar la pila.
Hay interrupciones enmmascarables (IRQ) o no enmascarables (NMI). Las enmascarables, son las que pueden ser ignoradas (tocando un bit usando una mascara de bits, de ahi su nombre), las NMI, no tienen una mascara de bits asociada para tocar, por lo que no pueden ser ignoradas (siempre serán llamadas: otra cosa es que apuntemos a una rutina "vacia", por ejemplo).
Tambien está el tipo de interrupción por software, que es una que no se llama automáticamente por la cpu, si no que es un programa la que la genera, y se hace mediante la instrucción BRK o pulsando RUN-STOP/RESTORE
En resumen, solo hay una interrupción (las de software) que podremos "llamarla" nosotros, las otras, son continuamente llamadas por el propio sistema.
En general, además, tal como viene el sistema al encenderlo, el vector de interrupción de cada interrupción están inmutables, no cambian cada vez que tiene que hacer una tarea, en realidad, una interrupción por ejemplo, comprueba el reloj y hace parpadear el cursor en el mismo fragmento de código, y otras tareas las hace otra interrupción, como por ejemplo gestionar el teclado...
En nuestros programas, si que podemos cambiar muchas veces ese vector para hacer cosas como múltiples interrupciones pero no es aconsejable más de dos, por que restan ciclos tambien de la CPU.
Tambien se pueden programar la frecuencia a la que las interrupciones serán ejecutadas, con el raster, o con los timers.
-
Os pongo un ejemplo de una interrupción que lee el teclado y escribe en pantalla. Lo que no consigo entender es en qué parte se llama a la interrupción en el programa... o simplemente poniendo la dirección en los dos bytes, ejecutaría mi interrupción... pero sólo lo haría una vez, porque se queda en un bucle infinito en la etiqueta HERE... No sé... hay algo que no termino de ver.
[code]
MAIN SEI
LDA #00
STA USRVTR
LDA #$C1
STA USRVTR+1
CLI
HERE JMP HERE
EQU $C100
IRQ JSR SCNKEY
LDX +$C6
BEQ OUT
DEX
STX +$C6
LDA $0277
JSR CHROUT
OUT LDA IRQCTL
PLA
TAY
PLA
TAX
PLA
RTI
[/quote]
Tras un vistazo rápido:
En la parte Main, lo unico que hace es indicarle al sistema que
el nuevo vector de interrupción apunte a $C100, que es donde estará
la rutina etiquetada IRQ, tras esto la rutina se ejecutara 50 veces por segundo (PAL). luego llega al bucle infinito, si IRQ fuera llamada de otra manera que no fuera por una interrupción solo se ejecutaria una vez.
Como ves un bucle infinito en realidad no bloquea el sistema... Hay otras tareas que estan sucediendo por dentro (que nosotros percibimos paralelamente al programa actual en ejecución), como por ejemplo las rutinas llamadas por las interrupciones.
Para que veas como se harmonizan las interrupciones con el basic y ver un poco más acerca de las interrupciones,
te pongo este otro ejemplo donde la primera posicion de la memoria de video se va incrementando (mostrando un caracter distinto a cada vez que la interrupcion es llamada). Fijate que al volver el control a la misma rutina que se llamaba antes de modificar el vector, incluso podemos escribir cosas mientras la rutina sigue ejecutándose :wink:
Aqui programo la interrupción del primer chip CIA (complex interface adapter): hay dos CIA en el c64. En cada uno de estos chips podemos programar un reloj ("timers" A y B) que aquí se usa para poner la frecuencia de llamado de la interrupción 60 veces por segundo.
[code]
sei
lda #<irq
sta $0314
lda #>irq
sta $0315
// frecuencia de la int($411a = 60 ints x sec.).
lda #$1a
ldy #$41
sta $dc04
sty $dc05
// permite timer A en el CIA1
lda #$81
sta $dc0d
// pone timer A en modo continuo
lda #$91
sta $dc0e
cli
rts
//----------------------------------
irq: inc $0400
lda $dc0d //hacer una lectura de este registro implica que la int volverá a ser rellamada despues
asl $d019
jmp $ea31 // salta a rutinas del vector original [/quote]
Si no quieres regresar al basic (con RTS), puedes sustituir el jmp $ea31 por:
[code]PLA
TAY
PLA
TAX
PLA
RTI[/quote]
que es basicamente el fragmente estandard de finalizacion de una rutina de interrupcion en el 6502. Si te fijas en un desensamblado de la ROM del basic verias que la rutina situada en $ea31, al final usa esto mismo tambien.
si quieres tambien en lugar del RTS pones HERE JMP HERE, como tenias en tu ejemplo, para lo del bucle infinito, y veras que los caracteres siguen girando... :wink:
NOTA: si usas RTS para regresar al basic, es necesario finalizar nuestra rutina con JMP $EA31 (que hará que el basic se comporte con normalidad)
-
Dr. Fred, lobogris te lo ha dejado planchado... :wink:
-
Dr. Fred, lobogris te lo ha dejado planchado... :wink:
Ya te digo! jajaja. Muchas gracias a los dos. Ya lo veo bastante más claro y además ya hemos empezado con ellas en clase. Ahora a hacer programillas toca.
Lo dicho, gracias!