Skip to content

Commit

Permalink
Added new mode that relocates and runs programs to RAM.
Browse files Browse the repository at this point in the history
  • Loading branch information
ggnkua committed Jul 28, 2024
1 parent f4cd0e7 commit 9b76e51
Show file tree
Hide file tree
Showing 5 changed files with 414 additions and 43 deletions.
Binary file added prg_loader.bin
Binary file not shown.
305 changes: 305 additions & 0 deletions prg_loader.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,305 @@
; Code originally by tIn/Newline, "creatively adjusted" by GGN.
; Obviously in need of a cleanup!

ULTRADEV EQU 0
START_PAYLOAD EQU 01
start:


move.l 4(sp),a0 ; Obtain pointer to basepage
move.l a0,d7 ; Save a copy (start of TPA)
; add.l #$100,a0 ; add basepage size (end of TPA)
; move.l $c(a0),a1 ; Text size
; adda.l $14(a0),a1 ; Data size
; adda.l $18(a0),a1 ; BSS size
; adda.l $1C(a0),a1 ; Add BSS size
; adda.l #$100,a1 ; Add Basepage size
; adda.l #$200,a1 ; Add stack size

;move.l %a1,%sp ; Move your stack pointer to
; your new stack.

; suba.l d7,a1 ; TPA size
; move.l a1,-(sp)
move.l #$100,-(sp) ; new size - just the basepage if you don't mind
move.l d7,-(sp) ; start of TPA
clr.w -(sp)
move.w #$4a,-(sp) ; Mshrink()
trap #1
lea 12(sp),sp ; Fix up stack

; ;malloc
; move.l #payload-run,D0
; move.l #-1,-(sp) ; Return amount of largest chunk of RAM
; move.w #72,-(sp)
; trap #1 ; GEMDOS
; addq.l #6,sp
;
; move.l D0,A0
; move.l D0,A3
; lea run,A1
; lea payload,A2
;.cl:
; move.b (A1)+,(A0)+
; cmp.l A2,A1
; blt.s .cl
;
; jmp (A3)

run:

IFNE START_PAYLOAD
;from http://www.bitsavers.org/pdf/atari/ST/Atari_ST_GEM_Programming_1986/GEM_0042.pdf
;TPA structure
p_lowtpa EQU $00 ;.l p_lowtpa -> base of TPA
p_hitpa EQU $04 ;.l p_hitpa -> end of TPA
p_tbase EQU $08 ;.l p_tbase base of text segment
p_tlen EQU $0c ;.l p_tlen size of text segment
p_dbase EQU $10 ;.l p_dbase base of data segment
p_dlen EQU $14 ;.l p_dlen size of data segment
p_bbase EQU $18 ;.l p_bbase base of BSS segment
p_blen EQU $1c ;.l p_blen size of BSS segment
p_dta EQU $20 ;.l p_dta Disk Transfer Address (DTA)
p_parent EQU $24 ;.l p_parent -> parent's basepage
p_reserved EQU $28 ;.l (reserved)
p_env EQU $2c ;.l p_env -> enviroment string
p_cmdlin EQU $80 ;.l p_cmdlin commandline image
;PRG file header
prg_magic EQU $00 ;.w Ox601A (magic number)
prg_tlen EQU $02 ;.l Size of text segment
prg_dlen EQU $06 ;.l Size of data segment
prg_blen EQU $0a ;.l Size of BSS segment
prg_slen EQU $0e ;.l Size of symbol table
prg_reserved1 EQU $12 ;.l (reserved)
prg_reserved2 EQU $16 ;.l (reserved)
prg_reserved3 EQU $1a ;.l (reserved)
prg_text EQU $1e ;(start of text segment)

;pea 0
;pea 0
;pea null_long
;move.w #5,-(sp) ; PE_BASEPAGE
;move.w #$4B,-(sp)
;trap #1
;lea 16(sp),sp


move.l #-1,-(sp) ; Return amount of largest chunk of RAM
move.w #72,-(sp)
trap #1 ; GEMDOS
addq.l #6,sp
;@TODO handle not enough memory error
move.l D0,-(sp)
move.w #72,-(sp)
trap #1 ; GEMDOS
addq.l #6,sp
;@TODO handle malloc error

move.l D0,A0
lea $100(A0),A0 ;reserve basepage
; lea payload,A1
lea 'STRT',A1 ; will be filled later
; lea eop,A2
lea 'END!',A2 ; will be filled later
.cl:
move.b (A1)+,(A0)+
cmp.l A2,A1
blt.s .cl

; lea pbasepage(PC),A1
; move.l D0,(A1)
move.l d0,d7 ;save a copy of basepage address
move.l D0,A0
lea $100(A0),A1 ;prg header

move.l A0,p_lowtpa(A0)

