GAMEX game launcher code source with comments

* Castle Master  Gamex/normal play  launcher
* Compatible on all ST(E) , Falcon ....

* running from hard drive
* Game exit to Desktop, pos saving
* 2MB RAM needed...  1MB vers. too much complications would be...
* but with 1MB can play normally, without Gamex

* Created by P. Putnik, April-July 2009 .
* This is likely final version - with all RAM tests, MSTE, Falcon settings

* Launcher stage 1: testing low RAM occupation, physical RAM size
* by ST(E) - abort if not enough RAM, set gxf (gamex flag)
* reserving TOP RAM - lovering (or increasing if is already  lowered) memtop, phystop.

* Gamex  Values for this game:
GameScrB       equ  $F8000    *For games working with 1M
AltRamPos     equ  $100000     * Here will copy low RAM by game exit . At offset 8 .
* Usually same as New Phystop

MainInb        equ  $1FFF40    * All relevant addresses for header build and continue from RAM here
* Pointer to MainInb is always at Phystop+4

SwapLen        equ  $DFCF8   * in fact save len

GameRest    equ   $FFD20   * Place for game restoring code, stage 2, which swaps RAM

      *  always save as much as this launcher reaches
* together with both SP in moment of launching game  !!!!
* so, set them to be in workspace of ...
FreeMem    equ    $1FFD20       *For 1M games, 2MB total RAM
SysStor    equ    $1FFF80     *Place for storing TOS system - 128 bytes

begin        *Beginning of program

* Low RAM usage check and exit if too much is used...
* not really needed when no Gamex, but is good to inform user
* that better run games without too much crap in low RAM !

    lea    hwpal(pc),a1
    cmp.l    #FreeMem-DeskCopy-48,a1  *Place available in high RAM to store TOS

* In fact, by RAM over 2MB DeskCopy may be placed over 2MB .... later...

    bcs.s    lowRamOK

    lea    lowRamTM(pc),a0    *Message
toPMex    bsr    pmess

    move.w    #1,-(sp)   *Give chance for user to read it ...
    trap    #1
    addq.l    #2,sp

    clr.w    -(sp)
    trap    #1    *Exit


NewPhyst     equ  $100000    *For 1M games - usually same as AltRamPos, but may be lower

* First test HW, if only 512KB phys. then skip whole Gamex stuff

    pea          hwdet(pc)    *Call supervisor code for HW test
    move.w    #38,-(sp)
    trap          #14
    addq.l       #6,sp

    lea         machin(pc),a1     *TOS vers. major
    cmp.b    #3,(a1)  *TT TOS vers.
    cmp.b    #4,(a1)  *Falcon TOS vers.

* Check Physical RAM size

    cmp.b    #1,7(a1)  * Is only 512K ?   RAM size in 512KB steps, byte var.
    bne.s      che1m
    lea         RAMne(pc),a0    * Message and abort if only 512K
    bra.s       toPMex


    cmp.b    #2,7(a1)  * Is only 1M ?  
    sne    gxf   * Set Gamex flag if over 1MB ( = min 2MB )

    move.l      4(sp),a2   *basepage adr.
    lea    $F7FE0,sp    *Must move stack below 1M
    clr.l    (sp)
    move.l    a2,4(sp)    * Set basepage pointer in new stack

* Following will correct memtop, Phystop, this allocation variables by need :


    move.b     #2,machin+2    * 'Set' TOS RAM size
    move.l      a2,basep
    move.l      4(a2),d2   *memtop

    move.l     d2,memt
    move.l     #NewPhyst,d1
    sub.l        #$8000,d1   *This is new memtop
    move.l     d1,4(a2)     * Correct in basepage

* Conditional settings in subrutine following :
    pea     lowmsuv(pc)
    move.w     #38,-(sp)
    trap    #14
    addq.l    #6,sp


 * Now TOP RAM is reserved, TOS sees only 1MB of RAM !

* Launcher stage 2:  set screen, storing  stack pointers, MFP, screen


* Get current screen resolution:

    move.w    #4,-(sp)
    trap    #14
    addq.l    #2,sp
* Falcon patch:
    cmp.w    #3,d0   *Allow only  0-2 !
    bcs.s    store_res
    clr.w    d0

store_res     move.w    d0,DeskRes

    dc.w     $A00A       * Hide mouse
    clr.w     -(sp)   *set low res
    pea     GameScrB
    pea    GameScrB
     move.w    #5,-(sp)
    trap    #14
    lea    12(sp),sp

 *We need supervisor mode from now :
    clr.l    -(sp)
    move.w    #32,-(sp)
    trap    #1
    addq.l    #6,sp
    move.l    d0,uspstor

    tst.b    gxf
    beq    show_hw   * Skip gamex part if only 1M

* Preparing some IKBD storage:
* Will be executed by restoring TOS, when exit game

     move.w    #34,-(sp)   *Kbdvbase
     trap    #14
     addq.l      #2,sp   
    move.l     d0,a1
    lea           32(a1),a1   * IKBD system vector
    move.l     a1,ikbdsysv    *  Write in TOS restoring code
    move.l     (a1),orgikbds

SysStor  struct :
*   relative pos,   what

*     0    USP
*    4    Desktop screen resolution at prg start !
*    6    SSP
*    10    Palette, 32 bytes
*    42    MFP state, 24 bytes
*    66    ?

* 66 bytes used so far (128 avail)

mfpof    equ  42

   lea    SysStor+10,a6   *palette store pos

* Save desktop palette:

    lea    $FFFF8240.w,a1
    moveq    #15,d1
.palc    move.w    (a1)+,(a6)+
    dbf    d1,.palc

* Saving MFP state.....

    lea    $FFFFFA01.w,a1
    moveq    #23,d2   *24 registers, up to $FFFA2F
.mfpsl    move.b    (a1),(a6)+
    addq.l    #2,a1
    dbf    d2,.mfpsl

*Timer B and C needs accurate reading:
* Other 2 is off in TOS....

*So we read them some time and take
*Max value:

   * To speed it up we can test both in same time !

    lea    $FFFFFA21.w,a1
    lea    $FFFFFA23.w,a2
    move.w    #3777,d7   *Determines time for read
    clr.b    d2
    clr.b    d4

retimbl    move.b    (a1),d1
    cmp.b    d1,d2
    bcc.s    renotbb

