;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Universal Loading System: v3.12(j)
;; ----------------------------------
;;
;; Started:    04/10/08
;; This build: 17/03/09  
;;
;; (c) 2005-2009 D-Bug
;;
;; Concept and core code by Cyrano Jones / D-Bug 
;; MFP and PMMU code by Defjam / Checkpoint
;; Additional code by GGN / D-Bug
;; 
;; I would also like to thank Klapauzius for the field testing and additional input
;;
;; The RAMdisk is Dead! Long live ULS!
;; 
;; Universal Loading System v3 (c) 2005-2008 D-Bug. All Rights Reserved.
;; This software is released as Open Source and may be used, viewed or modified
;; by anyone.
;;
;; D-Bug accept no responsibility for any loss of data or damage to your equipment from using
;; this code or any of our patches (Although, of course, we don't expect there ever to be any!)
;;
;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Defines (Sorry, it still needs some)
;;


; Moved to stubloader source for easier access while debugging
;
;max_filesize		equ 142*1024		; Size of biggest file to be read/written via ULS
;adv_debug					; Define for debugging screen


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; ULS jmp offsets
;;

uls_setup	equ $0			; Call to initialize the ULS system
					;
					; ULS Parameters:
					;
					; A0.L: RAMTop for ULS
					; D0.W: CPU Clock Control (-1: 8mhz / 1: 16mhz)
					; D1.W: CPU Cache Control (-1: Off / 1: on)
					;
					; RAMDisk Parameters:
					;
					; D6.L: 4 char ASCII of initial folder to make ramdisk from
					; D7.L: Ramdisk Creation Flag (D7.L="RAMD" for create)
					; A6.L: Size of RAMDISK in bytes (Size of Data+(20*No of files))+8
					; A5.L: Pointer to a filespec to use to build the ramdisk
					;
					; Returns:
					;
					; A0=JMP Table address
					; A1=Filebuffer address
					; A2=Highest address saved
					; A3=Low memory address during ULS
					; D0.L=Machine type
					; D1.L=!HD! flag
					; D2.W=VGA (1) / RGB (2)
		
uls_file_io	equ $4			; Call for file_io
					;
					; A0.L: address of filename  
					; A1.L: address to transfer to/from
					; D0.L: bytes to IO ($ffffffff = all - if write, as much as was in overwritten file)
					; D1.L: seek offset ($00000000 = start of file) NB: Can't seek and overwrite in WRITE MODE
					; D7.L: READ MODE:  Load to ULS_buffer flag (0=normal, -1=Load to ULS_buffer)
					;       WRITE MODE: -1 = f_create, otherwise file already exists.
					;
					; Returns:
					;
					; D0.L: UNPACKED length of file from Pack Header (If known packer)
					; D1.L: Actual length bytes written/read
					; D0.L: -1 if File Not Found

uls_terminate	equ $c			; Call to put system back to init
					;
					; D0.L: set to #'RTS!' to not exit to system (P_TERM/TRAP #1)
					; A0.L: Address to JMP to if D0=#'RTS!'
					;

uls_setread	equ $10			; Call to put ULS in read mode
uls_setwrite	equ $14			; Call to put ULS in write mode
uls_dumpscreen	equ $18			; Call to grab screenshot as PI1
uls_execute	equ $1c			; call to execute user code under TOS

uls_statesave	equ $20			; Call to snapshot system to disk for later resume	
					;
					; D0.L: Ramtop for dump file
					; D1.L: return JMP address for resume
					; ULS_Filebuffer must be loaded with a register dump (See function for details)

uls_stateload	equ $24			; Call to resume system from a previously created statesave

uls_setpath	equ $28			; Call to change the DATA name
					;
					; D0.L: 4 byte ascii for new folder name.

uls_req_rd_addr	equ $2c			; Call to get the address of a file in the RAMdisk
					;
					; A0.L: address of filename
					;
					; Returns:
					;
					; A0.L: address of file header in RAMdisk
					;       File is at 20(a0)


uls_F30set200	equ $30			; Call to set the VIDEL to 320x200x16 (RGB/VGA detected from INIT)

uls_F30set240	equ $34			; Call to set the VIDEL to 320x240x16 (RGB/VGA detected from INIT)

uls_F30set200TC	equ $38			; Call to set the VIDEL to 320x200xTC (RGB/VGA detected from INIT)

uls_update_rdsk	equ $3c			; Call to update the RAMdisk
					;
					; D0.L: 4 char ASCII of initial folder to make ramdisk from
					; D1.W: -1 = replace ramdisk
					;       +1 = append to ramdisk
					; A0.L: pointer to filespec for ramdisk (eg *.*)
					;
					;
					; NOTE: The new ramdisk *MUST* fit inside the paramters passed to "uls_setup"
					;

uls_search	equ $40			; Call to search / replace a byte sequence between 2 memory ranges
					;
					; A0.L: address to start searching
					; A1.L: address to end searching
					; A2.L: pointer to bytes to match
					; A3.L: pointer to bytes to overwrite
					; D0.L: length of search string
					; D1.L: length of replace string


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Universal Loading System
;;
;; (c) 2005-2008 D-Bug
;;
;; 

uls	bra uls_init			; +$00 	
	bra uls_core			; +$04
	bra uls_post_relocate_init	; +$08
	bra uls_restore_launch_env	; +$0c
	bra uls_read_mode		; +$10
	bra uls_write_mode		; +$14
	bra uls_screenshot		; +$18
	bra uls_usercode_exec		; +$1c
	bra uls_suspend_disk		; +$20
	bra uls_resume_disk		; +$24
	bra uls_change_data_folder	; +$28
	bra uls_get_ramdisk_address	; +$2c
	bra uls_F30set320x200		; +$30
	bra uls_F30set320x240		; +$34
	bra uls_F30set320x200TC		; +$38
	bra uls_update_rd		; +$3c
	bra uls_search_replace		; +$40

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Variables
;;
;;

;;
;; Variables *NOT* saved to statefile (There should be a lot more of these and I will tidy this up in the future!)
;;

TOS_rambase		ds.l 1			; base address of loader stored here (End of GEMDOS copy)
ULS_SYS_mem		ds.l 1			; Game env. memory dump starts here
SYS_stack		ds.l 1			; system stack
ramdisk_enable		ds.l 1			; Ramdisk flag
ramdisk_base		ds.l 1			; address of RAMdisk base
ramdisk_spec		ds.l 1			; pointer to filespec for ramdisk pre-loader
SYS_sr			ds.w 1			; SR on entry
TOS_pal			ds.w 16			; pallette from application
TOS_res			ds.w 1			; resolution on entry
ikbd_SYS		ds.l 1			; the original IKBD vector
request_16mhz		ds.w 1			; flag used by init to see if you want 16mhz
ULS_scr			ds.l 1			; debug/pi1 workspace
ULS_TOS_mem		ds.l 1			; GEMDOS env. memory dump starts here
ULS_filebuffer		ds.l 1			; workspace for load/save data
TOS_ramtop		ds.l 1			; Physical system RAMtop
SYS_PSG			ds.w 1			; psg on init (ffff8800 Port a/b)
GEM_fa0d		ds.b 1			; additional MFP data
GEM_fa11		ds.b 1
			ds.b 8
GEMta_control     	ds.b 1			; GEMDOS MFP state
GEMtb_control     	ds.b 1
GEMtcd_control    	ds.b 1
GEMta_data        	ds.b 1
GEMtb_data        	ds.b 1
GEMtc_data        	ds.b 1
GEMtd_data        	ds.b 1
	               	even
GEMmfp_save       	ds.b 64
SYS_484			ds.w 1			; keyclick
ULS_on_hd		ds.l 1			; Set to '!HD!' during ULS_init if not A/B
ULS_drive		ds.w 1			; Number of launch drive
machine			ds.w 1			; 0=st 1=ste 2=mste 3=falcon 4=tt
old_mhz			ds.w 1			; speed on entry to ULS core
SYS_VBR			ds.l 2			* location of original VBR
SYS_cacr		ds.l 1			* state of cache control register before init
SYS_PMMU		ds.l 3			* state of tc/tt0/tt1 MMU registers
sys_FCPUC		ds.w 1			; Falcon CPU Control
falc_scr		ds.w 1			; Falcon Screen Mode
TOS_screen		ds.l 1			; desktop screen base
initial_rd_folder	ds.l 1			; Initial 4-char ASCII folder name passed to init

;;
;; Variables saved to statefile
;;

top_of_variable_table



read_write_flag		ds.w 1			; +vs read / -ve write
SYS_screen		ds.l 1			; game env. screen address
copy_data		ds.w 1			; flag for read to buffer only/read to load address (useful if skewing tracks)
			ds.w 1			; degas header
SYS_pal			ds.w 16			; pallette on entry

APP_PSG			ds.w 1			; psg for application
APP_sr			ds.w 1			; sr for application
SYS_res			ds.w 1			; system resolution
fnf_flag		ds.l 1			; file not found flag
user_code_addr		ds.l 1			; address of user routine

sys_filename		ds.l 1			; address of filename in RAW or F_OPEN format
ULS_fn_header		dc.b "DATA\"
ULS_filename		ds.b 14			; filename re-built here 
			even
ULS_load_addr		ds.l 1			; org load address
ULS_bytes_loaded	ds.l 1			; returned byte count (From pack header)
ULS_bytes_loaded2	ds.l 1			; returned byte count (Actual size)
ULS_bytes_io		ds.l 1			; bytes to read/write(!)
ULS_seek_offset		ds.l 1			; offset to seek
ULS_ret_add		ds.l 1			; where ULS was called from
ULS_registers		ds.l 64			; system register storage
write_tick		ds.w 1			; used for "write cooldown" after file save
ikbd_key		ds.w 1			; used by dummy IKBD
APP_fa17		ds.w 1
APPta_control     	ds.b 1			; Game env. MFP state
APPtb_control 	    	ds.b 1
APPtcd_control 	   	ds.b 1
APPta_data     	   	ds.b 1
APPtb_data        	ds.b 1
APPtc_data        	ds.b 1
APPtd_data        	ds.b 1
                	even
APPmfp_save       	ds.b 64
scr_fn			dc.b "ULS_0000.PI1",0	; screendump filename
			even
scr_count		ds.w 1			; screendump counter
uls_cpus		ds.w 1
my_vecs			ds.l 11			; Used during falcon IDE delay
falc_frame		ds.w 1			; Used during falcon IDE delay
ULS_handle		ds.w 1			; ULS file handle
current_a7		ds.l 1
composite		ds.w 1			; 1=VGA 2=RGB

bot_of_variable_table	

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Put ULS in read mode
;;

uls_read_mode

	move.l a5,-(a7)
	lea read_write_flag(pc),a5
	move.w #1,(a5)	
	move.l (a7)+,a5
	rts

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Put ULS in write mode
;;

uls_write_mode

	move.l a5,-(a7)
	lea read_write_flag(pc),a5
	move.w #-1,(a5)
	move.l (a7)+,a5	
	rts

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Change the name of the data folder
;;

uls_change_data_folder
	move.l a5,-(a7)
	lea ULS_fn_header(pc),a5
	move.l d0,(a5)
	move.l (a7)+,a5
	rts


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Restore the system
;;


uls_restore_launch_env
	lea uls(pc),a7

	lea term_mode(pc),a6
	move.l d0,(a6)+
	move.l a0,(a6)

	move.w #$2700,SR
	clr.b   $FFFFFA19.w		; timers stop
        clr.b   $FFFFFA1B.w
        clr.b   $FFFFFA1D.w

	lea $8.w,a1			; destination
	lea ULS_TOS_mem(pc),a0
	move.l (a0),a0			; source
	lea TOS_rambase(pc),a2		; last byte
	move.l (a2),d7
	bsr block_move			; restore GEMDOS memory

	lea machine(pc),a6		; Falcon / TT test
	cmp.w #3,(a6)
	beq.s .re_pmmu
	cmp.w #4,(a6)			* restore stuff on the TT too
	beq.s .re_pmmu
	bra.s .no_pmmu
.re_pmmu
	lea machine(pc),a5
	cmp.w #3,(a5)			; Falc Test
	bne.s .ftt			* restore CPU mode only on falcon

	lea 	sys_FCPUC(pc),a0	; restore CPU mode
	move.b (a0),d0
	or.b #%00100101,d0
	move.b 	d0,$ffff8007.w
.ftt
	dc.l	$f0002400		* pflusha - flush caches
	lea	SYS_cacr(pc),a0		* restore cache
	move.l	(a0),d0
	dc.l	$4e7b0002		* movec d0,cacr

	lea	SYS_VBR(pc),a0
	dc.l	$f0104c00		* pmove (a0),VBR *restore VBR*

	lea	SYS_PMMU(pc),a0		* restore tc/tt0/tt1
	dc.w	$f028,$4000,$0000	* pmove (a0),tc
	dc.w	$f028,$0800,$0004	* pmove 4(a0),tt0
	dc.w	$f028,$0c00,$0008	* pmove 8(a0),tt1

.no_pmmu
	bsr flush_acia
	
	lea $ffff8800.w,a0		; kill sound
	move.l #$08080000,(a0)
	move.l #$09090000,(a0)
	move.l #$0a0a0000,(a0)

	lea GEMta_data(PC),A3		; restore GEMDOS timers
	lea GEMta_control(PC),A4
	bsr restore_timers
	lea GEMmfp_save(pc),a1
	bsr restore_mfp

	lea GEM_fa0d(pc),a0
	move.b (a0)+,$fffffa0d.w	; fix up MFP a bit
	move.b (a0)+,$fffffa11.w

	lea SYS_sr(pc),a0		; restore SR
	move.w (a0),sr

	lea ikbd_SYS(pc),a0
	move.l (a0),$118.w		; restore system keyboard vector

	move.b #$80,d0			; reset ikbd
	bsr .sikbd
	move.b #$1,d0
	bsr .sikbd

	lea SYS_484(pc),a0		; restore keyclick
	move.b (a0),$484.w

	lea SYS_PSG(pc),a0		; restore psg
	bsr load_PSG

	lea TOS_screen(pc),a5		; restore screen
	move.b 1(a5),$ffff8201.w
	move.b 2(a5),$ffff8203.w
	move.b 3(a5),$ffff820d.w

	lea TOS_pal(pc),a5		; restore pallette
	movem.l (a5),d0-7
	movem.l d0-7,$ffff8240.w

	lea SYS_stack(pc),a0		; restore stack
	move.l (a0),a7

	moveq #0,d0
	lea machine(pc),a5
	cmp.w #3,(a5)
	bne.s .ok1
	move.w #3,d0
	move.l #14,d7
	move.w falc_scr(pc),-(a7)
	bra.s .ok2
.ok1	lea TOS_res(pc),a5		; restore resolution
	move.b (a5),d0
	move.l #12,d7
.ok2	move.w d0,-(a7)
	lea TOS_screen(pc),a5
	move.l (a5),-(a7)
	move.l (a5),-(a7)
	move.w #5,-(a7)
	trap #14
	add.l d7,a7

	lea term_mode(pc),a0
	cmp.l #'RTS!',(a0)+
	bne.s .pterm
	move.l (a0)+,a0
	jmp (a0)

.pterm	clr.l -(a7)			; sayonara!
	trap #1

.sikbd	btst #1,$fffffc00.w
	beq.s .sikbd
	move.l #$600,d1
.hang1	subq.l #1,d1
	bne.s .hang1
	move.b d0,$fffffc02.w
	rts


term_mode	dc.l 0
term_add	dc.l 0

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Write "cooldown" (Allow drives to flush cache after a write operation)
;;


write_cooldown
	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; print function status
	lea t_wrcd(pc),a1
	bsr info			
	movem.l (a7)+,d0-7/a0-6
	endc

	movem.l d0-7/a0-6,-(a7)
	lea write_vbl_old(pc),a0	; store system VBL
	move.l $70.w,(a0)
	lea write_vbl(pc),a0		; set up my own
	move.l a0,$70.w

	lea write_tick(pc),a0		; tick counter
	
	move.w #49,d7			; 50 frames=1 second
.onesec	bsr write_hold_vbl	
	dbra d7,.onesec

	lea write_vbl_old(pc),a0
	move.l (a0),$70.w		; system vbl back

	move.w sr,-(a7)
	move.w #$2700,sr		; kill all interupts
	lea $808.w,a0			; refresh gemdos shadow memory (But not the base/vectors)
	lea ULS_TOS_mem(pc),a1
	move.l (a1),a1			; destination
	lea $800(a1),a1
	lea TOS_rambase(pc),a2		; last byte
	move.l (a2),d7
	sub.l #$800,d7
	bsr block_move
	move.w (a7)+,sr

	movem.l (a7)+,d0-7/a0-6
	rts

write_hold_vbl
	clr.w (a0)			; wait 1 vbl
	move.w (a0),d0
.hold	cmp.w (a0),d0
	beq.s .hold
	rts

write_vbl
	move.l a0,-(a7)
	lea write_tick(pc),a0
	add.w #1,(a0)
	move.l (a7)+,a0
	dc.w $4ef9
write_vbl_old	dc.l 0

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; C_CONWS Debug Output (Used during init)
;;

i_prnt	movem.l d0-a6,-(a7)		; if you need this routine explained, then this source
	move.l a4,-(a7)			; file is NOT for you :-)
	move.w #9,-(a7)
	trap #1
	lea 6(a7),a7
	move.l #$ffff,d0
.wank	nop
	subq.l #1,d0
	bne.s .wank
	movem.l (a7)+,d0-a6
	rts


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Call with:
;;
;; A0.L:RAMTOP
;; D0.L:16mhz Request        (-ve = 8mhz)
;; D1.L:Cache Request (030)  (-ve = off!)
;;
;; D6.L: 4 char ASCII of initial folder to make ramdisk from
;; D7.L: Ramdisk Creation Flag (D7.L="RAMD" for create)
;; A6.L: Size of RAMDISK in bytes (Size of Data+(17*No of files))
;; A5.L: Pointer to a filespec to use to build the ramdisk
;;
;; Returns:
;;
;; A0=JMP Table address
;; A1=Filebuffer address
;; A2=Highest address saved
;; A3=Low memory address during ULS
;;
;; D0.L=Machine type
;; D1.L=!HD! flag
;; D2.W=VGA (1) / RGB (2)

