Fusion_C and HTIMI

Page 2/4
1 | | 3 | 4

By zPasi

Champion (495)

zPasi's picture

01-10-2019, 07:26

Grauw wrote:
zPasi wrote:

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?

By Grauw

Ascended (8931)

Grauw's picture

01-10-2019, 10:34

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.

By ducasp

Champion (273)

ducasp's picture

02-10-2019, 01:02

zPasi wrote:
Grauw wrote:
zPasi wrote:

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. Smile

By fregarni

Supporter (16)

fregarni's picture

06-04-2020, 11:54

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.

By ducasp

Champion (273)

ducasp's picture

06-04-2020, 18:08

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...

By ducasp

Champion (273)

ducasp's picture

06-04-2020, 18:37

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)...

By ericb59

Paladin (947)

ericb59's picture

06-04-2020, 19:31

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?

By ducasp

Champion (273)

ducasp's picture

06-04-2020, 19:59

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. Wink

By ericb59

Paladin (947)

ericb59's picture

06-04-2020, 20:47

ducasp wrote:

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. Wink

Thank you.
I 'm waiting for you... Wink

By DarkSchneider

Paladin (906)

DarkSchneider's picture

07-04-2020, 12:54

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.

Page 2/4
1 | | 3 | 4