rebiggerb    move.b    d1,d2
renotbb    move.b    (a2),d3
    cmp.b    d3,d4
    bcc.s    renotbc

rebiggerc    move.b    d3,d4
renotbc    dbf    d7,retimbl

    move.b    d2,-8(a6)      * Timer B Data reg
    move.b    d4,-7(a6)      * Timer C Data reg.

* TOS values are normally:  Timer B: $41 (PAL mode), Timer C:  $C0  !

* Launcher stage 3:   storing TOS, desktop, this prg active part in * Upper RAM for later restore

* Best is that we do HW show and pic show at this point !!

    bsr    clearkb
    move.l    #GameScrB,screnb   *screen pos. for pic show
    pea    hwpal(pc)    * Palette with blue text
    move.w #6,-(sp)
    trap  #14
    addq.l    #6,sp
    move.w  #37,-(sp)
    trap  #14
    addq.l  #2,sp

    bsr    machipr    *HW detected printing

    lea    langs(pc),a0    * This is game specific selection, for Castle Master only !
    bsr    pmess

* Define some pause, to see it:
    move.w    #1177,d7

dell1    move.w  #37,-(sp)
    trap  #14
    addq.l  #2,sp

* Allow abort with keypress:
    pea    $600ff
    trap    #1
    addq.l    #4,sp
    tst.b    d0
    beq.s    cycl

    cmp.b    #"M",d0
    beq    megastes  * Optional MSTE or Falcon settings
    cmp.b    #"m",d0
    beq    megastes

    andi.b    #$DF,d0   * Game specific
    cmp.b    #$44,d0    * Allows entering only D, E or F
    blt.s    cycl
    cmp.b    #$46,d0
    bgt.s    cycl
    move.b    d0,$200.w
    bra.s    toPicsh
cycl    dbf    d7,dell1


    lea    infstr(pc),a0   * Again game specific
    bsr    pmess

    move.w    #1,-(a7)
    trap    #1
    addq.l    #8,a7

    ori.b    #$20,d0
    move.b    d0,$300.w
* Trainer or not above

      cmp.b   #4,machin
    bne.s    steph   *Skip pic show on Falc.

* Falcon Pic show:

    bsr    falcpic
    bra.s      loadg

steph         bsr    photoc    *Call Photochrome pic show rut., on (M)ST(E)


* Game specific - need Mshrink before pexec game executables
    pea    hwpal-begin+266
    pea    begin-256(pc)
    pea    $4A0000    *Mshrink
    trap    #1
    lea    $C(a7),a7


     *now set stack pointers in area what will be saved up
* and this is imortant for following pexec too here !
    lea      hwpal(pc),sp
    lea      -200(sp),a1
    move.l    a1,usp

    tst.b    gxf
    beq    lau_2

    lea    SysStor,a6  
    move.l    a1,(a6)+     *Store USP
    move.w    DeskRes(pc),(a6)+

    move.l    sp,(a6)   *SSP  to SysStor ....

* Header build support #2 :
* Fill MainInb :

    lea    MainInb,a2
    lea    64(a2),a1

    move.l    #SwapLen,(a2)+
    move.l    #FreeMem,(a2)+   
    move.l    #SysStor,(a2)+
    move.l    #GameRest,(a2)+
*    move.l    #GameStat,(a2)+
    move.l    #depak3,(a2)+
*    move.l    #GameStoPl+backingam-gamex,(a2)+
    move.l    #backingam,(a2)+
    move.w    #$C3C2,(a2)+   *Keys

clr_maininb    clr.w    (a2)+
    cmp.l    a2,a1
    bne.s    clr_maininb   *Clear rest for future good
* Needs Falcon  Cache setting store too
    lea    MainInb+38,a2
    move.w    falccach(pc),(a2)

* Saving  area from adr 8 to  hwpal  in  high RAM

DeskCopy    equ    $1A0108   *   Game specific ...
* what must be enough for TOS 2.06 with hard ddriver, buffers
    lea    8.w,a5    * Always at adr. 8
    lea    DeskCopy,a6   *
    lea    hwpal(pc),a1
    move.l    a1,d0
    divu        #48,d0     *get loop count
    move.w    d0,swapln+2    *Set same len for TOS restore *swap part

.cod    movem.l      (a5)+,d1-d7/a0-a4   *48 bytes at once
     movem.l    d1-d7/a0-a4,(a6)   
    lea    48(a6),a6
    dbf    d0,.cod   
* Little overshot, no problems...

Stage 4:  preparing setting Exit to Desktop in stored mem.  :

* We need only  regular exit TOS call at certain point...
* Copy code in free area at top top
*FreeMem    equ    $1FFD20       *For 1M games, 2MB total RAM

    lea    GamexCtrl(pc),a1
    lea    FreeMem,a2
    move.w    #127,d2      *There is 768 bytes place !
* But top is reserved for storing state, palette etc....
* so copying only 512 bytes ....

.cou    move.l    (a1)+,(a2)+
    dbf    d2,.cou

* Now load game

* Part 1 first :

    pea    0.w
    pea    zer(pc)
    pea    exe1(pc)   * Castle1 run
    pea    $4B0000
    trap    #1
    lea    $10(a7),a7

    pea    0.w
    pea    zer(pc)
    pea    exe2(pc)   * Castle2
    pea    $4B0003   *Load only
    trap    #1
    lea    $10(a7),a7

* Now depack this special FIC.... CTE extension used
* CTE  means  Compressed TOS Executable

* CTE build:   at begin is regular TOS header.  Code len is len of packed
* data. Must be terminated with long 0 at even position.  Data len is always 0
* BSS len is same as in unpacked TOS exec
* Following rutine will correct Code and Data len in basepage after depack :
* Packed data is C3 FIC without header !

  * Packed Code is loaded at BP + 256
  * So, move up, and then depack to same place...

    move.l  d0,-(sp)

     move.l  d0,a1
    lea  256(a1),a2
    move.l  a2,-(sp)   * Save code begin
    lea  $90000,a3   *may be too low on Falc
    tst.b    gxf
    beq.s    copa3
    lea  $110000,a3

copa3    move.l    a3,a1
    move.w  #26672,d2   * ~ 213379