uls_init
	ifd adv_debug
	lea i_init(pc),a4
	bsr i_prnt
	endc

	bsr detect_hardware

	ifd adv_debug
	lea i_cvars(pc),a4
	bsr i_prnt
	endc
	lea SYS_stack(pc),a1
	move.l a7,(a1)

	sub.l #(ULS_TRASH_RAM-uls),a0
	move.l a0,-(a7)			; relocate ULS to desired address

	lea ramdisk_enable(pc),a1
	move.l d7,(a1)

	lea ramdisk_spec(pc),a1
	move.l a5,(a1)

	lea ramdisk_base(pc),a1
	move.l a6,(a1)

	lea initial_rd_folder(pc),a1
	move.l d6,(a1)			; set ramdisk-builder to correct default folder

	lea ULS_fn_header(pc),a1	
	move.l d6,(a1)			; point ULS at default directory

	lea SYS_sr(pc),a1		; save SR
	move.w sr,(a1)

	movem.l d0-7,-(a7)
	lea TOS_pal(pc),a1		; save pallette
	movem.l $ffff8240.w,d0-7
	movem.l d0-7,(a1)
	movem.l (a7)+,d0-7

	lea TOS_res(pc),a1		; save resolution
	move.b $ffff8260.w,(a1)

	ifd adv_debug
	lea i_reloc(pc),a4
	bsr i_prnt
	endc

	lea uls(pc),a1			; top of ULS code
	lea ULS_TRASH_RAM(pc),a2	; end of ULS code
.movuls	move.b (a1)+,(a0)+
	cmp.l a1,a2
	bne.s .movuls
	move.l (a7)+,a0
	lea 8(a0),a0

	jmp (a0)			; init ULS!

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Init debug text
;;

	ifd adv_debug
i_init	dc.b 27,"EULS init called....",13,10
	dc.b 13,10
	dc.b "Detecting Hardware...",13,10,0
i_cac_o	dc.b "68030 caches disabled...",13,10,0
i_cvars	dc.b "Storing ULS base variables...",13,10,0
i_cbuff	dc.b "Calculating buffers...",13,10,0
i_reloc	dc.b "Relocating ULS to High Memory...",13,10,0
i_snap	dc.b "Creating Low Memory snapshot...",13,10,0
i_hw	dc.b "Configuring hardware...",13,10,0
i_rd	dc.b "Building RAMdisk...",13,10,0
i_lfcr	dc.b 13,10,0
i_exit	dc.b "Exit ULS_init",13,10,0
	even

	endc

uls_post_relocate_init
	sub.l #8,a0			; start of ULS below RAMTOP
	move.l a0,-(a7)

	lea ikbd_SYS(pc),a1		; save system ikbd vector and install my own dummy one
	move.l $118.w,(a1)
	lea uls_ikbd(pc),a1
	move.l a1,$118.w

	lea request_16mhz(pc),a6	; store cpu speed requested
	move.w d0,(a6)

	tst.w d1	
	bmi.s .cac_off
	lea nop_me_out(pc),a6
	move.l #$4e714e71,(a6)		; if cache=on, disable the cache off command
.cac_off
	ifd adv_debug
	lea i_cbuff(pc),a4
	bsr i_prnt
	endc

	move.l a0,d1			; RAMTop
	sub.l #32512,d1
	clr.b d1
	lea ULS_scr(pc),a5
	move.l d1,(a5)			; ULS debug/pi1 buffer
	
	lea ramdisk_enable(pc),a5
	cmp.l #'RAMD',(a5)
	bne .no_rd

	lea ramdisk_base(pc),a5
	move.l (a5),d0			; get ramdisk size
	add.l #512,d0
	sub.l d0,d1
	bclr #0,d1
	move.l d1,(a5)			; base of ramdisk

.no_rd	sub.l #uls,d1
	sub.l #128,d1			
	bclr #0,d1
	lea ULS_TOS_mem(pc),a5
	move.l d1,(a5)			; TOS saved here

	move.l #uls,d0
	lea TOS_rambase(pc),a5
	move.l d0,(a5)			; GEMDOS highest byte

	sub.l d0,d1
	sub.l #128,d1
	lea ULS_SYS_mem(pc),a5
	move.l d1,(a5)			; Application saved here

	sub.l #1024,d1			; overflow clearance

	sub.l #max_filesize,d1
	sub.l #128,d1
	bclr #0,d1
	lea ULS_filebuffer(pc),a5	
	move.l d1,(a5)			; filebuffer here

	move.l $42e.w,d0
	lea TOS_ramtop(pc),a5
	move.l d0,(a5)			; store Physical RAMtop

	lea ULS_TRASH_RAM(pc),a5
	move.l a5,d0
	cmp.l d1,d0			; ran out of memory?
	bge.s .all_ok

.memerr	neg.w $ffff8240.w
	bra.s .memerr
.all_ok
	lea ULS_on_hd(pc),a0
	clr.l (a0)
	move.w #$19,-(a7)
	trap #1				; get drive
	add.l #2,a7
	lea ULS_on_hd(pc),a0
	tst.w d0
	beq.s .flop
	cmp.w #1,d0
	beq.s .flop
	move.l #'!HD!',(a0)
.flop	lea ULS_drive(pc),a0
	move.w d0,(a0)			; store launch drive

	nop
	lea SYS_PSG(pc),a0		; save PSG
	bsr save_PSG

	move.w #$2700,sr		; save gemdos timers
	lea GEMmfp_save(pc),a1
        bsr save_mfp
        lea GEMta_control(PC),A0
        lea GEMta_data(PC),A3
        bsr save_timers
	lea GEMta_data(pc),a3
	lea GEMta_control(pc),a4
	bsr restore_timers
	lea GEMmfp_save(pc),a1
	bsr restore_mfp

	bsr uls_read_mode		; put ULS in read mode

	lea TOS_screen(pc),a6		; store desktop screen base
	move.b $ffff8201.w,d0
	move.b $ffff8203.w,d1
	move.b $ffff820d.w,d2
	move.b d0,1(a6)
	move.b d1,2(a6)
	move.b d2,3(a6)

	lea GEM_fa0d(pc),a0
	move.b $fffffa0d.w,(a0)+	; save extra MFP
	move.b $fffffa11.w,(a0)+

	lea SYS_484(pc),a0		; save keyclick
	move.b $484.w,(a0)
	clr.b $484.w			; kill keyclick

	ifd adv_debug
	lea i_cac_o(pc),a4
	bsr i_prnt
	endc
	bsr core_cache_off

	ifd adv_debug
	lea i_snap(pc),a4
	bsr i_prnt
	endc
	
	lea $8.w,a0			; source
	lea ULS_TOS_mem(pc),a1
	move.l (a1),a1			; destination
	lea TOS_rambase(pc),a2		; last byte
	move.l (a2),d7
	bsr block_move

	bsr flush_acia			; flush ikbd

	lea ramdisk_enable(pc),a5	; pre-build the RAMdisk automagically
	cmp.l #'RAMD',(a5)
	bne.s .no_rd2

	ifd adv_debug
	lea i_rd(pc),a4
	bsr i_prnt
	endc
	bsr init_ramdisk
.no_rd2
	ifd adv_debug
	lea i_hw(pc),a4
	bsr i_prnt
	endc

	bsr core_cache_on

	bsr setup_hardware		; set video hardware
	bsr kill_f030			; PMMU and cache settings
	bsr info_init			; init text pointers

	bsr proc_16mhz_req

	lea $4ce.w,a0			; shut down ICDtools vbl-queue driver
	moveq #7,d0			; (ULS will re-init it on copy-back for IO)
.killchain
	clr.l (a0)+
	dbra d0,.killchain

	lea machine(pc),a1	
	move.w (a1),d0			; machine type in d0

	lea ULS_on_hd(pc),a1		; #!HD! if on HD in d1
	move.l (a1),d1

	lea composite(pc),a1		; 1=VGA
	moveq #0,d2			; 2=RGB
	move.w (a1),d2

	lea TOS_rambase(pc),a1
	move.l (a1),a2			; return highest byte in a2

	lea ULS_SYS_mem(pc),a1		; return address of low-memory during ULS
	move.l (a1),a3

	lea ULS_filebuffer(pc),a1
	move.l (a1),a1			; return address of ULS filebuffer

	move.l (a7)+,a0			; return address of ULS jmp table

	rts


proc_16mhz_req
	lea request_16mhz(pc),a5
	lea machine(pc),a6
	cmp.w #2,(a6)
	beq .mste
	cmp.w #3,(a6)
	beq .falc
	rts

.mste	lea nop_me_out(pc),a6
	cmp.l #$4e714e71,(a6)		; check cache enable request
	bne .mcoff
.mcon	or.b #%11111110,$ffff8e21.w	; enable MSTe cache
	bra.s .mgo
.mcoff	and.b #%00000001,$ffff8e21.w	; disable MSTe cache
.mgo	tst.w (a5)			; now test CPU speed
	bpl .mset16
.mset8	bclr.b #0,$ffff8e21.w		; set 8mhz
	rts
.mset16	bset.b #0,$ffff8e21.w		; set 16mhz
	rts

.falc	tst.w (a5)
	bpl .fset16
.fset8	bclr.b #0,$ffff8007.w
	rts
.fset16	bset.b #0,$ffff8007.w
	rts

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Videl set 320x200 
;;

uls_F30set320x200
	move.l a0,-(a7)
	lea composite(pc),a0
	cmp.w #2,(a0)
	beq .rgb
.vga	move.l (a7)+,a0
	bsr vga200
	rts
.rgb	move.l (a7)+,a0
	bsr rgb200
	rts

vga200	move.l	#$170012,$ffff8282.w		;falcon 60Hz vga
	move.l	#$1020e,$ffff8286.w		;
	move.l	#$d0012,$ffff828a.w		;
	move.l	#$41903ff,$ffff82a2.w		;
	move.l	#$3f008d,$ffff82a6.w		;
	move.l	#$3ad0415,$ffff82aa.w		;
	move.w	#$200,$ffff820a.w		;
	move.w	#$186,$ffff82c0.w		;
	clr.w	$ffff8266.w			;
	clr.b	$ffff8260.w			;
	move.w	#$5,$ffff82c2.w			;
	move.w	#$50,$ffff8210.w		;
	rts

rgb200	move.l	#$300027,$ffff8282.w		;falcon 50Hz rgb
	move.l	#$70229,$ffff8286.w		;
	move.l	#$1e002a,$ffff828a.w		;
	move.l	#$2710265,$ffff82a2.w		;
	move.l	#$2f0081,$ffff82a6.w		;
	move.l	#$211026b,$ffff82aa.w		;
	move.w	#$200,$ffff820a.w		;
	move.w	#$185,$ffff82c0.w		;
	clr.w	$ffff8266.w			;
	clr.b	$ffff8260.w			;
	clr.w	$ffff82c2.w			;
	move.w	#$50,$ffff8210.w		;
	rts

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Videl set 320x240 
;;

uls_F30set320x240
	move.l a0,-(a7)
	lea composite(pc),a0
	cmp.w #2,(a0)
	beq .rgb
.vga	move.l (a7)+,a0
	bsr vga240
	rts
.rgb	move.l (a7)+,a0
	bsr rgb240
	rts

vga240	move.l #$170012,$ffff8282.w
	move.l #$02020e,$ffff8286.w
	move.l #$0d0012,$ffff828a.w
	move.l #$041903fd,$ffff82a2.w
	move.l #$3f003d,$ffff82a6.w
	move.l #$03fd0415,$ffff82aa.w
	move.w #$200,$ffff820a.w
	move.w #$186,$ffff82c0.w
	clr.w $ffff8266.w
	clr.b $ffff8260.w
	move.w #$5,$ffff82c2.w
	move.w #$50,$ffff8210.w
	rts

rgb240	move.l #$c7009f,$ffff8282.w
	move.l #$1f02b9,$ffff8286.w
	move.l #$8800ab,$ffff828a.w
	move.l #$020d0201,$ffff82a2.w
	move.l #$17001b,$ffff82a6.w
	move.l #$01fb0207,$ffff82aa.w
	move.w #$200,$ffff820a.w
	move.w #$185,$ffff82c0.w
	clr.w $ffff8266.w
	clr.b $ffff8260.w
	move.w #$10,$ffff82c2.w
	move.w #$0,$ffff8210.w
	rts

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Videl set 320x200xTC 
;;

uls_F30set320x200TC
	move.l a0,-(a7)
	lea composite(pc),a0
	cmp.w #2,(a0)
	beq .rgb
.vga	move.l (a7)+,a0
	bsr vgaTC
	rts
.rgb	move.l (a7)+,a0
	bsr rgbTC
	rts

vgaTC	MOVE.L   #$C6008D,$FFFF8282.W		; falcon VGA
        MOVE.L   #$1502AC,$FFFF8286.W
        MOVE.L   #$8D0097,$FFFF828A.W
        MOVE.L   #$4190385,$FFFF82A2.W
        MOVE.L   #$650065,$FFFF82A6.W
        MOVE.L   #$3850415,$FFFF82AA.W
        MOVE.W   #$200,$FFFF820A.W
        MOVE.W   #$186,$FFFF82C0.W
        CLR.W    $FFFF8266.W
        MOVE.W   #$100,$FFFF8266.W
        MOVE.W   #$5,$FFFF82C2.W
        MOVE.W   #$140,$FFFF8210.W
	rts

rgbTC	MOVE.L   #$FE00CB,$FFFF8282.W		; falcon TV 320x200xTC@50Hz
        MOVE.L   #$27002E,$FFFF8286.W
        MOVE.L   #$8F00D9,$FFFF828A.W
        MOVE.L   #$2710265,$FFFF82A2.W
        MOVE.L   #$2F007F,$FFFF82A6.W
        MOVE.L   #$20F026B,$FFFF82AA.W
        MOVE.W   #$200,$FFFF820A.W
        MOVE.W   #$183,$FFFF82C0.W
        CLR.W    $FFFF8266.W
        MOVE.W   #$100,$FFFF8266.W
        MOVE.W   #$0,$FFFF82C2.W
        MOVE.W   #$140,$FFFF8210.W
	rts


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; ULS Dummy IKBD Routine
;;

uls_ikbd
	move.l a0,-(a7)
	lea ikbd_key(pc),a0
	move.b $fffffc02.w,(a0)
	move.l (a7)+,a0
	bclr.b #6,$ffffffa11.w
	rte

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; ULS Ramdisk Updater 
;;
;; D0.L: 4 char ASCII of initial folder to make ramdisk from
;; D1.W: -1 = replace ramdisk
;;       +1 = append to ramdisk
;;
;; A0.L: pointer to filespec for ramdisk (eg *.*)
;;

uls_update_rd
	move.l a0,-(a7)
	lea new_rd_filespec(pc),a6
	move.l a0,(a6)			; store new filespec pointer

	lea new_rd_dir(pc),a0
	move.l d0,(a0)			; store new RAMdisk folder name

	lea rd_update_type(pc),a0	; store RAMdisk update mode
	move.w d1,(a0)

	lea read_write_flag(pc),a6	; store ULS access mode
	move.w (a6),-(a7)
	move.w #'RU',(a6)		; put ULS in RAMdisk Update mode
	lea user_code_addr(pc),a6
	move.l a0,(a6)
	bsr uls_core
	lea read_write_flag(pc),a6
	move.w (a7)+,(a6)		; restore ULS access mode

	lea new_rd_dir(pc),a0
	clr.l (a0)
	lea rd_update_type(pc),a0
	clr.w (a0)
	move.l (a7)+,a0
	rts

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; ULS_search
;; 
;; Call to search / replace a byte sequence between 2 memory ranges
;;
;; A0.L: address to start searching
;; A1.L: address to end searching
;; A2.L: pointer to bytes to match
;; A3.L: pointer to bytes to overwrite
;; D0.L: length of search string
;; D1.L: length of replace string
;;

uls_search_replace
	
	move.l a2,-(a7)			; store search sequence pointer

.search	cmp.l a0,a1
	beq .end_search
	move.b (a2),d6
	cmp.b (a0)+,d6
	bne.s .search			; find first byte

	move.l a0,-(a7)

	move.l d0,d7
	subq.l #1,d7
	move.b (a2)+,d6
.find	move.b (a2)+,d6
	cmp.b (a0)+,d6
	bne.s .nomatch
	subq.l #1,d7
	bne.s .find

.found	move.l (a7)+,a0			; address of pattern
	subq.l #1,a0
	move.l (a7)+,a2			; pop search sequence address
.write	move.b (a3)+,(a0)+
	subq.l #1,d1
	bne.s .write
	rts
	
.nomatch
	move.l (a7)+,a0			; continue from next byte
	move.l (a7),a2			; restore sequence pointer
	bra.s .search

.end_search
	move.l (a7)+,a2
	rts

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; User Code Execute
;;
;; Call with A0=address of code to execute under TOS (RTS terminated)
;;

uls_usercode_exec
	lea read_write_flag(pc),a6	; store ULS access mode
	move.w (a6),-(a7)
	move.w #'UC',(a6)		; put ULS in usercode mode
	lea user_code_addr(pc),a6
	move.l a0,(a6)
	bsr uls_core
	lea read_write_flag(pc),a6
	move.w (a7)+,(a6)		; restore ULS access mode
	rts

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; State Save
;;
;; Call with:
;;
;; ULS filebuffer with register/sr dump using the following code from the stub:
;;
;;
;;	move.l a0,-(a7)
;;	lea uls_fb(pc),a0
;;	move.l (a0),a0
;;	add.l #4,a7			; correct the stack for reg-dump
;;	movem.l d0-7/a1-7,(a0)
;;	sub.l #4,a7			; and put it back
;;	lea 60(a0),a0
;;	move.w sr,(a0)+
;;	move.l (a7),(a0)+
;;	move.l (a7)+,a0
;;
;; D0.L: RAMtop for Dump File
;; D1.L: return JMP address for resume
;;


