GAMEX game launcher code source with comments

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

 * Atari ST gaming system GAMEX
* Features:  it needs min 1MB RAM for games working with 512KB normally
* Game may be exited to Desktop. In that case gamestate is preserved in area 512KB-1MB
* User may after exit to Desktop to continue playing or to save gamestate on disk

* This will be open source
* Created by Pera Putnik, May 2009.

* Example of Single part, TOS independent game

* Game : Sideways
* Sideways is originally with Exec and 10 data files,
* but I made it singleparted + packed ...

* Launcher stage 1:  reserving TOP RAM - lovering memtop, phystop

* Values for this game:
GameScrB       equ  $78000    *For games working with 512KB
AltRamPos    equ  $80000
MainInb        equ  $FFF40
SwapLen        equ  $7FCF8

GameRest    equ   $7FD20
GameJmp    equ   $14D5C   *  for this game

begin        *Beginning of program

* Adding low RAM usage check and exit if too much is used...

    lea    hwpal(pc),a1
    cmp.l    #FreeMem-DeskCopy-48,a1  *Place available to store TOS
    bcs.s    lowRamOK

    lea    lowRamTM(pc),a0
toPMex    bsr    pmess

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

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

NewPhyst     equ  $80000    *For 512K games

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

    pea    hwdet(pc)
    move.w    #38,-(sp)
    trap    #14
    addq.l    #6,sp

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

* Check Physical RAM

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

    move.l      4(sp),a2   *basepage adr.
    lea    $77F00,sp
    clr.l    (sp)
    move.l    a2,4(sp)

    move.b    #1,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 512KB of RAM !

* Launcher stage 2:  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
    clr.l    -(sp)
    move.w    #32,-(sp)
    trap    #1
    addq.l    #6,sp
    move.l    d0,uspstor

    tst.b    gxf
    beq    show_hw


* SysSto layout :
*   relative pos,   what

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

mfpof    equ  42

SysStor    equ    $FFF80     *Place for storing TOS system - 128 bytes

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

* 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 B and C need 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, Timer C:  $C0  !

* Preparing some IKBD storage:

    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
    move.l    (a1),orgikbds

    bsr    clearkb

    pea    swpal(pc)
    move.w #6,-(sp)
    trap  #14
    addq.l    #6,sp

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

    bsr    machipr    *HW detected print

*Little 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    wait_k
    cmp.b    #"M",d0
    beq    megastes   * Opt MSTE or Falcon settings
    cmp.b    #"m",d0
    beq    megastes

    bra.s    toPicsh
wait_k    dbf    d7,dell1

toPicsh   * No cover pic for this unreleased game

    clr.w    -(a7)
    pea    packn(pc)
    move.w    #$3D,-(a7)
    trap    #1
    addq.l    #8,a7
    move.w    d0,d7
    pea    $68000    * Loading game ...
    pea    41524     * Total len of packed complete game
    move.w    d7,-(a7)
    move.w    #$3F,-(a7)
    trap    #1
    lea    12(sp),sp

    move.w    d7,-(a7)
    move.w    #$3E,-(a7)
    trap    #1
    addq.l    #4,a7


     *now set stack pointers in picshow area
    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

* Launcher stage 3:   storing lower 512KB in area  $80008 - $FFD00

    * Header build support #2 : filling 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    #GameJmp,(a2)+
*    move.w    #$C3C2,(a2)+   *Keys
*    move.w    #$1200,(a2)+   * Disable mouse
*    clr.l    (a2)+   *Forced Timer regs
*    move.l    #DeskCopy,(a2)+
*    clr.l    (a2)+
*    move.w    #1,(a2)+     *Flag for COS 1.00 at $C0100

*     pos 38,  Falcon cache setting, byte...

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    $C0108   *
* what must be enough for TOS 2.06 with hard ddriver, buffers
      lea    8.w,a5
    lea    DeskCopy,a6   * We have enough place...
    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 $FFD00 - $FFFFF

FreeMem    equ    $FFD20       *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

lau_2   * Game launch, step 2

    pea    intrt(pc)   * Some info for game before run
    move.w   #9,-(sp)
    trap       #1
    addq.l  #6,sp

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

    moveq    #27,d7
dell11    move.w  #37,-(sp)
    trap  #14
    addq.l  #2,sp
    dbf    d7,dell11

    lea     $68000,sp

    lea    coup(pc),a2  * Moving up...
    lea    $67600,a3
    move.l    a3,a1
    moveq    #126,d2
coul    move.l    (a2)+,(a3)+
    dbf    d2,coul
    jmp    (a1)   


coup    lea    $68020,a1
    lea    $144C0,a4
    bsr     depak3

    clr.l    -(sp)     * Back to user mode
    move.w    #32,-(sp)
    trap    #1
    addq.l    #6,sp