mou1  move.l  (a2)+,(a3)+
   move.l  (a2)+,(a3)+   
   dbf  d2,mou1

  * There is no FIC header ! Of course ....

   move.l   (sp),a4
   lea  -28(a4),a4   * Depacking with TOS exec header !
   bsr  depak3

     move.l  (sp)+,a1   *Code begin

* Now reloc :
    move.l     a1,a0
    lea   -28(a0),a3   *Header
    lea  -256(a0),a5   *Basepage
    move.l    a1,d0
    add.l    2(a3),a0   *Code  len for this prg
 *No data here
*    add.l    6(a3),a0   *Data  len for this prg
    move.l    a0,a2 * reloc table begin

    tst.l    (a0)
    beq.s    corrbp *

    add.l    (a0)+,a1
    clr.l    d1
relol    add.l    d0,(a1)
    move.b    (a0)+,d1
    beq.s    corrbp
    cmp.b    #1,d1
    bne.s    nmd
    lea    $FE(a1),a1
    bra.s    bigd
nmd    adda.l    d1,a1
    bra.s    relol

    move.l        2(a3),$C(a5)   *Code len
move.l        6(a3),$14(a5)  *Data len
move.l        $A(a3),$1C(a5)   *BSS len
move.l        8(a5),d2
move.l       $C(a5),d1
    add.l          d2,d1
move.l       d1,$10(a5)     *Data start adr
move.l       $14(a5),d2
    add.l          d2,d1
move.l       d1,$18(a5)   *BSS start adr

    lea           6600(a0),a0    * May need more by some

xy         clr.l    (a2)+ * clear BSS area begin
            cmp.l    a2,a0
            bgt.s    xy      

     move.l  (sp)+,d0    *get BP address back
    move.l    d0,a5
    move.l    d0,a3

    lea    gxf(pc),a2
    tst.b    (a2)
    beq.s     rungame

* 2 addresses to correct in key test for exit
    move.l    d0,a2
    add.l    #$3F5F4-$191E2,a2
    move.l    a2,gamnoex+2

    move.l    d0,a2
    add.l    #$3F66C-$191E2,a2
    move.l    a2,jubag+2

* Inject  game  exit activation :

*     lea    $DF000,a2      * Game soecific
*    lea    gamex(pc),a1
*    moveq    #100,d2
*.gac    move.l    (a1)+,(a2)+
**   dbf    d2,.gac
* No need for above as we have this resident in RAM !

* Link to :    *   To pos  $3F666-$191E2 + d0

    add.l    #$3F666-$191E2,a3
    move.w    #$4EF9,(a3)+
*    move.l    #$DF000,(a3)
   move.l    #gamex,(a3)

    pea    (a5)
    pea    (a5)
    pea    (a5)

    pea    $4B0004   *Start it
    trap    #1
    lea    $10(a7),a7

exitu     clr.w -(sp)
    trap #1

zer    dc.b    0,0,0,0


gxf          dc.w    $0100    *Preset because Falc. Phys RAM skip at begin
*gemdap   dc.l   0

*Game exit code:  * Goes to pos: 
- here stays

gamex      cmp.b   #$C3,d0   * For F9
    beq.s  gamex_w

gamnoex         tst.w    $3F5F4  * This 2 address will be corrected according to load pos
jubag           jmp    $3F66C
* Above 2 address will be corrected by game load pos.

* Code for game state store when exit is requested:

*GameStat    equ    $DF180   *Set for particular game always
*GameStoPl    equ      $DF000   *Where to place code for gamestate save
* Here no need for extra RAM locations...

GameSto    * The code itself. Must be PC relative !!!

* Presumable we are in supervisor mode....
* For games not running in SV need some switch, workaround...
* will see later....

*     0    USP
*     4    Cur screen resolution - almost always 0 !
*     6    SSP
*     10    Palette, 32 bytes
*     42    MFP state, 24 bytes
*     66    Screen base
*     70    IKBD joy status, 8 bytes
*     80    SR,  2 bytes
*     84    PSG status, 14 bytes
*     100    IKBD mouse status, 8 bytes
*     108   STE DMA audio if used
*     116    Next thing worth to store  :-)

ikbdof         equ    70
ikbdm_of    equ      100
srofs          equ    80
psgofs        equ    84

* Store CPU regs, SR, stack pointers
    movem.l    d0-d7/a0-a6,-(sp)
*    lea     GameStat,a6
    lea    depak3(pc),a6
    move.w    sr,80(a6)

    move.l    usp,a1
    move.l    a1,(a6)+     *Store USP
    move.b    $FFFF8260.w,d1
    and.w    #$3,d1
    move.w    d1,(a6)+   * Res. Usually 0

    move.l    sp,(a6)+  *SSP

* Saving PSG state:
    lea    $FFFF8800.w,a1
*    lea    GameStat+psgofs,a2
    lea    depak3+psgofs,a2
    moveq    #0,d2
.psgl    move.b    d2,(a1)
    move.b    (a1),(a2)+
    addq.b    #1,d2
    cmp.b    #14,d2
    bne.s    .psgl

* Save palette:

    lea    $FFFF8240.w,a1
    moveq    #15,d1
.palc    move.w    (a1)+,(a6)+
    dbf    d1,.palc

* Saving MFP state.....

* Save MFP registers :

    lea    $FFFFFA01.w,a1
    moveq    #23,d2   *24 registers, up to $FFFA2F
.mfpsl    move.b    (a1),(a6)+
    addq.l    #2,a1
    dbf    d2,.mfpsl

*Timer A, C and D need accurate reading:
* we presume that timer B is intact (for now)

*So we read them some time and take
*Max value:

   * To speed it up we can test all 3 in same time !

    lea    $FFFFFA1F.w,a1   *Timer A data
    lea    $FFFFFA23.w,a2   *Timer C data
    lea    $FFFFFA25.w,a3   *Timer D data

* Trying with longer test: worked not

    move.w    #6777,d7   *Determines time for read
    clr.b    d2
    clr.b    d4
    clr.b    d6

gatimbl    move.b    (a1),d1
    cmp.b    d1,d2
    bcc.s    ganotba
    move.b    d1,d2

ganotba    move.b    (a2),d3
    cmp.b    d3,d4
    bcc.s    ganotbc
    move.b    d3,d4

ganotbc    move.b    (a3),d5
    cmp.b    d5,d6
    bcc.s    ganotbd
    move.b    d5,d6

    dbf    d7,gatimbl

    move.b    d2,-9(a6)      * Timer A Data reg
    move.b    d4,-7(a6)      * Timer C Data reg.
    move.b    d6,-6(a6)    * Timer D Data reg.

