aboutsummaryrefslogtreecommitdiff
path: root/src/aexec.dasm
diff options
context:
space:
mode:
Diffstat (limited to 'src/aexec.dasm')
-rw-r--r--src/aexec.dasm206
1 files changed, 206 insertions, 0 deletions
diff --git a/src/aexec.dasm b/src/aexec.dasm
new file mode 100644
index 0000000..9338c4c
--- /dev/null
+++ b/src/aexec.dasm
@@ -0,0 +1,206 @@
+
+; Load an Atari DOS executable, including support for init and run vectors
+; Parameters: nul-terminated filename pointer in A/X (lo/hi)
+; Return value: 0 for success, nonzero on error, never returns if exe has
+; a run address.
+
+; TODO: learn ca65 syntax better, port this to ca65
+
+; Usage: build with "dasm aexec.dasm -f3 -oaexec.xex"
+; "Link" to your program with "cat aexec.xex yourprog.xex > newprog.xex"
+
+; int __fastcall__ (*atari_exec_p)(char *) = (int __fastcall__ (*)(char *))0x600;
+; #define atari_exec(x) ((*atari_exec_p)(x))
+; then call with: atari_exec("D:PROGRAM.XEX");
+
+; If the file can't be opened for whatever reason, atari_exec() returns a
+; nonzero result (the Atari error number).
+
+; If the file loads OK and has a run address, atari_exec() never returns
+; (runs the loaded program, then exits to DOS if/when the program exits).
+; This means there's no memory conflict between caller and callee.
+
+; If there was no run address, atari_exec returns 0 to the caller.
+; The caller is responsible for making sure the loaded program doesn't
+; step on the memory used by the caller or atari_exec itself!
+
+; If the file is openable but invalid (not a XEX, or truncated), current
+; atari_exec() implementation hangs the machine with a red screen, since
+; there's no way to know whether the partially-loaded program overwrote
+; the caller...
+
+
+ processor 6502
+ include "equates.inc"
+
+tmp = $d4 ; aka FR0
+loadaddr = $d6
+
+main = $0600
+
+ org main-6
+ word $FFFF
+ word main
+ word endmain-1
+
+ org main
+ pha
+ txa
+ pha
+ jsr fclose
+ pla
+ tax
+ pla
+
+ sta ICBAL+16
+ stx ICBAH+16
+ sta tmp
+ stx tmp+1
+ ldy #0
+
+; do an OPEN #1,4,0,$filename
+
+; get length of filename
+fnameloop:
+ lda (tmp),y
+ beq fndone
+ iny
+ bne fnameloop
+
+ ; set IOCB #1 buffer addr, buffer len, etc
+fndone:
+ sty ICBLL+$10
+ lda #0
+ sta ICBLH+$10
+ sta ICAX2+$10
+
+ ; init these to 0 so we can tell if they change
+ sta RUNAD
+ sta RUNAD+1
+ sta INITAD
+ sta INITAD+1
+
+ ldx #4
+ stx ICAX1+$10
+ dex
+ stx ICCOM+$10 ; cmd #3 = OPEN
+
+ ldx #$10
+ jsr CIOV ; do the OPEN
+ bpl readheader
+
+ tya ; CIO returns error code in Y reg
+ ldx #0
+ rts
+
+fail:
+ lda #$48
+ sta 710
+hang bne hang
+
+readheader:
+; read 2 bytes into local buffer
+ jsr read2bytes
+ bpl ok
+ cpy #136 ; EOF
+ bne fail
+ beq close_file ; if at EOF, close the file
+
+; if they're $ffff, try again
+ok:
+ lda tmp
+ tax
+ and tmp+1
+ cmp #$ff
+ beq readheader
+
+; store those 2 bytes in loadaddr
+ lda tmp+1
+ sta loadaddr+1
+ stx loadaddr
+
+; read 2 more bytes into local buffer (end addr)
+ jsr read2bytes
+ bmi fail
+; subtract loadaddr from end addr, add 1, to get length
+; store length into IOCB
+ lda loadaddr
+ sta ICBAL+$10
+ lda loadaddr+1
+ sta ICBAH+$10
+
+ sec
+ lda tmp
+ sbc loadaddr
+ sta ICBLL+$10
+ lda tmp+1
+ sbc loadaddr+1
+ sta ICBLH+$10
+ inc ICBLL+$10
+ bne noinc
+ inc ICBLH+$10
+noinc:
+ jsr read_segment
+ bmi fail
+
+; if INITAD modified, JSR there
+ lda INITAD
+ ora INITAD+1
+ beq readheader
+
+ jsr do_init
+
+ lda #0
+ sta INITAD
+ sta INITAD+1
+ beq readheader ; branch always
+
+do_init
+ jmp (INITAD)
+
+close_file:
+ jsr fclose
+
+; JSR through RUNAD if it's not zero
+ lda RUNAD
+ ora RUNAD+1
+ beq norun
+
+ jsr do_run
+ jmp (DOSVEC) ; does not return
+
+; If there was no run address, we were probably loading an R: driver, so
+; our caller is safe to return to
+norun
+ lda #0 ; return 0
+ tax
+ rts
+
+read2bytes:
+ lda #tmp
+ sta ICBAL+$10
+ lda #2
+ sta ICBLL+$10
+ lda #0
+ sta ICBAH+$10
+ sta ICBLH+$10
+read_segment:
+ lda #C_GETCHR
+ sta ICCOM+$10
+ ldx #$10
+ jmp CIOV
+
+do_run
+ jmp (RUNAD)
+
+fclose
+ lda #C_CLOSE
+ sta ICCOM+$10
+ ldx #$10
+ jmp CIOV
+
+endmain
+
+; word RUNAD
+; word RUNAD+1
+; word main