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.
I'm using interslot call. In SetInterruptHandler() I install an "int-handler" (starting at inthandler_start: ) to page 3. That handler makes interslot call to the user code, that may reside even on page 0.
So I could skip that "int-handler" and use CALLF instead?
The thing I'm not sure about is, will it work, if the user code is near page-boundary? Normally it will be fine, when the hook is been called, page 0 is BIOS and page 1 and following are RAM, it doesn't matter where there user code is. But what if page 1 is some ROM?
Ah, yes good point, I missed that! Because I saw a C3H in the hook instead of a CALLF I assumed you didn’t.
But you got a good point that if the code that you’re calling is near a page boundary there will still be an issue, because e.g. if the handler address is at 3FF0H and the handler is 20H bytes long, then it will only have swapped in the correct page 0. And page 1 can be ROM when an interrupt occurs (e.g. DiskROM). I suppose the only thing you can do is to make sure the code doesn’t cross a page boundary (I don’t know how to instruct the linker to make sure that doesn’t happen). Or configure the entire slot layout in the handler, but that seems to become quite cumbersome.
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.
I'm using interslot call. In SetInterruptHandler() I install an "int-handler" (starting at inthandler_start: ) to page 3. That handler makes interslot call to the user code, that may reside even on page 0.
So I could skip that "int-handler" and use CALLF instead?
The thing I'm not sure about is, will it work, if the user code is near page-boundary? Normally it will be fine, when the hook is been called, page 0 is BIOS and page 1 and following are RAM, it doesn't matter where there user code is. But what if page 1 is some ROM?
Makes sense, for a library it is better, in my code I've preferred to move the function at startup using ldir for page 4 and used a simple call to get better performance.
Hi to all,
I am testing the interrupts with the example that comes in Fusion-C v1.2 on an MSX1. When I run the compiled example, the screen turns black and I think the keyboard stops responding. If I test it on an MSX2, it works correctly. Any idea why it happens on MSX1?
I have tried with the version of interrupt.s that @zPasi, I recompile the Fusion-C library, but when I compile the counter example through the interrupt, the compiler crashed.
Thanks a lot.
I did something like this in a previous project:
unsigned char interruptRealloc[512]; // Program interrupt handler to call our routine first void programInt(void) { __asm ; Disable interrupts, it will not be nice if an interrupt occurs before all ; was properly set DI ; Save the registers we are going to use PUSH BC PUSH DE PUSH HL ; This is the area where we are going to save the original interrupt handler ; Why? It is the beginning of the routine that is called before main is ; executed and it will not be called anymore, so we put it to good use ; First copy our interrupt routine to _interruptRealloc LD DE,#_interruptRealloc ; This is the address Z80 will call everytime interrupts are triggered LD HL,#_myIntHandler ; Counter of how many bytes need to be transferred LD BC,#_enterIntMode - _myIntHandler ; Copy data LDIR LD DE,#0x0100 ; This is the address Z80 will call everytime interrupts are triggered LD HL,#0xFD9A ; Counter of how many bytes need to be transferred LD BC,#0x5 ; Copy data LDIR ; HL changes after LDIR, so restore it to the interrupt handler address LD HL,#0xFD9A ; First we will put the JP command LD B,#0xC3 ; Now, put that into the memory LD (HL),B ; Increment our memory copy address INC HL ; Load the memory address of our function in BC pair of registers LD BC,#_interruptRealloc ; Move the LSB of the address just after JP LD (HL),C ; Increment our memory copy address INC HL ; Move the MSB of the address after the LSB LD (HL),B ; We are done, restore registers we have used POP HL POP DE POP BC ; Enable interrupts again EI __endasm; } // Restore interrupt handler so we won't be called before processing interrupt // Useful when exiting the program, as once our program no longer runs, it won't // proccess anything and interrupts will go crazy if handler is not restored void restoreInt(void) { __asm ; Disable interrupts, it will not be nice if an interrupt occurs before all ; was properly set DI ; Save the registers we are going to use PUSH BC PUSH DE PUSH HL ; This is the area where we are going to restore the original interrupt handler LD DE,#0xFD9A ; This is the address where the original handler was saved LD HL,#0x0100 ; 5 bytes LD BC,#0x5 ; copy it LDIR ; We are done, restore registers we have used POP HL POP DE POP BC ; Enable interrupts again EI __endasm; } void myIntHandler(void) __naked { __asm ; Interrupt Routine goes here ret __endasm; } void enterIntMode(void) {
interruptRealloc is just to make sure the interrupt is in place other than page 0, you might do things differently to achieve this (compile order, etc) and skip reallocating the interrupt, that worked for me at that time, perhaps nowadays I would do it differently...
By the way, this code uses the general interrupt, not the VDP interrupt...
P.s.: it is important to keep your interrupt routine out of page 0, it is very possible that BIOS is paged in that by the time your routine is called and then a crash is going to happen, and perhaps this is what is getting the example to fail on some machines. In the case where this code was taken, I knew interruptRealloc was outside page 0 by looking at the map file, but you could manually allocate an address for that on a high page (fast and easy to set a C000 address if your program is up to 44~45KB in size) or use the sdcc directives to force an address (I do not like it, don't remember why)...
Hello,
I'm having trouble integrating a proper interrupt system into Fusion-C.
I do not have enough knowledge on the subject.
Is one of you have some code I can add to Fusion-c?
Ducasp? Can II use your? Do you have example of usage of your code?
Hi Eric,
I probably can work on an example and send it to you, it would take a couple of days, would be glad to help for sure.
Hi Eric,
I probably can work on an example and send it to you, it would take a couple of days, would be glad to help for sure.
Thank you.
I 'm waiting for you...
Without more details, this is how I set the H.TIMI routine before moving to IM2:
TIMI equ 0FD9FH RAMAD0 equ 0F341H RAMAD1 equ 0F342H RAMAD2 equ 0F343H RAMAD3 equ 0F344H ; set H.TIMI public isrset@ isrset@: di ; TIMI ld hl, TIMI ld de, oldtim ld bc, 5 ldir ld a, 0F7H ld (TIMI), a ld a, (RAMAD1) ld (TIMI+1), a ld hl, newtim@ ld (TIMI+2), hl ld a, 0c9h ld (TIMI+4), a ei ret ; restore H.TIMI public isrrst@ isrrst@: di ; TIMI ld hl, oldtim ld de, TIMI ld bc, 5 ldir ei ret oldtim: ret ret ret ret ret At newtim, remember to put at the end: ;public newtim@ newtim@: ... jp oldtim
Instead RAMAD1 you could use the one which the code is located, but usually all the segments point to the same RAM slot, not involving DOS2 segment functions (that's another story). By this way it works (tested) even when located at page 0, as the system will call the ISR, and the ISR will use the hook, doing the inter-slot by itself.