* Screen Base:
    move.b    $FFFF8201.w,(a6)+   * High byte
    move.b    $FFFF8203.w,(a6)+   * Mid byte

*  IKBD status  will store  after  setting  TOS workable - in restoring it....

* so, may  jump to  TOS restore:

* Clear abort flag in game   !!!!
* If needed !   

    jmp    FreeMem

* C3 depacker:
depak3    clr.l d0
    moveq    #6,d4
    moveq    #$3f,d5   *for masking bits 5-0

* Bit meaning:  7 - if set it's back referrer , if 0 then bits
* 6-0 give count of literals to copy
* if all bits are 0 it is terminator

* When bit 7 set, bit 6: if 1 then long distance back given by 2 following byte
*  bit 6: when 0  then short distance given by following 1 byte
*  bits 5-0  count of bytes referred.
*  By short refer.  0 means 3, 1 means 4, etc  up to 66 .
*  By long refer.  0 means 4, 1 means 5, etc  up to 67 .

main3     clr.w d0 *prep for dbf
    move.b (a1)+,d0
    bmi.s back3
    beq.s nom3 *end
    subq.w #1,d0 *compens dbf
litc     move.b (a1)+,(a4)+
    dbf d0,litc
    bra.s main3

nom3    rts

back3    move.b d0,d2
    and.w d5,d2 *d5=$3f
* Test is long or short referrer:
    btst    d4,d0   *test bit 6
    bne.s  longr
    addq.w #2,d2 *compens   
displl    move.b (a1)+,d0 * displac
calcadr    move.l a4,a2
    sub.l d0,a2
baksl    move.b (a2)+,(a4)+
    dbf d2,baksl
    bra.s main3

longr    addq.w #3,d2 *compens
    move.b (a1)+,d0 * displac
    lsl.w  #8,d0   *MSB
    bra.s   displl

* End of C3 depak

* Game files :

exe1    dc.b   "CASTLE1.TOS",0
exe2    dc.b   "CASTLE2.CTE",0


* Rutine for setting new Phystop, memtop and allocated block's variables
lowmsuv     *Supervisor mode needed for set some sysvars...

    move.l    $42E.w,d5   *Old Phystop
    move.l    #NewPhyst,$42E.w
* See is Memtop sysvar $8000 bytes below Phystop :
* By Falcon is usually $7E00 bytes below

    move.l    $436.w,d3
    move.l    d5,d4
    sub.l    d3,d4
    move.l    #$8000,d3
    sub.l    d4,d3    * add diff

    sub.l    #NewPhyst,d5    *Get diff.
    sub.l     d5,$436.w    *Correct Memtop sysvar

    sub.l    d3,$436.w    * By Falcon if....

*    Get os_end :

    move.l     $4F2.w,a1
    move.l      12(a1),a1   *seek until this addr
    lea      $800,a2     *from here seek

* Seek basepage value, followed by free RAM for... :

    move.l    basep(pc),d1
    move.l    memt(pc),d2
    sub.l    d1,d2   *free RAM for

bvseekl     cmp.l    (a2),d1
          bne.s    bvseendt

* if found test freeram value matching :

    cmp.l    4(a2),d2
    beq.s    bvgotit

bvseendt    addq.l    #2,a2
        cmp.l    a2,a1
    bgt.s    bvseekl

bvgotit   * decrease  free RAM value by diff. :

    sub.l     d5,4(a2)
* Dirty hack, but works !

    * By stoopid Falcon it is $200 bytes higher !!!!
    sub.l    d3,4(a2)


* If no RAM for GX skip Signature writing :

    tst.b    gxf
    beq.s    fin_lowm

* Header build support  #1:
    move.l    $42E.w,a2
    move.l    #"PPGX",(a2)+
    move.l    #MainInb,(a2)
fin_lowm    rts

DeskRes    dc.w    0
basep    dc.l      0
memt    dc.l      $F8000    *preset for case...
uspstor    dc.l    0

GamexCtrl     *Code for controlling game exit ....
   * Must be PC relative !!

RamSwap     *This swaps  2 RAM halves

    move.w    #$2700,sr  

* MFP restoring flow:

* disable all MFP interrups
* allow little time that CPU finish

* Clear IE registers
    clr.b    $FFFFFA07.w
    clr.b    $FFFFFA09.w
* Clear Pending  regs
    clr.b    $FFFFFA0B.w
    clr.b    $FFFFFA0D.w
*Clear  in Service regs :
    clr.b    $FFFFFA0F.w
    clr.b    $FFFFFA11.w


*Some little delay
* Until find not better solution ... ?
     move.l   #3984,d1
.del    subq.l    #1,d1
    bne.s   .del

* Swapping only  used Sys area, after it just copy left game area
* to top RAM !!!

* no need for swap, in fact .....

* First copy game up, then TOS down, then rest of game up
* 256KB max at once

ramswp    lea     8.w,a5
    move.w    #5460,d0     * For 256KB

    movem.l      (a5)+,d1-d7/a0-a4   *48 bytes at once
    movem.l    d1-d7/a0-a4,(a6)   
    lea    48(a6),a6
     *48 bytes in one cycle

    tst.b    d0
    bne.s    ramsw_loop
 *Little fade/flash :
    move.w    $FFFF8240.w,d1
    addq.w    #1,d1
    cmp.w    #$0FFF,d1
    bcs.s    .colup
    clr.w    d1
.colup    move.w    d1,$FFFF8240.w

ramsw_loop    dbf    d0,ramswl

* game up to $3FFF8  copied

* Copy saved TOS RAM back down
    lea    8.w,a6
    lea    DeskCopy,a5
swapln    move.w    #0,d0   * Will be set in stage 3

.cod2    movem.l      (a5)+,d1-d7/a0-a4   *48 bytes at once
     movem.l    d1-d7/a0-a4,(a6)   
    lea    48(a6),a6
    dbf    d0,.cod2   

* Now only copy remaining of game in high RAM
     lea    $3FFF8,a5   *src
AltRamPos+$3FFF8,a6   *dest

     move.w    #13637,d0      *for rest, to  $DFCF8 !   by SaveLen !
