; 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		pexec5
	bsr		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	pexec5
	bsr.s	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

pexec5:
	move.l	10(a6),-(sp)
	move.l	6(a6),-(sp)
	clr.l	-(sp)
	move	#5,-(sp)
	move	#$4b,-(sp)	; Pexec
	trap	#1		; Gemdos
	lea		16(sp),sp
	tst.l	d0
	bmi.s	pexecerr
	rts
pexecerr:
	addq	#4,sp
	bra.s	gohome

reloc:
	movem.l	a3-a5/d6-d7,-(sp)
	move.l	d0,a5
	clr 	-(sp)
	move.l	2(a6),-(sp)
	move	#$3d,-(sp)	; Fopen
	trap	#1		; Gemdos
	addq	#8,sp

	move.l	d0,d6
	move.l	a5,-(sp)
	add.l	#228,(sp)
	pea 	$1c.w
	move	d6,-(sp)
	move	#$3f,-(sp)	; Fread
	trap	#1		; Gemdos
	lea 	12(sp),sp

	cmp.w	#$601a,228(a5)  ; Check program header magic
	beq.s	magic_ok
	move	d6,-(sp)
	move	#$3e,-(sp)	; Fclose
	trap	#1		; Gemdos
	addq	#4,sp
	move.l	a5,-(sp)
	move.w	#$49,-(sp)	; Mfree
	trap	#1		; Release "pexeced" memory
	addq.l	#6,sp
	move.l	#-66,d0         ; Error code: Invalid PRG format
	movem.l	(sp)+,a3-a5/d6-d7
	addq	#4,sp           ; Drop return address
	bra	gohome          ; Abort
magic_ok:
	; TODO: check size!!
	move.l	a5,-(sp)
	add.l	#256,(sp)
	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
	lea		8(a5),a4
	move.l	a5,d0
	add.l	#$100,d0
	move.l	d0,(a4)+		; text start
	move.l	230(a5),d0
	move.l	d0,(a4)+		; text length
	add.l	8(a5),d0		; data start
	move.l	d0,(a4)+
	move.l	234(a5),(a4)+	; data length
	add.l	234(a5),d0
	move.l	d0,(a4)+		; bss start
	move.l	238(a5),(a4)+	; bss length
	move.l	a5,d0
	add.l	#$80,d0
	move.l	d0,32(a5)
	move.l	24(a5),a4
	add.l	242(a5),a4		; symbol table length
	move.l	8(a5),a3
	move.l	a3,d0
	tst.w	254(a5)
	bne.s	relocdone

	; 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),d7
	clr.b	(a4)+
	lsl.w	#8,d7
	move.b	(a4),d7
	clr.b	(a4)+
	swap	d7
	move.b	(a4),d7
	clr.b	(a4)+
	lsl.w	#8,d7
	move.b	(a4),d7
	clr.b	(a4)+

	tst.l	d7
	beq.s	relocdone
	adda.l	d7,a3
	moveq	#0,d7
relloop0:
	add.l	d0,(a3)
relloop:
	move.b	(a4),d7
	move.b	#$00,(a4)+		; Some programs like GFA-Basic expect a clear memory
	tst.b	d7
	beq.s	relocdone
	cmp.b	#1,d7
	bne.s	no254
	lea 	254(a3),a3
	bra.s	relloop
no254:
	adda.w	d7,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-d7
	rts



; 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
