Título: FD9APATCH.ASM Publicado por: SapphiRe en 09 de Abril de 2006, 04:29:04 pm Hi all!!
There's a routine to patch FD9A hook and save some extra raster lines in our games (sorry, commentaries in Spanish): Código: di ; Desactivamos las interrupciones call FD9APATCHON ; Parcheamos la interrupcion IM 1 ; Modo de interrupcion 1 ei ; Reactivamos las interrupciones ld hl,$0303 ; COLOR ,3,3 ld [$F3EA],hl ; actualizamos las variables RAM call INIGRP ; SCREEN 2 test: halt ; Sincronizamos con la interrupcion ld bc,$0407 ; Color azul... call WRTVDP ; ...de borde ld b,8 ; 8 loops completos waitext: ld c,b ; Guardamos el contador exterior ld b,0 ; 256 loops internos waitint: djnz waitint ; cerramos el bucle interior ld b,c ; Recuperamos el contador exterior djnz waitext ; cerramos el bucle exterior ld bc,$0F07 ; Color blanco... call WRTVDP ; ...de borde jp test ; Cerramos el test FD9APATCHON: ; --- PARCHEO DE LA INTERRUPCION --- ld hl,FD9APATCHCODE ; Direccion del codigo del path ld [$FD9C],hl ; Puesta en FD9C ld hl,$C3F1 ; HL = Pop AF; JP xxxx ld [$FD9A],hl ; Puesto en FD9A ret ; Volvemos FD9APATCHOFF: ; --- DESACTIVAMOS EL PARCHEO --- ld a,$C9 ; A = Ret ld [$FD9A],a ; Colocamos un RET en FD9A ret ; Volvemos FD9APATCHCODE: ; --- RUTINA DE RESTAURACION RAPIDA DE INTERRUPCION --- in a,[$99] ; Reseteamos el bit de interrupcion pop IX ; Restauramos IX pop IY ; Restauramos IY pop af ; Restauramos AF' pop bc ; Restauramos BC' pop de ; Restauramos DE' pop hl ; Restauramos HL' ex af,af' ; Cambiamos a los registros normales exx ; Cambiamos a los registros normales pop af ; Restauramos AF pop bc ; Restauramos BC pop de ; Restauramos DE pop hl ; Restauramos HL ei ; Reactivamos las interrupciones ret ; Volvemos Explanation: On every VDP interruption the RST#38 routine first pushes all registers and after that calls to FD9A. If the path is on, before call FD9APATCHCODE, we pop the return address stored in stak. The first line of the routine clears interrupt bit. After that, pops all registers (in the correct order), and finally enables interrupts again and returns. I've tested this routine in several MSX configurations and it works perfectly, also with C-Bios. There' also an example code to visualize the effect of the path (copy the code and test it with and without the second line). I've made two screenshoots of the result: First image: path is off (http://personal.telefonica.terra.es/web/sphworld/Karoshi/FD9APATCH-OFF.PNG) Second image: path is on (http://personal.telefonica.terra.es/web/sphworld/Karoshi/FD9APATCH-ON.PNG) Image explanation: Green: screen area Blue: time used by our code White: time used by BIOS Red (hand-added): interrupt free time As you can see, there are around 16 extra free lines when path is on. I also made an additional test: patch the BIOS to avoid the PUSH's and POP's. The minimum code needed is: Código: push af ; Guardamos AF in a,[$99] ; Reseteamos el bit de interrupcion pop af ; Restauramos AF ei ; Reactivamos las interrupciones ret ; Volvemos This code gives us two additional extra lines when compared to the proposed one, but you need to have (and find) RAM on page 0 to copy and patch the BIOS. Regards -- SapphiRe Título: Re: FD9APATCH.ASM Publicado por: jltursan en 09 de Abril de 2006, 05:40:26 pm ¡Great work!
Título: Re: FD9APATCH.ASM Publicado por: SapphiRe en 09 de Abril de 2006, 06:19:03 pm ¡Great work! Thanks!Additionally if you want to use FD9F hook you need to patch this patching routine inserting two new lines as follows: Código: in a,[$99] ; Reseteamos el bit de interrupcion bit 7,a ; If bit 7 is off... call z,$FD9F ; ...call FD9F @@POPS: pop IX ; Restauramos IX Obviously you can change $FD9F and place here your favourite routine ;D Regards -- SapphiRe Título: Re: FD9APATCH.ASM Publicado por: SapphiRe en 16 de Abril de 2006, 12:50:44 pm Hi again!
There's another patch to the patching routine to get a better halt synchronization: Código: FD9APATCHCODE: ; --- FAST INTERRUPT ROUTINE, HALT SYNCHRONIZATION UPDATE --- in a,[$99] ; Reset interrupt bit bit 7,a ; If bit 7 is off... jp z,@@ISVDP ; ...is a VDP interrupt @@NOVDP: call @@POPS ; pops all registers ei ; Reactivate interrupts halt ; Resyncrhonization (wait till the next interrupt) ret ; Return @@ISVDP: call $FD9F ; ...call FD9F (you can call to your favourite routine) call @@POPS ; pops all registers ei ; Reactivate interrupts ret ; Return @@POPS: pop IX ; Pop IX pop IY ; Pop IY pop af ; Pop AF' pop bc ; Pop BC' pop de ; Pop DE' pop hl ; Pop HL' ex af,af' ; Normal registers exx ; Normal registers pop af ; Pop AF pop bc ; Pop BC pop de ; Pop DE pop hl ; Pop HL ret ; Return [2006-04-17] A minor update: the code may fail if an interrupt occurs just between the RET and the HALT, so I have modified the routine and now should work well... anyone can take a look? If an interrupt not due to the VDP occurs, the routine will execute another HALT before return to the main program. So this routine ensures HALT's in the main program will wait till a VDP interrupt occurs. Título: Re: FD9APATCH.ASM Publicado por: SapphiRe en 04 de Mayo de 2006, 04:06:46 pm Ok, no one took a look at the previous routine. Why I know? Because the routine doesn't work properly ;D (lesson: please test the code on your MSX, not on your mind).
Here is a routine that actually works well: Código: FD9APATCHCODE: ; --- FAST INTERRUPT ROUTINE, HALT SYNCHRONIZATION UPDATE. THIS CODE WORKS ON RAM/ROM!! --- in a,[$99] ; Reset interrupt bit bit 7,a ; If bit 7 is on... jp nz,@@ISVDP ; ...is a VDP interrupt @@NOVDP: pop IX ; Pop IX pop IY ; Pop IY pop af ; Pop AF' pop bc ; Pop BC' pop de ; Pop DE' pop hl ; Pop HL' ex af,af' ; Normal registers exx ; Normal registers pop af ; Pop AF pop bc ; Pop BC pop de ; Pop DE pop hl ; Pop HL ei ; Reactivate interrupts halt ; Resyncrhonization (wait till the next interrupt) ret ; Return @@ISVDP: call $FD9F ; ...call FD9F (you can call to your favourite routine) pop IX ; Pop IX pop IY ; Pop IY pop af ; Pop AF' pop bc ; Pop BC' pop de ; Pop DE' pop hl ; Pop HL' ex af,af' ; Normal registers exx ; Normal registers pop af ; Pop AF pop bc ; Pop BC pop de ; Pop DE pop hl ; Pop HL ei ; Reactivate interrupts ret ; Return What was the problem? Well: you can't call a routine that only performs POPs. Obvious, isn't it? :spank: I will continue investigating... cmptr:) Regards -- SapphiRe Título: Re: FD9APATCH.ASM Publicado por: jltursan en 04 de Mayo de 2006, 07:37:34 pm It's really a good one!! :o. A routine doing only POPs,.....what a... :-[
...but now, looking such a space used doing POPs, why not write a self modifying one? (only for RAM of course). ;D Título: Re: FD9APATCH.ASM Publicado por: SapphiRe en 05 de Mayo de 2006, 11:37:00 am It's really a good one!! :o. A routine doing only POPs,.....what a... :-[ ...but now, looking such a space used doing POPs, why not write a self modifying one? (only for RAM of course). ;D Easy... Código: FD9APATCHCODE: ; --- FAST INTERRUPT ROUTINE, HALT SYNCHRONIZATION UPDATE. THIS CODE ONLY WORKS ON RAM!! --- in a,[$99] ; Reset interrupt bit bit 7,a ; If bit 7 is off... jp z,@@NOVDP ; ...is not a VDP interrupt call $FD9F ; ...call FD9F (you can call to your favourite routine) xor a ; a = NOP code @@POPS: ld [@@HALTNOP],a ; Correct instruction for resyncrhonization or to do nothing pop IX ; Pop IX pop IY ; Pop IY pop af ; Pop AF' pop bc ; Pop BC' pop de ; Pop DE' pop hl ; Pop HL' ex af,af' ; Normal registers exx ; Normal registers pop af ; Pop AF pop bc ; Pop BC pop de ; Pop DE pop hl ; Pop HL ei ; Reactivate interrupts @@HALTNOP: halt ; Resyncrhonization (wait till the next interrupt) or DO NOTHING ret ; Return @@NOVDP: ld a,$76 ; a = HALT code jp @@POPS ; goto @@POPS I can't test this routine now. Can anyone take a look or (better) test it? JL? What do you think? Regards -- SapphiRe Título: Re: FD9APATCH.ASM Publicado por: jltursan en 05 de Mayo de 2006, 05:25:24 pm Works fine!. To be easily relocated in RAM (if the source is a ROM) the following changes could be applied:
Código: FD9APATCHCODE: ; --- FAST INTERRUPT ROUTINE, HALT SYNCHRONIZATION UPDATE. THIS CODE ONLY WORKS ON RAM!! --- in a,[$99] ; Reset interrupt bit bit 7,a ; If bit 7 is off... jr z,@@NOVDP ; ...is not a VDP interrupt call $FD9F ; ...call FD9F (you can call to your favourite routine) xor a ; a = NOP code @@POPS: ld hl,INITPATCH+(HALTNOP-FD9APATCHCODE) ld [hl],a ; Correct instruction for resyncrhonization or to do nothing pop IX ; Pop IX pop IY ; Pop IY pop af ; Pop AF' pop bc ; Pop BC' pop de ; Pop DE' pop hl ; Pop HL' ex af,af' ; Normal registers exx ; Normal registers pop af ; Pop AF pop bc ; Pop BC pop de ; Pop DE pop hl ; Pop HL ei ; Reactivate interrupts HALTNOP: halt ; Resyncrhonization (wait till the next interrupt) or DO NOTHING ret @@NOVDP: ld a,$76 ; a = HALT code jr @@POPS ; goto @@POPS Where INITPATH is the RAM addres where this routine will be moved from ROM using an LDIR during the initialization of our program (the routine is 35 bytes long). I'll use it for sure! ;) Título: Re: FD9APATCH.ASM Publicado por: SapphiRe en 05 de Mayo de 2006, 05:48:12 pm I'll use it for sure! ;) Yeah! I'm currently using the ROM version :D Título: Re: FD9APATCH.ASM Publicado por: SapphiRe_MSX en 16 de Noviembre de 2007, 07:49:31 pm Ooook, the routine is stupid ;D ;D the BIOS returns after FD9A jump if the interrupt was not VDP generated, so:
Código: FD9APATCHON: ; --- PARCHEO DE LA INTERRUPCION --- ld hl,INTERRUPT ; Direccion del codigo del path ld [$FD9B],hl ; Puesta en FD9B ld a,$C3 ; A JP xxxx ld [$FD9A],a ; Puesto en FD9A ret ; Volvemos FD9APATCHOFF: ; --- DESACTIVAMOS EL PARCHEO --- ld a,$C9 ; A = Ret ld [$FD9A],a ; Colocamos un RET en FD9A ret ; Volvemos INTERRUPT: call RDVDP ; Leemos el byte de interrupcion del VDP bit 7,a ; Si la interrupcion fue provocada por el VDP ret nz ; Volvemos ei ; Si no, reactivamos interrupciones halt ; Esperamos a la siguiente ret ; Y volvemos Using this routine, the HALTs in the main program will wait till a VDP interrupt occurs, preventing bad syncs in our code. Of course you can change the RET NZ for a JP NZ,XXXX to do more things on a VDP interruption. Comments, please -- Sph. P.D. Thanks to GuyveR800 for the tip :D |