News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu
avatar_lachlank

Save file without firmware

Started by lachlank, 21:52, 06 October 16

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

lachlank

Hello I am working on a game, primarily written in c using CPCTelera. I disable the firmware and use double-buffered screens at 0x8000/0xC000.


I would like the user to be able to save the current game state to disk. Is there an easy way to do this? I know the firmware can be re-instated, which just re-enables the interrupts, but can the jumpblock/variables be restored temporarily? Or alternatively can the rom be enabled directly and the open/save functions be called directly?


Any ideas appreciated.

Shining

#1
In Defence I'm saving the current game state like that:


- Ingame I have my double-buffer, like you, at 0x8000/0xC000.
- My application starts at 0x40 so the lower jumpblock is no problem.
- During menus and when a game finishes, I switch my double-buffer off and only use 0xC000
- I reenable the jumptable and then amsdos (and I also try to enable rom6 for paraods or M4 for example)
- I save to disk (or load)
- Reenable my own IRQ-Routine
- Finished


Some not very cleared copy+paste example for sdcc:


(When the game starts, call StoreDriveLetter() for remembering the drive from which the game startet. So you do not blame the |B users ;D )


My save-data is in a struct called sPlayerSaveData. So I save like that:


SaveFile(SaveGameFileName,(char *)playerSaveData,6,sizeof(struct sPlayerSaveData));


////////////////////////////////////////////////////////////////////////


