top of page

Interrupció de línia

  • Writer: MoltS Xalats
    MoltS Xalats
  • Apr 29
  • 9 min de lectura

Introducció

Fins ara, havíem uitlitzat el VBlank per portar el tempo del joc. El VBlank és el temps que tarda el raig de llum de passar de l'última línia de baix de tot a la primera de dalt de tot. Segons el tipus de codificació, PAL o NTSC, aquest viatge de tornada es fa 50 vegades o 60 vegades per segon, respectivament. Però el VDP 9938 i 9958 permet fer una interrupció de línia, li podem indicar a quina de les 212 línies que pinta (i les que estan ocultes) volem que el VDP generi una interrupció.


I de què ens pot servir que en lloc de fer-ho al final de la pantalla ho faci entre mig? Un cop interrumput en una línia, podem modificar els registres del VDP i quan continuï pintant que estigui mostrant una altra pàgina, o que canviï la paleta de colors, etc. En el nostre cas ho farem perquè dins de la pantalla de l'scroll hi hagi una part que es mantingui fixe, que no es desplaci amb l'scroll, així aquesta part es podria fer de marcador, per mostrar informació sense que es mogui.


Abans de conèixer la interrupció de línia, havia començat a desenvolupar la part estàtica de la pantalla fent copy's, però els càlculs eren molts i hi havia pampallugues degut al retard per tota la computació. Aleshores vaig trobar aquest codi del msxpen que utilitzava la interrupció de línia en un programa curtet per observar el seu funcionament. I vaig pensar que aquesta seria una bona solució pel problema que tenia en tenir una part fixa.


Com es programa una interrupció de línia

La interrupció de línia només es dóna en els MSX2 o superiors. Utilitza el registre 19 per guardar el número de línia a la que es produirà la interrupció i s'ha de configurar el VDP perquè generi les interrupcions de línia escrivint un 1 al bit 4 del registre 0, al que a la documentació de Yamaha anomena IE1 Enables interrupt from horizontal line.


A part de tenir-la activada, haurem de canviar el ganxo (hook) que en aquests moments no fa res. Això és el mateix que fem en el ganxo del VSync, del retrocés de carro, posar a l'adreça que salta la línia un salt al nostre programa en comptes del codi que fa per defecte.


Les operacions que fem durant aquesta interrupció han de ser curtes, ja que el VDP continua pintant el que té a la VRAM, si tardem molt, el gruix de línies amb el VDP inestable, vull dir en estats desconeguts, serà més gran.


Canviem el color del fons

Un programa senzill que ens permet aprendre com crear una interrupció de línia és el que tot seguit veurem. Utilitzarem la interrupció per canviar el color del fons, creant una franja de diferent color, que pujarà i baixarà.


Primer de tot definim la rutina que ja hem utilitzat altres vegades per crear el ganxo de la interrupció: InterruptHandlerHelper, InitializeMyInterruptHandler, EndMyInterruptHandler.

Després d'això definim la variable cpt que ens indicarà a quina part de la interrupció de línia estic. És a dir, he de fer dues interrupcions de línia per refresc vertical, la primera interrupció que és quan fem un canvi a la pantalla i indiquem quina serà la següent línia d'interrupció. I la segona interrupció que és al final de la franja vertical que hem modificat i que hem de tornar a la pantalla original.


Les variables Ystart i Yend indiquen el número de línia a on es causarà la interrupció, primer a Ystart i la següent a Yend. La variable Y la utilitzarem per fer l'scroll del fons de pantalla i la variable d l'utilitzarem per la direcció de l'scroll, si puja (d>0) o baixa (d<0).


I a la línia 83 definim la funció que s'executarà a cada interrupció de línia HBlankHook, a on el primer que fem és saber si estem a la primera part de la interrupció o a la segona amb la variable cpt. Si estem a la segona (cpt = 0), marquem la següent interrupció de línia al registre 19 i canviem els colors del fons amb la funció SetColors i canviem el valor de cpt per poder identificar el nou estat a la següent interrupció. A la següent interrupció (cpt !=0) tornem a col·locar la interrupció al final i tornem a canviar el color de fons i el del valor cpt.


Després a la línia 100 tenim el ganxo del VDP, que detectem si està feta per interrupció horitzontal amb la funció IsHsync. Si és així executem la funció anterior a on es gestionava la interrupció de línia. Si no detectem que venim de la interrupció de línia, també s'executa aquest ganxo en la interrupció vertical, ja que com heu pogut comprovar és la mateixa rutina que utilitzàvem per canviar el ganxo en altres programes.

Definim la funció FT_Wait que s'encarregarà d'esperar perquè poguem veure com va evolucionant l'scroll, si no aniria tan ràpid que no veuríem res.