* Formula:  (SwapLen-$3FFF8)/48
.cou    movem.l      (a5)+,d1-d7/a0-a4   *48 bytes at once
     movem.l    d1-d7/a0-a4,(a6)   
     lea    48(a6),a6
     dbf    d0,.cou   

* May be little overshot, so set locations min 24 bytes over !


* Now need to restore stack pointers, screen, MFP, PSG ....

*   relative pos,      what  in SysStor

*     0    USP
*     4    Desktop screen resolution at prg start !
*     6    SSP
*     10    Palette, 32 bytes
*     42    MFP state....

    lea           SysStor,a1
    move.l     (a1)+,a4
    move.l     a4,usp
    move.w    (a1)+,d7   *Resolution
    move.l     (a1)+,sp

*Set palette pointer Sysvar: 
    move.l    a1,$45A.w   *Colorptr - will set palette in first Vblank

* Here deal with MFP....

    lea          $FFFFFA01.w,a1
    lea          SysStor+mfpof,a2
    moveq     #23,d2   *24 registers
mfprl           move.b    (a2)+,(a1)
    addq.l      #2,a1
    dbf          d2,mfprl

    move.w    #$2300,sr

*Signal and silencing possible tone
    lea forvs(pc),a6
    lea $ffff8800.w,a0
    moveq #0,d0
sounl    move.b d0,(a0)
    move.b (a6)+,2(a0)
    addq.b #1,d0
    cmp.b #14,d0
    blt.s sounl

* Flush IKBD ACIA buffer - may be blocked
aciafl        btst    #0,$FFFFFC00.w
    beq.s    aciaempt
    tst.b     $FFFFFC02.w
    bra.s     aciafl

    move.l   #3984,d1
.del    subq.l    #1,d1
    bne.s   .del

* Here need IKBD mode test and store
* Here not really  needed

* by other games it may be different !!!

* Prepare fetching code:
    lea    GameStat+ikbdof+AltRamPos,a4
    lea    ikbstoc+2(pc),a2
    move.l    a4,(a2)

* Need to receive status packet:

    move.l    ikbdsysv(pc),a1
    lea    my_ikbds(pc),a2
    move.l    a2,(a1)

    pea  joysta(pc)   
    move.w  #0,-(sp)   *1 byte only to send
    move.w  #25,-(sp)
    trap  #14
    addq.l  #8,sp

*Some delay   * Or solve with counting receives.... 
     move.l   #6984,d1
.del2    subq.l    #1,d1
    bne.s   .del2

    cmp.b  #$00,1(a4)  * Normal value
    bne.s    go_mor3
    clr.b    (a4)

* Back org ikbdsys vector:
    move.l    ikbdsysv(pc),a1
    lea    orgikbds(pc),a2
    move.l    (a2),(a1)

    pea  ikbdres(pc)    *Back regular IKBD mode
    move.w  #1,-(sp)
    move.w  #25,-(sp)
    trap  #14
    addq.l  #8,sp

* Set screen
    move.w    d7,-(sp)
    pea     GameScrB
    pea     GameScrB
    move.w    #5,-(sp)
    trap       #14
    lea        12(sp),sp
* Write for sure :
    move.l    #"PPGX",(a2)+
    move.l    #MainInb,(a2)

ToDesktop    clr.w    -(sp)
    trap        #1    *Regular exit

* Reading 8-byte packet from IKBD:

*    btst    #0,$FFFFFC00.w
*    beq.s    ikbdpac

    movem.l    a3-a4,-(sp)

    tst.b    $FFFFFC00.w
ikbstoc    lea    0,a4     *****

    lea    ikbstoc+2(pc),a3
    move.b     $FFFFFC02.w,(a4)+
    move.l    a4,(a3)
    movem.l    (sp)+,a3-a4
    rts    *Not rte !
*  It was last part of saving gamestate !

ikbdsysv    dc.l    0
orgikbds    dc.l    0

ikbdres      dc.b     $80,1
joysta       dc.b     $92,0   


forvs   *Sound pattern, simple
  dc.b 66,2
  dc.b 125,2,80,2
  dc.b 1 *Noise perlen -here not used
  dc.b %11111000 *Mixer control
  dc.b 16,16,16
  dc.b 0,22,0

  * Detecting HW, RAM
    bclr      #1,$484.w   * Key repeat off !!! Important if using TOS call for key read
 *Check TOS version - may be not built inm, but running in RAM !
       move.l    $4F2.w,d1
   *      clr.b    d1  *on round address always
       move.l    d1,a1
      move.b    2(a1),d0  *TOS ver major
      move.b    3(a1),d1  *TOS ver minor

* Following is necessary to correct if run in low RAM
* in  area   below   launcher
* otherwise Trap #1 will write in code !!!!
*    move.l    $28(a1),gemdap  * Actual GEMDOS proc.

* Writing TOS version for later outprint
    lea          machin(pc),a2
    move.b   d0,(a2)+   *TOS V
    move.b   d1,(a2)+   *TOS v
    move.b   29(a1),4(a2)   *Lang code

*'Detecting' TOS RAM size, just by $42E

    move.l     $42E,d2
    swap       d2
    lsr.w        #3,d2   *shift so that 512KB will be 1
    move.b     d2,(a2)+

*If TOS is 4 or 3 , skip next tests...

    cmp.b    #4,d0
    beq      isfalc
    cmp.b         #3,d0
    beq           istt

* Physical RAM size by MemCTRL sysvar, or by Chip read ...

    clr.l           d3
*Instead orgphystop look MMU control register shadow $424
    move.b      $424.w,d3
    move.l        d3,d2
    and.b         #1,d2
    move.l        d3,d1
    and.b         #4,d1
    lsr.b           #2,d1
    add.b         d1,d2  *512K multiplier - 1 or 2 or 0

    move.l         d3,d4
    and.b          #2,d4
    move.l        d3,d1
     and.b          #8,d1
    lsr.b            #2,d1
    add.b          d1,d4  *2M mult.  2 or 4 or 0
    lsr.b            #1,d4  *now 1 or 2

    clr.l              d3
    tst.b             d2
    beq.s           seem2
    move.l         #$40000,d3  *256KB
    lsl.l              d2,d3  *mult by 2 or 4 
seem2             clr.l    d2
    tst.b            d4
    beq.s           keepms
    move.l        #$100000,d2  *1MB
    lsl.l            d4,d2
    add.l          d2,d3