uls_suspend_disk
	lea resuming(pc),a6	
	move.l #'NOPE',(a6)
	lea ULS_on_hd(pc),a0
	cmp.l #'!HD!',(a0)
	beq.s .go
	rts				; No suspend on Floppy!!!

.go	lea state_menu(pc),a0
	move.l #'SAVE',(a0)

	lea read_write_flag(pc),a6	; store ULS access mode
	move.w (a6),-(a7)
	move.w #'SD',(a6)		; put ULS in suspend mode
	bsr uls_core
	lea read_write_flag(pc),a6
	move.w (a7)+,(a6)		; restore ULS access mode
	rts

suspend_code
	move.w #$2300,sr		; ok we need timer-c at least!

	lea $ffff8800.w,a0		; kill sound
	move.l #$08080000,(a0)
	move.l #$09090000,(a0)
	move.l #$0a0a0000,(a0)

	lea machine(pc),a0
	cmp.w #3,(a0)
	beq.s .mc30
	cmp.w #4,(a0)
	bne.s .mc00
.mc30
	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; print function status
	lea t_flshc(pc),a1
	bsr info
	movem.l (a7)+,d0-7/a0-6
	endc

	dc.l	$f0002400		* pflusha - flush caches
.mc00	bsr falcon_delay


	move.l $ffff8240.w,-(a7)
	bsr state_menuscreen		; user interface!
	move.l (a7)+,$ffff8240.w
	
	tst.b d0			; esc or a file?
	bpl.s .yay

	lea resuming(pc),a6		; esc	
	move.l #'NOPE',(a6)

	rts

.yay	lea susp_fn+7(pc),a0		; correct the filename
	add.b #'0',d0
	move.b d0,(a0)

	lea ULS_RAMDUMP_HEADER(pc),a0
	move.l #'ULS3',(a0)+
	move.l #'RAMS',(a0)+
	move.l #'AVE!',(a0)+
	clr.l (a0)			; re-write the header

	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; print function status
	lea t_rdta(pc),a1
	bsr info
	movem.l (a7)+,d0-7/a0-6
	endc

	bsr reset_DTA

	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; print function status
	lea t_ssfc(pc),a1
	bsr info
	movem.l (a7)+,d0-7/a0-6
	endc

	clr.w -(a7)
	pea susp_fn(pc)
	move.w #$3c,-(a7)
	trap #1
	lea 8(a7),a7
	move.l d0,d7

	lea ULS_bytes_io(pc),a0
	move.l (a0),d0			
	subq.l #8,d0			; length of contiguous memory dump
	lea rd_size(pC),a0
	move.l d0,(a0)	

	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; print function status
	lea t_ssdh(pc),a1
	bsr info
	movem.l (a7)+,d0-7/a0-6
	endc

	lea ULS_RAMDUMP_HEADER(pc),a0
	move.l #16,d0
	bsr write_disk

	lea input_buff(pc),a0		; save comment
	move.l #34,d0
	bsr write_disk

	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; print function status
	lea t_ssdl(pc),a1
	bsr info
	movem.l (a7)+,d0-7/a0-6
	endc

	lea ULS_SYS_mem(pc),a0
	move.l (a0),a0			; start of low memory buffer
	lea TOS_rambase(pc),a1
	move.l (a1),d0			; length of data
	bsr write_disk

	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; print function status
	lea t_ssdn(pc),a1
	bsr info
	movem.l (a7)+,d0-7/a0-6
	endc
	
	lea ULS_bytes_io(pc),a0
	move.l (a0),d0			; end of ramdump
	lea TOS_rambase(pc),a0		; start of "normal memory"
	move.l (a0),a0
	sub.l a0,d0			; size
	sub.l #8,d0
	bsr write_disk

	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; print function status
	lea t_ssdv(pc),a1
	bsr info
	movem.l (a7)+,d0-7/a0-6
	endc

	lea top_of_variable_table(pc),a0
	lea bot_of_variable_table(pc),a1
	sub.l a0,a1
	move.l a1,d0	
	bsr write_disk

	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; print function status
	lea t_ssdr(pc),a1
	bsr info
	movem.l (a7)+,d0-7/a0-6
	endc

	lea ULS_filebuffer(pc),a0	
	move.l (a0),a0			
	move.l #66,d0			; dump registers and SR
	bsr write_disk

	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; print function status
	lea t_sscf(pc),a1
	bsr info
	movem.l (a7)+,d0-7/a0-6
	endc

	move.w d7,-(a7)
	move.w #$3e,-(a7)
	trap #1
	add.l #4,a7

	bsr write_cooldown

	rts

write_disk
	move.l a0,-(a7)
	move.l d0,-(a7)
	move.w d7,-(a7)
	move.w #$40,-(a7)
	trap #1
	lea 12(a7),a7
	rts

ULS_RAMDUMP_HEADER
	dc.b "ULS3RAMSAVE!"
rd_size	dc.l 0

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; State Resume
;;
;; Returns: 
;;
;; Resumes savestate if successful
;; Returns to call if fail
;;


state_menu	dc.l 0
resuming	dc.l 0			; am I resuming? (exit core flag)
resume_fail	dc.l 0			; did I fail? (exit core flag)
resume_a7	dc.l 0			; err a7!
resume_sr	dc.w 0			; err sr!
local_DTA	ds.b 44
local_DRV_BUFF	ds.l 4

uls_resume_disk
	lea resuming(pc),a6	
	move.l #'NOPE',(a6)
	lea ULS_on_hd(pc),a0
	cmp.l #'!HD!',(a0)
	beq.s .go
	rts				; No resume on Floppy!!!

.go	lea state_menu(pc),a0
	move.l #'LOAD',(a0)
	lea resume_fail(pc),a6
	move.l #'NOPE',(a6)
	lea resuming(pc),a6	
	move.l #'YES!',(a6)
	lea read_write_flag(pc),a6	; store ULS access mode
	move.w (a6),-(a7)
	move.w #'RD',(a6)		; put ULS in resume mode
	bsr uls_core
	lea read_write_flag(pc),a6
	move.w (a7)+,(a6)		; restore ULS access mode
	rts


reset_DTA
	movem.l d0-7/a0-6,-(a7)
	pea local_DTA(pc)
	move.w #$1a,-(a7)
	trap #1				; set the DTA to local memory (Just in case)
	lea 6(a7),a7
	bsr falcon_delay
	lea ULS_drive(pc),a0
	move.w (a0),-(a7)
	pea local_DRV_BUFF(pc)
	move.w #$36,-(a7)
	trap #1				; force some arbitrary gemdos function (D_free)
	lea 8(a7),a7
	bsr falcon_delay
	movem.l (a7)+,d0-7/a0-6
	rts

resume_code
	move.w #$2300,sr

	lea $ffff8800.w,a0		; kill sound
	move.l #$08080000,(a0)
	move.l #$09090000,(a0)
	move.l #$0a0a0000,(a0)

	lea machine(pc),a0
	cmp.w #3,(a0)
	beq.s .mc30
	cmp.w #4,(a0)
	bne.s .mc00
.mc30
	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; print function status
	lea t_flshc(pc),a1
	bsr info
	movem.l (a7)+,d0-7/a0-6
	endc

	dc.l	$f0002400		* pflusha - flush caches
.mc00	move.l #'TIMC',d7
	bsr falcon_delay

	move.l $ffff8240.w,-(a7)
	bsr state_menuscreen		; user interface
	move.l (a7)+,$ffff8240.w

	tst.b d0			; esc or a filename?
	bpl.s .yay

	lea resuming(pc),a6		; esc	
	move.l #'NOPE',(a6)

	rts

.yay	lea susp_fn+7(pc),a0		; correct the filename
	add.b #'0',d0
	move.b d0,(a0)

	lea ULS_RAMDUMP_HEADER(pc),a0
	clr.l (a0)+
	clr.l (a0)+
	clr.l (a0)+
	clr.l (a0)			; clear the header

	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; print function status
	lea t_rdta(pc),a1
	bsr info
	movem.l (a7)+,d0-7/a0-6
	endc

	bsr reset_DTA

	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; print function status
	lea t_ssfo(pc),a1
	bsr info
	movem.l (a7)+,d0-7/a0-6
	endc

	clr.w -(a7)
	pea susp_fn(pc)
	move.w #$3d,-(a7)
	trap #1
	lea 8(a7),a7
	move.l d0,d7
	tst.w d0
	bpl.s .ok
.failed	lea resume_fail(pc),a6
	move.l #'FAIL',(a6)
	rts

.ok
	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; print function status
	lea t_ssrh(pc),a1
	bsr info
	movem.l (a7)+,d0-7/a0-6
	endc

	lea ULS_RAMDUMP_HEADER(pc),a0
	move.l #16,d0
	bsr read_disk
	lea ULS_RAMDUMP_HEADER(pc),a0
	cmp.l #'ULS3',(a0)
	bne .failed

	lea input_buff(pc),a0		; skip comment
	move.l #34,d0
	bsr read_disk

	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; print function status
	lea t_ssrl(pc),a1
	bsr info
	movem.l (a7)+,d0-7/a0-6
	endc

	lea ULS_SYS_mem(pc),a0
	move.l (a0),a0			; start of low memory buffer
	lea TOS_rambase(pc),a1
	move.l (a1),d0			; length of data
	bsr read_disk

	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; print function status
	lea t_ssrn(pc),a1
	bsr info
	movem.l (a7)+,d0-7/a0-6
	endc

	lea ULS_RAMDUMP_HEADER+12(pc),a0
	move.l (a0),d0			; length of ramdump
	lea TOS_rambase(pc),a0
	move.l (a0),a0			; load address
	sub.l a0,d0			; bytes to load
	bsr read_disk

	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; print function status
	lea t_ssrv(pc),a1
	bsr info
	movem.l (a7)+,d0-7/a0-6
	endc
	
	lea top_of_variable_table(pc),a0
	lea bot_of_variable_table(pc),a1
	sub.l a0,a1
	move.l a1,d0	
	bsr read_disk

	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; print function status
	lea t_ssrr(pc),a1
	bsr info
	movem.l (a7)+,d0-7/a0-6
	endc

	lea ULS_filebuffer(pc),a0	
	move.l (a0),a0			
	move.l #66,d0
	bsr read_disk			; read registers and SR

	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; print function status
	lea t_sscf(pc),a1
	bsr info
	movem.l (a7)+,d0-7/a0-6
	endc

	move.w d7,-(a7)
	move.w #$3e,-(a7)
	trap #1
	add.l #4,a7

	lea resuming(pc),a6	
	move.l #'YES!',(a6)
	rts

read_disk
	move.l a0,-(a7)
	move.l d0,-(a7)
	move.w d7,-(a7)
	move.w #$3f,-(a7)
	trap #1
	lea 12(a7),a7
	rts


susp_fn	dc.b "RAMDUMPx.ULS",0
	even

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; SaveState menu
;;
;; Returns:
;;
;; d0=$ff (esc)
;; d0=0-9 for choice
;;

state_menuscreen
	bsr .proc_headers		; scan for all 10 statefiles

	lea t_curs_off(pc),a0
	move.l #(160*9)*5,(a0)		; reset the cursor

	lea t_curs_on(pc),a0
	move.l #(160*9)*5,(a0)		; reset the cursor

	lea .kmenu(pc),a0
	clr.w (a0)			; reset menu number

	lea ikbd_key(pc),a0
	clr.b (a0)			; make sure nothing in key buffer

	bsr flush_acia			; flush it from the game
	bset.b #6,$fffffa15.w		; enable acia
	
	move.w #$7,$ffff8240.w		; blue background
	move.w #$770,$ffff8242.w	; yellow text

	lea ULS_scr(pc),a0		; clear the workscreen
	move.l (a0),a0
	move.l #($7d00/4)-1,d7
.era	clr.l (a0)+
	dbra d7,.era

	lea t_kill(pc),a1		; load or save?
	lea state_menu(pc),a0
	cmp.l #'LOAD',(a0)
	beq.s .set_ld
.set_sa	move.b #-2,(a1)			; if save, carry on printing last line of text
	bra.s .set_dn
.set_ld	move.b #-1,(a1)			; if load, terminate before last line of text

.set_dn	lea t_savestate(pc),a1		; display menu
	bsr info
	lea t_curs_on(pc),a1		; display cursor
	bsr info

.hold	lea ikbd_key(pc),a0
	cmp.b #$c8,(a0)			; cursor up?
	beq .kcurs_up
	cmp.b #$d0,(a0)			; cursor down?
	beq .kcurs_dw
	cmp.b #$9c,(a0)			; enter?
	beq .kenter

	cmp.b #$81,(a0)			; esc?
	bne.s .hold
	
	lea .kmenu(pc),a0		; esc, so set to $ff
	move.w #$ff,(a0)

.s_exit	lea .kmenu(pc),a0
	move.w (a0),d0			; return menu number (0-9)
	bclr.b #6,$fffffa15.w		; disable acia	
	rts

.kcurs_up	
	lea .kmenu(pc),a0	
	tst.w (a0)			; check if at top (0)
	beq .kupo
	sub.w #1,(a0)			; up one!

	lea t_curs_off(pc),a1		; remove cursor
	bsr info
	lea t_curs_off(pc),a1
	sub.l #160*9,(a1)		; move cursor up the screen
	lea t_curs_on(pc),a1
	sub.l #160*9,(a1)
	bsr info			; draw cursor
	lea ikbd_key(pc),a0
.kupo	clr.b (a0)			; clear buffer
	bra .hold			; loop around

.kcurs_dw
	lea .kmenu(pc),a0
	cmp.w #9,(a0)			; check if at bottom (9)
	beq .kdwo
	add.w #1,(a0)			; down one!

	lea t_curs_off(pc),a1		; remove cursor
	bsr info
	lea t_curs_off(pc),a1
	add.l #160*9,(a1)		; move cursor down the screen
	lea t_curs_on(pc),a1
	add.l #160*9,(a1)
	bsr info			; draw cursor
	lea ikbd_key(pc),a0
.kdwo	clr.b (a0)			; clear buffer
	bra .hold			; loop around

.kenter
	lea state_menu(pc),a0
	cmp.l #'LOAD',(a0)		; are we doing a LOAD or a SAVE state?
	beq .state_load_select

.state_save_select			; save
	lea .kmenu(pc),a0		; menu number
	lea t_sav0(pc),a1
	move.w (a0),d0			; get vertical
	mulu #39,d0			; offset into ASCII
	add.w d0,a1
	add.w #4,a1
	move.w #30,d0
	lea .old_input_buff(pc),a2	
.copy	move.b (a1)+,(a2)+		; backup existing description (In case of ESC)
	dbra d0,.copy

	lea input_buff(pc),a0
	move.w #32,d0
.wipe	move.b #' ',(a0)+		; enpty out text buffer
	dbra d0,.wipe
	lea input_buff+1(pc),a0
	move.b #'-',(a0)
	lea .input_pos(pc),a0
	clr.w (a0)			; move cursor to start
	lea ikbd_key(pc),a0
	clr.b (a0)
	lea t_curs_on(pc),a0
	move.l (a0),d0			; where the cursor is
	add.l #16,d0
	lea input_buff-4(pc),a1
	move.l d0,(a1)			; where on screen
	bsr info

.iloop	lea ikbd_key(pc),a0	
	cmp.b #$81,(a0)			; esc
	beq .inp_done_esc
	cmp.b #$9c,(a0)			; enter
	beq .inp_done_ok
	cmp.b #$8e,(a0)			; backspace
	beq .bkc_space
	move.b (a0),d0
	bsr .proc_char			; convert scancode to ASCII
	cmp.b #'A',d0
	blt .no_az			;
	cmp.b #'Z',d0			;
	ble .is_az			;
.no_az	cmp.b #'0',d0			; check if valid (a-z/0-9/space)
	blt .no_nm			;
	cmp.b #'9',d0			;
	ble .is_az			;
.no_nm	cmp.b #' ',d0			;
	beq .is_az		
	bra .iloop			; branch around if not

.proc_char
	lea .scan(pc),a0		; scancode buffer
.cmploo	move.b (a0)+,d6			; scancode byte
	move.b (a0)+,d7			; ascii char
	cmp.b #$ff,d7			; end of table?
	beq.s .sout
	cmp.b d0,d6			; key=scancode?
	bne.s .cmploo
.sout	move.b d7,d0			; store ascii!
	rts

.is_az	lea ikbd_key(pc),a0		; clear buffer
	clr.b (a0)

	lea .input_pos(pc),a0		; chars typed
	move.w (a0),d1
	cmp.w #31,d1			; end of line?
	beq.s .maxl
	add.w #1,d1			; next char
	move.w d1,(a0)
	lea input_buff(pc),a0
	move.b d0,(a0,d1.w)		; write to string
	move.b #'-',1(a0,d1.w)		; move cursor over one

	lea input_buff-4(pc),a1		; redisplay line
	bsr info

.maxl	bra .iloop			; around we go!

.bkc_space
	lea ikbd_key(pc),a0		; clear buffer
	clr.b (a0)

	lea .input_pos(pc),a0		; get input position
	move.w (a0),d1			
	tst.w d1			; 1st char?
	beq .minl			; if so, can't delete - exit

	sub.w #1,d1
	move.w d1,(a0)			; chars=chars-1
	lea input_buff(pc),a0
	move.b #'-',1(a0,d1.w)		; write cursor to string
	move.b #' ',2(a0,d1.w)		; erase deleted cursor
	
	lea input_buff-4(pc),a1		; redisplay line
	bsr info