lea $1c(A1),A1
move.l A1,p_tbase(A0)
move.l prg_tlen+$100(A0),p_tlen(A0)
add.l prg_tlen+$100(A0),A1

move.l A1,p_dbase(A0)
move.l prg_dlen+$100(A0),p_dlen(A0)
add.l prg_dlen+$100(A0),A1

move.l A1,p_bbase(A0)
move.l prg_blen+$100(A0),p_blen(A0)
add.l prg_blen+$100(A0),A1

add.l prg_slen+$100(A0),A1

;/from ultraDev (TOS1.02 by ultra, blame TOS1 "fix" to tIn)
lea emptyEnvStr(PC),A2
move.l A2,p_env(A0)
;clr.l p_cmdlin(A0) ;is this correct? better use an empty commandline just to be sure
lea emptyCommandline(PC),A2
move.l A2,p_cmdlin(A0)

pea supervisor_code(pc)
move.w #$26,-(sp)
trap #14
addq.l #6,sp
bra past_supervisor_code

supervisor_code:
move.l d7,a0

movea.l $04F2.w,a2 ;get Sysbase
movea.l 8(a2),a4 ;get rom start
move.l $28(a4),a2 ;this is not present in TOS<1.02!
;/---------------------
;1MB TOS1.0 crash!!!
; move.l (a2),p_parent(A0) ;<====== this does not work with TOS1.0, ROMSTART+$28 process pointer isn't present
; move.l A0,(a2) ;set act pd
;1MB TOS1.0 crash!!!
;\_____________________
;START --------------------- TOS 1.0 workaround
;check if this is TOS1.0 - unfortunately TOS1.0 does not know the first thing about cookies
tst.l $5a0.w ;cookie jar pointer
bne.s .thisisnottos10 ;!=0 ==> TOS did set this, so we're definitively not on TOS 1.0
cmp.w #$100,2(A4)
beq.s .thisistos10
;END ----------------------- TOS 1.0 workaround
.thisisnottos10:
move.l (a2),p_parent(A0) ;<====== this does not work
move.l A0,(a2) ;set act pd
bra.s .no1
.thisistos10:
;START --------------------- TOS 1.0 workaround
;taken from BUGABOOs "init_all"
lea $602C.w,A2 ;act_pd (vor dem Blitter-TOS)
move.w $1C(A4),D0 ;os_conf holen
lsr.w #1,D0 ;PAL/NTSC-Mode ignorieren
subq.w #4,D0 ;Spanisches TOS 1.0?
bne.s .noESTOS10 ;Nein! =>
lea $873C-$602C(A2),A2 ;act_pd des spanischen TOS 1.0
.noESTOS10:
move.l A0,(A2)
;END ----------------------- TOS 1.0 workaround
.no1:
;\from ultraDev


;@TODO: better stack handling
; move.l $44e.w,SP
; move.l SP,p_hitpa(A0) ;SSP
; lea -10000(SP),A3 ;USP
; move #$700,sr

rts

past_supervisor_code:
; move.l A3,SP


move.l d7,a0

;/from ultraDev
move.l A0,-(a7) ;put code page to stack
clr.l -(a7) ;clear something ;)
;\from ultraDev

;move.l pbasepage(PC),A0
move.l d7,A0
lea $100(A0),A0
move.l A0,A1
bsr kernel_relocate

lea 0.w,A0 ;apparently we need to set this to zero? why? TPA address _should_ work?
;move.l pbasepage(PC),A3
move.l d7,A3
jmp $100+$1c(A3)
;pbasepage: DC.L 0
;=================================================
; PRG-Header
kernel_prg_text_len: EQU 2
kernel_prg_data_len: EQU 2+4
kernel_prg_bss_len: EQU 2+4+4
kernel_prg_symbol_len: EQU 2+4+4+4
kernel_prg_flags: EQU 2+4+4+4+4+4
kernel_prg_relocflag: EQU 2+4+4+4+4+4+4
;=================================================
; PRG-Relocator
;=================================================
;A0=>Start PRG
;A1=>where's the PRG actually _started_?
;out: A1=>Start BSS
kernel_relocate:
tst.w kernel_prg_relocflag(A0)
bne.s .k_noreloc
lea $1c(A1),A3 ;address to relocate to
move.l A3,D2
lea $1c(A0),A3
move.l A3,A2
adda.l kernel_prg_text_len(A0),A2
adda.l kernel_prg_data_len(A0),A2
move.l kernel_prg_bss_len(A0),D3
move.l A2,A1
adda.l kernel_prg_symbol_len(A0),A2
move.l (A2)+,D0
beq.s .k_noreloc
moveq #0,D1
.k_relocloop: add.l D2,0(A3,D0.l)
.k_relocloop2: move.b (A2)+,D1
beq.s .k_noreloc
cmp.b #1,D1
beq.s .k_reloclong
add.l D1,D0
bra.s .k_relocloop
.k_reloclong: add.l #254,D0
bra.s .k_relocloop2
.k_noreloc:
rts
ELSE
w: bra.s w
ENDC