keepms          swap     d3
    lsr.w          #3,d3   *shift so that 512KB will be 1
    move.b      d3,4(a2)

*Detecting machine HW - is STE, MSTE ?

*Is MSTE ?
    move.l    sp,a3
    lea    buser1(pc),a1
    move.l    8.w,backorb-buser1+2(a1)
    move.l    a1,8.w
    move.b    $FFFF8E21.w,d1   *  read from HW reg
*Will do bus error if not Mega STE
    move.b   #3,(a2)+   *Code for MSTE

* d1  -  bit 0 = cache on/off   ,  bit 1 (?) = 8/16MHz   
     btst    #1,d1
    sne    (a2)

* After this may set 16MHz by need, or even back to 8...
    addq.l   #1,a2
    move.b  #$FF,$FFFF8E21.w
    st    (a2)
    bra.s    backorb
buser1    lea    buser2(pc),a1
    move.l    a1,8.w
    tst.b    $FFFF8924.w  *Microwire for STE detect
    move.b   #2,(a2)   *Code for STE
    bra.s    restosp

buser2    move.b    #1,(a2)

restosp    move.l  a3,sp
backorb    move.l    #0,8.w    *here comes original buserror vector

machin    dc.b  0,0,0,0,0,0,0,0,0,0   *TOS V Major, TOS v minor, RAM size, HW
    * MSTE clock at start,  MSTE clock set,  Lang code, Real RAM size

istt     move.b   #5,(a2)   *HW code

isfalc    move.b   #4,(a2)   *HW code

*PMMU moving   needed because of restore possible difference ...
newpos equ $3FE000

    lea     pmmuop(pc),a1   
    move.b    #0,(a1)
    clr.l    d0
    movec    cacr,d0
    move.w    #$20A,d0
    movec    d0,cacr
    lea    $700.w,a0

    lea     newpos,a1
    move.w    #$100,d0
pmmml    move.b    (a0)+,(a1)+
    dbf    d0,pmmml
    lea    pmmuop+2(pc),a0
    pmove.d    crp,(a0)
    move.l     #newpos,4(a0)
    pmove.d    (a0),crp
    lea    pmmuop+10(pc),a1
    move.l    #$FF8707,(a1)
    pmove.l    (a1),tt0

* Setting CPU caches best for game :
    move.w    #$809,d7   * Instr cache on, data off
    movec    d7,cacr
    move.w    d7,d2
    and.w    #1,d2
    lsr.w    #7,d7
    and.w    #2,d7
    or.w    d7,d2
    lea    falccach(pc),a1
    move.b    d2,(a1)+
    move.b    #$CF,(a1)   * Validity flag !

*Setting bus, by game :
    and.b     #%11011111,$ffff8007.w  *16MHz,  STE bus
    or.b    #%00000001,$FFFF8007.w

pmmuop  ds.b 32
falccach    dc.w    0


machipr  *Outprints machine parameters

    lea hwpos(pc),a0
    bsr  pmess
    lea mait(pc),a0
    bsr  pmess

    lea  machin+3(pc),a1
    cmp.b  #1,(a1)
    bne.s   isstem
    lea   hwst(pc),a0
    bra.s  hwoup

isstem    cmp.b  #2,(a1)
    bne.s   ismstem
    lea   hwste(pc),a0
    bra.s  hwoup

ismstem    cmp.b  #3,(a1)
    bne.s   isfalcm
    lea   hwmste(pc),a0
    bsr    pmess

    *Outprint CPU clock too if MSTE:
    lea  machin+4(pc),a1
    tst.b    (a1)
    bne.s   sho16   *if begin clock 16 then print 16 only
    addq.l   #1,a1
    tst.b   (a1)
    beq.s   sho8   *if begin and end is 8 show 8 only
* Show 8>16
    lea   hwm816m(pc),a0
    bra.s  hwoup
sho16    lea   hwm16m(pc),a0
    bra.s  hwoup
sho8    lea   hwm8m(pc),a0
    bra.s  hwoup

isfalcm    cmp.b  #4,(a1)
    bne.s   seetv
    lea   hwfalc(pc),a0

hwoup     bsr     pmess

seetv    *TOS version outprint

    lea tosvit(pc),a0
    bsr  pmess

    lea   tosvp+1(pc),a2
    lea  machin(pc),a1
    move.b  (a1)+,d0   *Major
    add.b #"0",d0
    move.b   d0,(a2)

    move.b  (a1),d1   *Minor
    cmp.b  #$62,d1    *is TOS 1.62 ?
    beq.s  t162s

    add.b  #"0",d1
    moveq #"0",d0
    bra.s   tosvpri

t162s    moveq #"6",d0
    moveq  #"2",d1

tosvpri    addq.l  #2,a2
    move.b  d0,(a2)+
    move.b  d1,(a2)
    lea   tosvp(pc),a0
    bsr  pmess

*TOS RAM size outprint
    lea ramit(pc),a0
    bsr  pmess   
    lea  machin+2(pc),a1
    cmp.b  #1,(a1)
    bne.s   not512
    lea   rams512(pc),a0
    bra.s  ramsoup

not512   *needs some calc...
    moveq   #0,d1
    move.b (a1),d1
    lsr.b #1,d1
    scs   d6   *Flag for half MB at end
    lea  ramsiu+1(pc),a1  *Some aligning...
    tst.b   d6
    beq.s   bratoa
    lea  ramsiu(pc),a1
bratoa    bsr  toasc

    tst.b  d6
    beq.s  ramsta
    move.b #".",(a1)+
    move.b #"5",(a1)
ramsta    lea  ramsiu(pc),a0

ramsoup  bsr.s  pmess

* ST RAM size outprint
    lea  machin+3(pc),a1
    cmp.b       #5,(a1)
    beq.s    end_hwpr
    cmp.b      #4,(a1)
    beq.s    end_hwpr

    lea ramst(pc),a0
    bsr  pmess   
    lea  machin+7(pc),a1
    cmp.b    #1,(a1)
    bne.s    not512rs
    lea         rams512(pc),a0
    bra.s     ramsouprs

not512rs   *needs some calc...
    moveq   #0,d1
    move.b (a1),d1
    lsr.b #1,d1
    scs   d6   *Flag for half MB at end
    lea       ramsiu+1(pc),a1  *Some aligning...
    tst.b     d6
    beq.s   bratoars
    lea       ramsiu(pc),a1
