; 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