.minl	bra .iloop			; around we go!
	
.inp_done_esc
	lea input_buff(pc),a0		; esc pressed
	lea .old_input_buff(pc),a1
	move.w #32,d0
.repl	move.b (a1)+,(a0)+		; copy previous line back
	dbra d0,.repl

	lea ikbd_key(pc),a0
	clr.b (a0)			; clear buffer

.inp_done_exit
	bsr .input_proc			; process line to output buffer
	bra .hold			; loop around

.inp_done_ok
	lea .input_pos(pc),a0
	move.w (a0),d1
	lea input_buff(pc),a0
	move.b #' ',1(a0,d1.w)		; write to string
	lea ikbd_key(pc),a0
	move.b #$81,(a0)
	bsr .input_proc			; process line to output buffer

.state_load_select
	bra .s_exit			; exit out if load selected (no edit!)

.old_input_buff	ds.b 33			; what was there
		even
.input_pos	ds.w 1			; char counter


.input_proc
	lea .kmenu(pc),a0		; copy what we typed/restored to the screen buffer
	lea t_sav0(pc),a1
	move.w (a0),d0			; get vertical
	mulu #39,d0
	add.w d0,a1
	add.w #4,a1
	move.w #31,d0
	lea input_buff(pc),a2
.copyx	move.b (a2)+,(a1)+
	dbra d0,.copyx

.editout
	lea t_savestate(pc),a1		; update screen
	bsr info

	lea t_curs_on(pc),a1		; redraw cursor
	bsr info
	rts

.proc_headers
	move.b #'0',d7			; start with RAMSAVE0.ULS
.loop	lea susp_fn+7(pc),a0
	move.b d7,(a0)
	bsr .read_state_header		; process it
	add.b #1,d7			; increment filename
	cmp.b #'9'+1,d7			; until all done
	bne.s .loop
	rts