bratoars    bsr       toasc

    tst.b    d6
    beq.s  ramstars
    move.b #".",(a1)+
    move.b #"5",(a1)
ramstars    lea  ramsiu(pc),a0

ramsouprs  bsr.s  pmess

    lea   noGXp(pc),a0
    tst.b    gxf
    beq.s    skip_gxki
    lea   gamext(pc),a0
skip_gxki         bsr  pmess


pmess      pea  (a0)
    move.w  #9,-(sp)
    trap   #1
    addq.l  #6,sp

toasc    *cover values from 1 to 14

    divu #10,d1
    move.b d1,d2
    swap  d1
    add.b #"0",d2   *10s of MB
    cmp.b #"0",d2
    bne.s   putdig1
    move.b #" ",d2
putdig1    move.b d2,(a1)+
    add.b #"0",d1   *1s of MB
    move.b d1,(a1)+


hwst dc.b  "   ST",0
hwste  dc.b "  STE",0
hwmste dc.b "Mega STE",0
hwfalc   dc.b " Falcon",0

hwm8m  dc.b 13,10," 8 MHz",0
hwm16m  dc.b 13,10," 16 MHz",0
hwm816m  dc.b 13,10,"8>16 MHz",0

tosvp  dc.b  " 1.00",0

rams512 dc.b " 512 KB",0     *  ,27,"H",0

ramsiu  dc.b  "    MB",0 

hwpos  dc.b    27,"E",27,"Y",48,32,0

homec  dc.b  27,"H",0   *Cursor back to top left

* Info texts:

mait  dc.b  "Machine: ",0
ramit  dc.b  13,10,"TOS RAM:",0
ramst  dc.b  ", ST RAM:",0
tosvit  dc.b  13,10,"TOS ver: ",0

gamext  dc.b   13,10,13,10,"GAMEX: key F9",27,"H",0

langs     dc.b     27,"H","Press E for English,",13,10
    dc.b  "D for Deutsch",13,10
    dc.b  "or F for Francais",13,10,0

infstr    dc.b  13,10,"Press I for infinite strength",0

lowRamTM   dc.b  13,10,"Too much low RAM occupied !",0
RAMne   dc.b  13,10,"Min RAM: 1MB !",0
noGXp    dc.b  13,10,13,10,"For Gamex min 2MB RAM !",27,"H",0

* Adding Mega STE and  Falcon  machine settings as option :

megastes    *see machine

    lea    machin+3(pc),a2
    cmp.b    #3,(a2)
    beq.s    itsMSTE

    cmp.b    #4,(a2)
    beq    itsFalc

* return if not MSTE or Falcon :
    bra    show_hw

* Mega STE
 * Only setting 8/16MHz, together with cache off/on

    bsr    clearkb     * Clear ikbd buffer for sure

    lea    mstest(pc),a0
    bsr    pmess

    tst.b    machin+5   * Clock ?
    bne.s    its16m1
    lea    mste8mt(pc),a0   * Change txt on screen
    bsr    pmess
    clr.b    mstetems

its16m1    move.w    #7,-(sp)
    trap    #1
    addq.l    #2,sp

    cmp.b    #"1",d0
    beq.s    msteset8
    cmp.b    #"2",d0
    beq.s    msteset16

    cmp.b    #" ",d0
    beq.s    msteexit

    cmp.b    #13,d0
    beq.s    mstesetexit
    bra.s    its16m1

msteset8    lea    mste8mt(pc),a0   * Change txt on screen
    bsr    pmess
    moveq    #0,d1
mstecls    move.b    d1,mstetems   
    bra.s    its16m1

msteset16    lea    mste16mt(pc),a0   * Change txt on screen
    bsr    pmess
    st    d1
    bra.s    mstecls

mstesetexit   * We are in supervisor mode
    move.b    #$FC,d1
    tst.b    mstetems   
    beq.s    set8caoff
    move.b    #$FF,d1
set8caoff        move.b    d1,$FFFF8E21.w
    addq.b    #1,d1
    seq    machin+5

msteexit        bra    show_hw

mstetems        dc.b    255,0   *Must preset to on !

mstest     dc.b   27,"E","     Mega STE CPU clock setting",13,10
    dc.b  13,10,"Press:   1 for 8 MHz,   2 for 16 MHz",13,10
    dc.b  "Enter  for  set and exit",13,10
    dc.b   "Space exits without change",13,10

    dc.b   13,10,13,10,"CPU clock: 16 MHz",0

mste8mt    dc.b    27,"Y",39,43," 8",0       
mste16mt    dc.b    27,"Y",39,43,"16",0

itsFalc    * Set bus - CPU, Blitter clock, STE emul., CPU instr and Data


    bsr    clearkb     * Clear ikbd buffer for sure

    lea    falconst(pc),a0
    bsr    pmess

* Falcon bus settings:
* FF8007   Bit 0 = CPU clock,  Bit 2 = Blitter clock,  Bit 5 = STE bus emul

when = 0 !

    move.b    $FFFF8007.w,d7
    btst    #0,d7
    bne.s    fas1
    lea    falcc8mt(pc),a0   * Change txt on screen
    bsr    pmess
    clr.b    falset1

fas1    btst    #2,d7
    bne.s    fas2
    lea    falcb8mt(pc),a0   * Change txt on screen
    bsr    pmess
    clr.b    falset1+1

fas2    btst    #5,d7
    bne.s    fas3
    lea    falcsten(pc),a0   * Change txt on screen
    bsr    pmess
    clr.b    falset1+2

fas3    move.b    falccach(pc),d7
    btst    #0,d7    *Instr cache
    bne.s    fas4
    lea    falcincf(pc),a0   * Change txt on screen
    bsr    pmess
    clr.b    falset1+3

fas4    btst    #1,d7    *Data cache
    bne.s    fas5
    lea    falcdcf(pc),a0   * Change txt on screen
    bsr    pmess
    clr.b    falset1+4

    move.w    #7,-(sp)
    trap    #1
    addq.l    #2,sp

    cmp.b    #"1",d0
    beq.s    falsetc8
    cmp.b    #"2",d0
    beq.s    falsetc16

    cmp.b    #"3",d0
    beq.s    falsetb8
    cmp.b    #"4",d0
    beq.s    falsetb16

    cmp.b    #"5",d0
    beq    falsetsteoff
    cmp.b    #"6",d0
    beq    falsetsteon

    cmp.b    #"7",d0
    beq    falsetinof
    cmp.b    #"8",d0
    beq    falsetinon

    cmp.b    #"9",d0
    beq    falsetdaof
    cmp.b    #"0",d0
    beq    falsetdaon

    cmp.b    #" ",d0
    beq    msteexit    *same exit

    cmp.b    #13,d0
    beq    falsetexit
    bra.s    fas5