* Copy panel to it's place:
* it's not in one block with other datas

    lea  $144C0+$23B40,a1
    lea   $75AA0,a2
    move.w  #2199,d2   
.cop    move.l   (a1)+,(a2)+
    dbf  d2,.cop

* Prevent load attempts: - due to singleparting
    move.w  #$4E75,$187EA

* Skip screen and palette setting in game :
* Otherwise Falcon palette error !
    move.w  #$601C,$1450E

*  Need to find good place in game where can abort it and
* doing state storing,  then  ramswap and exit to Desktop....

    lea    $14F86,a1  * Here will replace org. Game exit code...

    lea    gxf(pc),a2
    tst.b    (a2)
    beq.s     runit5
    move.w    #$4EF9,(a1)+
    move.l    #GameStoPl,(a1)   *storing code here

* Copy code to place:
    lea    GameStoPl,a2
    lea    GameSto(pc),a1
    move.w    #127,d2
.cop2    move.l    (a1)+,(a2)+
    dbf    d2,.cop2
    bra.s    runit

runit5    * Reset if no Gamex (on 512KB machines) when press escape...
    move.w    #$2278,(a1)+  * Jump to TOS start - reset
    move.l    #$00044ED1,(a1)

runit      jmp $144C0    * Run game

gxf    dc.b   1,0

uspstor     dc.l    0


* Game's palette here:
  dc.w   0,$777,0,0,0,23,$333,$510
  dc.w  0,$45,$555,$630,0,$67,$777,$750

packn     dc.b  "S123.FIC",0


* Code for game state store when exit is requested:

* By Sideways it can be little under $144C0 for instance...

GameStat    equ    $14000   *Set for particular game always

GameStoPl    equ      $14100   *Where to place code for gamestate save

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 status, 8 bytes
*    80    SR,  2 bytes
*     84    PSG status, 14 bytes
*    100    ???

ikbdof    equ    70
srofs    equ    80
psgofs     equ    84

* Store CPU regs, SR, stack pointers

    movem.l    d0-d7/a0-a6,-(sp)
    lea    GameStat,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)+   * Usually 0

    move.l    sp,(a6)+

* Saving PSG state:
    lea    $FFFF8800.w,a1
    lea    GameStat+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
    move.w    #4777,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   !!!!
    clr.b    $1477B     *Game specific
* Above will be present in savegames too always !!!

    jmp    FreeMem

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

* Following will set TOS RAM like we have only 512KB machine !

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 !!!!
*    cmp.b    #4,machin+3
*    bne.s    corr_2
    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      $78000    *preset for case...

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

ramswp    lea     8.w,a5
    lea    AltRamPos+8,a6
    move.w    #5460,d0    

    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

    lea    8.w,a6
    lea    DeskCopy,a5
swapln    move.w    #0,d0

.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
    lea    AltRamPos+$3FFF8,a6   *dest

    move.w    #5445,d0      *for rest, to  $7FD00 !

.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

* Restore  MFP   regs ....
    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

* Now save IKBD status (mode set)
* Requesting joystick mode:
* by other games it may be different !!!

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

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

* Need to receive status packet:

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



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

* 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 :
    lea    NewPhyst,a2
    move.l    #"PPGX",(a2)+
    move.l    #MainInb,(a2)

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

* 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,0,0
joysta      dc.b  $94,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. Called right after start

 *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)+

*Detecting machine HW - is STE, MSTE ?

*If TOS is 4, 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)

*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)
    move.b  #$FC,$FFFF8E21.w   *Set 8 MHz

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

    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 !

*    and.b    #%11011111,$FFFF8007.w
    or.b    #%00000001,$FFFF8007.w   * CPU 16MHz, Blitter irrelevant


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: Escape",27,"H",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 1MB RAM !",27,"H",0

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

* 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

    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 cache

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

intrt   dc.b  27,"H"
  dc.b "--------------------------------------------",13,10
  dc.b "Sideways - By Jamie Woodhouse",13,10
  dc.b "--------------------------------------------",13,10
  dc.b "Game prototype developed in 1989-1990",13,10,13,10

   dc.b "Basic Instructions:",13,10,13,10

  dc.b "Move about and press fire to shoot",13,10
  dc.b "crystals, turrets and aliens.",13,10
  dc.b "Shield goes down if you get hit by",13,10
  dc.b "aliens on bullets.",13,10
  dc.b "Energy goes down over time, shoot",13,10
  dc.b "crystals (on floor) to restore energy.",13,10
  dc.b "Shoot a full wave of aliens (8) and",13,10
  dc.b "then collect a bonus item left behind.",13,10
  dc.b "-----------------------------------------------",13,10