.read_state_header
	lea ULS_filebuffer(pc),a0
	move.l (a0),a0			; address of filebuffer	
	clr.l $200(a0)			; offset into filebuffer (don't want to trash registers!)	

	move.l d7,-(a7)			; save filename number
	clr.w -(a7)
	pea susp_fn(pc)
	move.w #$3d,-(a7)
	trap #1				; open the file
	lea 8(a7),a7
	move.w d0,d6

	tst.w d6
	bmi .fnf_error			; branch if it wasn't there
	
	lea ULS_filebuffer(pc),a0
	move.l (a0),a0			; address of filebuffer	
	lea $200(a0),a0			; offset into filebuffer (don't want to trash registers!)	
	move.l a0,-(a7)
	move.l #16+32,-(a7)
	move.w d6,-(a7)
	move.w #$3f,-(a7)
	trap #1				; read header
	lea 12(a7),a7

.fnf_error
	move.w d6,-(a7)
	move.w #$3e,-(a7)
	trap #1				; close file anyway (even if not found)
	lea 4(a7),a7

	lea ULS_filebuffer(pc),a0
	move.l (a0),a0			; address of filebuffer	
	lea $200(a0),a0

	lea .fnf_errort(pc),a1
	cmp.l #'ULS3',(a0)		; ULS savefile?
	bne.s .f_error
	lea 16(a0),a1			; comment header
.f_error
	move.l (a7)+,d7
	move.b d7,d0			
	sub.b #'0',d0
	bsr .insert_table		; write comment to menu
	
	rts

.insert_table
	and.l #$f,d0			; get the filename number
	lea t_sav0(pc),a2
	mulu #39,d0
	add.w d0,a2
	add.w #4,a2
	move.w #31,d0
.copyy	move.b (a1)+,(a2)+		; and write header string into table
	dbra d0,.copyy
	rts

.fnf_errort
;	dc.b "0123456789012345678901234567890123"
	dc.b " MEMORY SAVE SLOT UNUSED          ",-1	; unused slot text
	even
	

.kmenu	dc.w 0				; menu number

.scan	dc.b $1e,'A',$30,'B',$2e,'C',$20,'D',$12,'E',$21,'F',$22,'G'	; scancode table
	dc.b $23,'H',$17,'I',$24,'J',$25,'K',$26,'L',$32,'M',$31,'N'	;
	dc.b $18,'O',$19,'P',$10,'Q',$13,'R',$1f,'S',$14,'T',$16,'U'	; dc.b scancode,ascii
	dc.b $2f,'V',$11,'W',$2d,'X',$15,'Y',$2c,'Z',$0b,'0',$02,'1'	;
	dc.b $03,'2',$04,'3',$05,'4',$06,'5',$07,'6',$08,'7',$09,'8'
	dc.b $0a,'9',$39,' ',$ff,$ff

		dc.l 160*180		; screen offset
input_buff	ds.b 33			; buffer to type on
		dc.b -1			; termination char
		even

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Get address of a file in ramdisk
;;


uls_get_ramdisk_address
	movem.l d0-7/a1-6,-(a7)

	lea sys_filename(pc),a6
	move.l a0,(a6)
	bsr process_filename		; convert the filename
	movem.l (a7),d0-7/a0-6

	lea ULS_fn_header(pc),a5
	move.l (a5),d4

	lea ramdisk_base(pc),a5		; get address of RAMdisk base
	move.l (a5),a5
.finder
	lea ULS_filename(pc),a6		; filename requested
	move.l a5,-(a7)

	cmp.l 16(a5),d4			; same data folder?
	bne .err	

	move.w #11,d0			; 12 chars/name
.floop	tst.b (a6)			; end of name?
	beq .foundit
	cmp.b (a5)+,(a6)+		; compare filename
	bne .err
	dbra d0,.floop			; name length overflow check
	bra .foundit			; all chars match!	
.err	move.l (a7)+,a5

	move.l 12(a5),d7
	btst #0,d7
	beq.s .notodd1
	addq.l #1,d7
	bclr #0,d7
.notodd1
	add.l d7,a5			; wrong name, get next pointer

	lea 20(a5),a5
	cmp.l #'END!',(a5)		; end of table?
	bne.s .finder

	movem.l	(a7)+,d0-7/a0-6		; file not in RAMdisk - call ULS as per normal
	bra normalio

.foundit
	cmp.b #'.',(a6)			; check if this is the end of the filename
	beq.s .noerr			; (dupe init characters check)
	tst.b (a6)
	bne .err

.noerr	move.l (a7)+,a5			; header!!
	move.l a5,a0
	movem.l (a7)+,d0-7/a1-6

	rts

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Screenshot grabber
;;

uls_screenshot
	lea ULS_on_hd(pc),a0
	cmp.l #'!HD!',(a0)
	beq.s .go
	rts				; No PI1 on Floppy!!!

.go	lea read_write_flag(pc),a6	; store ULS access mode
	move.w (a6),-(a7)
	move.w #'SC',(a6)		; put ULS in screenshot mode
	bsr uls_core
	lea read_write_flag(pc),a6
	move.w (a7)+,(a6)		; restore ULS access mode
	rts

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Process screenshot filename
;;

screenshot_filename
	lea scr_count(pc),a5		; get and increment filename counter
	add.w #1,(a5)
	move.w (a5),d1
	bsr hashing
	lea hexad+4(pc),a5		; patch counter into filename
	lea scr_fn+4(pc),a6
	move.l (a5),(a6)
	rts

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Save screenshot as PI1
;;

save_screenshot
	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; print function status
	lea t_scr(pc),a1
	bsr info			
	movem.l (a7)+,d0-7/a0-6
	endc

	move.w #$2300,sr

	bsr reset_DTA

	clr.w -(a7)			; open file
	pea scr_fn(pc)
	move.w #$3c,-(a7)		; GEMDOS fwrite
	trap #1
	add.l #8,a7
	move.w d0,d7			; file handle
	bmi io_error_oops		; loop if create error

	lea SYS_res(pc),a5		; put the resolution into the PI1 header
	lea SYS_pal-2(pc),a6
	move.b (a5),1(a6)

	move.l a6,-(a7)			; address of pallette-2 (PI1 header)
	move.l #34,-(a7)		; bytes to write
	move.w d7,-(a7)
	move.w #$40,-(a7)		; GEMDOS fwrite
	trap #1
	lea 12(a7),a7
	move.l d0,d6
	bmi io_error_oops

	lea ULS_scr(pc),a6
	move.l (a6),-(a7)		; address of screen
	move.l #32000,-(a7)		; bytes to write
	move.w d7,-(a7)
	move.w #$40,-(a7)		; GEMDOS fwrite
	trap #1
	lea 12(a7),a7
	move.l d0,d6
	bmi io_error_oops

	move.w d7,-(a7)			
	move.w #$3e,-(a7)		; GEMDOS fclose
	trap #1
	addq.l #4,a7

	bsr write_cooldown

	rts


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; ULS "Core" Cache control
;;
;; The ULS Core/Init routines will not run with cache on - these routines control caches
;; on 68030 machines (Falcon/TT)
;; 

core_cache_off
	move.l a0,-(a7)	
	lea machine(pc),a0
	cmp.w #3,(a0)			; Falcon?
	beq.s .core_off
	cmp.w #4,(a0)			; TT?
	beq.s .core_off
	move.l (a7)+,a0
	rts
.core_off
	movem.l d0/a5,-(a7)
	moveq   #0,D0
       	DC.L $4E7A0002  		; movec cacr,d0
       	lea     core_cacr(PC),A5	; Save cache state
       	move.l  D0,(A5)
	moveq   #0,D0
	DC.L $4E7B0002  		; movec d0,cacr (kill caches)
	movem.l (a7)+,d0/a5
	move.l (a7)+,a0
	rts

core_cache_on
	move.l a0,-(a7)	
	lea machine(pc),a0
	cmp.w #3,(a0)			; Falcon?
	beq.s .core_on
	cmp.w #4,(a0)			; TT?
	beq.s .core_on
	move.l (a7)+,a0
	rts
.core_on
	dc.l $f0002400			; pflusha - flush caches
	nop
	nop
	movem.l d0/a5,-(a7)
	lea core_cacr(pc),a5
	move.l (a5),d0
	dc.l $4e7b0002			; movec d0,cacr (return to whatever it was)
	nop
	nop
	dc.l $f0002400			; pflusha - flush caches
	nop
	nop
	movem.l (a7)+,d0/a5
	move.l (a7)+,a0
	rts

core_cacr	dc.l 0

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; "ULS Core"
;;
;; (All things have a beginning... and an end.... but they must pass through here!)
;;
;; Assumes:
;;
;; a0=pointer to filename
;; a1=load address
;; d0=bytes loaded 	-1 = all / saved
;; d1=seek offset 	0  = start of file [read only]
;; d7=0 load to RAM
;; d7=-1 load to buffer only
;;
;; Returns:
;;
;; d0=bytes loaded/saved (Packed)
;; d1=bytes loaded/saved (Actual filesize)
;; d7=ffffffff if file not found
;;

uls_core
	move.l a0,-(a7)

	lea resume_a7(pc),a0
	move.l a7,(a0)
	add.l #4,(a0)

	lea resume_sr(pc),a0
	move.w sr,(a0)

	lea ULS_bytes_io(pc),a0		; bytes to load/save
	move.l d0,(a0)

	lea ULS_seek_offset(pc),a0	; offset into file
	move.l d1,(a0)

	lea copy_data(pc),a0		; to filebuffer only flag
	move.w d7,(a0)

	lea machine(pc),a0		; get machine type
	cmp.w #1,(a0)			; STe?
	beq .blitwait
	cmp.w #2,(a0)			; MSTe?
	beq .blitwait
	cmp.w #3,(a0)			; Falcon?
	beq .blitwait
	bra .noblit

.blitwait
	btst.b #7,$ffff8a3c.w		; wait if blitter is busy
	bne.s .blitwait			

.noblit	lea read_write_flag(pc),a0	; check if "Special Operation" or normal read
	cmp.w #'SC',(a0)
	beq .do_uls			
	cmp.w #'UC',(a0)
	beq .do_uls			
	cmp.w #'SD',(a0)
	beq .do_uls
	cmp.w #'RD',(a0)
	beq .do_uls
	cmp.w #'RU',(a0)
	beq .do_uls
	tst.w (a0)
	bmi .do_uls

	lea ramdisk_enable(pc),a0	; its a normal read
	cmp.l #'RAMD',(a0)		
	bne .do_uls			; so did we init a RAMdisk?

	move.l (a7)+,a0
	bra ULS_ramdisk_handler

.do_uls	move.l (a7)+,a0
	bsr core_cache_off		; Disable caches on 68030


normalio
	move.w sr,-(a7)			; save SR

	move.l a0,-(a7)			; save registers
	lea APP_sr(pc),a0
	move.w sr,(a0)
	move.w #$2700,sr		; kill all interupts

	lea ULS_registers(pc),a0
	movem.l d0-7/a1-7,4(a0)
	move.l (a7)+,(a0)
	move.l (a0),a0

	bsr set_16			; Turbo (if possible)

	lea SYS_res(pc),a6		; save resolution
	move.b $ffff8260.w,1(a6)
	move.b #0,$ffff8260.w		; low res

	lea ULS_ret_add(pc),a6
	move.l 2(a7),(a6)		; return address

	lea sys_filename(pc),a6
	move.l a0,(a6)

	lea $ffff8240.w,a6		; save application pallette
	lea SYS_pal(pc),a5		
	move.w #15,d7
.advpax	move.w (a6)+,(a5)+
	dbra d7,.advpax

	lea SYS_screen(pc),a6		; save application screen
	move.b $ffff8201.w,1(a6)
	move.b $ffff8203.w,2(a6)
	move.b $ffff820d.w,3(a6)

	move.l (a6),a6			; save screen memory to debug workspace
	lea ULS_scr(pc),a5
	move.l a5,-(a7)
	move.l (a5),a5
	move.l #(32000/4)-1,d7
.mover	move.l (a6)+,(a5)+
	dbra d7,.mover

	move.l (a7)+,a6			; point screen to uls workspace
	move.b 1(a6),$ffff8201.w
	move.b 2(a6),$ffff8203.w
	move.b 3(a6),$ffff820d.w	
		
	lea ULS_stk(pc),a7		; local stack

	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; save current screen address
	lea ULS_scr(pc),a0		; clear uls debug screen
	move.l (a0),a1
	move.l #(32000/4)-1,d7
.advwp	clr.l (a1)+
	dbra d7,.advwp
	lea $ffff8240.w,a0
	move.w #15,d7
.advpa	move.w #$777,(a0)+		; set debug pallette
	dbra d7,.advpa
	clr.w $ffff8240.w
	lea t_init(pc),a1		; "Entering ULS"
	bsr info
	lea ULS_ret_add(pc),a0
	move.l (a0),d1
	sub.l #4,d1			; correct for the JSR
	bsr hashing
	lea hexad(pc),a1
	lea t_jmpa(pc),a0
	move.l (a1)+,(a0)+
	move.l (a1),(a0)
	lea t_jmp(pc),a1
	bsr info			; print "Called from: $xxxxxxxx"

	lea t_uls(pc),a1
	bsr info

	lea uls(pc),a1			; debug: ULS Base address
	move.l a1,d1
	bsr hashing
	lea hexad(pc),a1
	lea t_ulsba(pc),a0
	move.l (a1)+,(a0)+
	move.l (a1),(a0)
	lea t_ulsb(pc),a1
	bsr info

	lea ULS_TOS_mem(pc),a1		; debug: ULS TOS copy address
	move.l (a1),d1
	bsr hashing
	lea hexad(pc),a1
	lea t_gemba(pc),a0
	move.l (a1)+,(a0)+
	move.l (a1),(a0)
	lea t_gemb(pc),a1
	bsr info

	lea ULS_SYS_mem(pc),a1		; debug: ULS APP copy address
	move.l (a1),d1
	bsr hashing
	lea hexad(pc),a1
	lea t_appba(pc),a0
	move.l (a1)+,(a0)+
	move.l (a1),(a0)
	lea t_appb(pc),a1
	bsr info

	lea TOS_rambase(pc),a1		; debug: ULS High Byte Copies
	move.l (a1),d1
	bsr hashing
	lea hexad(pc),a1
	lea t_hibya(pc),a0
	move.l (a1)+,(a0)+
	move.l (a1),(a0)
	lea t_hiby(pc),a1
	bsr info

	lea ULS_scr(pc),a5		; debug: Horizontal lines!
	move.l (a5),a5
	move.w #39,d7
.draw	move.l #$ffff,160*110(a5)
	move.l #$ffff,160*187(a5)
	lea 4(a5),a5
	dbra d7,.draw

	lea ULS_registers(pc),a5	; debug: register dump
	move.l (a5)+,d1
	lea t_a0(pc),a6
	bsr .hashing_reg
	move.l (a5)+,d1
	lea t_d0(pc),a6
	bsr .hashing_reg
	move.l (a5)+,d1
	lea t_d1(pc),a6
	bsr .hashing_reg
	move.l (a5)+,d1
	lea t_d2(pc),a6
	bsr .hashing_reg
	move.l (a5)+,d1
	lea t_d3(pc),a6
	bsr .hashing_reg
	move.l (a5)+,d1
	lea t_d4(pc),a6
	bsr .hashing_reg
	move.l (a5)+,d1
	lea t_d5(pc),a6
	bsr .hashing_reg
	move.l (a5)+,d1
	lea t_d6(pc),a6
	bsr .hashing_reg
	move.l (a5)+,d1
	lea t_d7(pc),a6
	bsr .hashing_reg
	move.l (a5)+,d1
	lea t_a1(pc),a6
	bsr .hashing_reg
	move.l (a5)+,d1
	lea t_a2(pc),a6
	bsr .hashing_reg
	move.l (a5)+,d1
	lea t_a3(pc),a6
	bsr .hashing_reg
	move.l (a5)+,d1
	lea t_a4(pc),a6
	bsr .hashing_reg
	move.l (a5)+,d1
	lea t_a5(pc),a6
	bsr .hashing_reg
	move.l (a5)+,d1
	lea t_a6(pc),a6
	bsr .hashing_reg
	move.l (a5)+,d1
	lea t_a7(pc),a6
	bsr .hashing_reg
	lea APP_sr(pc),a5
	move.w (a5),d1
	bsr hashing
	lea hexad+4(pc),a5
	lea t_sr(pc),a6
	move.l (a5),(a6)
	lea t_regi(pc),a1
	bsr info	
	bra .rout

.hashing_reg
	bsr hashing
	lea hexad(pc),a1
	move.l (a1)+,(a6)+
	move.l (a1),(a6)
	rts

.rout	movem.l (a7)+,d0-7/a0-6
	endc

	lea read_write_flag(pc),a6	; read or write! 
	cmp.w #'SC',(a6)
	beq .screenshot			; its a kodak moment
	cmp.w #'UC',(a6)
	beq .usercode			; run some user code
	cmp.w #'SD',(a6)
	beq .susdcode			; state save
	cmp.w #'RD',(a6)
	beq .resdcode			; state load
	cmp.w #'RU',(a6)		
	beq .ramucode			; ramdisk update
	tst.w (a6)
	bpl .read_file
	bra .write_file

.susdcode
	bsr restore_gemdos
	bsr suspend_code
	bsr restore_game_env
	bra .exit_core

.resdcode
	bsr restore_gemdos
	bsr resume_code
	bsr restore_game_env
	bra .exit_core
	
.usercode
	bsr restore_gemdos
	lea user_code_addr(pc),a6
	move.l (a6),a6
	jsr (a6)
	bsr restore_game_env
	bra .exit_core

.screenshot
	bsr screenshot_filename
	bsr restore_gemdos
	bsr save_screenshot
	bsr restore_game_env
	bra .exit_core

.ramucode
	bsr restore_gemdos
	bsr update_ramdisk
	bsr restore_game_env
	bra .exit_core

.read_file
	bsr process_filename
	bsr restore_gemdos
	bsr load_file
	bsr restore_game_env
	lea copy_data(pc),a6
	tst.w (a6)
	bmi.s .no_rd
	lea fnf_flag(pc),a6
	tst.l (a6)
	bmi.s .no_rd
	bsr bytecopy_file_down
.no_rd	bra .exit_core

.write_file
	bsr process_filename
	bsr bytecopy_file_up
	bsr restore_gemdos
	bsr save_file
	bsr write_cooldown
	bsr restore_game_env
	bra .exit_core


.exit_core
	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)
	lea t_done(pc),a1
	bsr info			; print "Done!"

	move.l #$4ffff,d0	
.lngwai	eor.w #$7,$ffff8240.w		; delay so you can read it
	subq.l #1,d0
	bne.s .lngwai

	lea SYS_res(pc),a6		; restore resolution
	move.b 1(a6),$ffff8260.w

	lea SYS_pal(pc),a0
	lea $ffff8240.w,a1
	move.w #15,d0
.palt2	move.w (a0)+,(a1)+		; restore pallette
	dbra d0,.palt2
	movem.l (a7)+,d0-7/a0-6
	endc
	
	lea SYS_screen(pc),a0		; restore screen
	move.b 1(a0),$ffff8201.w
	move.b 2(a0),$ffff8203.w
	move.b 3(a0),$ffff820d.w

	bsr flush_acia
	bsr set_8			; back to whatever it was on entry

	lea ULS_registers(pc),a0	; restore registers
	move.l (a0)+,-(a7)
	movem.l (a0),d0-7/a1-7

	bclr.b #3,$fffffa17.w		; enable acia	

	lea resume_fail(pc),a0
	cmp.l #'FAIL',(a0)
	beq .no_resume

	lea resuming(pc),a0
	cmp.l #'YES!',(a0)
	beq .resume_exit

.no_resume
	lea resume_fail(pc),a0
	move.l #'NOPE',(a0)

	lea ULS_bytes_loaded(pc),a0
	move.l (a0),d0			; RAW or Packed filesize

	lea ULS_bytes_loaded2(pc),a0	
	move.l (a0),d1			; RAW filesize

	lea fnf_flag(pc),a0
	move.l (a0),d7			; d7 -ve if file not found

	move.l (a7)+,a0
	move.w (a7)+,sr
	bsr core_cache_on		; restore 68030 cache values
	rts

.resume_exit
	movem.l d0-7/a0-6,-(a7)
	bsr flush_acia

	lea machine(pc),a0
	cmp.w #3,(a0)
	beq.s .mc30
	cmp.w #4,(a0)
	bne.s .mc00
.mc30	dc.l	$f0002400		* pflusha - flush caches
.mc00	bsr falcon_delay

	movem.l (a7)+,d0-7/a0-6
	move.b $fffffc02.w,d0

	lea $ffff8800.w,a0		; kill sound
	move.l #$08080000,(a0)
	move.l #$09090000,(a0)
	move.l #$0a0a0000,(a0)

	lea ULS_seek_offset(pc),a6
	move.l (a6),a0
	lea .jmp+2(pc),a6
	move.l a0,(a6)

	lea resuming(pc),a0
	move.l #'NOPE',(a0)
	bsr uls_read_mode

	lea ULS_filebuffer(pc),a0
	move.l (a0),a0			; address of filebuffer
	movem.l (a0),d0-7/a1-7
	lea 60(a0),a0

	move.w (a0)+,sr
	move.l (a0),a0			; all registers returned to dump state

	movem.l d0-7/a0-6,-(a7)
	bsr falcon_delay
	lea SYS_pal(pc),a0
	movem.l (a0),d0-7
	movem.l d0-7,$ffff8240.w
	movem.l (a7)+,d0-7/a0-6

	bsr core_cache_on		; restore 68030 cache values

.jmp	jmp $12345678

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; ULS AutoMagic Ramdisk Handler
;;

ULS_ramdisk_handler
	movem.l d0-7/a0-6,-(a7)

	lea sys_filename(pc),a6
	move.l a0,(a6)

	bsr process_filename		; convert the filename

	movem.l (a7),d0-7/a0-6

	lea ULS_fn_header(pc),a5
	move.l (a5),d4

	lea ramdisk_base(pc),a5		; get address of RAMdisk base
	move.l (a5),a5
.finder
	lea ULS_filename(pc),a6		; filename requested
	move.l a5,-(a7)

	cmp.l 16(a5),d4			; same data folder?
	bne .err	

	move.w #11,d0			; 12 chars/name
.floop	tst.b (a6)			; end of name?
	beq .foundit
	cmp.b (a5)+,(a6)+		; compare filename
	bne .err
	dbra d0,.floop			; name length overflow check
	bra .foundit			; all chars match!	
.err	move.l (a7)+,a5

	move.l 12(a5),d7
	btst #0,d7
	beq.s .notodd1
	addq.l #1,d7
	bclr #0,d7
.notodd1
	add.l d7,a5			; wrong name, get next pointer

	lea 20(a5),a5
	cmp.l #'END!',(a5)		; end of table?
	bne.s .finder

	movem.l	(a7)+,d0-7/a0-6		; file not in RAMdisk - call ULS as per normal
	bra normalio

.foundit
	cmp.b #'.',(a6)			; check if this is the end of the filename
	beq.s .noerr			; (dupe init characters check)
	tst.b (a6)
	bne .err

.noerr	move.l (a7)+,a5			; header!!
	move.l 12(a5),d0		; length

	lea 20(a5),a0			; start of data!
	move.l a0,-(a7)
	move.l d0,-(a7)

	lea ULS_bytes_io(pc),a3		; bytes to load/save
	tst.l (a3)
	bmi.s .do_seek
	move.l (a3),d0
	move.l d0,(a7)			; bytes loaded

.do_seek
	lea ULS_seek_offset(pc),a3	; offset into file
	add.l (a3),a0	

	lea copy_data(pc),a3		; load to buffer only?
	tst.w (a3)
	bpl.s .reader
	lea ULS_filebuffer(pc),a1
	move.l (a1),a1

.reader	move.b (a0)+,(a1)+		; load addr still in a1! (Amazing eh?)
	subq.l #1,d0
	bne.s .reader

	move.l (a7)+,d6
	move.l (a7)+,a6
	bsr pack_header_process	
	
	movem.l (a7)+,d0-7/a0-6

	move.l a0,-(a7)
	lea ULS_bytes_loaded(pc),a0
	move.l (a0),d0			; RAW or Packed filesize
	lea ULS_bytes_loaded2(pc),a0	
	move.l (a0),d1			; RAW filesize
	moveq #0,d7
	move.l (a7)+,a0

	rts

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Packed header processing
;;
;; Call with:
;;
;; D6.L: Size of file as loaded from disk
;; A6.L: Address of start of file
;;
;; Returns:
;;
;; ULS_bytes_loaded & ULS_bytes_loaded2 correctly for exit routine
;;

pack_header_process
	lea ULS_bytes_loaded2(pc),a5
	move.l d6,(a5)

	lea ULS_bytes_loaded(pc),a5
	move.l d6,(a5)			; save bytes loaded counter

	cmp.l #'ATM5',(a6)
	beq .its_packed4
	cmp.l #'LSD!',(a6)
	beq .its_packed4
	cmp.l #'Ice!',(a6)
	beq .its_packed
	cmp.l #'ICE!',(a6)
	beq .its_packed
	cmp.l #'FIRE',(a6)
	beq .its_packed
	cmp.l #'Fire',(a6)
	beq .its_packed
	rts

.its_packed4
	move.l 4(a6),(a5)
	rts

.its_packed
	move.l 8(a6),(a5)		; get original file length
	rts

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; 68030 cpu control
;;

;; VBR code - ok

mc68030_uls_on

	lea machine(pc),a6
	cmp.w #4,(a6)
	beq.s .dott
	cmp.w #4,(a6)
	beq.s .do30
	rts

.do30
; CPU STATE
	lea 	uls_cpus(pc),a1			; Restore its APPLICATION its state
	move.b	(a1),$ffff8007.w

.dott
; VBR
        moveq   #0,D0
        DC.L $4E7B0801  			; MOVEC     D0,VBR     Vektorbase=0 (eigentlich Standard)

; PMMU
run_tc  DC.L $F0394000,$DEADF030 		; PMOVE     pmmu_tab,TC
        DC.L $F0390800,$DEADF030 		; PMOVE     pmmu_tab,TT0
        DC.L $F0390C00,$DEADF030 		; PMOVE     pmmu_tab,TT1
skip

; Cache
    	moveq   #0,D0
	DC.L $4E7B0002  			; movec d0,cacr

	rts

mc68030_gem_on
	lea machine(pc),a6
	cmp.w #4,(a6)
	beq.s .dott
	cmp.w #4,(a6)
	beq.s .do30
	rts

.do30
; CPU STATE
	lea uls_cpus(pc),a0
	move.b $ffff8007.w,(a0)		; store current CPU state
	lea 	sys_FCPUC(pc),a0	; restore CPU mode
	move.b (a0),d0
	or.b #%00100101,d0
	move.b 	d0,$ffff8007.w

.dott
; VBR
	lea	SYS_VBR(pc),a0
	dc.l	$f0104c00		* pmove (a0),VBR *restore VBR*
; PMMU
	lea	SYS_PMMU(pc),a0		* restore tc/tt0/tt1
	dc.w	$f028,$4000,$0000	* pmove (a0),tc
	dc.w	$f028,$0800,$0004	* pmove 4(a0),tt0
	dc.w	$f028,$0c00,$0008	* pmove 8(a0),tt1
; CACHE
	dc.l	$f0002400		* pflusha - flush caches
	lea	SYS_cacr(pc),a0		* restore cache
	move.l	(a0),d0
	dc.l	$4e7b0002		* movec d0,cacr

	rts

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Memory block move 
;;
;; a0-source
;; a1-destination
;; d7-bytes to move
;;

block_move
	divu #48,d7
	swap.w d7
	move.w d7,-(a7)
	swap.w d7
	subq.w #1,d7			; itterations of 48 bytes
.mvloop	movem.l (a0)+,d0-6/a2-6
	movem.l d0-6/a2-6,(a1)
	lea 48(a1),a1
	dbra d7,.mvloop
	move.w (a7)+,d7			; overflow remainder
	beq.s .mdone
	subq.w #1,d7
.myloop	move.b (a0)+,(a1)+
	dbra d7,.myloop
.mdone	rts


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Process the filename & load address
;;
;; BBC DMA loader does not contain the '.' in the filename and is in RAW 11 byte format
;; Neil's loader does contain the '.' in the filename and is in 8.3 format
;;
;; expects:
;;	a0 - pointer to filename
;;	a1 - address to load at
;;
;; *Patched for odd source address of filename
;;

force_upper
	cmp.b #'a',d0
	blt.s .don
	cmp.b #'z',d0
	bgt.s .don
	sub.b #$20,d0
.don	rts

fn_temp	dc.l 0

process_filename
	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; print function status
	lea t_prfn(pc),a1
	bsr info
	movem.l (a7)+,d0-7/a0-6
	endc

	lea ULS_load_addr(pc),a6
	move.l a1,(a6)			; save IO address

	lea sys_filename(pc),a0
	move.l (a0),a0
	
	lea ULS_filename(pc),a1

	move.w #7,d7			; filename
.fna	move.b (a0)+,d0
	bsr force_upper
	cmp.b #' ',d0
	beq.s .space
	cmp.b #'.',d0
	beq.s .dotspace
	move.b d0,(a1)+

.space	dbra d7,.fna
	cmp.b #'.',(a0)
	bne.s .dotspace
	move.b (a0)+,d0
	
.dotspace				; if here, either 8th, dot or space
	lea fn_temp(pc),a6
	move.b (a0),(a6)
	move.b 1(a0),1(a6)
	move.b 2(a0),2(a6)
	clr.b 3(a6)			; make copy of extender
	tst.b (a0)
	beq .done			; no extender = don't '.' terminate
	cmp.l #$20202000,(a6)
	beq .done			; space extender = no extender = don't '.' terminate

	move.b #'.',(a1)+

	rept 3
	move.b (a0)+,d0
	cmp.b #' ',d0
	beq .done			; terminate on space
	tst.b d0
	beq .done			; and on null
	bsr force_upper
	move.b d0,(a1)+			; extender
	endr

.done	clr.b (a1)			; terminate with 0

	ifd adv_debug
	movem.l d0-d7/a0-a6,-(a7)	; display filename info

	lea ramdisk_enable(pc),a6
	cmp.l #'RAMD',(a6)
	beq.s .adv_dn
	lea t_proc(pc),a1
	lea prt_fn(pc),a0
	clr.l (a0)
	clr.l 4(a0)
	clr.l 8(a0)
	lea ULS_filename(pc),a2
.fncopy	move.b (a2)+,d0
	beq.s .fncopdone
	move.b d0,(a0)+
	bra.s .fncopy
.fncopdone
	move.b #-1,(a0)
	bsr info			; print filename
.adv_dn	movem.l (a7)+,d0-d7/a0-a6
	endc

	rts

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Restore GEMDOS system state
;;

restore_gemdos
	move.w #$2700,sr

	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; print function status
	lea t_sapp(pc),a1
	bsr info
	movem.l (a7)+,d0-7/a0-6
	endc

	lea $8.w,a0			; source
	lea ULS_SYS_mem(pc),a1
	move.l (a1),a1			; destination
	lea TOS_rambase(pc),a2		; last byte
	move.l (a2),d7
	bsr block_move			; save memory

	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; print function status
	lea t_satm1(pc),a1
	bsr info
	movem.l (a7)+,d0-7/a0-6
	endc

	lea APPmfp_save(pc),a1		; save MFP timer states
	bsr save_mfp

	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; print function status
	lea t_satm2(pc),a1
	bsr info
	movem.l (a7)+,d0-7/a0-6
	endc

	lea APPta_control(PC),A0
	lea APPta_data(PC),A3
	bsr save_timers

	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; print function status
	lea t_SPSG(pc),a1
	bsr info
	movem.l (a7)+,d0-7/a0-6
	endc

	lea APP_PSG(pc),a0
	bsr save_PSG

	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; print function status
	lea t_rgem(pc),a1
	bsr info
	movem.l (a7)+,d0-7/a0-6
	endc

	lea $8.w,a1			; destination
	lea ULS_TOS_mem(pc),a0
	move.l (a0),a0			; source
	lea TOS_rambase(pc),a2		; last byte
	move.l (a2),d7
	bsr block_move			; restore GEMDOS memory

	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; print function status
	lea t_683g(pc),a1
	bsr info
	movem.l (a7)+,d0-7/a0-6
	endc
	bsr mc68030_gem_on

	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; print function status
	lea t_retm1(pc),a1
	bsr info
	movem.l (a7)+,d0-7/a0-6
	endc

	lea GEMta_data(PC),A3
	lea GEMta_control(PC),A4
	bsr restore_timers

	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; print function status
	lea t_retm2(pc),a1
	bsr info
	movem.l (a7)+,d0-7/a0-6
	endc

	lea GEMmfp_save(pc),a1
	bsr restore_mfp

	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; print function status
	lea t_entcp(pc),a1
	bsr info
	movem.l (a7)+,d0-7/a0-6
	endc

	lea ULS_TimerC(pc),a0
	move.l a0,$114.w

	bclr #6,$fffffa15.w		; mask acia
 	bset.b #5,$fffffa09.w		
	bset.b #5,$fffffa15.w		
	lea APP_fa17(pc),a0	
	move.b $fffffa17.w,(a0)
	bclr.b #3,$fffffa17.w		; auto eoi!

	move.b #$c0,$fffffa23.w		; <- Timer C data (thnx Grazey)
	move.w #$2300,sr		; ok we need timer-c at least!

	move.l $4ba.w,d0
.wait	cmp.l $4ba.w,d0			; wait for a timer c tick
	beq.s .wait

	bsr falcon_delay
	
	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; print function status
	lea t_LPSG(pc),a1
	bsr info
	movem.l (a7)+,d0-7/a0-6
	endc

	lea SYS_PSG(pc),a0
	bsr load_PSG

;	lea $ffff8800.w,a0		; Force F30 IDE enable
;	move.b #14,(a0)
;	move.b (a0),d0
;	bset #7,d0
;	move.b #14,(a0)
;	move.b d0,2(a0)

.out	rts

ULS_TimerC
	add.l #1,$4ba.w
	ifd adv_debug
	move.w $ffff8240.w,-(a7)
	move.w #$700,$ffff8240.w	
	move.w (a7)+,$ffff8240.w	
	endc

	move.b #$c0,$fffffa23.w		; <- Timer C data (thnx Grazey)
	bclr.b #5,$fffffa11.w
	rte

falcon_delay
	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; print function status
	lea t_f30d(pc),a1
	bsr info
	movem.l (a7)+,d0-7/a0-6
	endc

	move.w sr,-(a7)
	move.w #$2700,sr
	movem.l d0-7/a0-6,-(a7)		; set up frame counter and delay for 7VBLS

	lea .my_rte(pc),a2		; ok now we only want the VBL running
	lea $64.w,a3
	lea my_vecs(pC),a4
	moveq #6,d0
.sa	move.l (a3),(a4)+
	move.l a2,(a3)+
	dbra d0,.sa
	move.l $110.w,(a4)+
	move.l a2,$110.w
	move.l $134.w,(a4)+
	move.l a2,$134.w
	move.l $120.w,(a4)+
	move.l a2,$120.w
	move.l $114.w,(a4)+
	move.l a2,$114.w

	lea cur_vbl+2(pc),a0		; works with 4 but i thought a "safety buffer" was a good idea
	move.l $70.w,(a0)		; (and its only 3/50ths of a second...)
	lea falc_vbl(pc),a0
	move.l a0,$70.w

	move.w #$2300,sr

	lea falc_frame(pc),a1
	move.w #24,(a1)			; re: was 6. then 12.
.hold	tst.w (a1)
	bpl.s .hold
.out	lea $64.w,a3
	lea my_vecs(pc),a4
	moveq #6,d0
.lo	move.l (a4)+,(a3)+
	dbra d0,.lo
	move.l (a4)+,$110.w
	move.l (a4)+,$134.w
	move.l (a4)+,$120.w
	move.l (a4)+,$114.w

	bclr.b #5,$fffffa11.w
	movem.l (a7)+,d0-7/a0-6
	move.w (a7)+,sr
	rts

.my_rte	rte

falc_vbl
	move.l a0,-(a7)			
	lea falc_frame(pc),a0		
	sub.w #1,(a0)
	move.l (a7)+,a0
cur_vbl	jmp $12345678


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Restore game environment
;;

restore_game_env
	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; print function status
	lea t_low(pc),a1
	bsr info
	movem.l (a7)+,d0-7/a0-6
	endc

	move.w #$2700,sr

	lea $8.w,a1			; destination
	lea ULS_SYS_mem(pc),a0
	move.l (a0),a0			; source
	lea TOS_rambase(pc),a2		; last byte
	move.l (a2),d7
	bsr block_move			; put memory back

	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; print function status
	lea t_683a(pc),a1
	bsr info
	movem.l (a7)+,d0-7/a0-6
	endc
	bsr mc68030_uls_on

	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; print function status
	lea t_retm3(pc),a1
	bsr info
	movem.l (a7)+,d0-7/a0-6
	endc

        lea APPta_data(PC),A3		; restore MFP timer data
        lea APPta_control(PC),A4
        bsr restore_timers

	lea APP_fa17(pc),a0	
	move.b (a0),$fffffa17.w		; restore EOI flag

	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; print function status
	lea t_retm4(pc),a1
	bsr info
	movem.l (a7)+,d0-7/a0-6
	endc

	lea APPmfp_save(pc),a1
        bsr restore_mfp

	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; print function status
	lea t_lpsga(pc),a1
	bsr info
	movem.l (a7)+,d0-7/a0-6
	endc

	lea APP_PSG(pc),a0
	bsr load_PSG
	
	bsr falcon_delay


	rts

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Load file (Using GEMDOS trap #1)
;;


load_file
	move.w #$2300,sr
	bsr falcon_delay

	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; print function status
	lea t_3d(pc),a1
	bsr info			
	movem.l (a7)+,d0-7/a0-6
	endc

	clr.w -(a7)			; open file
	pea ULS_fn_header(pc)		; push filename
	move.w #$3d,-(a7)		; GEMDOS fopen
	trap #1
	add.l #8,a7
	lea ULS_handle(pc),a5
	move.w d0,(a5)
	bmi .file_not_found

	lea fnf_flag(pc),a6
	clr.l (a6)		

	lea ULS_filebuffer(pc),a6
	move.l (a6),-(a7)		; read file into high memory 

	lea ULS_seek_offset(pc),a6
	move.l (a6),d0
	beq.s .nosk			; skip seek if 0

	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; print function status
	move.l d0,d1
	bsr hashing
	lea hexad(pc),a1
	lea t_seekoff(pc),a0
	move.l (a1)+,(a0)+
	move.l (a1),(a0)
	lea t_seek(pc),a1
	bsr info
	movem.l (a7)+,d0-7/a0-6
	endc

	clr.w -(a7)			; from start of file
	lea ULS_handle(pc),a5
	move.w (a5),-(a7)
	move.l d0,-(a7)			; this many bytes
	move.w #$42,-(a7)		; f_seek
	trap #1
	lea 10(a7),a7

.nosk
	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)
	lea ULS_filebuffer(pc),a6
	move.l (a6),d1
	bsr hashing			; address ULS loads data at 
	lea hexad(pc),a1
	lea t_3fa(pc),a0
	move.l (a1)+,(a0)+
	move.l (a1),(a0)
	lea ULS_load_addr(pc),a6	; address caller wants data loaded at
	move.l (a6),d1
	bsr hashing
	lea hexad(pc),a1
	lea t_3fb(pc),a0
	move.l (a1)+,(a0)+
	move.l (a1),(a0)
	lea t_3f(pc),a1
	bsr info			; print load address
	movem.l (a7)+,d0-7/a0-6
	endc

	lea ULS_bytes_io(pc),a6
	move.l (a6),d0			; get bytes to load
	bpl.s .shrtrd			; if 
	move.l #$400000,d0		; if -ve, set to 4mb (Practical file limit!)
.shrtrd	move.l d0,-(a7)
	lea ULS_handle(pc),a5
	move.w (a5),-(a7)
	move.w #$3f,-(a7)		; GEMDOS fread
	trap #1
	lea 12(a7),a7
	move.l d0,d6
	bmi io_error_oops

	lea ULS_filebuffer(pc),a6
	move.l (a6),a6
	bsr pack_header_process

.exit_read
	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)
	move.l (a5),d1			; print bytes processed (unpacked length)
	bsr hashing
	lea hexad(pc),a1
	lea t_3fda(pc),a0
	move.l (a1)+,(a0)+
	move.l (a1),(a0)
	lea t_3fd(pc),a1
	bsr info			; print bytes loaded
	movem.l (a7)+,d0-7/a0-6
	endc

	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; print function status
	lea t_3e(pc),a1
	bsr info			
	movem.l (a7)+,d0-7/a0-6
	endc

	lea ULS_handle(pc),a5
	move.w (a5),-(a7)
	move.w #$3e,-(a7)		; GEMDOS fclose
	trap #1
	addq.l #4,a7

	rts