void StoreDriveLetter(void)
{
  __asm


      ;;------------------------------------------------------------------------
      ;; store the drive number the loader was run from to InitializeAmsdos
      ld hl,(#0xbe7d)
      ld a,(hl)                 
      ld (_driveLoad+1),a                 
      ;ld (_driveSave+1),a
   
    ;;------------------------------------------------------------------------
    ;; store jump restore call to InitializeAmsdos
    ;ld hl,(#0xbD38)
      ld a,(#0xbD38)                 
      ld (_firmJump+1),a
   
   
   __endasm;
 
}

  ////////////////////////////////////////////////////////////////////////

void InitializeAmsdos(void) __naked
{
  __asm
   
      ;; ** INITIALISE ALTERNATE REGISTER SET FOR FIRMWARE **
     
      exx
      ld bc,#0x7f88            ;initialise lower rom and select mode 0
      out (c),c               ;this routine must be located above &4000
      exx 
      ex af,AF
      xor a
      ex af,af
     
      ;; ** INITIALISE FIRMWARE **


      call #0x0044                ;initialise lower jumpblock (&0000-&0040)
                           ;and high kernal jumpblock (&b800-&bae4)
      _firmJump: call #0x08bd                ;initialise firmware jumpblock entries
    ;call #0xBD37
                           ;(&bb00- ...)
      call #0xbb00                ;initialise keyboard manager
      call #0xb909                ;disable lower rom


      ;;; ** INITIALISE DISK ROM FOR LOADING/SAVING **
    ;
      ld c,#7                      ;disk rom
      ld de,#0x8000                 ;lowest useable byte of memory
      ld hl,#0xb0ff                 ;highest useable byte of memory
      call #0xbcce           ;initialise disk rom
   
    ld c,#6                      ;disk rom
      ld de,#0x8000                 ;lowest useable byte of memory
      ld hl,#0xb0ff                 ;highest useable byte of memory
      call #0xbcce           ;initialise disk rom
   
    ld a,#0xc9
      ld (#0xbb5a),a           ;prevent printing of text characters
                           ;don t get error messages corrupting screen
   
    ;; ** INITIALISE ALL ROMS (FOR LOADING/SAVING) **


      ;ld c,#7                      ;disk rom
      ;ld de,#0x8000                 ;lowest useable byte of memory
      ;ld hl,#0xb0ff                 ;highest useable byte of memory
      ;call #0xbccB           ;initialise disk rom (KL ROM WALK)


     
   
      ;xor a                       ;select drive (A)
      ;ld (#0xac00),a


      ld a,#0xff
      ld (#0xbe78),a                ;turn of disc error messages


     
                           
      ;;------------------------------------------------------------------------
      ;; when AMSDOS is enabled, the drive reverts back to drive 0!
      ;; This will restore the drive number to the drive the loader was run from
      _driveLoad: ld a, #0x00
      ld hl,(#0xbe7d)
      ld (hl),a 
   
    ret
   
  __endasm;
}


////////////////////////////////////////////////////////////////////////


void LoadFile(char *sFileName, char *pLoadAddress, unsigned char nFileNameLen)
{
   sFileName;
   pLoadAddress;
   nFileNameLen;
   
   __asm
      di
      ld (stackLoad+1),sp             ;save stack used by program
      ld sp,#0xc000                 ;new stack used by firmware and load routines
   
      call _InitializeAmsdos
     
      ;; ** LOAD FILE USING FIRMWARE **                           


      ;; B = length of the filename in characters
      ld b, 8 (IX) ;nFileNameLen


      ;; HL = address of the start of the filename
      LD L, 4 (IX) ;sFileName
      LD H, 5 (IX) ;sFileName     
      ;LD HL, #_filename


      LD DE, #0
      call #0xbc77 ; cas_in_open
     
      ld bc,#0
      ld a,#2   
      ;LD DE,#162 ; laenge
      ;LD E, 9 (IX) ;laenge
      ;LD D,10 (IX) ;laenge   
      ;; HL = address of the start of the filename
      LD L, 6 (IX) ;sFileName
      LD H, 7 (IX) ;sFileName   
      call #0xbc83 ;cas_in_direct
      call #0xbc7a ;cas_in_close
      di
      LD HL,#0X0038
      LD (HL),#0XFB      ;EI
      INC HL
      LD (HL),#0XC9      ;RET
      EI
   
      stackLoad: ld sp,#0              ;old stack back and...
      ;ret                         ;...exit to program!!
     


   __endasm;
}


void SaveFile(char *sFileName, char *pSaveAddress, unsigned char nFileNameLen, unsigned short fileLen)
{
   sFileName;
   pSaveAddress;
   nFileNameLen;
   fileLen;
   
   __asm
      di
      ld (stack+1),sp             ;save stack used by program
      ld sp,#0xc000                 ;new stack used by firmware and load routines
     
     
   
      call _InitializeAmsdos
   
     
      ;; ** SAVE FILE USING FIRMWARE **                           


      ;; B = length of the filename in characters
      ld b, 8 (IX) ;nFileNameLen


      ;; HL = address of the start of the filename
      LD L, 4 (IX) ;sFileName
      LD H, 5 (IX) ;sFileName     
      ;LD HL, #_filename


      LD DE, #0
      call #0xbc8c ; cas_out_open
     
      ld bc,#0
      ld a,#2   
      ;LD DE,#162 ; laenge
      LD E, 9 (IX) ;laenge
      LD D,10 (IX) ;laenge   
      ;; HL = address of the start of the filename
      LD L, 6 (IX) ;sFileName
      LD H, 7 (IX) ;sFileName   
      call #0xbc98 ;cas_out_direct
      call #0xbc8f ;cas_out_close
      ld bc,#0xFA7E            ; FLOPPY MOTOR OFF
      out (c),c               
      di
      LD HL,#0X0038
      LD (HL),#0XFB      ;EI
      INC HL
      LD (HL),#0XC9      ;RET
      EI
   
      stack: ld sp,#0              ;old stack back and...
      ;ret                         ;...exit to program!!
     


   __endasm;
}
TGS is back

Download my productions at:
cpc.scifinet.org

lachlank

Quote from: Shining on 22:04, 06 October 16
In Defence I'm saving the current game state like that:




Perfect, that's exactly what I was looking for thanks.

arnoldemu

I am making a game using cpctelera and I wanted both loading and saving of files uisng the firmware because I want compatibility with AcmeDOS etc.

So I have made some functions.

The main file is loaded by a basic program and called:

5 a=HIMEM
10 memory &3e00
20 load"code.bi0",&3f00
30 call &3f00,a

The problem I had was that the load address is always changing because main() is not at the beginning of the file. I haven't looked into it more but i may need to change the crt to have a jp.

I have attached some files I sent to ronaldo to be included into cpctelera.

This has the load function. I need to fix up and test the save function (I too wanted to use it for save game).

I hope this is useful.

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

reidrac

Quote from: arnoldemu on 08:09, 07 October 16
The problem I had was that the load address is always changing because main() is not at the beginning of the file. I haven't looked into it more but i may need to change the crt to have a jp.

With SDCC you need to process the .map file for the binary you're building and look for the address of "_main_init" (that's usually the entry point of crt0, if you're using it; otherwise use _main -- but having a custom crt0 is usually a good idea if you have initialised data).

That's one of the "annoying" bits of SDCC, but AFAIK that's automatically resolved for you by cpctelera.
Released The Return of Traxtor, Golden Tail, Magica, The Dawn of Kernel, Kitsune`s Curse, Brick Rick, Hyperdrive and The Heart of Salamanderland for the CPC.

If you like my games and want to show some appreciation, you can always buy me a coffee.

arnoldemu

Quote from: reidrac on 08:26, 07 October 16
With SDCC you need to process the .map file for the binary you're building and look for the address of "_main_init" (that's usually the entry point of crt0, if you're using it; otherwise use _main -- but having a custom crt0 is usually a good idea if you have initialised data).

That's one of the "annoying" bits of SDCC, but AFAIK that's automatically resolved for you by cpctelera.
But I don't want to do that.

I have used SDCC before and setup a custom crt and put a jp _main at the beginning.
Then I could call the load address to start the program. Much simpler :)
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

Shining

Since there was no CPCtelera before. I always used my own CRT0 with the same start-address always. So I'm doing like arnoldemu suggested.


But instead of arnoldemu I'm using a binary-loader (located in my later double-buffer) so that I'm able to load directly to 0x40 and to do stuff like decrunching.... (and bank-switching).
TGS is back

Download my productions at:
cpc.scifinet.org

reidrac

Quote from: Shining on 14:32, 07 October 16
Since there was no CPCtelera before. I always used my own CRT0 with the same start-address always. So I'm doing like arnoldemu suggested.


But instead of arnoldemu I'm using a binary-loader (located in my later double-buffer) so that I'm able to load directly to 0x40 and to do stuff like decrunching.... (and bank-switching).

Yes, I do exactly that!

I don't find that difficult to find the start address of my crt0; once you write that in your Makefile... is done for ever :)
Released The Return of Traxtor, Golden Tail, Magica, The Dawn of Kernel, Kitsune`s Curse, Brick Rick, Hyperdrive and The Heart of Salamanderland for the CPC.

If you like my games and want to show some appreciation, you can always buy me a coffee.

PulkoMandy

You could tweak the linker scripts to make sure the CRT0 is always the first thing put in your binary. This way the entry point will be at a fixed address as long as the CRT0 doesn't change.

ronaldo

Sorry for taking so long, to reply, guys. These days I'm completely overloaded. Hope to have more time soon to answer all of you. And of course, thank you very much for all contributions I have received. I will reply to all of you, I promise.

Regarding the entry point, I wouldn't use a CRT0 to add a jp: there is no need to loose those 3 bytes having other alternatives. Just write the main() function at the start of the first file of your code and it will have always the same address (the one you choose in the build_config.mk). There are also other alternatives (like setting it manually with absolute memory alocation macros, for instance), but I think this one is the easiest.

I you need examples, I can upload one :).

Powered by SMFPacks Menu Editor Mod