;from ultraDev
emptyEnvStr: dc.b "PATH=",0
dc.b "A:\",0,0
emptyCommandline: dc.b 0
even

;null_long: dc.l 0

;clearScreen:
; pea cls(PC)
; move.w #9,-(SP)
; trap #1
; addq.l #6,SP
; rts
;;A0: text
;;D0: X
;;D1: Y
;printText:
; lea gotox(PC),A1
; add.w #32,D0
; add.w #32,D1
; move.b D0,(A1)
; move.b D1,gotoy-gotox(A1)
;
; pea goto-gotox(A1) ;move cursor
; move.w #9,-(SP)
; trap #1
; addq.l #6,SP
;
; pea (A0) ;print text
; move.w #9,-(SP)
; trap #1
; addq.l #6,SP
; rts
;cls: DC.B 27,'E',0
;goto: DC.B 27,'Y'
;gotoy: DC.B 0
;gotox: DC.B 0
; DC.B 0
; EVEN

; include "hwinfo.s"
; EVEN
payload:
IFNE START_PAYLOAD
;incbin "ikaifill.tos"
ENDC
eop:
1 change: 1 addition & 0 deletions prg_loader_build.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
vasm -quiet -Fbin -o prg_loader.bin prg_loader.s
25 changes: 14 additions & 11 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ where:

- *-s* is optional and allows creation of STEem Engine compatible carts
- *-d* enables creation of diagnostic cartridges (only one program allowed, which will relocate to $fa0004)
- *-bX* allows setting the BSS address to an address other than the default ($20000)
- *-fY* allows setint the INIT flag. y can be
- *-c* to switch to the classic way of adding the application to the ROM
- *-bX* allows setting the BSS address to an address other than the default ($only when -c is active, default: $20000)
- *-fY* allows seting the INIT flag. y can be
- 0 Execute prior to display memory and interrupt vector initialization
- 1 Execute just before GEMDOS is initialized
- 3 Execute prior to boot disk
Expand All @@ -25,23 +26,24 @@ where:
- *image_filename* is the filename of the cart image
- *list of programs to add with optional -b and -f* is a list of ST PRG programs to add to the image, optionally postfixed by a *-b* and/or *-f* to set the parameters for the current file only

More on defaults: The default value for *-b* is $20000, and the default value for *-f* is nothing. Passing *-b* and/or *-f* at the start of the parameter list will override the default values. Passing *-b* and/or *-f* after each program in the list, will override the defaults for that file only.
More on defaults: The default value for *-b* is $20000, and the default value for *-f* is 0. Passing *-b* and/or *-f* at the start of the parameter list will override the default values. Passing *-b* and/or *-f* after each program in the list, will override the defaults for that file only.

How it works (briefly)
Two modes of operation
----------------------

Current (and only) mode of operation is that the program gets the PRG (or PRGs), relocates TEXT and DATA sections to ROM space and BSS to RAM at a hardcoded address, and hopes for the best.
Until the second release there was a single mode of operation (explained below).

This is not the best (or robust) idea in the world, but at least it made sense when the program was conceptualised. See below for ideas for further development.
The current default mode is to add a TOS PRG file with a small stub loader included which will copy the actual program from ROM to RAM, try to set up the system as well as it can, and then execute the program from RAM.

Caveats (boy, here we go)
-------------------------
The old mode adds the program to ROM and relocates it to run from there, with the BSS start address set in RAM by the user (or default value is used). This mode works for simple applications, but there will be many problems down the road for non properly written applications for this mode (i.e. pretty much all of them).

Caveats
-------

- Only use single file PRG programs. Programs that try to load external files will not work
- TODO: Some sanity checks are performed, but the program is far from bullet proof
- TODO: The BSS start address has to be supplied by user (or accept the default value of $20000). Unfotunately it doesn't seem possible to do this automatically. If anyone has an idea on how to do this, happy to discuss!
- On BSS: programs that access the BSS using PC relative code will most likely fail
- TODO: Date and Time are still set to bogus vaules
- TODO: Date and Time are still set to bogus values
- On BSS, for "old" mode: programs that access the BSS using PC relative code will most likely fail

Building
--------
Expand All @@ -59,3 +61,4 @@ Thank yous
----------

Diego Parrilla for supplying the Github actions to automatically build binaries for all platforms, and some other fixes in the code.
tIn/Newline for the original stub loader source code.
Loading

0 comments on commit 9b76e51

Please sign in to comment.