.file_not_found
	lea fnf_flag(pc),a5
	move.l #-1,(a5)
	rts

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; save file (Using GEMDOS trap #1)
;;

overwrite	dc.w 0

save_file
	move.w #$2300,sr

	lea overwrite(pc),a6
	clr.w (a6)			; clear overwrite flag

	lea copy_data(pc),a6
	cmp.l #-1,(a6)			; check for F_Create (New file?)
	beq .create_new

	lea ULS_bytes_io(pc),a6		; replace file?
	cmp.l #-1,(a6)
	bne.s .new_size

	movem.l d0-a6,-(a7)

	lea overwrite(pc),a6
	move.w #1,(a6)			; set overwrite flag

	pea ULS_DTA(pc)			; set DTA
	move.w #$1a,-(a7)
	trap #1
	lea 6(a7),a7

	move.w #$02,-(a7)
	pea ULS_fn_header(pc)
	move.w #$4e,-(a7)
	trap #1				; get 1st entry
	lea 8(a7),a7

	lea ULS_DTA(pc),a0
	move.l 26(a0),-(a7)		; get filesize
	lea ULS_bytes_io(pc),a0
	move.l (a7)+,(a0)		; make the written file this big

	movem.l (a7)+,d0-a6
	bra .new_size

.create_new
	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; print function status
	lea t_40f(pc),a1
	bsr info			
	movem.l (a7)+,d0-7/a0-6
	endc

	clr.w -(a7)			; open file
	pea ULS_fn_header(pc)
	move.w #$3c,-(a7)		; GEMDOS fcreate
	trap #1
	add.l #8,a7
	move.w d0,d7			; file handle
	bmi io_error_oops		; loop if create error
	bra .nosk

.new_size
	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; print function status
	lea t_40f(pc),a1
	bsr info			
	movem.l (a7)+,d0-7/a0-6
	endc

	move.w #1,-(a7)			; open file for WRITE
	pea ULS_fn_header(pc)
	move.w #$3d,-(a7)		; GEMDOS f_open
	trap #1
	add.l #8,a7
	move.w d0,d7			; file handle
	bmi io_error_oops		; loop if create error

	lea ULS_seek_offset(pc),a6
	move.l (a6),d0
	beq.s .nosk			; skip seek if 0

	lea overwrite(pc),a6
	cmp.w #1,(a6)
	beq.s .nosk			; skip seek if overwriting

	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; print function status
	move.l d0,d1
	bsr hashing
	lea hexad(pc),a1
	lea t_seekoff(pc),a0
	move.l (a1)+,(a0)+
	move.l (a1),(a0)
	lea t_seek(pc),a1
	bsr info
	movem.l (a7)+,d0-7/a0-6
	endc

	clr.w -(a7)			; from start of file
	move.w d7,-(a7)
	move.l d0,-(a7)			; this many bytes
	move.w #$42,-(a7)		; f_seek
	trap #1
	lea 10(a7),a7

.nosk
	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)
	lea ULS_filebuffer(pc),a6
	move.l (a6),d1
	bsr hashing			; address ULS saved data from
	lea hexad(pc),a1
	lea t_40a(pc),a0
	move.l (a1)+,(a0)+
	move.l (a1),(a0)
	lea ULS_load_addr(pc),a6	; address caller wants data saved at
	move.l (a6),d1
	bsr hashing
	lea hexad(pc),a1
	lea t_40b(pc),a0
	move.l (a1)+,(a0)+
	move.l (a1),(a0)
	lea t_40(pc),a1
	bsr info			; print save address
	movem.l (a7)+,d0-7/a0-6
	endc

	lea ULS_filebuffer(pc),a6
	move.l (a6),-(a7)		; address of filebuffer
	lea ULS_bytes_io(pc),a6
	move.l (a6),-(a7)		; bytes to write

	move.w d7,-(a7)
	move.w #$40,-(a7)		; GEMDOS fwrite
	trap #1
	lea 12(a7),a7
	move.l d0,d6
	bmi io_error_oops

	lea ULS_bytes_loaded(pc),a6
	move.l d6,(a6)			; save bytes loaded counter

	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)
	move.l d6,d1			; print bytes processed
	bsr hashing
	lea hexad(pc),a1
	lea t_40da(pc),a0
	move.l (a1)+,(a0)+
	move.l (a1),(a0)
	lea t_40d(pc),a1
	bsr info			; print bytes saved
	movem.l (a7)+,d0-7/a0-6
	endc

	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; print function status
	lea t_3e(pc),a1
	bsr info			
	movem.l (a7)+,d0-7/a0-6
	endc

	move.w d7,-(a7)			
	move.w #$3e,-(a7)		; GEMDOS fclose
	trap #1
	addq.l #4,a7

	ifd adv_debug
	movem.l d0-7/a0-6,-(a7)		; print function status
	lea t_3e(pc),a1
	bsr info			
	movem.l (a7)+,d0-7/a0-6
	endc

	movem.l d0-7/a0-6,-(a7)
	lea ramdisk_enable(pc),a6	; if the file we just wrote is in the Ramdisk, we must now devalidate it
	cmp.l #'RAMD',(a6)
	bne.s .exit_write

	lea ULS_fn_header(pc),a5
	move.l (a5),d4

	lea ramdisk_base(pc),a5		; get address of RAMdisk base
	move.l (a5),a5
.finder
	lea ULS_filename(pc),a6		; filename requested
	move.l a5,-(a7)

	cmp.l 16(a5),d4			; same data folder?
	bne .err

	move.w #11,d0			; 12 chars/name
.floop	tst.b (a6)			; end of name?
	beq .foundit
	cmp.b (a5)+,(a6)+		; compare filename
	bne .err
	dbra d0,.floop			; name length overflow check
	bra .foundit			; all chars match!	
.err	move.l (a7)+,a5

	move.l 12(a5),d7
	btst #0,d7
	beq.s .notodd1
	addq.l #1,d7
	bclr #0,d7
.notodd1
	add.l d7,a5			; wrong name, get next pointer

	lea 20(a5),a5
	cmp.l #'END!',(a5)		; end of table?
	bne.s .finder
	bra .exit_write			; yes, file not in Ramdisk

.foundit
	cmp.b #'.',(a6)			; check if this is the end of the filename
	beq.s .noerr			; (dupe init characters check)
	tst.b (a6)
	bne .err

.noerr	move.l (a7)+,a5			; header!!
	move.l #$f0f0f0f0,(a5)+
	move.l #$0f0f0f0f,(a5)+		; trash the filename in the ramdisk table (Devalidate from Ramdisk!)

.exit_write
	movem.l (a7)+,d0-7/a0-6
	rts	

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; IO Error loop
;;

io_error_oops
	add.w #1,$ffff8240.w
	bra.s io_error_oops


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Bytecopy the loaded file to correct address (allows loading to any address)
;;
;;

bytecopy_file_down
	lea ULS_bytes_loaded2(pc),a6
	move.l (a6),d6			; bytes to move

	lea ULS_filebuffer(pc),a6
	move.l (a6),a0			; where we trap loaded file at

	lea ULS_load_addr(pc),a6
	move.l (a6),a1			; where it should have loaded

;	move.l a1,d0
;	cmp.l #$100000,d0		; is it trying to load above 1mb?
;	blt.s	.fload
;	bra io_error_oops

.fload	move.b (a0)+,(a1)+		; byte copy the file (must be byte - might be odd address/length)		
	subq.l #1,d6
	bne.s .fload

	rts

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Bytecopy the save-area to protected high memory address (allows GEM to overwrite data to be saved)
;;
;;

bytecopy_file_up
	lea ULS_filebuffer(pc),a6
	move.l (a6),a0			; address to move data to (temp storage)

	lea ULS_load_addr(pc),a6
	move.l (a6),a1			; address save data stars at

	lea ULS_bytes_io(pc),a6		; bytes to save
	move.l (a6),d6
	cmp.l #-1,d6
	bne.s .fwrit
	move.l #max_filesize,d6		; fill the buffer

.fwrit	move.b (a1)+,(a0)+		; byte copy the file 		
	subq.l #1,d6
	bne.s .fwrit

	rts	

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;
;; properly saving/restoring of the timer data registers
;; (hopefully)
;;
;; (w)Defjam/Checkpoint, September 2005
;; defjam_cp@gmx.net
;;

                OPT D+
flush_acia	move.w  D0,-(a7)
flush_acia_loop	btst    #0,$FFFFFC00.w
                beq.s   acia_empty
                move.b  $FFFFFC02.w,D0
                bra.s   flush_acia_loop
acia_empty	move.w  (a7)+,D0
                rts

save_mfp        lea     mfp_list(PC),A0
save_mfp_loop	movea.w (A0)+,A2
                move.b  (A2),(A1)+
                tst.w   (A0)
                bne.s   save_mfp_loop
                rts

restore_mfp     lea     mfp_list(PC),A0
restore_mfp_loop
                movea.w (A0)+,A2
                move.b  (A1)+,(A2)
                tst.w   (A0)
                bne.s   restore_mfp_loop
                rts

mfp_list        DC.W $FA07
                DC.W $FA09
                DC.W $FA13
                DC.W $FA15
                DC.W $FA17

                DC.W 0

save_timers
		move.b  $FFFFFA19.w,(A0)+ 	; ta_control - save timer control registers
                move.b  $FFFFFA1B.w,(A0)+ 	; tb_control
                move.b  $FFFFFA1D.w,(A0)+ 	; tcd_control

		move.w #$2700,sr
                clr.b   $FFFFFA19.w		; timers stop
                clr.b   $FFFFFA1B.w
                clr.b   $FFFFFA1D.w

		
                lea     timer_list(PC),A2
timer_save_loop	move.w  #$FA00,D0
                move.b  (A2)+,D0        	; tX_data
                movea.w D0,A0
                move.b  (A2)+,D0        	; tX_ctrl
                movea.w D0,A1
                move.b  (A2)+,D0        	; tX_ctrlSet
                bsr.s   evaluate_timer
                move.b  D0,(A3)+

                tst.b   (A2)
                bne.s   timer_save_loop

		clr.b   $FFFFFA19.w		; timers stop
                clr.b   $FFFFFA1B.w
                clr.b   $FFFFFA1D.w

                rts

restore_timers	
		clr.b   $FFFFFA19.w		; timers stop
                clr.b   $FFFFFA1B.w
                clr.b   $FFFFFA1D.w

                lea     timer_list(PC),A2	; restore timer_data
