Atari ST cartridge programming

  Example of game on ST cartridge:   Here is a way how to put some regular game, not intended to work from cartridge.
Principle:  game will work from RAM, not from cartridge, as there is certainly no such which can do it, except some, written specially for cartridge.
Of course game is stored in cartridge, but we will copy it to RAM by start. To place games longer than 128KB we may use data packing, what is case here too.
And I did this so, that game may start automatically or by Desktop doubleclick.  Game normally starts after reset, but if user holds Left Shift key after reset, then it will not run automatically, and we will have normal start of ST. To achieve it do not press shift key while reset, but right after it, and hold down couple seconds.


 *  Revenge of the Mutant Camels  Atari ST cartridge  version

*Rom cartridge

  org $FA0000
  dc.l    $abcdef42     *magic
  dc.l    second
  dc.l     $08000000+autorev    * Bit 27 set
* what means run before Disk-boot

  dc.l    autorev
  dc.w     %0111101000100100   *time, GEMDOS format, 15 h, 17 min
  dc.w    %0011101011011010  *date - 2009, VI, 26
  dc.l     fin-autorev
  dc.b     "AUTOREV",0

  dc.l     0
  dc.l     $40000000   * TOS app.
  dc.l     deskrev
  dc.w     %0111101000100100   *time, GEMDOS format
  dc.w     %0011101011011010 *date - 2009, VI, 26
  dc.l     fin-deskrev
  dc.b    "REVENGE.TOS",0

autorev    * Starting game automatically
* with option to not start, if left shift is pressed

* Need some delay before key test :

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

    pea    $BFFFF
    trap    #13
    addq.l    #4,sp

    btst    #1,d0
    beq.s    runauto

    rts      *Exit if left Shift is pressed

runauto    move.l    $432.w,a3   * Membot

    move.l    $436.w,a4    *Memtop
    move.w    #$0300,sr   *Set user mode

    lea    -8(a4),sp
    clr.l    (sp)
    move.l    a3,4(sp)

deskrev    *  Depack to basepage+256,
*relocate and run

    lea    gamc3(pc),a1
    move.l    4(sp),a2      *Basepage
    lea    228(a2),a4   *Depack with header
    move.l    a2,-(sp)
    bsr    depak3

    move.l    (sp)+,a5   *Basepage
    lea    256(a5),a1   *code
* Now reloc :
    move.l     a1,a0
    lea      -28(a0),a3   *Header
      move.l     a1,d0
    add.l        2(a3),a0   *Code  len for this prg
        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
    lea      6600(a0),a0

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

    move.l    d0,a0
    jmp    (a0)

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

gamc3    incbin   "GAMEC3"


 Note:  In this example Basepage is not filled with TOS regular values used by standard APP start, as game does not need it. By some other ones it may be required...

Download files

  In archive is Steem compatible cartridge image file - REVCART.STC.  It has 4 zeros at beginning (as Steem likes so). And such image works well in latest Hatari versions too.  For using with real cartridge you need to strip that 4 zeros. Then file will be exactly 128KB long. You need to split that 128KB file to HI/LO if have cartridge with 2 EPROMs only. In case of cart. with 4 EPROMs need to split to 4 parts...

What is not possible with cart. SW:  to load file from cartridge via usual GEMDOS file load functions. And that means that you can not load some RSC with usual RSCload AES function. It is possible to solve it with RSC embedded in executable. Or in tricky way, but that's longer story. And I don't see that it is possible to run some ACC from cartridge.

Example of very simple, "Hello World" program in cartridge:


  org   $FA0000     * Start address
  dc.l    $abcdef42     *magic at begin

  dc.l       0       * no further prg. in cartrodge
  dc.l       $40000000   * TOS app.
  dc.l       hellow     * address of prg. start
  dc.w     %0111101000100100   *time, GEMDOS format, 15 h, 17 min
  dc.w     %0011101011011010  *date - 2009, VI, 26
  dc.l        fin-hellow     *  length of prg. in bytes
  dc.b      "HELLOW.TOS",0    * Name

hellow      pea      helwtxt
    move.w    #9,-(sp)   * Txt to screen
    trap    #1
    addq.l    #6,sp

    move.w    #1,-(sp)   * Wait some key pressed
    trap    #1
    addq.l    #2,sp

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

helwtxt    dc.b   "Hello World!",0


For GFA programmers:  I don't know GFA Basic, can give only some hints:  This is not regular TOS executable, and starts with 'magic' value: hex ABCDEF42 (4 bytes). Then comes header of first (and here last too) executable.  dc.l  is  4 bytes,   dc.w is 2 bytes - can give more, separated by comma.   dc.b  is 1 byte, but if followed by string in brackets it is txt data.   After it, we have simple TOS function calls .

DL Hello World src. and Steem cart.

CA_NEXT points to header of next program, or has value 0 if no more.
CA_INIT holds address of optional init. routine. Bits 24-31 aren't used for addressing, and ensure in which moment by system init prg. will be initialized and/or started. Bits have following meanings, 1 means execution:
bit 24: Init. or start of cartridge SW after succesfull HW init. System variables and vectors are set, screen is set, Interrupts are disabled - level 7.
bit 25: As by bit 24, but right after enabling interrupts on level 3. Before GEMDOS init.
bit 26: System init is done until setting screen resolution. Otherwise as bit 24.
bit 27: After GEMDOS init. Before booting from disks.
bit 28: -
bit 29: Program is desktop accessory - ACC .
bit 30: TOS application .
bit 31: TTP .
CA_RUN: Program start address. All optional inits are done before. This is required only if program runs under GEMDOS.
CA_TIME and CA_DATE: File's time and date stamps. In GEMDOS format.
CA_SIZE: Lenght of app. in bytes. Not really used.
CA_NAME: DOS/TOS filename 8.3 format. Terminated with 0 .

  Little help for cartridge HW :
 Pins  :  


  Schematic of cartridge with 2 EPROMs :

More games adapted for ST cartridge:
Buggy Boy
Joust and Moon Patrol
Missile Command
Rick Dangerous
Star Raiders
Star Wars

All games above with source code (Devpac 3 ASM recommended), included all files for possible modding. Used diverse packings, diverse systems - some games must be started from Desktop. Basically, everything can work from cartridge - but in case of simple cartridge it must fit in 128KB. My opinion is that larger games is better to run from some Flash card and regular Atari filesystem.

   P. Putnik,  June 2009- Jan. 2016.

         Menu Properties Quick Reference