falsetc8    lea    falcc8mt(pc),a0   * Change txt on screen
    bsr    pmess
    moveq    #0,d1
fal1cls    move.b    d1,falset1   
    bra.s    fas5

falsetc16    lea    falcc16mt(pc),a0   * Change txt on screen
    bsr    pmess
    st    d1
    bra.s    fal1cls

falsetb8    lea    falcb8mt(pc),a0   * Change txt on screen
    bsr    pmess
    moveq    #0,d1
fal1bls    move.b    d1,falset1+1   
    bra    fas5

falsetb16    lea    falcb16mt(pc),a0   * Change txt on screen
    bsr    pmess
    st    d1
    bra.s    fal1bls

falsetsteoff    lea    falcstef(pc),a0   * Change txt on screen
    bsr    pmess
    st    d1      * When set, then is off !!!
fal1ste    move.b    d1,falset1+2   
    bra    fas5

falsetsteon    lea    falcsten(pc),a0   * Change txt on screen
    bsr    pmess
    moveq    #0,d1
    bra.s    fal1ste

falsetinof        lea    falcincf(pc),a0   * Change txt on screen
    bsr    pmess
    moveq    #0,d1
fal1inc    move.b    d1,falset1+3   
    bra    fas5

falsetinon     lea    falcincn(pc),a0   * Change txt on screen
    bsr    pmess
    st    d1
    bra.s    fal1inc

falsetdaof        lea    falcdcf(pc),a0   * Change txt on

    bsr    pmess
    moveq    #0,d1
fal1dac    move.b    d1,falset1+4   
    bra    fas5

falsetdaon     lea    falcdcn(pc),a0   * Change txt on screen
    bsr    pmess
    st    d1
    bra.s    fal1dac

falsetexit       *activate changes :

    lea    falset1(pc),a3
    moveq    #0,d3
    moveq    #0,d4
    tst.b    (a3)   * CPU clock
    beq.s    fnot1
    bset    #0,d3

fnot1    addq.l    #1,a3
    tst.b    (a3)   * Blitter clock
    beq.s    fnot2
    bset    #2,d3

fnot2    addq.l    #1,a3
    tst.b    (a3)   * STE bus emul
    beq.s    fnot3
    bset    #5,d3

fnot3    addq.l    #1,a3
    tst.b    (a3)   * Instr. cache
    beq.s    fnot4
    bset    #0,d4

fnot4    addq.l    #1,a3
    tst.b    (a3)   * Data cache
    beq.s    fnot5
    bset    #1,d4

fnot5      * Now set HW regs :

    move.b    $FFFF8007.w,d2
    and.b    #%11011010,d2   * Mask required bits
    or.b    d3,d2
    move.b    d2,$FFFF8007.w
*    move.b    d3,$FFFF8007.w

    move.b    d4,falccach
    move.b    d4,d3
    and.w    #1,d3
    lsl.w    #7,d4
    and.w    #$0100,d4
    or.w    d3,d4
    or.w    #$0808,d4   * Clear order prepare
    movec    d4,cacr

    bra    show_hw

falconst     dc.b   27,"E","     Falcon bus and cache settings",13,10
    dc.b  13,10,"Press: 1 for 8 MHz, 2 for 16 MHz CPU",13,10
    dc.b   "     3 for 8 MHz, 4 for 16 MHz Blitter",13,10
    dc.b   "     5 for not STE, 6 for STE bus",13,10
    dc.b   "     7 for instr. cache off, 8 for on",13,10
    dc.b   "     9 for data cache off, 0 for on",13,10

    dc.b  "Enter  for  set and exit",13,10
    dc.b   "Space exits without change",13,10

    dc.b   13,10,13,10,"CPU clock:     16 MHz"
    dc.b   13,10,"Blitter clock: 16 MHz"
    dc.b   13,10,"STE bus:       off"
    dc.b   13,10,"Instr. cache:   on"
    dc.b   13,10,"Data  cache:    on",0

falcc8mt    dc.b    27,"Y",43,47," 8",0       
falcc16mt    dc.b    27,"Y",43,47,"16",0

falcb8mt    dc.b    27,"Y",44,47," 8",0       
falcb16mt    dc.b    27,"Y",44,47,"16",0

falcstef    dc.b    27,"Y",45,47,"off",0       
falcsten    dc.b    27,"Y",45,47," on",0

falcincf    dc.b    27,"Y",46,47,"off",0       
falcincn    dc.b    27,"Y",46,47," on",0

falcdcf    dc.b    27,"Y",47,47,"off",0       
falcdcn    dc.b    27,"Y",47,47," on",0


falset1    dc.b    255,255,255,255,255,0

clearkb    pea    $10002   *Keyboard, Bconstat
    trap    #13
    addq.l    #4,sp
    tst.b    d0
    beq.s    nocha

    pea    $20002   *Keyboard, Bconin
    trap    #13
    addq.l    #4,sp
    bra.s    clearkb

nocha    rts

* After displaying Photochrome pic area above will be stack
* area below will be free for TOS, pexec

hwpal   *Palette with white #0 and all other as blue
   *because of medres/lowres switch bug

   dc.w   $666,$116,$116,$116,$116,$116,$116,$116
   dc.w   $116,$116,$116,$116,$116,$116,$116,$116

screnb  ds.l 1

picfn    dc.b    "CASTLEM.PCH",0   * Unpacked PhotoChrome pic

   include  "PCHTOF3.S"     *Rutine which converts PCH to Falcon 16-bit display

  include  "PHOTUS.S"     * Original Photochrome Show little reworked

 section data

  * Workspace for displaying PCH pic :
  section  bss
head     ds.b  6   *PCH header here...
stbitm    ds.b  32000
stpal      ds.b  $4B20
stbm2    ds.b 32000
stpal2    ds.b  $4B20
convtbl  ds.b  8192