timer_data_restore
                move.w  #$FA00,D0
                move.b  (A2)+,D0        	; tX_data
                movea.w D0,A0
                addq.l  #2,A2           	; tX_ctrl, tX_ctrlSet

                move.b  (A3)+,D0        	; saved timer_data
                move.b  D0,(A0)
                tst.b   (A2)
                bne.s   timer_data_restore

                move.b  (A4)+,$FFFFFA19.w	; restore timer_control
                move.b  (A4)+,$FFFFFA1B.w
                move.b  (A4)+,$FFFFFA1D.w
	
                rts

timer_list
 	        DC.B $1F,$19,%00000101 		; ta_data, ta_ctrl, ta_ctrlSet 1:64
                DC.B $21,$1B,%00000101 		; tb_data, tb_ctrl, tb_ctrlSet 1:64
                DC.B $23,$1D,%01010000 		; tc_data, tc_ctrl, tc_ctrlSet 1:64
                DC.B $25,$1D,%00000101 		; td_data, td_ctrl, td_ctrlSet 1:64
                DC.B 0
                EVEN

evaluate_timer	move.w  #$1FFF,D1       	; timeout counter (if timer_data==1 !!)
		clr.l d2
                move.b  D0,(A1)         	; timer control: start
et_sync1	move.b  (A0),D0
                subq.b  #1,D0
                bne.s et_sync1
		move.w #$1fff,d1
et_sync_reload  move.b  (A0),D0
                subq.b  #1,D0
                dbne    D1,et_sync_reload
                addq.b  #1,D0
                clr.b   (A1)            	; timer control: stop
		rts

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Machine specific Video Setup routines
;;

detect_hardware
	movem.l d0-a6,-(a7)
	lea machine(pc),a5
	move.l	#"_MCH",d1			;cookie we want	
	move.l	$5a0.w,d0			;get address of cookie jar in d0
	beq.s	.nojar				;If zero, there's no jar.
	move.l	d0,a0				;move the address of the jar to a0
.search	tst.l	(a0)				;is this jar entry the last one ?
	beq.s	.nofind				;yes, the cookie was not found
	cmp.l	(a0),d1				;does this cookie match what we're looking for?
	beq.s	.foundit			;yes, it does.
	addq.l	#8,a0				;advance to the next jar entry
	bra.s	.search				;and start over
.nofind	moveq	#-1,d0				;a negative (-1) means cookie not found
	bra.s	.set_st
.nojar	moveq	#-2,d0				;a negative (-2) means there's no jar
	lea machine(pc),a5
	bra.s	.set_st				;no jar
.foundit
	cmp.l 	#$00030000,4(a0)
	beq	.set_f030
	cmp.l 	#$00010000,4(a0)
	beq	.set_ste
	cmp.l 	#$00010008,4(a0)		; this one is unofficial, NO Atari systems were released with this cookie
	beq	.set_ste			
	cmp.l	#$00010010,4(a0)
	beq	.set_mste
	cmp.l 	#$00020000,4(a0)
	beq	.set_tt
	cmp.l 	#$00010001,4(a0)
	beq	.set_stbook			

.set_st	clr.w (a5)
	movem.l (a7)+,d0-a6
	rts

.set_stbook
	move.b $ffff8260.w,d0
	cmp.b #2,d0				; HiRez Check
	bne.s .NotSTB
	bra machine_set
.NotSTB	illegal					; Pointless, but if here then Cookie Jar is fucked

.set_tt	move.w #4,(a5)
	movem.l (a7)+,d0-a6
	rts
	
.set_f030
	move.w #3,(a5)
	movem.l (a7)+,d0-a6
	rts

.set_ste
	move.w #1,(a5)
	movem.l (a7)+,d0-a6
	rts

.set_mste	
	move.w #2,(a5)
	movem.l (a7)+,d0-a6
	rts

setup_hardware
	lea machine(pc),a5
	tst.w (a5)
	beq vid_st	
	cmp.w #1,(a5)
	beq vid_ste
	cmp.w #2,(a5)
	beq vid_mste
	cmp.w #3,(a5)
	beq vid_f030
	cmp.w #4,(a5)
	beq vid_tt
error	add.w #1,$ffff8240.w
	bra.s error


vid_st
vid_tt
vid_ste
	bsr st_vidsetup
	bra machine_set

vid_mste
	bsr st_vidsetup
;	bclr #1,$ffff8e21.w
	bra machine_set

vid_f030
	bsr f030_vidsetup
	bra machine_set



st_vidsetup
	move.b #0,$ffff8260.w			; set STLOW
	rts

f030_vidsetup
	move.w	#$59,-(a7)			;check monitortype (falcon)
	trap	#14				;
	addq.l	#2,a7				;
	cmp.w	#1,d0				;if 1 = rgb
	beq.w	.rgb				;
	cmp.w	#3,d0				;if 3 = tv
	beq.w	.rgb				;otherwise assume vga (ignore mono..)

.vga60:	lea composite(pc),a0
	move.w #1,(a0)
	bsr save_videl
	move.l	#$170012,$ffff8282.w		;falcon 60Hz vga
	move.l	#$1020e,$ffff8286.w		;
	move.l	#$d0012,$ffff828a.w		;
	move.l	#$41903ff,$ffff82a2.w		;
	move.l	#$3f008d,$ffff82a6.w		;
	move.l	#$3ad0415,$ffff82aa.w		;
	move.w	#$200,$ffff820a.w		;
	move.w	#$186,$ffff82c0.w		;
	clr.w	$ffff8266.w			;
	clr.b	$ffff8260.w			;
	move.w	#$5,$ffff82c2.w			;
	move.w	#$50,$ffff8210.w		;
	bra.s	.fvideo_done

.rgb:	lea composite(pc),a0
	move.w #2,(a0)
	bsr save_videl
	move.l	#$300027,$ffff8282.w		;falcon 50Hz rgb
	move.l	#$70229,$ffff8286.w		;
	move.l	#$1e002a,$ffff828a.w		;
	move.l	#$2710265,$ffff82a2.w		;
	move.l	#$2f0081,$ffff82a6.w		;
	move.l	#$211026b,$ffff82aa.w		;
	move.w	#$200,$ffff820a.w		;
	move.w	#$185,$ffff82c0.w		;
	clr.w	$ffff8266.w			;
	clr.b	$ffff8260.w			;
	clr.w	$ffff82c2.w			;
	move.w	#$50,$ffff8210.w		;

.fvideo_done:
	rts

save_videl
	move.w #-1,-(a7)
	move.w #88,-(a7)
	trap #14
	lea 4(a7),a7				; falc screen mode
	lea falc_scr(pc),a0
	move.w d0,(a0)
	rts

machine_set
	clr.w -(a7)
	pea -1
	pea -1
	move.w #5,-(a7)
	trap #14
	lea 12(a7),a7
	rts

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Set 16Mhz (If available)
;;

set_16		lea machine(pc),a6
		cmp.w #2,(a6)
		beq .mste16
		cmp.w #3,(a6)
		beq .falc16
		rts

.mste16		lea old_mhz(pc),a6
		move.b $ffff8e21.w,(a6)
		bset.b #0,$ffff8e21.w
		rts

.falc16		lea old_mhz(pc),a6
		move.b $ffff8007.w,(a6)
		bset.b #0,$ffff8007.w
		rts

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Restore CPU speed back to entry conditions
;;

set_8		lea machine(pc),a6
		cmp.w #2,(a6)
		beq .mste8
		cmp.w #3,(a6)
		beq .falc8
		rts

.mste8		lea old_mhz(pc),a6
		move.b (a6),$ffff8e21.w
		rts

.falc8		lea old_mhz(pc),a6
		move.b (a6),$ffff8007.w	
		rts


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Read/Write PSG Port A/B status
;;

load_PSG	lea $ffff8800.w,a5   	; (Restore from A0)
		move.b #14,(a5)
		move.b (a0)+,d0
		bclr #7,d0		; enable falcon IDE
		move.b d0,2(a5)
		move.b #15,(a5)
		move.b (a0),2(a5)
		rts
	
save_PSG
		lea $ffff8800.w,a5   	; (Save to a0)
		move.b #14,(a5)
		move.b (a5),(a0)+
		move.b #15,(a5)
		move.b (a5),(a0)
		rts

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Falcon & TT  CPU / Cache / PMMU settings
;;

kill_f030
		lea machine(pc),a0			; check for falcon / tt
		cmp.w #4,(a0)
		beq.s .do_it
		cmp.w #3,(a0)
		beq.s .do_it
		rts
.do_it
		move    SR,-(a7)
        	move    #$2700,SR

		lea SYS_VBR(pc),a0			*
		dc.l $f0104e00				* pmove vbr,(a0) (Get VBR address)

		lea	SYS_PMMU(pc),a0			*save TC/TT0/TT1
		dc.w	$f028,$4200,$0000		*pmove tc,(a0)
		dc.w	$f028,$0a00,$0004		*pmove tt0,4(a0)
		dc.w	$f028,$0e00,$0008		*pmove tt1,8(a0)

        	lea     pmmu_table(PC),A0
		lea	run_tc+4(pc),a1
        	move.l  A0,(A1)         		; TC_access+4
        	move.l  A0,8(A1)        		; TT0_access+4
        	move.l  A0,16(A1)       		; TT1_access+4
		lea     TC_access+4(PC),A1
        	move.l  A0,(A1)         		; TC_access+4
        	move.l  A0,8(A1)        		; TT0_access+4
        	move.l  A0,16(A1)       		; TT1_access+4


        	movea.l $00000010.w,A6
        	pea     no_cacr(PC)			; disable CACHE
        	move.l  (a7)+,$00000010.w
        	moveq   #0,D0
        	DC.L $4E7A0002  			; movec cacr,d0
        	lea     SYS_cacr(PC),A5			*Save cache state
        	move.l  D0,(A5)
       	 	moveq   #0,D0
nop_me_out      DC.L $4E7B0002  			; movec d0,cacr

no_cacr 	nop
                pea     no_pmmu(PC)			; move the PMMU
                move.l  (a7)+,$00000010.w
                moveq   #0,D0
                DC.L $4E7B0801  			; MOVEC     D0,VBR     Vektorbase=0 (eigentlich Standard)

TC_access       DC.L $F0394000,$DEADF030 		; PMOVE     pmmu_tab,TC
TT0_access      DC.L $F0390800,$DEADF030 		; PMOVE     pmmu_tab,TT0
TT1_access      DC.L $F0390C00,$DEADF030 		; PMOVE     pmmu_tab,TT1

no_pmmu         nop
                move.l  A6,$00000010.w  		;restore old $10

		lea machine(pc),a6
		cmp.w #4,(a6)				; test for TT
		beq no_f030_proc_control

                movea.l $00000008.w,A6
                pea     no_f030_proc_control(PC)
                move.l  (a7)+,$00000008.w
                lea     $FFFF8007.w,A0  		; Falcon Processor Control
                move.b  (A0),D0
		lea 	sys_FCPUC(pc),a1		* Save its state
		move.b	d0,(a1)				*
                bclr    #5,D0           		; STe Bus Emulation  ON
                bclr    #2,D0           		; Blitter Speed      8 MHz
                move.b  D0,(A0)

no_f030_proc_control
		nop
                move.l  A6,$00000008.w  		;restore old $8
                move    (a7)+,SR
                rts
               
pmmu_table	DCB.W     4,0 				; F030 StartUp(boot) PMMU Table
      		DC.B      $79,$FF,$3C,$00,$00,$00,$00,$00 
		DCB.W     2,0 
	        DC.B      $79,$FF,$3C,$00,$00,$00,$00,$00 
	        DCB.W     2,0 
	        DC.B      $79,$FF,$3C,$00,$00,$00,$00,$00 
	        DCB.W     2,0 
	        DC.B      $79,$FF,$3C,$00,$00,$00,$00,$00 
	        DCB.W     2,0 
	        DC.B      $79,$FF,$3C,$00,$00,$00,$00,$00 
	        DCB.W     2,0 
	        DC.B      $79,$FF,$3C,$00,$00,$00,$00,$00 
	        DCB.W     2,0 
 	        DC.B      $79,$FF,$3C,$00,$00,$00,$00,$00 
	        DCB.W     2,0 
	        DC.B      $79,$FF,$3C,$00,$00,$00,$00,$00 
	        DCB.W     2,0 
	        DC.B      $79,$FF,$3C,$00,$00,$00,$00,$00 
	        DCB.W     2,0 
 	        DC.B      $79,$FF,$3C,$00,$00,$00,$00,$00 
	        DCB.W     2,0 
	        DC.B      $79,$FF,$3C,$00,$00,$00,$00,$00 
	        DCB.W     2,0 
	        DC.B      $79,$FF,$3C,$00,$00,$00,$00,$00 
	        DCB.W     2,0 
	        DC.B      $79,$FF,$3C,$00,$00,$00,$00,$00 
	        DCB.W     2,0 
	        DC.B      $79,$FF,$3C,$00,$00,$00,$00,$00 
	        DCB.W     2,0 
	        DC.B      $79,$FF,$3C,$00,$00,$00,$00,$00 
	        DCB.W     2,0 
	        DC.B      $79,$FF,$3C,$00,$00,$00,$00,$00 
	        DCB.W     2,0 
	        DC.B      $F9,$FF,$3E,$00,$00,$00,$00,$00 
	        DCB.W     2,0 
	        DC.B      $F9,$FF,$3E,$00,$00,$00,$00,$00 
	        DCB.W     2,0 
	        DC.B      $F9,$FF,$3E,$00,$00,$00,$00,$00 
	        DCB.W     2,0 
	        DC.B      $F9,$FF,$3E,$00,$00,$00,$00,$00 
 	        DCB.W     2,0 
	        DC.B      $F9,$FF,$3E,$00,$00,$00,$00,$00 
  
		EVEN



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; call with long to convert in d1
;; string placed at hexad
;;

hashing	moveq #0,d0
	lea .table(pc),a0
	lea hexad+8(pc),a2
	bsr.s .first
	moveq.w #5,d3
.loop	bsr.s .next
	dbra d3,.loop
.next	ror.l #4,d1
.first	move.b d1,d0
	and #$f,d0
	move.b (a0,d0),-(a2)
	rts


.table	dc.b "0123456789ABCDEF"
hexad	ds.l 2
	dc.l $ffffffff
	even

font_x	DC.B      $00,$38,$66,$00,$00,$00,$00,$18 		; the debug screen font
      	DC.B      $1E,$78,$00,$00,$00,$00,$00,$00 
      	DC.B      $7C,$38,$7C,$FE,$1C,$FE,$7E,$FE 
      	DC.B      $7C,$7C,$00,$00,$00,$00,$00,$7C 
      	DC.B      $00,$7C,$FC,$7E,$FC,$FE,$FE,$7E 
      	DC.B      $00,$38,$EE,$00,$00,$00,$00,$18 
      	DC.B      $3E,$7C,$00,$00,$00,$00,$00,$00 
      	DC.B      $FE,$78,$FE,$FC,$3C,$FE,$FE,$FE 
      	DC.B      $FE,$FE,$00,$00,$00,$00,$00,$EE 
      	DC.B      $00,$FE,$FE,$FE,$FE,$FE,$FE,$FE 
      	DC.B      $00,$38,$CC,$00,$00,$00,$00,$30 
      	DC.B      $38,$1C,$00,$00,$00,$00,$FC,$00 
      	DC.B      $0E,$00,$00,$00,$0C,$00,$00,$00 
      	DC.B      $06,$86,$60,$30,$00,$00,$00,$0E 
      	DC.B      $00,$06,$0E,$00,$06,$00,$00,$00 
      	DC.B      $00,$38,$00,$00,$00,$00,$00,$30 
      	DC.B      $38,$1C,$00,$00,$00,$00,$FC,$00 
      	DC.B      $C6,$38,$1C,$1C,$CC,$FC,$FC,$38 
      	DC.B      $7C,$7E,$60,$30,$00,$00,$00,$1C 
      	DC.B      $00,$FE,$FC,$C0,$E6,$FC,$FC,$EE 
      	DCB.W     4,0 
      	DC.B      $38,$1C,$00,$00,$30,$00,$00,$00 
      	DC.B      $E6,$38,$38,$0E,$FE,$0E,$EE,$70 
      	DC.B      $C6,$0E,$00,$00,$00,$00,$00,$30 
      	DC.B      $00,$FE,$C6,$C0,$E6,$E0,$E0,$E6 
      	DC.B      $00,$38,$00,$00,$00,$00,$00,$00 
      	DC.B      $3E,$7C,$00,$00,$60,$30,$00,$00 
      	DC.B      $FE,$FE,$7E,$EE,$1C,$EE,$EE,$70 
      	DC.B      $FE,$1C,$60,$30,$00,$00,$00,$00 
      	DC.B      $00,$EE,$FE,$FE,$FE,$FE,$E0,$FE 
      	DC.B      $00,$38,$00,$00,$00,$00,$00,$00 
      	DC.B      $1E,$78,$00,$00,$00,$30,$00,$00 
      	DC.B      $7C,$FE,$FE,$FC,$1C,$FC,$7C,$70 
      	DC.B      $7C,$78,$60,$60,$00,$00,$00,$30 
      	DC.B      $00,$EE,$FC,$7E,$FC,$FE,$E0,$7E 
      	DCB.W     20,0
      	DC.B      $EE,$7C,$0E,$EE,$E0,$EE,$C6,$7C 
      	DC.B      $FC,$7C,$FC,$7E,$FE,$EE,$EE,$C6 
      	DC.B      $C6,$EE,$FE,$00,$00,$00,$00,$00 
      	DCB.W     8,0 
      	DC.B      $EE,$7C,$0E,$FE,$E0,$FE,$E6,$FE 
      	DC.B      $FE,$FE,$FE,$FE,$FE,$EE,$EE,$C6 
      	DC.B      $EE,$EE,$FE,$00,$00,$00,$00,$00 
      	DCB.W     10,0
      	DC.B      $E0,$7E,$76,$0E,$0E,$0E,$0E,$00 
      	DC.B      $00,$EE,$00,$D6,$7C,$00,$00,$00 
      	DCB.W     10,0
      	DC.B      $FE,$38,$0E,$FC,$E0,$BE,$BE,$EE 
      	DC.B      $FE,$EE,$FC,$7C,$38,$EE,$EE,$BE 
      	DC.B      $38,$7C,$38,$00,$00,$00,$00,$00 
      	DCB.W     8,0 
      	DC.B      $EE,$38,$EE,$FE,$00,$D6,$DE,$EE 
      	DC.B      $FC,$EE,$FC,$0E,$38,$00,$EE,$7E 
      	DC.B      $7C,$38,$70,$00,$00,$00,$00,$00 
      	DCB.W     8,0 
      	DC.B      $EE,$7C,$EE,$EE,$FE,$C6,$CE,$FE 
      	DC.B      $E0,$FC,$EE,$FE,$38,$FE,$7C,$FE 
      	DC.B      $EE,$38,$FE,$00,$00,$00,$00,$00 
      	DCB.W     8,0 
      	DC.B      $EE,$7C,$7C,$E6,$FE,$C6,$C6,$7C 
      	DC.B      $E0,$7E,$EE,$FC,$38,$7E,$38,$EE 
      	DC.B      $C6,$38,$FE,$00,$00,$00,$00,$00 
      	DCB.W     48,0
	even

