News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu
avatar_Arnaud

Mixing Firmware function and Interruption [Cpctelera]

Started by Arnaud, 21:32, 29 November 15

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Arnaud

Hello,
once again i need some help :D

I have trouble to use in the same time, firmware functions and interruption.
I use only firmware to read files (i'll also have to write file later to save game), i don't know how to do differently.

Here what i do :
- Read my data on files
- Disable firmware (cpct_disableFirmware)
- Set interruption (cpct_setInterruptHandler)
- Running main loop -> All is OK

When i want to load the data of the new room :
- Enable firmware (cpct_reenableFirmware with previous stored firmware code)
- Disable interruption (or not this doesn't change anything) (cpct_removeInterruptHandler)
- Read file -> Nasty crash

I don't write data above 0x989C, i shouldn't have overwritten firmware.

Thanks for help,
Arnaud.






arnoldemu

@Arnaud: You need to restore the old firmware interrupt function. Using firmware functions enables interrupts and you need them active.
Also you should be sure that the z80 alternative registers are setup for firmware.

So to load do this:

* disable interrupts
* restore firmware interrupt
* restore alternative registers for firmware
* re-enable interrupts
* do load
* disable interrupts
* restore your interrupt
* re-enable interrupts.

In main:

* store firmware interrupt jump.
* store alternative registers.

In assembler it looks like this:

This stores firmware interrupt function and alternative registers:


store_firmware_state:
di
ld a,(&0038)
ld hl,(&0039)
ld (firmware_int_jump),a
ld (firmware_int_jump+1),hl
exx
ld (firmware_alt_hl),hl
ld (firmware_alt_de),hl
ld (firmware_alt_bc),hl
exx
ex af,af'
push af
pop hl
ld (firmware_alt_af),hl
ex af,af'
ei
ret


firmware_alt_hl:
defw 0
firmware_alt_de:
defw 0
firmware_alt_bc:
defw 0
firmware_alt_af:
defw 0
firmware_int_jump:
defs 3


Then you do this before load:


restore_firmware:
di
ld a,(firmware_int_jump)
ld (&0038),a
ld hl,(firmware_int_jump+1)
ld (&0039),hl
exx
ld hl,(firmware_alt_hl)
ld de,(firmware_alt_de)
ld bc,(firmware_alt_bc)
exx
ex af,af
ld hl,(firmware_alt_af)
push hl
pop af
ex af,af'
ei
ret


Now you can use the load etc.

I'm not sure if cpctelera allows you to do this yet.

@ronaldo: does cpctelera do this for you?


My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

ronaldo

@Arnaud: This wasn't your fault. The disable-reenable sequence had a bug: I didn't properly test the code. I've fixed it 5 minutes ago and it is now on master branch at github.

Take into account that firmware code is executed as a interrupt handler itself. Disabling firmware is exactly the same as removing the present interrupt handler. So, when you reenable firmware (with cpct_reenableFirmware) you are restoring firmware's interrupt handler. Then, if you call again cpct_removeInterruptHandler, you are disabling it again.

@arnoldemu has fully detailed the sequence. With CPCtelera, you can sum it up as follows:


u16 fw_pointer = cpct_disableFirmware();

// Your fancy game's code...

cpct_setInterruptHandler(my_fancy_interrupt_function);

// More fancy code...

// Reenabling the firmware also disables your interrupt handler, as previously stated
cpct_reenableFirmware(fw_pointer);

//...
// Your DISK I/O code
//...

// Disabling firmware again and continuing with the game
fw_pointer = cpct_disableFirmware();

// Game continues....


If you do not overwrite firmware variables, this should work as expected with latest version of CPCtelera.

Arnaud

@arnoldemu : thanks for your answer i understand better how handle interrupt

@ronaldo : Perfect it works (in fact not really but it's in my code now  :doh: ).

However, after disable firmware i have to set again my interrupt handler, is this normal ?


...

// Disabling firmware again and continuing with the game
fw_pointer = cpct_disableFirmware();

// Game continues....
cpct_setInterruptHandler(my_fancy_interrupt_function);


And to finish a little question : what is the address area of the firmware i must not write above (i think it's 0xA67C, but i'm not sure) ?

PS : for information, the installation script of the git version try to compile RGAS 1.0, and the version is 1.1 it leads to an error of build.

ronaldo

@Arnaud: Yes, that's completely normal. In fact, you can forget about disabling firmware again if you are going to set your own interrupt handler. This code should do the same:

// No need to disable firmware again, 'cause we are going to set
// up a new custom interrupt handler
// fw_pointer = cpct_disableFirmware();

// Game continues....

// Setting a custom interrupt handler automatically disables firmware.
cpct_setInterruptHandler(my_fancy_interrupt_function);


You have to take into account how interrupt handlers work. An interrupt occurs 300 times per second (6 per frame). When interrupts trigger, if CPU is set to interrupt mode 1, it does a CALL 0x0038. Therefore, next instruction to be executed is that located at 0x0038. When you turn on the machine and see the "READY" prompt, if you PEEK locations 0x0038, 0x0039, 0x003A, 0x003B you get this:
[attachimg=1]
(Depending on your CPC model, address 0xB939 may vary)

This JP instrucction is what jumps to firmware code, which is located at 0xB939 (you can examine this with the debugger). So, firmware is executed 300 times per second as a default interrupt handler. Setting up a custom interrupt handler is done by changing bytes 0x0039 and 0x003A to point to the start of the code of the custom interrupt handler. When we do this, firmware code stops being called, and our code is called instead. That effectively disables firmware.

Therefore, whenever you set a custom interrupt handler, you are disabling firmware. Also, if you call cpct_disableFirmware function, you are disabling any interrupt handler, as this function sets kind of a "NULL" interrupt handler (if puts instructions EI:RET at 0x0038, to make code reenable interrupts and return). These details are further explained in the documentation :) .

Arnaud


Powered by SMFPacks Menu Editor Mod