409 lines
9.2 KiB
ArmAsm
409 lines
9.2 KiB
ArmAsm
; Cartridge assembler code.
|
|
; 68000 code that is used for starting programs from the emulated GEMDOS harddisk
|
|
; and for using bigger VDI resolutions
|
|
|
|
; Hatari's "illegal" (free) opcodes:
|
|
GEMDOS_OPCODE equ 8
|
|
SYSINIT_OPCODE equ 10
|
|
VDI_OPCODE equ 12
|
|
|
|
; System variables:
|
|
_longframe equ $059E
|
|
|
|
|
|
org $fa0000
|
|
|
|
|
|
; This is the cartridge header:
|
|
dc.l $ABCDEF42 ; C-FLAG (magic value)
|
|
dc.l $00000000 ; C-NEXT
|
|
dc.l sys_init+$08000000 ; C-INIT - flag has bit 3 set = before disk boot, but after GEMDOS init
|
|
dc.l infoprgstart ; C-RUN
|
|
dc.w %0101100000000000 ; C-TIME
|
|
dc.w %0011001000101001 ; C-DATE
|
|
dc.l infoprgend-infoprgstart ; C-BSIZ, offset: $14
|
|
dc.b 'HATARI.TOS',0,0 ; C-NAME
|
|
|
|
.even
|
|
|
|
|
|
old_gemdos: ds.l 1 ; has to match the CART_OLDGEMDOS define!
|
|
vdi_opcode: dc.w VDI_OPCODE ; Address to call after Trap #2 (VDI), causes illegal instruction
|
|
|
|
; New GemDOS vector (0x84) - for intercepting Pexec
|
|
new_gemdos:
|
|
dc.w GEMDOS_OPCODE ; Returns NEG as run old vector, ZERO to return or OVERFLOW to run pexec
|
|
bvs.s pexec
|
|
bne.s go_oldgemdos
|
|
rte
|
|
|
|
; Branch to old GemDOS
|
|
go_oldgemdos:
|
|
move.l old_gemdos(pc),-(sp) ; Set PC to 'old_gemdos' and continue execution, WITHOUT corrupting registers!
|
|
rts
|
|
|
|
; Progam Execute
|
|
pexec:
|
|
move usp,a0 ; Parameters on user stack pointer?
|
|
btst #5,(sp) ; Check if program was in user or supervisor mode
|
|
beq.s p_ok
|
|
lea 6(sp),a0 ; Parameters are on SSP
|
|
tst.w _longframe.w ; Do we use a CPU > 68000?
|
|
beq.s p_ok ; No: A0 is OK
|
|
addq #2,a0 ; Skip 2 additional stack frame bytes on CPUs >= 68010
|
|
p_ok:
|
|
addq #2,a0 ; Skip GEMDOS function number
|
|
tst (a0) ; Test pexec mode
|
|
bne.s no_0
|
|
|
|
; Simulate pexec mode 0
|
|
move.l a6,-(sp)
|
|
move.l a0,a6
|
|
bsr.s find_prog
|
|
bsr load_n_reloc
|
|
clr.l 2(a6)
|
|
clr.l 10(a6)
|
|
move.l d0,6(a6)
|
|
|
|
move.w #48,-(sp) ; Sversion: get GEMDOS version
|
|
trap #1 ; call GEMDOS
|
|
addq #2,sp
|
|
ror.w #8,d0 ; Major version to high, minor version to low byte
|
|
cmp.w #$0015,d0
|
|
bge.s use_gemdos_015
|
|
move.w #4,(a6) ; pexec mode 4 for exec. prepared program
|
|
bra.s mode0_ok
|
|
use_gemdos_015:
|
|
move.w #6,(a6) ; On GEMDOS 0.15 and higher, we can use mode 6
|
|
mode0_ok:
|
|
|
|
move.l (sp)+,a6
|
|
bra.s go_oldgemdos
|
|
|
|
no_0:
|
|
cmp #3,(a0)
|
|
bne.s go_oldgemdos
|
|
|
|
; Simulate pexec mode 3
|
|
move.l a6,-(sp)
|
|
move.l a0,a6
|
|
bsr.s find_prog
|
|
bsr.s load_n_reloc
|
|
gohome:
|
|
move.l (sp)+,a6
|
|
rte
|
|
|
|
find_prog:
|
|
move #$2f,-(sp) ; Fgetdta
|
|
trap #1 ; Gemdos
|
|
addq #2,sp
|
|
move.l d0,a0
|
|
move.l (a0)+,-(sp)
|
|
move.l (a0)+,-(sp)
|
|
move.l (a0)+,-(sp)
|
|
move.l (a0)+,-(sp)
|
|
move.l (a0)+,-(sp)
|
|
move.l (a0)+,-(sp)
|
|
move.l (a0)+,-(sp)
|
|
move.l (a0)+,-(sp)
|
|
move.l (a0)+,-(sp)
|
|
move.l (a0)+,-(sp)
|
|
move.l (a0)+,-(sp)
|
|
move.l a0,-(sp)
|
|
move #$17,-(sp)
|
|
move.l 2(a6),-(sp)
|
|
move #$4e,-(sp) ; Fsfirst
|
|
trap #1 ; Gemdos
|
|
addq #8,sp
|
|
move.l (sp)+,a0
|
|
move.l (sp)+,-(a0)
|
|
move.l (sp)+,-(a0)
|
|
move.l (sp)+,-(a0)
|
|
move.l (sp)+,-(a0)
|
|
move.l (sp)+,-(a0)
|
|
move.l (sp)+,-(a0)
|
|
move.l (sp)+,-(a0)
|
|
move.l (sp)+,-(a0)
|
|
move.l (sp)+,-(a0)
|
|
move.l (sp)+,-(a0)
|
|
move.l (sp)+,-(a0)
|
|
tst.l d0
|
|
beq.s findprog_ok
|
|
addq #4,sp
|
|
bra.s gohome
|
|
findprog_ok:
|
|
rts
|
|
|
|
|
|
load_n_reloc:
|
|
movem.l a3-a5/d6,-(sp)
|
|
|
|
clr.w -(sp)
|
|
move.l 2(a6),-(sp)
|
|
move.w #$3d,-(sp) ; Fopen
|
|
trap #1 ; Gemdos
|
|
addq #8,sp
|
|
move.l d0,d6 ; Keep file handle in d6
|
|
tst.l d0
|
|
bmi lr_err_out
|
|
|
|
clr.w -(sp) ; Temporary space for prg header magic
|
|
move.l sp,-(sp)
|
|
move.l #2,-(sp)
|
|
move d6,-(sp)
|
|
move #$3f,-(sp) ; Fread
|
|
trap #1 ; Gemdos: Read header magic
|
|
lea 12(sp),sp
|
|
move.w (sp)+,d1
|
|
cmp.l #2,d0
|
|
bne load_reloc_error
|
|
|
|
cmp.w #$601a,d1 ; Check program header magic
|
|
beq.s hdr_magic_ok
|
|
move.l #-66,d0 ; Error code: Invalid PRG format
|
|
bra load_reloc_error
|
|
hdr_magic_ok:
|
|
clr.w -(sp)
|
|
move.w d6,-(sp)
|
|
move.l #22,-(sp) ; offset of the program flags
|
|
move.w #66,-(sp) ; Fseek
|
|
trap #1 ; Gemdos: Seek to program flags
|
|
lea 10(sp),sp
|
|
cmp.l #22,d0
|
|
bne load_reloc_error
|
|
|
|
clr.l -(sp) ; Temporary space for program flags
|
|
move.l sp,-(sp)
|
|
move.l #4,-(sp)
|
|
move d6,-(sp)
|
|
move #$3f,-(sp) ; Fread
|
|
trap #1 ; Gemdos: Read program flags
|
|
lea 12(sp),sp
|
|
move.l (sp)+,a3 ; Program flags now in a3
|
|
cmp.l #4,d0
|
|
bne load_reloc_error
|
|
|
|
; Let's call Pexec now to create the basepage, first try
|
|
; Pexec(7) and if that does not work fall back to mode 5
|
|
move.l 10(a6),-(sp)
|
|
move.l 6(a6),-(sp)
|
|
move.l a3,-(sp) ; program flags in program header
|
|
move.w #7,-(sp) ; Create basepage wrt program flags
|
|
move.w #$4b,-(sp) ; Pexec (mode 7)
|
|
trap #1 ; Gemdos
|
|
lea 16(sp),sp
|
|
tst.l d0
|
|
bpl.s pexec_ok
|
|
|
|
move.l 10(a6),-(sp)
|
|
move.l 6(a6),-(sp)
|
|
clr.l -(sp)
|
|
move.w #5,-(sp) ; Create basepage
|
|
move.w #$4b,-(sp) ; Pexec (mode 5)
|
|
trap #1 ; Gemdos
|
|
lea 16(sp),sp
|
|
tst.l d0
|
|
bmi load_reloc_error
|
|
|
|
pexec_ok:
|
|
move.l d0,a5 ; Basepage in a5
|
|
|
|
clr.w -(sp)
|
|
move.w d6,-(sp)
|
|
clr.l -(sp) ; Back to the start of the file
|
|
move.w #66,-(sp) ; Fseek
|
|
trap #1 ; Gemdos: Seek to start of the file
|
|
lea 10(sp),sp
|
|
tst.l d0
|
|
bne lr_err_free
|
|
|
|
lea 256(a5),a3 ; a3 points now to the program header
|
|
move.l a3,-(sp)
|
|
move.l #$1c,-(sp)
|
|
move d6,-(sp)
|
|
move #$3f,-(sp) ; Fread
|
|
trap #1 ; Gemdos: Read full program header
|
|
lea 12(sp),sp
|
|
cmp.l #$1c,d0
|
|
bne lr_err_free
|
|
|
|
lea 8(a5),a4
|
|
move.l a5,d0
|
|
add.l #$100,d0
|
|
move.l d0,(a4)+ ; text start
|
|
move.l 2(a3),d0
|
|
move.l d0,(a4)+ ; text length
|
|
add.l 8(a5),d0
|
|
move.l d0,(a4)+ ; data start
|
|
move.l 6(a3),(a4)+ ; data length
|
|
add.l 6(a3),d0
|
|
move.l d0,(a4)+ ; bss start
|
|
move.l 10(a3),(a4)+ ; bss length
|
|
|
|
add.l 10(a3),d0
|
|
cmp.l 4(a5),d0 ; is the TPA big enough?
|
|
bhi tpa_not_ok
|
|
|
|
move.l a5,d0
|
|
add.l #$80,d0
|
|
move.l d0,32(a5) ; default DTA always points to cmd line space!
|
|
|
|
move.l 24(a5),a4
|
|
add.l 14(a3),a4 ; add symtab length => a4 points to reloc table
|
|
move.w 26(a3),a3 ; a3 is now the absflag (0 means reloc)
|
|
|
|
pea 256(a5)
|
|
pea $7fffffff
|
|
move d6,-(sp)
|
|
move #$3f,-(sp) ; Fread
|
|
trap #1 ; Gemdos
|
|
lea 12(sp),sp
|
|
|
|
move d6,-(sp)
|
|
move #$3e,-(sp) ; Fclose
|
|
trap #1 ; Gemdos
|
|
addq #4,sp
|
|
|
|
move.w a3,d1
|
|
tst.w d1 ; check absflag
|
|
bne.s relocdone
|
|
|
|
move.l 8(a5),a3
|
|
move.l a3,d0
|
|
|
|
; Get first offset of the relocation table. Since A4 seems sometimes not
|
|
; to be word aligned (if symbol table length is uneven), we have to read
|
|
; byte by byte...
|
|
move.b (a4),d1
|
|
clr.b (a4)+
|
|
lsl.w #8,d1
|
|
move.b (a4),d1
|
|
clr.b (a4)+
|
|
swap d1
|
|
move.b (a4),d1
|
|
clr.b (a4)+
|
|
lsl.w #8,d1
|
|
move.b (a4),d1
|
|
clr.b (a4)+
|
|
|
|
tst.l d1
|
|
beq.s relocdone
|
|
adda.l d1,a3
|
|
moveq #0,d1
|
|
relloop0:
|
|
add.l d0,(a3)
|
|
relloop:
|
|
move.b (a4),d1
|
|
clr.b (a4)+ ; Some programs like GFA-Basic expect a clear memory
|
|
tst.b d1
|
|
beq.s relocdone
|
|
cmp.b #1,d1
|
|
bne.s no254
|
|
lea 254(a3),a3
|
|
bra.s relloop
|
|
no254:
|
|
adda.w d1,a3
|
|
bra.s relloop0
|
|
|
|
relocdone:
|
|
move.l 28(a5),d0
|
|
beq.s cleardone
|
|
move.l 24(a5),a0
|
|
clear:
|
|
clr.b (a0)+
|
|
subq.l #1,d0
|
|
bne.s clear
|
|
cleardone:
|
|
move.l a5,d0
|
|
movem.l (sp)+,a3-a5/d6
|
|
rts
|
|
|
|
tpa_not_ok:
|
|
move.l #-39,d0 ; Error code: Not enough memory
|
|
lr_err_free:
|
|
move.l d0,-(sp)
|
|
move.l a5,-(sp)
|
|
move.w #$49,-(sp) ; Mfree
|
|
trap #1 ; Release "pexeced" memory
|
|
addq.l #6,sp
|
|
move.l (sp)+,d0
|
|
load_reloc_error:
|
|
move.w d6,-(sp)
|
|
move.l d0,d6 ; Save error code
|
|
move.w #$3e,-(sp) ; Fclose
|
|
trap #1 ; Gemdos
|
|
addq #4,sp
|
|
move.l d6,d0 ; Restore error code
|
|
lr_err_out:
|
|
movem.l (sp)+,a3-a5/d6
|
|
addq #4,sp ; Drop return address
|
|
bra gohome ; Abort
|
|
|
|
|
|
|
|
; This code is called during TOS' boot sequence.
|
|
; It gets a pointer to the Line-A variables and uses an illegal opcode
|
|
; to run our system initialization code in OpCode_SysInit().
|
|
sys_init:
|
|
dc.w $A000 ; Line-A init (needed for VDI resolutions)
|
|
dc.w SYSINIT_OPCODE ; Illegal opcode to call OpCode_SysInit()
|
|
rts
|
|
|
|
|
|
|
|
; This code is run when the user starts the HATARI.PRG
|
|
; in the cartridge. It simply displays some information text.
|
|
infoprgstart:
|
|
pea hatarix32(pc)
|
|
move.w #32,-(sp)
|
|
trap #14 ; Dosound - play some music :-)
|
|
addq.l #6,sp
|
|
|
|
pea infotext(pc)
|
|
move.w #9,-(sp)
|
|
trap #1 ; Cconws - display the information text
|
|
addq.l #6,sp
|
|
|
|
move.w #7,-(sp)
|
|
trap #1 ; Crawcin - wait for a key
|
|
addq.l #2,sp
|
|
|
|
clr.w -(sp)
|
|
trap #1 ; Pterm0
|
|
|
|
|
|
infotext:
|
|
dc.b 27,'E',13,10
|
|
dc.b ' =========================',13,10
|
|
dc.b ' Hatari keyboard shortcuts',13,10
|
|
dc.b ' =========================',13,10
|
|
dc.b 13,10
|
|
dc.b ' F11 : toggle fullscreen/windowed mode',13,10
|
|
dc.b ' F12 : activate the setup GUI of Hatari',13,10
|
|
dc.b 13,10
|
|
dc.b 'All other shortcuts are activated by',13,10
|
|
dc.b 'pressing AltGr or Right-Alt or Meta key',13,10
|
|
dc.b 'together with one of the following keys:',13,10
|
|
dc.b 13,10
|
|
dc.b ' a : Record animation',13,10
|
|
dc.b ' g : Grab a screenshot',13,10
|
|
dc.b ' i : Leave full screen & iconify window',13,10
|
|
dc.b ' j : joystick via key joystick on/off',13,10
|
|
dc.b ' m : mouse grab',13,10
|
|
dc.b ' r : warm reset of the ST',13,10
|
|
dc.b ' c : cold reset of the ST',13,10
|
|
dc.b ' s : enable/disable sound',13,10
|
|
dc.b ' q : quit the emulator',13,10
|
|
dc.b ' x : toggle normal/max speed',13,10
|
|
dc.b ' y : enable/disable sound recording',13,10
|
|
dc.b 0
|
|
|
|
|
|
hatarix32:
|
|
ibytes 'cart_mus.x32'
|
|
|
|
|
|
infoprgend:
|
|
|
|
END
|