info_init
	lea font_x(pc),a0			; Font offsets for plotter
	move.l a0,d0
	move.l d0,d1
	add.l #40*8,d1
	lea ascii(pc),a1
	move.w #39,d2
.adder	move.l d0,(a1)
	move.l d1,160(a1)
	addq.l #1,d0
	addq.l #1,d1
	lea 4(a1),a1
	dbra d2,.adder
	rts

ascii	ds.l 80

next_add	dc.l 0
n1		dc.l 1
n2		dc.l 7
old_pal		ds.w 16

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Text plotting routine
;;
;; call with a1 pointing at text
;;       

info	lea ULS_scr(pc),a0
	move.l (a0),a0
	add.l (a1)+,a0
	lea next_add(pc),a3
	move.l a0,(a3)
	move.l #1,4(a3)		; n1
	move.l #7,8(a3)		; n2
.loop	moveq.l #0,d0
	move.b (a1)+,d0
	bpl.s .write
	cmp.b #-1,d0
	beq.s .wrap
.nextline
	move.l #1,4(a3)		; n1
	move.l #7,8(a3)		; n2
	move.l (a3),a0
	add.l #160*9,a0
	move.l a0,(a3)
	bra.s .loop
.wrap	rts
.write	cmp.b #'.',d0		; '.' and '-' are swapped in the font. cheap hack :P
	bne.s .nodot
	move.b #'-',d0
	bra.s .ch_ok
.nodot	cmp.b #'-',d0
	bne.s .ch_ok
	move.b #'.',d0
.ch_ok	sub.b #' ',d0
	add d0,d0
	add d0,d0
	lea ascii(pc),a2
	move.l (a2,d0),a2
	bsr.s .plotit
	bra .loop
.plotit	
x	set 0
y	set 0
	rept 8
	move.b x(a2),y(a0)
x	set x+40
y	set y+160
	endr
	add.l 4(a3),a0
	move.l 4(a3),-(a7)
	move.l 8(a3),4(a3)
	move.l (a7)+,8(a3)
	rts

	ifd adv_debug

;	dc.b "0123456789012345678901234567890123456789"

t_regi	dc.l 114*160
	dc.b "D0: "
t_d0	ds.b 8
	dc.b "  A0: "
t_a0	ds.b 8
	dc.b "  SR: "
t_sr	dc.b "    "
	dc.b " ",-2
	dc.b "D1: "
t_d1	ds.b 8
	dc.b "  A1: "
t_a1	ds.b 8
	dc.b " ",-2
	dc.b "D2: "
t_d2	ds.b 8
	dc.b "  A2: "
t_a2	ds.b 8
	dc.b " ",-2
	dc.b "D3: "
t_d3	ds.b 8
	dc.b "  A3: "
t_a3	ds.b 8
	dc.b " ",-2
	dc.b "D4: "
t_d4	ds.b 8
	dc.b "  A4: "
t_a4	ds.b 8
	dc.b " ",-2
	dc.b "D5: "
t_d5	ds.b 8
	dc.b "  A5: "
t_a5	ds.b 8
	dc.b " ",-2
	dc.b "D6: "
t_d6	ds.b 8
	dc.b "  A6: "
t_a6	ds.b 8
	dc.b " ",-2
	dc.b "D7: "
t_d7	ds.b 8
	dc.b "  A7: "
t_a7	ds.b 8

	dc.b -1

	even

t_uls	dc.l (132*160)+112
	dc.b "UNIVERSAL",-2,"LOADING",-2,"SYSTEM",-2,"2005-2008",-2,"D-BUG",-1
	even

t_read	dc.l 010*160
	dc.b "ULS FUNCTION: READ",-1
	even

t_save	dc.l 010*160
	dc.b "ULS FUNCTION: WRITE",-1
	even

t_proc	dc.l 020*160
	dc.b "PROCESSING FILE: ",-2
prt_fn	ds.b 12
	dc.b -1
	even

t_ulsb	dc.l (0*160)+80
	dc.b "ULS BASE: " 
t_ulsba	ds.b 8
	dc.b -1
	even

t_gemb	dc.l (10*160)+80
	dc.b "GEM BASE: "
t_gemba	ds.b 8
	dc.b -1
	even

t_appb	dc.l (20*160)+80
	dc.b "APP BASE: "
t_appba	ds.b 8
	dc.b -1     

t_hiby	dc.l (30*160)+80
	dc.b "STUB ADD: "
t_hibya	ds.b 8
	dc.b -1  

t_init	dc.l 192*160
	dc.b "ULS EXECUTION:    "  
	dc.b "ENTERING ULS!        ",-1
	even	even

t_done	dc.l (192*160)+64
	dc.b "ALL DONE.            ",-1
	even

t_wrcd	dc.l (192*160)+64
	dc.b "WRITE COOLDOWN       ",-1
	even

t_f30d	dc.l (192*160)+64
	dc.b "FALCON IDE DELAY     ",-1
	even

t_scr	dc.l (192*160)+64
	dc.b "SCREENSHOT FUNCTION  ",-1
	even

t_seek	dc.l (192*160)+64
	dc.b "SEEK OFFSET "
t_seekoff	dc.b "        ",-1
	even

t_683a	dc.l (192*160)+64
	dc.b "RESTORING ULS 68030  ",-1
	even

t_683g	dc.l (192*160)+64
	dc.b "RESTORING APP 68030  ",-1
	even

t_rgem	dc.l (192*160)+64
	dc.b "RESTORING GEMDOS RAM ",-1
	even

t_prfn	dc.l (192*160)+64
	dc.b "PROCESS FILENAME     ",-1
	even

t_sapp	dc.l (192*160)+64
	dc.b "SAVING APP RAM       ",-1
	even

t_entcp	dc.l (192*160)+64
	dc.b "ENABLE ULS TIMER C   ",-1
	even

t_lpsga	dc.l (192*160)+64
	dc.b "LOADING APP PSG      ",-1
	even

t_satm1	dc.l (192*160)+64
	dc.b "SAVING APP MPF (RAW) ",-1
	even

t_satm2	dc.l (192*160)+64
	dc.b "SAVING APP MFP (TIM) ",-1
	even

t_retm1	dc.l (192*160)+64
	dc.b "LOADING GEM MFP (RAW)",-1
	even

t_retm2	dc.l (192*160)+64
	dc.b "LOADING GEM MFP (TIM)",-1
	even

t_retm3	dc.l (192*160)+64
	dc.b "LOADING APP MFP (RAW)",-1
	even

t_retm4	dc.l (192*160)+64
	dc.b "LOADING APP MFP (TIM)",-1
	even

t_LPSG	dc.l (192*160)+64
	dc.b "LOADING GEM PSG      ",-1
	even

t_SPSG	dc.l (192*160)+64
	dc.b "SAVING APP PSG       ",-1
	even

t_low	dc.l (192*160)+64
	dc.b "RESTORING LOW MEMORY ",-1
	even	

t_flshc	dc.l (192*160)+64
	dc.b "FLUSH 68030 CACHES   ",-1
	even

t_rdta	dc.l (192*160)+64
	dc.b "RESET DTA POINTER    ",-1
	even

t_ssfc	dc.l (192*160)+64
	dc.b "CREATE STATE FILE    ",-1
	even

t_ssfo	dc.l (192*160)+64
	dc.b "OPEN STATE FILE      ",-1
	even

t_ssdh	dc.l (192*160)+64
	dc.b "DUMPING HEADER INFO  ",-1
	even

t_ssrh	dc.l (192*160)+64
	dc.b "READING HEADER INFO  ",-1
	even

t_ssdl	dc.l (192*160)+64
	dc.b "DUMP RAM (LOW COPY)  ",-1
	even

t_ssrl	dc.l (192*160)+64
	dc.b "READ RAM (LOW COPY)  ",-1
	even

t_ssdn	dc.l (192*160)+64
	dc.b "DUMP RAM (MAIN)      ",-1
	even

t_ssrn	dc.l (192*160)+64
	dc.b "READ RAM (MAIN)      ",-1
	even

t_ssdv	dc.l (192*160)+64
	dc.b "DUMP ULS VARIABLES   ",-1
	even

t_ssrv	dc.l (192*160)+64
	dc.b "READ ULS VARIABLES   ",-1
	even

t_ssrr	dc.l (192*160)+64
	dc.b "READ APP REGISTERS   ",-1
	even

t_ssdr	dc.l (192*160)+64
	dc.b "DUMP APP REGISTERS   ",-1
	even

t_sscf	dc.l (192*160)+64
	dc.b "CLOSE STATE FILE     ",-1
	even

t_3e	dc.l 100*160
	dc.b "CLOSING FILE     ",-1
	even

t_40f	dc.l 100*160
	dc.b "WRITE FILE       ",-1
	even

t_3d	dc.l 050*160
	dc.b "OPENING FILE     ",-1
	even

t_jmp	dc.l (000*160)
	dc.b "CALLED FROM:     ",-2
t_jmpa	ds.b 8
	dc.b -1
	even

t_3f	dc.l 060*160
	dc.b "READING FILE AT: ",-2
t_3fa	ds.b 8
	dc.b "   ("
t_3fb	ds.b 8
	dc.b ")"
	dc.b -1
	even

t_3fd	dc.l 080*160
	dc.b "NUMBER OF BYTES: ",-2
t_3fda	ds.b 8
	dc.b -1
	even

t_40	dc.l 060*160
	dc.b "WRITING FILE AT: ",-2
t_40a	ds.b 8
	dc.b "   ("
t_40b	ds.b 8
	dc.b ")"
	dc.b -1
	even

t_40d	dc.l 080*160
	dc.b "NUMBER OF BYTES: ",-2
t_40da	ds.b 8
	dc.b -1
	even
	endc

t_curs_on	dc.l (160*9)*5
		dc.b " -",-1
		even

t_curs_off	dc.l (160*9)*5
		dc.b "  ",-1
		even

t_savestate
;	dc.b "012345678901234567890123456789123456789"
	dc.l 160*9
	dc.b " -------------------------------------",-2
	dc.b "  ULS V3.1 MEMORY SNAPSHOT MANAGEMENT ",-2
	dc.b " -------------------------------------",-2
	dc.b -2
t_sav0	dc.b "  0  NO FILE FOUND                    ",-2
	dc.b "  1  NO FILE FOUND                    ",-2
	dc.b "  2  NO FILE FOUND                    ",-2
	dc.b "  3  NO FILE FOUND                    ",-2
	dc.b "  4  NO FILE FOUND                    ",-2
	dc.b "  5  NO FILE FOUND                    ",-2
	dc.b "  6  NO FILE FOUND                    ",-2
	dc.b "  7  NO FILE FOUND                    ",-2
	dc.b "  8  NO FILE FOUND                    ",-2
	dc.b "  9  NO FILE FOUND                    ",-2
	dc.b -2
	dc.b " USE CURSOR UP AND DOWN TO MOVE AND",-2
	dc.b " ENTER TO SELECT.",-2
	dc.b " PRESS ESC TO EXIT BACK TO GAME",-2
t_kill	dc.b -2
	dc.b " YOU CAN TYPE UP TO 31 CHARS FOR A",-2
	dc.b " COMMENT FOR EACH SAVE SLOT.",-1
	even

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; ULS Auto-Ramdisk Pre-Builder 
;;

init_ramdisk
	move.w sr,-(a7)
	move.w #$2300,sr

	lea initial_rd_folder(pc),a0
	move.l (a0),-(a7)
	lea local_fn(pc),a0
	move.l (a7)+,(a0)		; copy initial folder to ramdisk creation

	lea ULS_DTA(pc),a0		; clear local DTA buffer
	lea 44(a0),a1
.ww	clr.b (a0)+
	cmp.l a0,a1
	bne.s .ww

	lea ramdisk_spec(pc),a0
	move.l (a0),a0
	lea local_fn+5(pc),a1
	moveq #11,d0
.qq	move.b (a0)+,(a1)+
	dbra d0,.qq

	pea ULS_DTA(pc)		; set DTA
	move.w #$1a,-(a7)
	trap #1
	lea 6(a7),a7

	lea ramdisk_base(pc),a6
	move.l (a6),a6		; base of ramdisk

	move.w #$02,-(a7)
	lea local_fn(pc),a0
	move.l a0,-(a7)
	move.w #$4e,-(a7)
	trap #1			; get 1st entry
	lea 8(a7),a7

	bsr .proc_ramdisk

.rdloop	move.w #79,-(a7)
	trap #1			; get next
	add.l #2,a7
	tst.w d0
	bmi.s .out
	bsr .proc_ramdisk
	bra .rdloop

.out	lea end_of_ramdisk(pc),a0
	move.l a6,(a0)		; store end-of-ramdisk (for append)

	move.l #'END!',(a6)+	; end of table marker
	move.l #'END!',(a6)+
	clr.l (a6)+
	clr.l (a6)+
	
	move.w (a7)+,sr

	rts

.proc_ramdisk
	lea ULS_DTA+30(pc),a5
	move.l a6,a4		 ; pointer to next entry
	moveq #11,d7
.fnm	move.b (a5)+,d0
	beq.s .done
	move.b d0,(a4)+		 ; filename
	dbra d7,.fnm
.done	move.l a6,a4
	move.l ULS_DTA+26(pc),d6
	move.l d6,d7
	add.l #1,d7
	bclr #0,d7
	move.l d7,-(a7)
;	add.l #1,d6
;	bclr #0,d6
	move.l d6,12(a4) 	; length

	move.l a6,d6
	lea local_fn+5(pc),a5
	move.w #11,d5
.fn	move.b (a6)+,(a5)+
	dbra d5,.fn
	lea -12(a6),a6

	clr.w -(a7)
	pea local_fn(pc)	; push filename
	move.w #$3d,-(a7)
	trap #1
	move.w d0,d7
	lea 8(a7),a7

	add.l #20,d6
	move.l d6,-(a7)		; address to start at
	move.l #$f0000,-(a7)	; bytes to load
	move.w d7,-(a7)		; handle
	move.w #$3f,-(a7)	; read
	trap #1
	lea 12(a7),a7

	move.w d7,-(a7)
	move.w #$3e,-(a7)
	trap #1			; close
	lea 4(a7),a7
	
	ifd adv_debug
	move.l a4,-(a7)
	lea local_fn(pc),a4
killadb	bsr i_prnt
	lea i_lfcr,a4
killadc	bsr i_prnt
	move.l (a7)+,a4
	endc

	lea local_fn(pc),a5
	move.l (a5),16(a4)	; 4 char DIR name to ramdisk

	add.l (a7)+,a6
;	add.l 12(a4),a6
	add.l #20,a6
		
	rts

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; ULS Auto-Ramdisk Updater 
;;

end_of_ramdisk	dc.l 0		; end of ramdisk (where End of Table markers are)
new_rd_dir	dc.l 0		; 4 char ascii of foldername
rd_update_type	dc.w 0		; -1 = refresh / 1 = append
new_rd_filespec	dc.l 0		; pointer to new filespec

update_ramdisk
	ifd adv_debug
	lea killadb(pc),a0
	move.l #$4e714e71,(a0)	; disable CONOUT (as game is now running no terminal screen)
	lea killadc(pc),a0
	move.l #$4e714e71,(a0)
	endc

	lea new_rd_filespec(pc),a0
	move.l (a0),-(a7)
	lea ramdisk_spec(pc),a0
	move.l (a7)+,(a0)

	lea rd_update_type(pc),a0
	cmp.w #-1,(a0)
	beq .rebuild_ramdisk
.append_ramdisk
	lea ramdisk_base(pc),a0
	move.l (a0),-(a7)	; store RAMdisk base address
	lea end_of_ramdisk(pc),a1
	move.l (a1),(a0)	; store End pointer as start (append)
	lea new_rd_dir(pc),a0
	move.l (a0),d0
	lea initial_rd_folder(pc),a0
	move.l d0,(a0)		; change the folder name
	bsr init_ramdisk
	lea ramdisk_base(pc),a0
	move.l (a7)+,(a0)	; restore RAMdisk base
	rts

.rebuild_ramdisk
	lea new_rd_dir(pc),a0
	move.l (a0),d0		; change the folder name
	lea initial_rd_folder(pc),a0
	move.l d0,(a0)
	bsr init_ramdisk	; rebuild the RAMdisk
	rts

local_fn
	dc.b "DATA\"
	ds.b 12
	even

ULS_DTA	ds.b 44

	even
	ds.b 2048		; some local stack space, can probably be reduced.
ULS_stk	ds.b 2

	ds.b 512		; "just in case"
ULS_TRASH_RAM