Hello, is it possible to install a HTIMI handler under Fusion_C? Is there a function that accept a function ptr being the function that should be called at Vblank ? Does it work under MSX-DOS?
Login or register to post comments
Hello, is it possible to install a HTIMI handler under Fusion_C? Is there a function that accept a function ptr being the function that should be called at Vblank ? Does it work under MSX-DOS?
Hi! You can set up your own interrupt routine like this, with or without Fusion-C :
(it's just an example, the program displays the number of loop cycles between two interrupts and stops when you press space)
#include < stdio.h > #include < stdlib.h > #include "fusion-c/header/msx_fusion.h" // io ports for vdp __sfr __at (0x98) VDP_port1; __sfr __at (0x99) VDP_port2; volatile char vdp_status; volatile int sync_flag; volatile int cpt; void interrupt_routine () __critical __interrupt(0) __preserves_regs(a,b,c,d,e,h,l,iyl,iyh) { // read the vdp status. Mandatory to have a new interrupt! vdp_status = VDP_port2; cpt++; sync_flag=1; // set the synchronization flag to 1 } void main (void) { unsigned int top=1; unsigned int im1; unsigned int key=0; unsigned int nbb=0; // save MSX system original interrupt address im1=Peekw(57); // printf("it=%x\n\r",im1); // causes the interrupt to skip the while statement, and then ends program! // interrupt setup sync_flag=0; __critical { *((unsigned int*)57)=(unsigned int)interrupt_routine; } cpt=0; /***** main cycle *****/ while (top==1) { nbb++; key=Inkey(); if (key==32) {top=2;} if (cpt==10) {cpt=0;printf("%d ",nbb);nbb=0;} // interruption detection // if sync_flag = 0 -> no interrupt occurred since the beginning of main cycle // if sync_flag = 1 -> 1 or more interrupts have already occurred if (!sync_flag) { sync_flag=0; } } // put back the original interrupt Pokew(57,im1); // address, data printf("Back to MSX-DOS\n\r"); Exit(0); }
I don’t think doing it like this is good practice though. Rather than overriding the system ISR completely like you do here, intercepting the VDP interrupt and never calling the hooks or the system ISR, it is much better to just use the standard H.TIMI hook, which is easy to set up with an (interslot) call to your handler.
This way all BIOS functions will continue to operate as normal, and any interrupt handling set up by anything else won’t be disrupted (like the DiskROM, which needs it or disk drives will never stop spinning).
Even if you need a high speed interrupt response (which you won’t if it’s C) for things like a line interrupt and you want to hook directly into 38H or IM 2 for that reason, I think one should still relay to the BIOS interrupt handler in case it’s any other type of interrupt.
@PingPong The topic was also briefly discussed here:
The H.TIMI and H.KEYI hooks work fine in DOS, and are the preferred way of hooking interrupts if you don’t need extremely quick response, and you don’t if you use C.
You need to place the ISR in memory page 3 (C000h-FFFFh), or do an interslot call, to ensure it continues to work while the BIOS (page 0) or DiskROM (page 1) or any other service routine is paged in.
Alternatively, remove the hook when doing a BIOS or BDOS call (if it’s H.KEYI, don’t forget to also disable the interrupt device). It’s more cumbersome but I think it may be difficult to ensure the C code is in page 3 so probably your best option.
Of course! Now that is obvious, when you wrote that. I think page 2 (8000h-BFFFh) should also be safe?
No, the common two (BIOS and DiskROM) are in pages 0 & 1, but afaik MSX-DOS2 uses page 2 as well when loading. Also inter-segment writes use page 2. And you don’t know what other extension is present that may switch out page 2 on some hooks.
I've made some progress. I have a small routine that I'll copy to somewhere in page 3, and hook on H.TIMI. That routine makes an interslot call to a handler that is located anywhere in RAM, and can be written in C or ASM. Seems to work well.
Sounds good. You can use CALLF, which is exactly 5 bytes and fits in a hook, then you won’t need the small helper routine.
You're right Grauw, I'm too focused on games for ROM , the development for MSX-DOS requires to respect the operating system.
Maybe someone has an example to give ?
Among Fusion-C examples there is :
// Interrupt functions Test // Fusion-c 1.1 #include "fusion-c/header/msx_fusion.h" #include static unsigned int count = 0; /* --------------------------------------------------------- */ static char my_interrupt( void ) { if( IsVsync() == 0 ) return 0; count++; return 1; } /* --------------------------------------------------------- */ int main( void ) { unsigned int prev_count; InitInterruptHandler(); SetInterruptHandler( my_interrupt ); prev_count = 0; while( prev_count < 600 ) { DisableInterrupt(); prev_count = count; EnableInterrupt(); printf( "%d\n\r", prev_count ); } EndInterruptHandler(); return 0; }
I have made a new interrupt system for Fusion-C, using H.TIMI. It didn't make it for Fusion-C v1.2, but it is coming.
I could share it here but I don't have it handy. I'll be back with it in the evening.
. @grauw:
About the use of CALLF I see it can be used to make a interslot call. However how I can use it in a C environment under msx dos 1 to hook HTIMI is unclear to me. What value I need to poke in the hook for the slot id parameter?
When I install my interrupt hook I m working on a standard msx dos configuration where all 64k are ram.
While I am able to poke into hook area the 0xc3 lowbyte highbyte sequence of my int hook routine I almost am sure that this will not work when the hook gets called because of paging issues...
You can get the slot ID of a currently paged address that you want to call with a GETSLT routine. There isn’t a BIOS routine for this, but it’s described in the MSX2 Technical Handbook and several other references.
Depending on your library it may exist there as well. To use the MSX2 Technical Handbook routine for page 3 you just need to adjust the shifts a bit so that the right bits are combined.
Here’s an implementation for all pages from the MAP:
RSLREG: equ 138H EXPTBL: equ 0FCC1H SLTTBL: equ 0FCC5H ; h = memory page ; a <- slot ID formatted FxxxSSPP ; Modifies: af, bc, de, hl Memory_GetSlot: call RSLREG bit 7,h jr z,PrimaryShiftContinue rrca rrca rrca rrca PrimaryShiftContinue: bit 6,h jr z,PrimaryShiftDone rrca rrca PrimaryShiftDone: and 00000011B ld c,a ld b,0 ex de,hl ld hl,EXPTBL add hl,bc ld c,a ld a,(hl) and 80H or c ld c,a inc hl ; move to SLTTBL inc hl inc hl inc hl ld a,(hl) ex de,hl bit 7,h jr z,SecondaryShiftContinue rrca rrca rrca rrca SecondaryShiftContinue: bit 6,h jr nz,SecondaryShiftDone rlca rlca SecondaryShiftDone: and 00001100B or c ret
Almost forgot... Here is my interrupt.s
There may still be room for improvement but for normal use, it's better than the old one in Fusion-C.
; ___________________________________________________________ ;/ __ _ \ ;| / _| (_) | ;| | |_ _ _ ___ _ ___ _ __ | ;| | _| | | / __| |/ _ \| '_ \ | ;| | | | |_| \__ \ | (_) | | | | | ;| |_| \__,_|___/_|\___/|_| |_| * | ;| | ;| The MSX C Library for SDCC | ;| V1.1 - 05-2019 | ;| | ;| Eric Boez & Fernando Garcia | ;| | ;| A S M S O U R C E C O D E | ;| | ;| | ;\___________________________________________________________/ ; ; ; Interrupt functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 2006/11/25 t.hara ;; ;; 2019/09/02 Pasi Kettunen ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; .area _CODE .globl _SetInterruptHandler .globl _EndInterruptHandler ; --------------------------------------------------------- reset_vect = 0x0000 bdos = 0x0005 H_TIMI = 0xFD9F INTHANDLER = 0xF975 ; Repurposing BASIC PLAY commands Voice A queue ; --------------------------------------------------------- ; void SetInterruptHandler( void (*p_handler)( void ) ) ; --------------------------------------------------------- _SetInterruptHandler:: di pop af pop hl push hl push af ld a,h or l jr z,isnull ld (user_interrupt + 2),hl ld hl,(savedhook + 1) ld a,h or l jr nz,already_set ld hl, #H_TIMI ld de, #savedhook ld bc, #5 ldir already_set: ld hl, #inthandler_start ld de, #INTHANDLER ld bc, #inthandler_end - inthandler_start ldir ld a, #0xc3 ; jp intr_handler ld (H_TIMI), a ld hl,#INTHANDLER ld (H_TIMI+1), hl isnull: ei ret ; --------------------------------------------------------- ; void EndInterruptHandler(void) ; --------------------------------------------------------- _EndInterruptHandler:: ld hl,(savedhook + 1) ld a,h or l ret z di ld hl, #savedhook ld de, #H_TIMI ld bc, #5 ldir ld hl,#0 ld (savedhook + 1), hl ld a,#0xF9 ; RET ld (savedhook),a ei ret ; --------------------------------------------------------- ; intr_handler ; --------------------------------------------------------- inthandler_start: push af push ix push iy user_interrupt: ld ix,#0 ld iy,(0xF341) ; main ram slotaddress call 0x001c ; interslotcall pop iy pop ix pass: pop af savedhook: ret .dw 0 .dw 0 inthandler_end:
Here is how to use it:
SetInterruptHandler( my_int_function ); ... //when done EndInterruptHandler();
I think there might come problems if using disk-rom etc when the handler is active, depending on where in ram "my_int_function" is located. Haven't tested that yet. But most BIOS usage, like KB / joystick reading etc should be fine.
I think there might come problems if using disk-rom etc when the handler is active, depending on where in ram "my_int_function" is located. Haven't tested that yet. But most BIOS usage, like KB / joystick reading etc should be fine.
It works fine if all the interrupt handling code is in page 3. If it’s in another page, some calls to e.g. BDOS can cause trouble, to avoid that use a CALLF instead of a jp (C3H). Hooks are exactly 5 bytes especially so that they can fit a CALLF interslot call.
Interrupt function MUST not be in page 0 (0x00000-0x3fff) if it is a MSX-DOS target, otherwise your hook will call bios if interrupt comes when your code or previous interrupt handler paged bios in page 0,not sure for other targets.
To elaborate, that is because even in DOS the BIOS ISR is swapped in and executing from page 0.
Unless you use an interslot call in your hook, then it’s fine to have the handler in page 0 as well.
(Did I mention yet that it’s best to use an interslot call? )
Don't you have an account yet? Become an MSX-friend and register an account!