I a la línia 116 comencem el que seria la funció main. Definim la variable IE1 que contindrà el valor del que hi havia al registre 0 del VDP abans que el modifiquéssim per permetre les interrupcions del número de línia (l'assignem a la línia 123) i que utilitzarem més tard per restaurar-lo.


Activem l'screen 5 del MSX i escrivim al registre 19 del VDP el número de línia de la propera interrupció, que és el 50. A la línia 123 llegim el valor del registre 0 i activem el bit 4 que és el del HSync, deixant la resta de bits iguals, amb el valor que tenien.


A les properes línies escrivim el nou valor a la memòria imatge i al registre 0. Inicialitzem les interrupcions, i a la línia 129 definim un bucle que sempre s'anirà executant fins que s'apreti la tecla ESC (número 27 de la matriu del teclat).


Dins del bucle ens esperem i augmentem el valor de la coordenada Y que és on es farà la nova interrupció. A la línia 132 mirem si el punt d'interrupció ha passat el límit que tenim de la franja de canvi de color i canviem la direcció de l'scroll.


Quan sortim del bucle retornem el valor que hi havia a IE1 desactivant el bit HSync, traiem el ganxo de la interrupció, tornem al mode 0 de pantalla i sortim de l'aplicació.

Aquest programa el podeu trobar al repositori de MoltSXalats.


Compliquem la interrupció de línia

Ara que hem tingut el primer contacte amb el funcionament de la interrupció de línia, volem aplicar aquests coneixements al nostre programa que feia l'scroll de patrons, per tal d'aconseguir que una part de la pantalla no es mogui i poder mostrar informació de punts, vides, armes o algun altre tipus d'informació.


Així les tasques que s'han de fer a la interrupció és canviar de pàgina a mostrar la pantalla, posant l'scroll horitzontal i vertical als valors per mostrar la part de pantalla corresponent, eliminar els sprites i tornar a posar la interrupció de línia a la següent posició. Si el programa es troba en aquesta següent posició ha de tornar els valors de l'scroll corresponents al mapeig dels patrons i tornar a dibuixar els sprites.


Primers desenvolupaments

Al principi, quan vaig activar la interrupció de línia, feia un pampallugueig, i no aconseguia esbrinar la seva causa. Vaig preguntar al fòrum del MSX Resource Center i amablement l'usuari Sandy Brand em va ajudar. El que passava és que dins de la interrupció de línia, les comandes que estava utilitzant tornaven a activar les interrupcions i per això es produïen les pampallugues.


Un cop vaig canviar totes les funcions de dins la interrupció de línia perquè no activessin les interrupcions, vaig veure que les pampallugues havien disminuït enormement, però de tant en tant també se'n produïa alguna i és que a vegades quedava el registre d'interrupcions activat i tornava a saltar, borrant el registre vaig aconseguir que ja no es produïssin les pampallugues. Però hi havia vegades que la interrupció de línia no es produïa, després de debugar vaig descobrir que aquest cop eren les funcions de comandes del VDP del Fusion-C que deshabilitaven les interrupcions per assegurar que es completava l'operació i per tant la interrupció de línia no es disparava.


Ara quedava eliminar el pintat a meitat de línia que succeïa quan es produïa la interrupció, ja que entre que el VDP detecta que es troba a la línia de la interrupció i es comencen a executar les comandes del ganxo, la línia queda pintada a diferent longitud. Com ho podem fer? En aquest article sobre interrupcions de línia del Grauw, es comenta de crear una línia negra i així queden els efectes ocults. Ho vam implementar, el problema és que en fer l'scroll el canvi de pantalla encara deixava brutícia de les altres línies. Com es podia solucionar? Una opció seria augmentar el número de línies negres i així el canvi sempre es produiria a la zona negra. El problema és que això augmentava l'ús del processador; una altra opció seria desconnectar el VDP, tal i com fan molts programes per pintar la pantalla i després mostrar-la. Però no apagaria això tota la pantalla i es prouiria un parpelleig? Doncs no, sembla que el VDP només desconnecta el mòdul de generar el senyal de vídeo, però continua amb els seus processos i quan es torna a reactivar ho fa a la línia que toca (això o que va tan ràpid que no ho he pogut detectar).


Aplicació al scroll amb mapa de patrons

Per tal de no copiar un altre cop tot de codi que ja s'ha explicat a un altre article, aquí només s'explicarà les funcions que han canviat per tal de tenir en compte la interrupció de línia.


Aquestes modificacions tenen com a objectiu eliminar la desactivació de les interrupcions, ja que el Fusion-C assegurava que es completés tota la comanda desactivant-les. Però a nosaltres no ens interessa, ja que després fa que hi hagi pampallugues a la pantalla ja que la imatge no s'ha refrescat quan tocava.


Comencem a definir tot de valors constants que utilitzarem per la interrupció i després definim la funció set_scrollH_NI(char n) que és una còpia de set_scrollH del Fusion-C però eliminant els ei i di. El que fem és llegir el paràmetre a la línia 342 i modificar els registres #26 i #27 amb els valors corresponents.

Aquí també fem el mateix, ens hem basat en la funció del Fusion-C vdpstatusni i hem creat la funció VDPstatusSenseInt( unsigned char registerNumber ) eliminant els ei i di. Aquesta funció llegeix el registre #1 del VDP que ens indica l'status per saber el tipus d'interrupció i per netejar l'indicador per si hi havia alguna a la cua.

Per a fer les comandes del VDP més ràpides i que hi hagi menys possibilitat de que quedin a mitges degut a una interrupció de línia, s'ha seguit el codi d'en Grauw presentat en aquesta pàgina i que hem transcrit a la funció en C fastVDP_Ni( FastVram2Vram *paramFastVDP ) i que també es troba desenvolupada a la llibreria Fusion-C (fastvdpcopy.c) però utilitzant els activadors d'interrupció. L'estructura FastVram2Vram es troba definida a vdp_graph2.h . El que fa la funció és preparar els registres del VDP per rebre comandes i enviar tots els valors que es troben a l'estructura i que van a registres consecutius del VDP amb la funció OutI.

I després tenim les comandes que s'executen durant la interrupció de línia. La variable repetirYMMM la utilitzem com a bandera per saber si caldrà repetir la comanda del VDP que s'hagi interromput del codi principal. Després tenim el selector de si ens trobem a la primera part de la interrupció o a la segona. Si ens trobem a la primera part apaguem la pantalla escrivint el valor 0x20 al registre #1 del VDP. Resituem l'scroll vertical escrivint al registre #23 i l'scroll horitzontal a través de la funció explicada anteriorment. Activem els sprites i canviem la pàgina visualitzada per la que conté les rajoles pintades. Engeguem la pantalla, indiquem la nova línia d'interrupció i llegim el registre d'interrupcions per deixar-lo net.

A la segona part fem els passos semblants: apagar pantalla, situar scrolls per als valors correctes del cartell, engeguem la pantalla, indiquem la nova interrupció de línia, activem els sprites i netegem el registre d'interrupcions.

La funció guardemLiniesAlBuffer( signed char offset ) serveix per guardar les línies que desapareixeran per amagar la porqueria que apareix quan es produeix la interrupció de línia, seran substituïdes per les línies negres. Com que és un bloc de dues línies, s'ha de tenir en compte el final de pàgina de VRAM, la línia 255, ja que si comença el bloc de 2 aquí, la segona línia del bloc agafarà la primera línia de la pàgina següent de VRAM en comptes de la primera de la mateixa pàgina que és el que volem. Per això a la línia 529 analitzem si ens trobem en aquest cas i separem el bloc a copiar en dues parts. Si en comptes de fer un bloc de dues línies fem un de 3, hauríem també de controlar el punt 254 i afegir un cas més. Però si fem només una línia només cal que fem com en el else.

Abans de cada comanda posem la bandera repetirYMMM a zero i comprovem després de cada comanda si s'ha quedat a mitges o no.

I la funció que fa el contrari, porta les línies que s'han guardat al buffer un altre cop a la pàgina de la VRAM visible, la funció retornemLiniesBorrades( signed char offset ). Té el paràmetre ja que depenent de quan es fa el càlcul en scroll_amunt o scroll_avall ha de prendre un valor o un altre. Tal i com passava amb guardemLiniesAlBuffer hem de tenir en compte la frontera de la línia 255.

Les diferents funcions que mouen la pantalla també s'han de modificar perquè utilitzin la funció que no deshabilita les interrupcions. Aquí mostrem com seria la que fa l'scroll cap amunt, scroll_amunt().


Conclusió

En aquest article s'ha presentat el funcionament bàsic de la interrupció de línia amb el programa intlin.c. Un cop hem experimentat amb un programa senzill el seu funcionament, s'ha aplicat aquest coneixement al programa que s'havia fet de l'scroll de patrons, havent hagut de debugar moltes vegades degut a la complexitat que no hi havia en el programa senzill, causada bàsicament per la deshabilitació de les interrupcions. Aquestes modificacions les podeu trobar al scfoInLi.c. Amb el que hem aconseguit tenir una part de la pantalla que no varia i que ens permetrà mostrà elements informatius del joc.


Clica aquí per a veure l'exemple funcionant.




 
 
 

Comments


Envia'ns un missatge i digues què et sembla

Gràcies pel teu missatge!

© 2035 Creat per Tren d'idees con Wix.com

bottom of page