; -----------------------------------------------------------------------------
; 680x0 Second Processor CiscOS v2.02 (c) Eelco Huininga 2007-2015
; DOS Filename   : CiscOS.x68
; Load address   : FFFF0000 for 68020+ / 00FF0000 for 68000 / 003F0000 for 68008
; Exec address   : FFFF0200 for 68020+ / 00FF0200 for 68000 / 003F0200 for 68008
; Length         : 00008000
; -----------------------------------------------------------------------------
;
; Thanks to Jonathan Harston and Dave (Hoglet) for their code reviews and additions

; -----------------------------------------------------------------------------
; ALIGN macro
; -----------------------------------------------------------------------------

ALIGN   MACRO
	IFARG   1
	DS.B    (*-1)/\1*\1+\1-*
	MEXIT
	ENDC
	DS.B    (*+3)&-4-*
	ENDM

; -----------------------------------------------------------------------------
; Compiler constants
; -----------------------------------------------------------------------------


DEBUG	SET 0                                     ; Set DEBUG to 0 for real hardware operation
                                                  ; Set DEBUG to 1 for Easy68k simulator operation

; Memory map for 68008 issue 3 board:
; RAM		000000-2FFFFF
; (nothing)	300000-3DFFFF
; TUBECS	3E0000-3EFFFF
; ROMCS		3F0000-3FFFFF

stacksize	             EQU	$00000200		; Size of stack is 512 bytes
prompt	                     EQU	$2A			; Prompt
flash_rom_sectors	     EQU	$08			; Am29F040 has 8 sectors, 64k each
max_ram_size	             EQU	$00300000               ; Address at which checkramsize will stop
bios_version	             SET	'v2.02 (20150913)'	; BIOS version
biossize                     EQU	$00008000               ; Size of BIOS ROM


; -----------------------------------------------------------------------------
; Hardware addresses
;
; OS workspace: SWI vectors, OS variables
; -----------------------------------------------------------------------------
vector_table                 EQU	$00000000 ; Hardware vectors are at $00000000

userv	                     EQU	$00000400 ; $00 UserV              (Not implemented)
errorv                       EQU	$00000404 ; $01 ErrorV
irqv	                     EQU	$00000408 ; $02 IrqV
wrchv	                     EQU	$0000040C ; $03 WrchV
readcv	                     EQU	$00000410 ; $04 ReadCV
cliv	                     EQU	$00000414 ; $05 CliV
bytev	                     EQU	$00000418 ; $06 ByteV
wordv	                     EQU	$0000041C ; $07 WordV
filev	                     EQU	$00000420 ; $08 FileV
argsv	                     EQU	$00000424 ; $09 ArgsV
bgetv	                     EQU	$00000428 ; $0A BgetV
bputv	                     EQU	$0000042C ; $0B BputV
gbpbv	                     EQU	$00000430 ; $0C GBPBV
findv	                     EQU	$00000434 ; $0D FindV
readlinev                    EQU	$00000438 ; $0E ReadLineV
fscontrolv                   EQU	$0000043C ; $0F FSControlV
eventv	                     EQU	$00000440 ; $10 EventV
uptv                         EQU	$00000444 ; $11 UPTV (Arthur OS)   (Reserved)
netv                         EQU	$00000448 ; $12 NETV (Arthur OS)   (Reserved)
keyv	                     EQU	$0000044C ; $13 KeyV               (Not implemented)
insv	                     EQU	$00000450 ; $14 InsV               (Not implemented)
remv	                     EQU	$00000454 ; $15 RemV               (Not implemented)
cnpv                         EQU	$00000458 ; $16 CnpV               (Not implemented)
ukvdu23v                     EQU	$0000045C ; $17 UKVDU23V           (Not implemented)
ukswiv                       EQU	$00000460 ; $18 UKSWIV
ukplotv                      EQU	$00000464 ; $19 UKPLOTV            (Not implemented)
mousev                       EQU	$00000468 ; $1A MouseV             (Not implemented)
vduxv                        EQU	$0000046C ; $1B VDUXV              (Not implemented)
tickerv                      EQU	$00000470 ; $1C TickerV            (Not implemented)
upcallv                      EQU	$00000474 ; $1D UpCallV            (Not implemented)
changeenvironmentv           EQU	$00000478 ; $1E ChangeEnvironmentV
spritev                      EQU	$0000047C ; $1F SpriteV            (Not implemented)
drawv                        EQU	$00000480 ; $20 DrawV              (Not implemented)
econetv                      EQU	$00000484 ; $21 EconetV            (Not implemented)
colourv                      EQU	$00000488 ; $22 ColourV            (Not implemented)
palettev                     EQU	$0000048C ; $23 PaletteV           (Not implemented)
serialv                      EQU	$00000490 ; $24 SerialV            (Not implemented)
fontv                        EQU	$00000494 ; $25 FontV              (Not implemented)
pointerv                     EQU	$00000498 ; $26 PointerV           (Not implemented)
timesharev                   EQU	$0000049C ; $27 TimeShareV         (Not implemented)
lowpriorityeventv            EQU	$000004A0 ; $28 LowPriorityV       (Not implemented)
fasttickerv                  EQU	$000004A4 ; $29 FastTickerV        (Not implemented)
graphicsv                    EQU	$000004A8 ; $2A GraphicsV          (Not implemented)
unthreadv                    EQU	$000004AC ; $2B UnthreadV          (Reserved)
;	                     EQU	$000004B0 ; $2C Reserved
;	                     EQU	$000004B4 ; $2D Reserved
;	                     EQU	$000004B8 ; $2E Reserved
;	                     EQU	$000004BC ; $2F Reserved

otherexceptionsv             EQU	$000004C0
callbackv                    EQU	$000004C4 ; 140 CallBack handler address
breakpointv                  EQU	$000004C8 ; 14C BreakPoint handler address
escapev                      EQU	$000004CC ; 158 Escape handler address
exitv                        EQU	$000004D0 ; 57C Exit handler address
error_wkspc_ptr              EQU	$000004D4 ; 138 R0 on entry to Error handler
callback_wkspc_ptr           EQU	$000004D8 ; 13C R12 on entry to CallBack handler
breakpoint_wkspc_ptr         EQU	$000004DC ; 148 R12 on entry to BreakPoint handler
escape_wkspc_ptr             EQU	$000004E0 ; 154 R12 on entry to Escape handler
event_wkspc_ptr              EQU	$000004E4 ; 15C R12 on entry to Event handler
exit_wkspc_ptr               EQU	$000004E8 ; 580 R12 on entry to Exit handler
unusedswi_wkspc_ptr          EQU	$000004EC ; 574 R12 on entry to Unused SWI handler
upcall_wkspc_ptr             EQU	$000004F0 ; 584 R12 on entry to UpCall handler
error_buffer_ptr             EQU	$000004F4 ; 134 Pointer to Error buffer
callback_buffer_ptr          EQU	$000004F8 ; 144 Pointer to CallBack register buffer
breakpoint_buffer_ptr        EQU	$000004FC ; 150 Pointer to BreakPoint register buffer

himem	                     EQU	$00000500 ; HIMEM: top of RAM excluding the stack
oshwm	                     EQU	$00000504 ; OSHWM: bottom of RAM; reserve page 4-7 for the OS
ramsize	                     EQU	$00000508 ; RAMSIZE: Total size of RAM available
applicationspace             EQU	$0000050C ; OS_ChangeEnvironment #14
error_pc	             EQU	$00000510 ; Pointer to location where last error occurred
error	                     EQU	$00000514 ; Pointer to last generated error block
returncode                   EQU	$00000518 ; Exit handler: Sys$ReturnCode (return code)
returncodelimit              EQU	$0000051C ; Exit handler: Sys$RCLimit (return code limit)
tubetransfer	             EQU	$00000520 ; Start address used for TUBE data transfers (NMI/INT5)
hoaddr	                     EQU	$00000524 ; High order pointer
osstarttime	             EQU	$00000528 ; OS start time (5 bytes)
programstarttime	     EQU	$0000052D ; Program start time (5 bytes)
cputype	                     EQU	$00000532 ; CPU type ($01=68008, $02=68000, $03=68010, $04=68020, $05=68030, $06=68040, $07=68060, $FF=unknown CPU)
fputype	                     EQU	$00000533 ; FPU type ($00=no FPU, $01=68881, $02=68882, $03=CPU integrated(68040/68060), $FF=unknown FPU)
mmutype	                     EQU	$00000534 ; MMU type ($00=no MMU, $01=68841, $02=68851, $03=CPU integrated(68030/68040/68060), $FF=unknown MMU)
escapeflag	             EQU	$00000535 ; Escape flag (bit 6=1 if ESCAPE condition)
                                                  ; Reserved
                                                  ; Reserved
exceptionregs                EQU	$00000538 ; Location where exception stack is dumped after an type 0 exception


buffer	                     EQU	$00000600 ; OSWORD &00 and OSCLI buffer

errorbuffer                  EQU	$00000700 ; Error buffer

	IFEQ DEBUG
r1status	             EQU	$FFFE0000 ; TUBE base address FFFE0000-FFFEFFFF (3E0000-3EFFFF for 68008)
	ENDC
	IFNE DEBUG
r1status	             EQU	$003E0000 ; TUBE base address 003E0000-003EFFFF for Easy68k emulator
	ENDC
r1data	                     EQU	r1status+1
r2status	             EQU	r1status+2
r2data	                     EQU	r1status+3
r3status	             EQU	r1status+4
r3data	                     EQU	r1status+5
r4status	             EQU	r1status+6
r4data	                     EQU	r1status+7

	IFEQ DEBUG
bios_address	             EQU	$FFFF0000 ; BIOS base address FFFF0000-FFFFFFFF (3F0000-3FFFFF for 68008)
	ENDC
	IFNE DEBUG
bios_address	             EQU	$003F0000 ; BIOS base address 003F0000-003FFFFF for Easy68k emulator
	ENDC



; -----------------------------------------------------------------------------
; Start of code
; -----------------------------------------------------------------------------

START
	INCLUDE	"SWIs.inc"

	IFNE DEBUG
		JMP	bios_address+$00000200
		ORG	$00008000
		INCBIN	"..\..\roms\Acorn\BASIC\Basic 2.rom"              ; Included for testing OSBYTE &8E (Jump to language rom), can be removed in final build
	ENDC

	ORG	bios_address
	                                          ;           CPU Reset vectors
	DC.L	$00000620                         ; $00000000  0: Initial stack pointer (initially in the general OS buffer)
	DC.L	reset_entry                       ; $00000004  1: Initial program counter (start address)
	                                          ;           CPU Exception vectors
	DC.L	bus_error_handler                 ; $00000008  2: Bus error
	DC.L	address_error_handler             ; $0000000C  3: Address error
	DC.L	illegal_instruction_handler       ; $00000010  4: Illegal instruction
	DC.L	int_divide_by_zero_handler        ; $00000014  5: Integer divide-by-zero
	DC.L	unknown_exception                 ; $00000018  6: CHK, CHK2 instruction
	DC.L	unknown_exception                 ; $0000001C  7: FTRAPcc, TRAPcc, TRAPV instruction
	DC.L	privilege_violation_handler       ; $00000020  8: Privilege violation
	DC.L	unknown_exception                 ; $00000024  9: Trace
	DC.L	unknown_exception                 ; $00000028 10: Line 1010 emulator (unimplemented A-line opcode)
	DC.L	unknown_exception                 ; $0000002C 11: Line 1111 emulator (unimplemented F-line opcode) / Floating-point unimplemented instruction / Floating-point disabled
	DC.L	unknown_exception                 ; $00000030 12: Emulator interrupt (MC68060 only)
	DC.L	unknown_exception                 ; $00000034 13: Coprocessor Protocol Violation (MC68020 & MC68030 only)
	DC.L	unknown_exception                 ; $00000038 14: Format Error ( >= MC68010)
	DC.L	unknown_exception                 ; $0000003C 15: Uninitialized interrupt vector
	DC.L	unknown_exception                 ; $00000040 16: (reserved)
	DC.L	unknown_exception                 ; $00000044 17: (reserved)
	DC.L	unknown_exception                 ; $00000048 18: (reserved)
	DC.L	unknown_exception                 ; $0000004C 19: (reserved)
	DC.L	unknown_exception                 ; $00000050 20: (reserved)
	DC.L	unknown_exception                 ; $00000054 21: (reserved)
	DC.L	unknown_exception                 ; $00000058 22: (reserved)
	DC.L	unknown_exception                 ; $0000005C 23: (reserved)
	DC.L	unknown_exception                 ; $00000060 24: Spurious Interrupt (Bus error during interrupt)
	                                          ;           Auto-vector interrupts
	DC.L	_irqv                             ; $00000064 25: Level-1 autovector (INT1)
	DC.L	irq_handler                       ; $00000068 26: Level-2 autovector (INT2) TUBE ULA IRQ
	DC.L	_irqv                             ; $0000006C 27: Level-3 autovector (INT3)
	DC.L	_irqv                             ; $00000070 28: Level-4 autovector (INT4)
	DC.L	nmi_handler                       ; $00000074 29: Level-5 autovector (INT5) TUBE ULA NMI
	DC.L	_irqv                             ; $00000078 30: Level-6 autovector (INT6)
	DC.L	_irqv                             ; $0000007C 31: Level-7 autovector (INT7)
	                                          ;           TRAP instruction vectors
	DC.L	unknown_exception                 ; $00000080 32: TRAP 0 vector (Unix system calls & OS/9 system call)
	DC.L	unknown_exception                 ; $00000084 33: TRAP 1 vector (Unix indirect system calls & Atari GEMDOS BDOS interface & Sinclair QDOS manager)
	DC.L	unknown_exception                 ; $00000088 34: TRAP 2 vector (CP/M BDOS calls & Atari AES and VDI & Sinclair QDOS basic I/O)
	DC.L	unknown_exception                 ; $0000008C 35: TRAP 3 vector (CP/M BIOS calls & Sinclair QDOS complex I/O)
	DC.L	unknown_exception                 ; $00000090 36: TRAP 4 vector (Sinclair BASIC command interpreter)
	DC.L	unknown_exception                 ; $00000094 37: TRAP 5 vector
	DC.L	unknown_exception                 ; $00000098 38: TRAP 6 vector
	DC.L	unknown_exception                 ; $0000009C 39: TRAP 7 vector
	DC.L	unknown_exception                 ; $000000A0 40: TRAP 8 vector
	DC.L	unknown_exception                 ; $000000A4 41: TRAP 9 vector
	DC.L	unknown_exception                 ; $000000A8 42: TRAP 10 vector (Sinclair QDOS - Switch to supervisor mode)
	DC.L	unknown_exception                 ; $000000AC 43: TRAP 11 vector
	DC.L	SWI_Handler                       ; $000000B0 44: TRAP 12 vector 68k BIOS SWI handler
	DC.L	unknown_exception                 ; $000000B4 45: TRAP 13 vector (Atari BIOS / OS/9 C I/O calls)
	DC.L	unknown_exception                 ; $000000B8 46: TRAP 14 vector (Atari XBIOS)
	DC.L	unknown_exception                 ; $000000BC 47: TRAP 15 vector (OS/9 Extended math calls)
	DC.L	unknown_exception                 ; $000000C0 48: FPU: Branch or Set on Unordered Condition
	DC.L	unknown_exception                 ; $000000C4 49: FPU: Inexact Result
	DC.L	unknown_exception                 ; $000000C8 50: FPU: Divide by Zero
	DC.L	unknown_exception                 ; $000000CC 51: FPU: Underflow
	DC.L	unknown_exception                 ; $000000D0 52: FPU: Operand Error
	DC.L	unknown_exception                 ; $000000D4 53: FPU: Overflow
	DC.L	unknown_exception                 ; $000000D8 54: FPU: Signaling NAN (Not-A-Number)
	DC.L	unknown_exception                 ; $000000DC 55: FPU: Unimplemented data type (MC68040 & MC68060 only)
	DC.L	unknown_exception                 ; $000000E0 56: MMU: Configuration Error (MC68030 & MC68851 only)
	DC.L	unknown_exception                 ; $000000E4 57: MMU: Illegal Operation Error (MC68851 only)
	DC.L	unknown_exception                 ; $000000E8 58: MMU: Access Level Violation Error (MC68851 only)
	                                          ;           Miscellaneous vectors
	DC.L	unknown_exception                 ; $000000EC 59: (reserved)
	DC.L	unknown_exception                 ; $000000F0 60: FPU: Unimplemented effective address (MC68060 only)
	DC.L	unknown_exception                 ; $000000F4 61: Unimplemented integer instruction (MC68060 only)
	DC.L	unknown_exception                 ; $000000F8 62: (reserved)
	DC.L	unknown_exception                 ; $000000FC 63: (reserved)
	                                          ;  64-255: user (acknowledged) interrupt vectors

; -----------------------------------------------------------------------------
; OS workspace: Software Vectors
; -----------------------------------------------------------------------------
	ORG     bios_address+$00000100
	                                          ; RiscOS vectors
	DC.L	not_supported                     ; $00000400 $00 UserV              (Not implemented)
	DC.L	_errorv                           ; $00000404 $01 ErrorV
	DC.L	_irqv                             ; $00000408 $02 IrqV
	DC.L	_wrchv                            ; $0000040C $03 WrchV
	DC.L	SWI_OS_ReadC                      ; $00000410 $04 ReadCV
	DC.L	SWI_OS_CLI                        ; $00000414 $05 CliV
	DC.L	SWI_OS_Byte                       ; $00000418 $06 ByteV
	DC.L	SWI_OS_Word                       ; $0000041C $07 WordV
	DC.L	SWI_OS_File                       ; $00000420 $08 FileV
	DC.L	SWI_OS_Args                       ; $00000424 $09 ArgsV
	DC.L	SWI_OS_Bget                       ; $00000428 $0A BgetV
	DC.L	SWI_OS_Bput                       ; $0000042C $0B BputV
	DC.L	SWI_OS_GBPB                       ; $00000430 $0C GBPBV
	DC.L	SWI_OS_Find                       ; $00000434 $0D FindV
	DC.L	SWI_OS_ReadLine                   ; $00000438 $0E ReadLineV
	DC.L	SWI_OS_FSControl                  ; $0000043C $0F FSControlV
	DC.L	_eventv                           ; $00000440 $10 EventV
	DC.L	not_supported                     ; $00000444 $11 UPTV (Arthur OS)   (Reserved)
	DC.L	not_supported                     ; $00000448 $12 NetV (Arthur OS)   (Reserved)
	DC.L	not_supported                     ; $0000044C $13 KeyV               (Not implemented)
	DC.L	not_supported                     ; $00000450 $14 InsV               (Not implemented)
	DC.L	not_supported                     ; $00000454 $15 RemV               (Not implemented)
	DC.L	not_supported                     ; $00000458 $16 CnpV               (Not implemented)
	DC.L	not_supported                     ; $0000045C $17 UKVDU23V           (Not implemented)
	DC.L	_ukswiv                           ; $00000460 $18 UKSWIV
	DC.L	not_supported                     ; $00000464 $19 UKPLOTV            (Not implemented)
	DC.L	SWI_OS_Mouse                      ; $00000468 $1A MouseV
	DC.L	not_supported                     ; $0000046C $1B VDUXV              (Not implemented)
	DC.L	not_supported                     ; $00000470 $1C TickerV            (Not implemented)
	DC.L	not_supported                     ; $00000474 $1D UpCallV            (Not implemented)
	DC.L	_ChangeEnvironmentV               ; $00000478 $1E ChangeEnvironmentV
	DC.L	not_supported                     ; $0000047C $1F SpriteV            (Not implemented)
	DC.L	not_supported                     ; $00000480 $20 DrawV              (Not implemented)
	DC.L	not_supported                     ; $00000484 $21 EconetV            (Not implemented)
	DC.L	not_supported                     ; $00000488 $22 ColourV            (Not implemented)
	DC.L	not_supported                     ; $0000048C $23 PaletteV           (Not implemented)
	DC.L	not_supported                     ; $00000490 $24 SerialV            (Not implemented)
	DC.L	not_supported                     ; $00000494 $25 FontV              (Not implemented)
	DC.L	not_supported                     ; $00000498 $26 PointerV           (Not implemented)
	DC.L	not_supported                     ; $0000049C $27 TimeShareV         (Not implemented)
	DC.L	not_supported                     ; $000004A0 $28 LowPriorityV       (Not implemented)
	DC.L	not_supported                     ; $000004A4 $29 FastTickerV        (Not implemented)
	DC.L	not_supported                     ; $000004A8 $2A GraphicsV          (Not implemented)
	DC.L	not_supported                     ; $000004AC $2B UnthreadV          (Not implemented)
	DC.L	$0                                ; $000004B0 $2C                    (Reserved)
	DC.L	$0                                ; $000004B4 $2D                    (Reserved)
	DC.L	$0                                ; $000004B8 $2E                    (Reserved)
	DC.L	$0                                ; $000004BC $2F                    (Reserved)
	DC.L	$0                                ; $000004C0 otherexceptionsv       ()
	DC.L	_callbackv                        ; $000004C4 callbackv              (CallBack handler address)
	DC.L	_breakpointv                      ; $000004C5 breakpointv            (BreakPoint handler address)
	DC.L	_escapev                          ; $000004CC escapev                (Escape handler address)
	DC.L	_exitv                            ; $000004D0 exitv                  (Exit handler address)
	DC.L	$0                                ; $000004D4 error_wkspc_ptr        (R12 on entry to Error handler)
	DC.L	$0                                ; $000004D8 callback_wkspc_ptr     (R12 on entry to CallBack handler)
	DC.L	$0                                ; $000004DC breakpoint_wkspc_ptr   (R12 on entry to BreakPoint handler)
	DC.L	$0                                ; $000004E0 escape_wkspc_ptr       (R12 on entry to Escape handler)
	DC.L	$0                                ; $000004E4 event_wkspc_ptr        (R12 on entry to Event handler)
	DC.L	$0                                ; $000004E8 exit_wkspc_ptr         (R12 on entry to Exit handler)
	DC.L	$0                                ; $000004EC unusedswi_wkspc_ptr    (R12 on entry to Unused SWI handler)
	DC.L	$0                                ; $000004F0 upcall_wkspc_ptr       (R12 on entry to UpCall handler)
	DC.L	errorbuffer                       ; $000004F4 error_buffer_ptr       (Pointer to Error handler buffer)
	DC.L	$0                                ; $000004F8 callback_buffer_ptr    (Pointer to CallBack register buffer)
	DC.L	$0                                ; $000004FC breakpoint_buffer_ptr  (Pointer to BreakPoint register buffer)



; -----------------------------------------------------------------------------
; Reset entry
; -----------------------------------------------------------------------------
	ORG	bios_address+$00000200            ; RAM at $00000000 is enabled when A19 is asserted (The 68030 issue 1 board uses A31 instead of A19)

reset_entry                                       ; Value of SR on RESET is $2700
	MOVE.L	#vector_table, A0                 ; Destination address
	MOVE.L	#bios_address, A1                 ; Source address
	MOVE.W	#$3F, D0                          ; Number of system vectors minus one
init_sysvectors
	MOVE.L	(A1)+, (A0)+                      ; Move data
	DBF	D0, init_sysvectors
	                                          ; Set all user vectors to 'Unknown Exception' handler
	MOVE.W	#$BF, D0                          ; Number of user vectors minus one
init_uservectors
	MOVE.L	#unknown_exception, (A0)+         ; Move data
	DBF	D0, init_uservectors

	MOVE.W	#$3F, D0                          ; Number of words minus one
	MOVE.L	#$00000400,  A0                   ; Destination address
	MOVE.L	#bios_address+$00000100,  A1      ; Source address
init_osworkspace
	MOVE.L	(A1)+, (A0)+                      ; Move data
	DBF	D0, init_osworkspace

	MOVE.L	#$1FEDF, D0                       ; ((&80000 - &500) / 4) - 1
	MOVE.L	#$00000500, A0
clear_memory
	MOVE.L	#$00000000, (A0)+
	DBF	D0, clear_memory

	BSR	checkramsize                      ; Check how much RAM this system has

	MOVE.L	D0, ramsize                       ; ...and store the hex value
	MOVE.L	D0, SP                            ; Set supervisor stack pointer to top of RAM
	SUBI.L	#stacksize, D0                    ; Reserve supervisor stack
	MOVE.L	D0, A6                            ; Set user stack pointer to top of RAM minus supervisor stack
	MOVE.L	A6, USP
	SUBI.L	#stacksize, D0                    ; Reserve user stack
	MOVE.L	D0, himem.L                       ; Set himem to top of RAM minus supervisor and user stack
	MOVE.W	#$0000, hoaddr.L                  ; Set high order pointer to $0000 (used by OS_Byte &82 and OS_Word &00)
	MOVE.L	#$00000800, oshwm.L

	BSR	check_cpu                         ; Find out which CPU is present
	MOVE.B	D0, cputype                       ; ...and store it
	BSR	check_fpu                         ; Find out which FPU is present
	MOVE.B	D0, fputype                       ; ...and store it
	BSR	check_mmu                         ; Find out which MMU is present
	MOVE.B	D0, mmutype                       ; ...and store it

	MOVE.B	#0, escapeflag                    ; Reset escape flag

;	MOVE.W	#$2000, SR
	BSR	SWI_OS_IntOn                      ; Enable interrupts

	ANDI.W	#$DFFF, SR                        ; Switch to user mode (not using SWI_OS_LeaveOS since the return address will be on the supervisor stack)

	MOVE.L	#startup_message1, D0             ; Location of startup message in D0
	BSR	SWI_OS_Write0                     ; Print the message

	MOVE.B	cputype, D0
	CMP	#$09, D0
	BLO	init_startup_msg
	MOVEQ	#$00, D0                          ; Unknown CPU, use CPU type 0

init_startup_msg
	CMP.B	#$FF, (cputype)
	BEQ	init_startup_msg_unknown_cpu

	MOVE.L	#startup_message_cpus, D0         ; A0 = A0 + (3*D0)
	ADD.B	(cputype), D0
	ADD.B	(cputype), D0
	ADD.B	(cputype), D0
	MOVE.L	#$3, D1                           ; Write 3 characters
	BSR	SWI_OS_WriteN
	BRA	init_startup_msg2

init_startup_msg_unknown_cpu
	MOVE.B	#'K', D0
	BSR	SWI_OS_WriteC

init_startup_msg2
	MOVE.L	#startup_message2, D0             ; Location of message in D0
	BSR	SWI_OS_Write0                     ; Print the message

	MOVE.L	ramsize, D0                       ; Get RAM size (use OS_ConvertFileSize???)
	LSR.L	#5, D0                            ; Divide by 1024
	LSR.L	#5, D0 
	MOVE.L	#buffer, D1                       ; Pointer to buffer
	MOVE.L	#$FF, D2                          ; Size of buffer
	BSR	SWI_OS_ConvertCardinal4           ; Convert value to string
	MOVE.L	#buffer, D0                       ; Pointer to buffer
	BSR	SWI_OS_Write0                     ; And print the RAM size in K

	MOVE.L	#startup_message3, D0             ; Print 'K' <cr> <cr>
	MOVE.L	#$7, D1                           ; Write 7 characters
	BSR	SWI_OS_WriteN                     ; Print the message

	MOVE.L	#$00000027, D1                    ; Perform Service_Reset call to modules
	BSR	SWI_OS_ServiceCall

	BSR	readbyte_from_tuber2              ; Wait for host to transfer data to copro and finish booting up
	MOVE.L	D0, -(SP)

	MOVE.L	#$00000001, D0
	MOVE.L	#osstarttime, D1
	BSR	SWI_OS_Word                       ; Get OS start time
	MOVE.B	#$00, programstarttime            ; Set program start time to 0
	MOVE.B	#$00, programstarttime+1
	MOVE.B	#$00, programstarttime+2
	MOVE.B	#$00, programstarttime+3
	MOVE.B	#$00, programstarttime+4

	IFNE DEBUG
	BSR	setup_osword_fa                   ; Set up the OSWORD &FA handler in the host
	ENDC

	MOVE.L	(SP)+, D0
	IFNE DEBUG
		MOVE.B	#$80, D0
		MOVE.L	#$00008000, tubetransfer
	ENDC
	CMP.B	#$80, D0                          ; Check if we need to enter a program at startup
;	BEQ	SWI_OS_Byte_8E                    ; Enter language ROM

main_loop
	MOVE.B	#prompt, D0                       ; * Prompt
	BSR	SWI_OS_WriteC

	MOVE.L	#buffer, D0                       ; Buffer address
	MOVE.L	#$FF, D1                          ; Maximum line length is 255
	MOVE.B	#$20, D2                          ; Minimum acceptable ASCII value
	MOVE.B	#$FF, D3                          ; Maximum acceptable ASCII value
	MOVE.L	#OS_ReadLine32, A0                ; SWI OS_ReadLine32: Read line from input
	TRAP	#SWI
	BCS	escape                            ; Jump if user pressed ESCAPE

	MOVE.L	#buffer, D0                       ; D0 points to the line read by the OS_ReadLine32 call
	MOVE.L	#OS_CLI, A0                       ; SWI OS_CLI: Process command
	TRAP	#SWI
	BRA	main_loop                         ; Loop infinitely

escape
	MOVEQ	#$7E, D0                          ; OSBYTE $7E: Acknowledge detection of an ESCAPE condition
	BSR	SWI_OS_Byte
	MOVE.L	#err_escape, D0                   ; Point D0 to the ESCAPE error message
	MOVE.L	#OS_GenerateError, A0             ; SWI OS_GenerateError
	TRAP	#SWI                              ; SWI call
	BRA	main_loop                         ; This command should never be reached



; -----------------------------------------------------------------------------
; Low level hardware stuff
;
; Wait for data in Tube Data 1 and return it in D0, while allowing requests via Tube R4
; -----------------------------------------------------------------------------
readbyte_from_tuber1
	BTST	#7, r1status                      ; Check Tube Status 1 for data present in Tube Data Register 1
	BNE	readbyte_from_tuber1_fetch        ; Data present, fetch it
	BTST	#7, r4status                      ; Check Tube Status 1 for data present in Tube Data Register 1
	BEQ	readbyte_from_tuber1              ; Nothing in Tube R4, loop back
	BSR	irq_transfer_or_error             ; Deal with Tube R4 request
	BRA	readbyte_from_tuber1              ; Loop back to wait for Tube R1 data

readbyte_from_tuber1_fetch
	MOVE.B	r1data, D0                        ; Fetch byte from Tube Register 1

	IFNE DEBUG
		MOVE.B  #5, D0
		TRAP    #15
		MOVE.B  D1, D0
	ENDC

	RTS

; -----------------------------------------------------------------------------
; Wait for data in TUBE ULA Data register 2 and return it in D0
; -----------------------------------------------------------------------------
readbyte_from_tuber2
	BTST	#7, r2status                      ; Check the DA2 flag of TUBE ULA Status register 2 (Data present in 2st register)
	BEQ	readbyte_from_tuber2              ; No? Then wait
	MOVE.B	r2data, D0                        ; D0.B = ?r2data
	RTS

; -----------------------------------------------------------------------------
; Write byte to TUBE ULA register 2
; -----------------------------------------------------------------------------
writebyte_to_tuber2
	BTST	#6, r2status                      ; Check the NF2 flag of TUBE ULA Status register 2 (2nd data register not filled)
	BEQ	writebyte_to_tuber2               ; Loop until TUBE ULA Data register 2 is empty
	MOVE.B	D0, r2data                        ; Write byte to r2data
	RTS

; -----------------------------------------------------------------------------
; Read byte from TUBE ULA register 4
; -----------------------------------------------------------------------------
readbyte_from_tuber4
	BTST	#7, r4status                      ; Check Tube Status 4 for data present in Tube Data Register 4
	BEQ	readbyte_from_tuber4              ; Loop until data present
	MOVE.B	r4data, D0                        ; Fetch byte from Tube Register 4
	RTS

; -----------------------------------------------------------------------------
; Read 32-bit long from TUBE via Data register 2 to D0
; -----------------------------------------------------------------------------
readlong_from_tuber2
	CLR.L	D0
	BSR	readbyte_from_tuber2              ; D0=&000000aa
	ROL.L	#8, D0                            ; D0=&0000aa00
	BSR	readbyte_from_tuber2              ; D0=&0000aabb
	ROL.L	#8, D0                            ; D0=&00aabb00
	BSR	readbyte_from_tuber2              ; D0=&00aabbcc
	ROL.L	#8, D0                            ; D0=&aabbcc00
	BRA	readbyte_from_tuber2              ; Fall through to get D0=&aabbccdd

; -----------------------------------------------------------------------------
; Send 32-bit long in D0 to TUBE via Data register 2
; -----------------------------------------------------------------------------
writelong_to_tuber2
	ROL.L	#8, D0
	BSR	writebyte_to_tuber2               ; Send b24-b31
	ROL.L	#8, D0
	BSR	writebyte_to_tuber2               ; Send b16-b23
	ROL.L	#8, D0
	BSR	writebyte_to_tuber2               ; Send b8-b15
	ROL.L	#8, D0
	BRA	writebyte_to_tuber2               ; Drop through to send b0-b7

; -----------------------------------------------------------------------------
; Read 32-bit long from TUBE via Data register 2 to D4
; -----------------------------------------------------------------------------
readlong_from_tuber4
	CLR.L	D0
	BSR	readbyte_from_tuber4              ; D0=&000000aa
	ROL.L	#8, D0                            ; D0=&0000aa00
	BSR	readbyte_from_tuber4              ; D0=&0000aabb
	ROL.L	#8, D0                            ; D0=&00aabb00
	BSR	readbyte_from_tuber4              ; D0=&00aabbcc
	ROL.L	#8, D0                            ; D0=&aabbcc00
	BRA	readbyte_from_tuber4              ; Fall through to get D0=&aabbccdd

; -----------------------------------------------------------------------------
; Send string at (A6) through TUBE ULA Data register 2
; -----------------------------------------------------------------------------
writestring_to_tuber2
	BTST	#6, r2status                      ; Test Tube Register 2 Status
	BEQ	writestring_to_tuber2             ; Loop until Tube Register 2 is empty
	MOVE.B	(A6)+, D0                         ; Get byte in D0
	BSR	writebyte_to_tuber2
	CMP.B	#$0D, D0                          ; Is it the last character in the string?
	BNE	writestring_to_tuber2             ; No? Then process next character
	RTS

; -----------------------------------------------------------------------------
; IRQ handler
; -----------------------------------------------------------------------------
irq_handler
;	MOVE.W	#$2700, SR
	BTST	#7, r4status                      ; Check Tube Status 4 to see if any data in Tube Register 4
	BNE	irq_transfer_or_error             ; Data in Tube R4, jump to process errors and transfers
	BTST	#7, r1status                      ; Check the DA2 flag of TUBE ULA Status register 2 (Data present in 2st register)
	BNE	irq_event_or_escape               ; Data in Tube R1, jump to process Escape and Events

	MOVE.L	A6, -(SP)                         ; Save A6
	MOVE.L	(irqv).L, A6                      ; IRQ not recognised, pass on to IRQV
	JSR	(A6)                              ; Jump to IRQV
	MOVE.L	(SP)+, A6                         ; Restore A6
;	MOVE.W	#$2000, SR

	RTE

; -----------------------------------------------------------------------------
; Interupt generated by data in Tube Register 1 - Escape change or Event
; -----------------------------------------------------------------------------
irq_event_or_escape
	MOVE.L	D0, -(SP)                         ; Save D0
	MOVE.B	r1data, D0                        ; Get data byte from Tube Register 1
	BMI	irq_escape                        ; b7=1, change Escape state

	MOVE.L	D1, -(SP)                         ; Save D1
	
	CLR.L	D0
	BSR	readbyte_from_tuber1              ; Get Event parameter Y
	ROL	#8, D0                            ; D0=&0000yy00
	BSR	readbyte_from_tuber1              ; Get Event parameter X
	MOVE.W	D0, D1                            ; Get 16-bit event parameter in D1

	BSR	readbyte_from_tuber1              ; Get Event number

	MOVE.L	A6, -(SP)                         ; Save A6
	MOVE.L	(eventv).L, A6                    ; IRQ not recognised, pass on to EventV
	JSR	(A6)                              ; Jump to EventV
	MOVE.L	(SP)+, A6                         ; Restore A6

	MOVE.L	(SP)+, D1                         ; Restore registers
	MOVE.L	(SP)+, D0
;	MOVE.W	#$2000, SR

	RTE                                       ; Return from interupt

; -----------------------------------------------------------------------------
; Escape state changed
; -----------------------------------------------------------------------------
irq_escape
	MOVE.L	A6, -(SP)                         ; Save A6
	MOVE.L	(escapev).L, A6                   ; Call the Escape handler
	JSR	(A6)                              ; Jump to EscapeV
	MOVE.L	(SP)+, A6                         ; Restore A6

	MOVE.L	(SP)+, D0
;	MOVE.W	#$2000, SR
	RTE

; -----------------------------------------------------------------------------
; Interrupt generated by data in Tube Register 4 - Initiate data transfer
; -----------------------------------------------------------------------------
irq_transfer_or_error
	MOVE.B	r4data, D0                        ; Get data byte from Tube Register 4
	BPL	irq_transfer                      ; b7=0, jump for data transfer

; -----------------------------------------------------------------------------
; Data transfer type b7=1 - Host error
; -----------------------------------------------------------------------------
	MOVE.L	D0, -(SP)                         ; Save D0
	MOVE.L	A6, -(SP)                         ; Save A6
	MOVE.L	#errorbuffer, A6                  ; Point A0 to error buffer
	BSR	readbyte_from_tuber2              ; Wait for BRK byte

	CLR.L	D0                                ; Only use lower 8 bits for error number (optimize:D0.B should already be $00)
	BSR	readbyte_from_tuber2              ; Wait for error number
	MOVE.L	D0, (A6)+                         ; Store error number

irq_error_lp
	BSR	readbyte_from_tuber2              ; Wait for error string character
	MOVE.B	D0, (A6)+                         ; Store in error buffer
	BNE	irq_error_lp                      ; Loop until final &00 byte

	MOVE.L	(SP)+, A6                         ; Restore A6
	MOVE.L	#errorbuffer, D0                  ; Point D0 to error buffer
	MOVE.L	D0, error
	MOVE.L	#$FFFF6502, error_pc              ; Location of error is somewhere in the host
	BSR	SWI_OS_GenerateError              ; Generate error
	MOVE.L	(SP)+, D0                         ; Restore D0
;	MOVE.W	#$2000, SR
	RTE

; -----------------------------------------------------------------------------
; Data transfer type b7=0 - Data transfer
; D0 = action
; Tube data via R4: ID address[4] sync, then via R3: data
; -----------------------------------------------------------------------------
irq_transfer
	MOVE.L	A0, -(SP)                         ; Save A0
	MOVE.L	D0, -(SP)                         ; Save D0
	ANDI.L	#%11111111, D0                    ; Ensure 8-bit value of reason code in D0
	LSL.L	#2, D0                            ; D0 = D0 * 4
	LEA	nmi_handler_table, A0             ; Pointer to NMI routine in A0
	ADDA.L	D0, A0                            ; Add offset
	MOVE.L	(A0), $00000074                   ; Store in NMI vector (INT5)

	BSR	readbyte_from_tuber4              ; Wait for claimer identity byte
	MOVE.L	(SP), D0                          ; Restore D0 but leave it on the stack for now

	CMP.B	#5, D0                            ; Was transfer type 'Tube Release'?
	BEQ	irq_transfer_exit                 ; TubeRelease - exit    

	BSR	readlong_from_tuber4              ; Read word from host
	MOVE.L	D0, tubetransfer.L                ; Store start address of data transfer

	MOVE.B	r3data, D0                        ; Read from Tube R3 twice to clear FIFO
	MOVE.B	r3data, D0
	BSR	readbyte_from_tuber4              ; Wait for sync byte and discard it (NMI transfers will start after this byte is removed from r4data)

	MOVE.L	(SP), D0                          ; Restore D0, but leave it on the stack for now
	CMP.B	#$06, D0
	BLO	irq_transfer_exit                 ; Exit if it`s reason code &00-&05
	BNE	irq_transfer_07                   ; Jump if it`s not reason code &06

	MOVE.L	A6, -(SP)                         ; Save A6
	MOVE.L	(tubetransfer), A6
	MOVE.L	#$FF, D0

irq_transfer_06_loop                              ; Reason code &06 handler, transfer 256 bytes from co-pro to host
	BTST	#7, r3status                      ; Check for data in TUBE register 3
	BEQ	irq_transfer_06_loop              ; If not, then loop
	MOVE.B	(A6)+, r3data                     ; Send byte to TUBE register 3
	DBF	D0, irq_transfer_06_loop

irq_transfer_06_exit
	BTST	#7, r3status                      ; Check for data in TUBE register 3
	BEQ	irq_transfer_06_exit              ; If not, then loop
	MOVE.B	-(A6), r3data                     ; Send byte to TUBE register 3
	MOVE.L	(SP)+, A6

irq_transfer_exit                                 ; Reason code &00-&05 handler
	MOVE.L	(SP)+, D0                         ; Restore D0
	MOVE.L	(SP)+, A0                         ; Restore A0
;	MOVE.W	#$2000, SR
	RTE

irq_transfer_07                                   ; Reason code &07 handler, transter 256 bytes from host to co-pro
	MOVE.L	A6, -(SP)                         ; Save A6
	MOVE.L	(tubetransfer), A6
	MOVE.L	#$FF, D0

irq_transfer_07_loop
	BTST	#7, r3status                      ; Check for data in TUBE register 3
	BEQ	irq_transfer_07_loop              ; If not, then loop
	MOVE.B	r3data, (A6)+                     ; Get byte from TUBE register 3
	DBF	D0, irq_transfer_07_loop          ; Loop 256 times
	MOVE.L	(SP)+, A6
	BRA	irq_transfer_exit

; -----------------------------------------------------------------------------
; NMI handler reason code &00 (Multiple single byte transfer from parasite to host)
; -----------------------------------------------------------------------------
nmi_data_transfer_00                              ; 96 cycles incl RTE
	MOVE.L	A6, -(SP)                         ; Save A6
	MOVE.L	tubetransfer, A6
	MOVE.B	(A6)+, r3data
	MOVE.L	A6, tubetransfer
	MOVE.L	(SP)+, A6
	RTE

; -----------------------------------------------------------------------------
; NMI handler reason code &01 (Multiple single byte transfer from host to parasite)
; -----------------------------------------------------------------------------
nmi_data_transfer_01                              ; 96 cycles incl RTE
	MOVE.L	A6, -(SP)                         ; Save A6
	MOVE.L	tubetransfer, A6
	MOVE.B	r3data, (A6)+
	MOVE.L	A6, tubetransfer
	MOVE.L	(SP)+, A6
	RTE

; -----------------------------------------------------------------------------
; NMI handler reason code &02 (Multiple double byte transfer from parasite to host)
; -----------------------------------------------------------------------------
nmi_data_transfer_02                              ; 116 cycles incl RTE
	MOVE.L	A6, -(SP)                         ; Save A6
	MOVE.L	tubetransfer, A6
	MOVE.B	(A6)+, r3data                     ; Timing???
	MOVE.B	(A6)+, r3data
	MOVE.L	A6, tubetransfer
	MOVE.L	(SP)+, A6
	RTE

; -----------------------------------------------------------------------------
; NMI handler reason code &03 (Multiple double byte transfer from host to parasite)
; -----------------------------------------------------------------------------
nmi_data_transfer_03                              ; 116 cycles incl RTE
	MOVE.L	A6, -(SP)                         ; Save A6
	MOVE.L	tubetransfer, A6
	MOVE.B	r3data, (A6)+                     ; Timing???
	MOVE.B	r3data, (A6)+
	MOVE.L	A6, tubetransfer                  ; Is faster than ADDQ #2, tubetransfer
	MOVE.L	(SP)+, A6
	RTE
; MOVE.B r2data, $F4F3F2F1 / MOVE.B r2data, $F4F3F2F2 / ADDI.B #2, $003FFFFF / ADDQ.B #2, $0033F2F2 also takes 116 cycles, so it isn`t faster

; -----------------------------------------------------------------------------
; NMI handler reason codes &04-&07
; -----------------------------------------------------------------------------
nmi_handler
	MOVE.B	D0, r3data
	RTE

nmi_handler_table
	DC.L	nmi_data_transfer_00              ; Multiple single byte transfer from parasite to host
	DC.L	nmi_data_transfer_01              ; Multiple single byte transfer from host to parasite
	DC.L	nmi_data_transfer_02              ; Multiple double byte transfer from parasite to host
	DC.L	nmi_data_transfer_03              ; Multiple double byte transfer from host to parasite
	DC.L	nmi_handler                       ; Execute code in parasite
	DC.L	nmi_handler                       ; Release TUBE
	DC.L	nmi_handler                       ; Transfer 256 bytes from co-pro to host
	DC.L	nmi_handler                       ; Transfer 256 bytes from host to co-pro



; -----------------------------------------------------------------------------
; 68k CPU exception handlers
;
; Bus error exception handler
; -----------------------------------------------------------------------------
bus_error_handler
	MOVE.L	#msg_bus_error, D0                 ; Exception message
	BSR	SWI_OS_Write0                      ; Not using OS_GenerateError since there must be something seriously wrong

bus_error_handler2
	MOVE.W	(SP)+, exceptionregs+12           ; Pop "Memory access type and function code" word (bit 4:0=Write/1=Read, bit3:0=Instruction/1=Not, bit2-0:FC2-FC0)
	MOVE.L	(SP)+, exceptionregs+8            ; Pop "Access address" long
	MOVE.W	(SP)+, exceptionregs+6            ; Pop "Instruction register" word
	MOVE.W	(SP)+, exceptionregs+4            ; Pop "Status register" word
	MOVE.L	(SP), exceptionregs               ; Pop "Program counter" long

	MOVE.L	#buffer, D1                       ; D1 is pointer to buffer
	MOVE.B	#$FF, D2                          ; Size of buffer
	MOVEQ	#$00, D0
	MOVE.L	exceptionregs, D0                 ; Pop "Program counter" long
	BSR	SWI_OS_ConvertHex8
	BSR	SWI_OS_Write0                     ; Write string
	BSR	SWI_OS_NewLine

	MOVE.L	#msg_exception_mf, D0             ; Bus error message
	BSR	SWI_OS_Write0
	MOVE.L	#buffer, D1                       ; D1 is pointer to buffer
	MOVE.B	#$FF, D2                          ; Size of buffer
	MOVEQ	#$00, D0
	MOVE.W	exceptionregs+12, D0              ; Pop "Memory access type and function code" word
	BSR	SWI_OS_ConvertHex4                ; Prepare string
	BSR	SWI_OS_Write0                     ; Write string
	BSR	SWI_OS_NewLine

	MOVE.L	#msg_exception_aa, D0             ; Bus error message
	BSR	SWI_OS_Write0
	MOVE.L	#buffer, D1                       ; D1 is pointer to buffer
	MOVE.B	#$FF, D2                          ; Size of buffer
	MOVEQ	#$00, D0
	MOVE.L	exceptionregs+8, D0               ; Pop "Access address" long
	BSR	SWI_OS_ConvertHex8
	BSR	SWI_OS_Write0                     ; Write string
	BSR	SWI_OS_NewLine

	MOVE.L	#msg_exception_ir, D0             ; Bus error message
	BSR	SWI_OS_Write0
	MOVE.L	#buffer, D1                       ; D1 is pointer to buffer
	MOVE.B	#$FF, D2                          ; Size of buffer
	MOVEQ	#$00, D0
	MOVE.W	exceptionregs+6, D0               ; Pop "Instruction register" word
	BSR	SWI_OS_ConvertHex4
	BSR	SWI_OS_Write0                     ; Write string

	MOVE.B	#' ', D0
	BSR	SWI_OS_WriteC
	MOVE.B	#'[', D0
	BSR	SWI_OS_WriteC
	MOVE.W	#exceptionregs+6, D0              ; Address of "Instruction register" word
	MOVE.L	#buffer, D1
	BSR	SWI_Debugger_Disassemble
	MOVE.L	D1, D0
	BSR	SWI_OS_Write0                     ; Write string
	MOVE.B	#']', D0
	BSR	SWI_OS_WriteC
	BSR	SWI_OS_NewLine

	MOVE.L	#msg_exception_sr, D0             ; Bus error message
	BSR	SWI_OS_Write0
	MOVE.L	#buffer, D1                       ; D1 is pointer to buffer
	MOVE.B	#$FF, D2                          ; Size of buffer
	MOVEQ	#$00, D0
	MOVE.W	exceptionregs+4, D0               ; Pop "Status register" word
	BSR	SWI_OS_ConvertBinary2
	BSR	SWI_OS_Write0                     ; Write string
	BSR	SWI_OS_NewLine

exception0handler2
	; Replace this with: re-initialize user- and supervisor stack to top of tam and jump to main loop (basically: *QUIT)
	BRA	exception0handler2
;	STOP	#$2700
	BSR	SWI_OS_ReadC
	BRA	main_loop                         ; We cannot return from an access error exception, so jump straight back to the main loop

; -----------------------------------------------------------------------------
; Address error exception handler
; -----------------------------------------------------------------------------
address_error_handler
	MOVE.L	#msg_address_error, D0            ; Bus error message
	BSR	SWI_OS_Write0                     ; Not using OS_GenerateError since there must be something seriously wrong
	BRA	bus_error_handler2

; -----------------------------------------------------------------------------
; Illegal Instruction handler
; -----------------------------------------------------------------------------
illegal_instruction_handler
	MOVE.L	D0, -(SP)                         ; Push D0 to the stack
	MOVE.L	#err_illegal_instruction, D0      ; Location of message in A6
	BRA	exception_handler

; -----------------------------------------------------------------------------
; Integer divide by zero handler
; -----------------------------------------------------------------------------
int_divide_by_zero_handler
	MOVE.L	D0, -(SP)                         ; Push D0 to the stack
	MOVE.L	#err_int_divide_by_zero, D0       ; Location of message in A6
	BRA	exception_handler

; -----------------------------------------------------------------------------
; Privilege violation handler
; -----------------------------------------------------------------------------
privilege_violation_handler
	MOVE.L	D0, -(SP)                         ; Push D0 to the stack
	MOVE.L	#err_privilege_violation, D0      ; Location of message in A6
	BRA	exception_handler

; -----------------------------------------------------------------------------
; Unknown exception handler
; -----------------------------------------------------------------------------
unknown_exception
	MOVE.L	D0, -(SP)                         ; Push D0 to the stack
	MOVE.L	#err_unknown_exception, D0        ; Location of message in A6

exception_handler
	MOVE.L	6(SP), error_pc                   ; Pull program counter from the stack
	BSR	SWI_OS_GenerateError              ; Print the message
	MOVE.L	(SP)+, D0                         ; Pull D0 from the stack
	RTE

; -----------------------------------------------------------------------------
; Handler for not supported OS calls
; -----------------------------------------------------------------------------
not_supported
	MOVE.L	#err_not_supported, D0
	MOVE.L	#OS_GenerateError, A0
	TRAP	#SWI
	RTS

; -----------------------------------------------------------------------------
; Check CPU type ($00=68008, $01=68000, $02=68010, $03=68020, $04=68030, $05=68040, $06=68060, $07=68070, $08=68300, $FF=unknown CPU)
; 68010 got new registers: RFC, DFC and VBR
; 68020 got new registers: CACR and CAAR
; -----------------------------------------------------------------------------

check_cpu                                         ; this needs to be run at reset or else a way to get the vector base address needs to be known
	MOVEQ	#$00,D0                           ; exception vector base, assumes 68000 here
	MOVEA.L	D0, A5                            ; point to vector base
	MOVEA.L	$0C(A5), A0                       ; save the address exception vector
	LEA	check_cpu2(PC), A1                ; get the continue address
	MOVE.L	A1, $0C(A5)                       ; save as the address exception vector
	MOVE.L	SP, D7                            ; copy the stack pointer
	MOVE.L	D7, D6                            ; copy the stack pointer again
	JMP	*+5(PC)                           ; cause an address error - all processors

	                                          ; now there is an address error exception frame on the stack the processor type can be
	                                          ; deduced from the size of this frame

check_cpu2
	MOVE.L	A0, $0C(A5)                       ; restore the address exception vector
	SUB.L	SP, D7                            ; calculate the size of the stack frame

	MOVEQ	#$01, D0                          ; default to 68000 processor
	CMPI.B	#$12, D7                          ; compare frame size with that of 68000
	BEQ.S	proc_found                        ; if 68000 size then exit

	MOVEQ	#$02, D0                          ; set 68010 processor
	CMPI.B	#$3E, D7                          ; compare frame size with that of 68010
	BEQ.S	proc_found                        ; if 68010 size then exit

	MOVEQ	#$07, D0                          ; set 68070 processor
	CMPI.B	#$26, D7                          ; compare frame size with that of 68070
	BEQ.S	proc_found                        ; if 68070 size then exit

	MOVE.L	#$08, D0                          ; set 68300 processor
	CMPI.B	#$1C, D7                          ; compare frame size with that of 68300
	BEQ.S	proc_found                        ; if 68300 size then exit

	MOVEQ	#$05, D0                          ; set 68040 processor
	CMPI.B	#$10, D7                          ; compare frame size with that of 68040
	BEQ.S	proc_found                        ; if 68040 size then exit

	MOVEQ	#$FF, D0                          ; set unknown processor
	CMPI.B	#$24, D7                          ; compare frame size with that of 68020/030
	BNE.S	proc_found                        ; if not 68020/030 size then exit

	                                          ; test for 68020/68030

	MOVE.L	$1A(A5), A0                       ; get illegal instruction exception vector
	MOVE.L	$7E(a5), A1                       ; get format error exception vector

	LEA	is_68020(pc), A2                  ; set our format error exception vector
	MOVE.L	A2, $7E(A5)                       ; save format error exception vector

	LEA	is_68030(pc), A2                  ; set our illegal instruction exception vector
	MOVE.L	A2, $1A(A5)                       ; save illegal instruction exception vector
	MOVEQ	#$03, D0                          ; default to 68020 processor

	DC.W	$06FA, $0000, $0002               ; CALLM #0, next_word(PC)
	                                          ; call module, 68020 only
next_word
	DC.W	-1                                ; dummy data, cause format error

is_68030                                          ; illegal instruction exception arrives here
	MOVEQ	#$04, D0                          ; set 68030 processor

is_68020                                          ; format error exception arrives here
	MOVE.L	A1, $7E(A5)                       ; restore format error exception vector
	MOVE.L	A0, $1A(A5)                       ; restore illegal instruction exception vector

proc_found
	MOVE.L	D6, SP                            ; restore the stack pointer
	RTS

; -----------------------------------------------------------------------------
; Check FPU type ($00=no FPU, $01=68881, $02=68882, $03=CPU integrated(68040/68060), $FF=unknown FPU)
; -----------------------------------------------------------------------------

check_fpu
	MOVEQ	#0, D0                            ; exception vector base, assumes 68000 here
	MOVEA.L	D0, A5                            ; point to vector base
	MOVEA.L	$2C(A5), A0                       ; save the address exception vector
	LEA	no_fpu(pc), A1                    ; get the continue address
	MOVE.L	A1, $2C(A5)                       ; save as the address exception vector
	MOVE.L	SP, D7                            ; copy the stack pointer

;	FMOVE.S	#0, FP0                           ; FPU instruction; if no FPU is available, an exception $10 will be generated

	MOVEQ	#$FF, D0                          ; Set FPU flag
	BRA	check_fpu2

no_fpu
	MOVEQ	#$00, D0                          ; Set FPU flag

check_fpu2
	MOVE.L	D7, SP                            ; restore the stack pointer
	MOVE.L	A0, $2C(A5)                       ; save as the address exception vector
	RTS

; -----------------------------------------------------------------------------
; MMU type ($00=no MMU, $01=68841, $02=68851, $03=CPU integrated(68030/68040/68060), $FF=unknown MMU)
; -----------------------------------------------------------------------------
check_mmu
	MOVEQ	#$00, D0
	RTS

; -----------------------------------------------------------------------------
; Resets the flash ROM to data mode
; -----------------------------------------------------------------------------
flash_reset
	MOVE.B	#$F0, bios_address
	MOVE.B	#$FF, bios_address
	RTS	

; -----------------------------------------------------------------------------
; Returns the flash ROMs vendor and device ID in D0
; -----------------------------------------------------------------------------
flash_identify
	MOVE.B	#$AA, bios_address+$5555          ; Switch flash ROM to command mode
	MOVE.B	#$55, bios_address+$AAAA
	MOVE.B	#$90, bios_address+$5555          ; Read identification command
	MOVE.B	D0, bios_address                  ; Get vendor ID
	ASL.W	#8, D0                            ; Shift D0 to make room for device ID
	BSR	flash_reset

	MOVE.B	#$AA, bios_address+$5555          ; Switch flash ROM to command mode
	MOVE.B	#$55, bios_address+$AAAA
	MOVE.B	#$90, bios_address+$5555          ; Read identification command
	MOVE.B	D0, bios_address+1                ; Get device ID
	BSR	flash_reset

	RTS

; -----------------------------------------------------------------------------
; Writes one sector (65536 bytes) in the flash ROM (D7=sector, A6=memory address)
; -----------------------------------------------------------------------------
flash_write_sector
	CMP.B	#flash_rom_sectors, D7            ; Check if sector is < 8
	BHS	flash_write_sector99              ; If not, exit
	ASL	#8, D7
	ASL	#8, D7

	MOVE.L	#$FFFF, D1                        ; 65536-1 bytes

flash_write_sector1
	MOVE.B	(A5), D0                          ; Get byte from memory
	BSR	flash_write_byte
;;;;;;
;	DBF	D2, shift_wo                      ; Do next nibble

flash_write_sector99
	RTS

; -----------------------------------------------------------------------------
; Writes one byte in the flash ROM
; -----------------------------------------------------------------------------
flash_write_byte
	CMP.B	(A6), D0                          ; Check if the address already contains this byte
	BEQ	flash_write_byte2                 ; Yes? Then exit

	MOVE.B	#$AA, bios_address+$5555          ; Switch flash ROM to command mode
	MOVE.B	#$55, bios_address+$AAAA
	MOVE.B	#$A0, bios_address+$5555          ; Read identification command
	MOVE.B	(A6), D0                          ; Write byte

flash_write_byte1
	CMP.B	#2, (A6)
	BNE	flash_write_byte1

	BSR	flash_reset

flash_write_byte2
	RTS

; -----------------------------------------------------------------------------
; Find out how much RAM is available
; On exit: D0 = total number of bytes in hex
; -----------------------------------------------------------------------------
checkramsize
	MOVE.L	A0, -(SP)                         ; Push A0 to the stack
	MOVE.L	$00000000, -(SP)                  ; Save original contents of $00000000 on the stack

	MOVE.L	#$00000000, A0                    ; Reset hex counter
	MOVE.L	#$DEADBEEF, $00000000             ; Set $00000000 to the magic marker (Yes, this is where the magic happens *^@@**)

checkramsize_loop
	ADDA.L	#$00000400, A0                    ; Increase hex counter with 1Kbyte
	CMPI.L	#$DEADBEEF, (A0)                  ; Is it the same as location $00000000?
	BEQ	checkramsize_exit                 ; Yes, then exit
	CMP.L	#max_ram_size, A0                 ; Prevent indefenitely looping
	BLO	checkramsize_loop

checkramsize_exit
	MOVE.L	A0, D0
	MOVE.L	(SP)+, $00000000                  ; Pull original contents of $00000000 from the stack
	MOVE.L	(SP)+, A0                         ; Pull A0 from the stack
	RTS



; -----------------------------------------------------------------------------
; SWI call support
; On entry: A0=SWI number, D0-D7 = R0-R7, A1-A2=R8-R9
;
; SWI handler (TRAP #12)
; -----------------------------------------------------------------------------
SWI_Handler
	MOVE.L	A6, -(SP)                         ; Push A6 to the stack
	MOVE.L	A1, -(SP)                         ; Push A1 to the stack
	MOVE.L	A0, -(SP)                         ; Push A0 to the stack
	MOVE.L	D1, -(SP)                         ; Push D1 to the stack
	EXG	A0, D0                            ; Swap A0 (SWI number) and D0
	ANDI.L	#$00FDFFFF, D0                    ; Remove 'X' bit and superflous bits

	LEA	SWITable, A1                      ; Point A1 to SWI lookup table

SWI_Handler_loop
	CMP.L	(A1)+, D0                         ; Check SWI number
	BEQ	SWI_Handler_dispatch              ; Yes, this is our SWI handler

SWI_Handler_loop2
	MOVE.L	(A1)+, D1                         ; Get next word
	CMP.B	#$FF, D1                          ; End of SWI-table?
	BEQ	SWI_Handler_WriteI                ; Yes, so pass this SWI call to the _UKSWIV
	CMP.B	#$00, D1                          ; Check for end of string marker
	BNE	SWI_Handler_loop2                 ; This loop can probably be optimized, but it works for now
	BRA	SWI_Handler_loop

SWI_Handler_dispatch
	MOVE.L	(A1)+, A6                         ; Get address of SWI function (this needs to be word-aligned; if not it will generate an address exception)
	EXG	A0, D0                            ; Swap A0 (SWI number) and D0
	CMP.L	#oshwm, A6                        ; Check if address in SWI jump table is a vector
	BHS	SWI_Handler_dispatch2             ; If not, jump
	MOVE.L	(A6), A6

SWI_Handler_dispatch2
	MOVE.L	(SP)+, D1                         ; Pull D1 from the stack
	MOVE.L	(SP)+, A0                         ; Pull A0 from the stack
	MOVE.L	(SP)+, A1                         ; Pull A1 from the stack
	JSR	(A6)                              ; Jump to SWI function

SWI_Handler_exit
	BVS	SWI_ErrorReturn                   ; V set, return or generate error
	BCS	SWI_ReturnCarrySet                ; C set, so set it in the return SR
	MOVE.L	(SP)+, A6                         ; Pull A6 from the stack
	ANDI.W	#$FFFC, (SP)                      ; Clear Carry and Overflow in stacked PSW
	RTE                                       ; Return to User world

SWI_ReturnCarrySet
	MOVE.L	(SP)+, A6                         ; Pull A2 from the stack
	ANDI.W	#$FFFD, (SP)                      ; Clear Overflow in stacked PSW
	ORI.W	#$0001, (SP)                      ; Set Carry in stacked PSW
	RTE                                       ; Return to User world

SWI_ErrorReturn
	BCS	SWI_ErrorReturn_cset
	ORI.W	#$0002, (SP)                      ; Set V flag in stacked PSW
	ANDI.W	#$FFFE, (SP)                      ; Clear C flag in stacked PSW
	BRA	SWI_ErrorReturn2

SWI_ErrorReturn_cset
	ORI.W	#$0003, (SP)                      ; Set V and C flag in stacked PSW
	
SWI_ErrorReturn2
	MOVE.L	(SP)+, A6                         ; Restore A6
	EXG	A0, D0                            ; Put the raw SWI number in D0 so we can test for the 'X' bit
	BTST	#17, D0                           ; Was 'X' bit set in raw SWI number?
	BEQ	SWI_ErrorGenerate                 ; 'X' was clear, generate an error
	EXG	A0, D0
	RTE                                       ; Return to User world (D0 points to error block and V is set)

SWI_ErrorGenerate
	EXG	A0, D0
	MOVE.L	D1, -(SP)                         ; Push D1 to the stack
	MOVE.L	#$00000006, D1                    ; Service call: Service_Error
	BSR	SWI_OS_ServiceCall                ; Issue an OS_ServiceCall (D0 still points to the error block)
	MOVE.L	(SP)+, D1

	MOVE.L	D0, (error)                       ; Store current error address
	MOVE.L	2(SP), (error_pc)
	MOVE.L	(errorv).L, 2(SP)                 ; Overwrite return address on stack with ErrorV
	RTE                                       ; Enter ErrorV handler in User world

SWI_Handler_WriteI
	MOVE.L	(SP)+, D1                         ; Pull D1 from the stack
	MOVE.L	(SP)+, A0                         ; Pull A0 from the stack
	MOVE.L	(SP)+, A1                         ; Pull A1 from the stack
	MOVE.L	D0, A0                            ; Temporary store original SWI value in A0
	AND.L	#$00FDFF00, D0                    ; SWI number is still in D0, check if it`s in the $100-$1FF range
	CMP.L	#OS_WriteI, D0
	BNE	SWI_Handler_unknown
	MOVE.L	A0, D0                            ; Restore original value of D0
	JSR	SWI_OS_WriteI
	MOVE.L	(SP)+, A6                         ; Restore A6
	ANDI.W	#$FFFC, (SP)                      ; Clear Carry and Overflow in stacked PSW
	RTE                                       ; Return to User world

SWI_Handler_unknown
	MOVE.L	A0, D0                            ; Restore original value of D0
	MOVE.L	(ukswiv), A6                      ; Get the vector for UKSWIV
	MOVE.L	6(SP), error_pc                   ; Put PC of original SWI call here
	JSR	(A6)                              ; And jump to it
	MOVE.L	(SP)+, A6                         ; Restore A6
	ORI.W	#$0002, (SP)                      ; Set V flag in stacked PSW
	RTE                                       ; Return to User world

; -----------------------------------------------------------------------------
; SWI &100-1FF: OS_WriteI: Write immediate byte to all active output strams
; -----------------------------------------------------------------------------
SWI_OS_WriteI
	MOVE.L	(SP)+, D0                         ; Pull D0 from the stack
	BRA	SWI_OS_WriteC


; -----------------------------------------------------------------------------
; SWI &00: OS_WriteC: Write D0.B character to output stream
; -----------------------------------------------------------------------------
SWI_OS_WriteC
	MOVE.L	(wrchv), -(SP)
	RTS

; -----------------------------------------------------------------------------
; SWI &01: OS_WriteS - Print string to output stream
; -----------------------------------------------------------------------------
SWI_OS_WriteS
	MOVE.L	D0, -(SP)                         ; Save D0
	MOVE.L	4(SP), D0                         ; Pull address from stack
	BSR	SWI_OS_Write0
	MOVE.L	D0, 4(SP)
	MOVE.L	(SP)+, D0
	RTS

; -----------------------------------------------------------------------------
; SWI &02: OS_Write0 - Print string to output stream
; -----------------------------------------------------------------------------
SWI_OS_Write0
	MOVE.L	A0, -(SP)                         ; Save A0
	MOVE.L	D0, A0

SWI_OS_Write0_loop
	MOVE.B	(A0)+, D0                         ; Get byte in D0
	BEQ	SWI_OS_Write0_exit                ; Exit if it was the last byte
	BSR	SWI_OS_WriteC                     ; Print byte
	BRA	SWI_OS_Write0_loop                ; And get the next one
	
SWI_OS_Write0_exit
	MOVE.L	A0, D0
	MOVE.L	(SP)+, A0                         ; Restore A0
	RTS

; -----------------------------------------------------------------------------
; SWI &03: OS_NewLine: Write a newline to selected output stream
; -----------------------------------------------------------------------------
SWI_OS_NewLine
	MOVE.L	D0, -(SP)                         ; Push D0 to the stack
	MOVEQ	#$0A, D0
	BSR	SWI_OS_WriteC
	MOVEQ	#$0D, D0
	BSR	SWI_OS_WriteC
	MOVE.L	(SP)+, D0                         ; Restore D0
	RTS

; -----------------------------------------------------------------------------
; SWI &04: OS_ReadC: Read character from input stream
; -----------------------------------------------------------------------------
SWI_OS_ReadC
	MOVEQ	#$00, D0                          ; Code $00 for OSRDCH call
	BSR	writebyte_to_tuber2               ; Write byte to TUBE ULA register 2

SWI_OS_ReadC1
	BSR	readbyte_from_tuber2              ; Wait for data in TUBE ULA Data register 2 and return it in A
	ASR.B	#8, D0                            ; Move bit 7 to carry flag
	BRA	readbyte_from_tuber2              ; And get the last byte

; -----------------------------------------------------------------------------
; SWI &05: OS_CLI: Process a command as if typed in the CLI
; -----------------------------------------------------------------------------
SWI_OS_CLI
	MOVE.L	A6, -(SP)                         ; Save A6
	MOVE.L	D0, -(SP)                         ; Save D0
	MOVE.L	D0, A6                            ; A6 => command string

SWI_OS_CLI2
	BSR	skip_spaces                       ; Find first non-space character
	MOVE.B	(A6)+, D0
	CMP.B	#prompt, D0
	BEQ	SWI_OS_CLI2                       ; Skip leading '*'

	MOVE.B	-(A6), D0
	LEA	OS_CLI_command_table, A1          ; A1 => command table

start_compare
	MOVE.L	A6, -(SP)                         ; Save command pointer for now
	MOVE.L	(A1)+, A2                         ; Pre-fetch jump address
	CMPA	#$FFFFFFFF, A2                    ; End of table marker
	BEQ	SWI_OS_CLI_to_host                ; Jump if end of table has been reached

SWI_OS_CLI_compare_loop
	MOVE.B	(A6)+, D0                         ; Get first character in D0
	ANDI.B	#$DF, D0                          ; Make character upper-case
	CMP.B	(A1)+, D0                         ; Compare command agains table entries
	BNE	SWI_OS_CLI_skip_entry             ; No match, so skip to next entry
	CMPI.B	#'.', (A6)                        ; Is the next character a '.'?
	BEQ	SWI_OS_CLI_matched                ; Yes, so we've got a match
	CMPI.B	#' ', (A1)                        ; Has the full table entry been processed?
	BEQ	SWI_OS_CLI_matched                ; Yes, so we`ve got a match
	CMPI.B	#$00, (A1)                        ; Has the end of the table entry been reached?
	BNE	SWI_OS_CLI_compare_loop           ; If not, check next character

SWI_OS_CLI_matched
	CMPI.B	#$0D, (A6)                        ; Check if the end of command has been reached
	BEQ	SWI_OS_CLI_matched2               ; If not, skip this entry and compare against next entry
	CMPI.B	#' ', (A6)                        ; Check if the end of command has been reached
	BNE	SWI_OS_CLI_skip_entry             ; If not, skip this entry and compare against next entry

SWI_OS_CLI_matched2
	BSR	skip_spaces                       ; Set A6 to first command line parameter
	MOVE.L	(SP)+, A1                         ; Clean up stack
	JSR	(A2)                              ; We`ve found the correct entry, so jump to it
	MOVE.L	(SP)+, D0                         ; Restore D0
	MOVE.L	(SP)+, A6                         ; Restore A6
	BCS	SWI_OS_CLI_to_host2
	RTS
	
SWI_OS_CLI_skip_entry
	CMPI.B	#$00, (A1)+                       ; Loop through
	BNE	SWI_OS_CLI_skip_entry

	MOVE.L	(SP)+, A6                         ; Restore original command pointer
	BRA	start_compare

SWI_OS_CLI_to_host
	MOVE.L	(SP)+, A6                         ; Clean up stack
	MOVE.L	(SP)+, D0                         ; Restore D0

SWI_OS_CLI_to_host2
	MOVE.L	D1, -(SP)
	MOVE.L	#$00000004, D1
	BSR	SWI_OS_ServiceCall
	MOVE.L	(SP)+, D1

	MOVE.L	D0, A6                            ; Put pointer to string in A6
	MOVEQ	#$02, D0                          ; Code $02 for OSCLI
	BSR	writebyte_to_tuber2
	BSR	writestring_to_tuber2             ; Send string to the host

	BSR	readbyte_from_tuber2              ; Get response from the host
	MOVE.L	(SP)+, A6                         ; Restore original A0 value
	CMP.B	#$80, D0
	BEQ	SWI_OS_Byte_8E                    ; Enter language rom
	ANDI	#$FD, CCR                         ; Clear overflow flag
	RTS

; -----------------------------------------------------------------------------
; SWI &06: OS_Byte handler
; -----------------------------------------------------------------------------
SWI_OS_Byte
	CMP.B	#$80, D0
	BHS	SWI_OS_Byte80ff

	CMP.B	#$7E, D0                          ; Is it OSBYTE $7E? (Acknowledge detection of an ESCAPE condition)
	BNE	SWI_OS_Byte_007f
;;;;	BCLR.B	#6, escapeflag                    ; Clear the Escape flag, and pass the OSBYTE call to the host (rem-ed out because the host should reset the flag via an IRQ call)

SWI_OS_Byte_007f
	MOVE.L	D0, -(SP)                         ; Push D0 to the stack

	MOVE.B	#$04, D0                          ; Code $04 for OSBYTE $00-$7F call
	BSR	writebyte_to_tuber2               ; Write byte to TUBE ULA register 2

	MOVE.B	D1, D0                            ; Send X value to the host
	BSR	writebyte_to_tuber2               ; Write byte to TUBE ULA register 2

	MOVE.L	(SP), D0                          ; Pull D0 from the stack
	BSR	writebyte_to_tuber2               ; Write byte to TUBE ULA register 2

	BSR	readbyte_from_tuber2              ; Wait for data in TUBE ULA Data register 2 and return it in A
	MOVE.B	D0, D1                            ; Set D1 to the new X value received from the host
	MOVE.L	(SP)+, D0                         ; Restore D0
	RTS

SWI_OS_Byte80ff
	CMP.B	#$82, D0                          ; Is it OSBYTE $82? (Read machine high order address)
	BEQ	SWI_OS_Byte_82
	CMP.B	#$83, D0                          ; Is it OSBYTE $83? (Read top of operating system RAM address (OSHWM)
	BEQ	SWI_OS_Byte_83
	CMP.B	#$84, D0                          ; Is it OSBYTE $84? (Read bottom of display RAM address (HIMEM)
	BEQ	SWI_OS_Byte_84

	MOVE.L	D0, -(SP)                         ; Push D0 to the stack

	MOVE.B	#$06, D0                          ; Code $06 for OSBYTE $80-$81, $85-$FF call
	BSR	writebyte_to_tuber2               ; Write byte to TUBE ULA register 2

	MOVE.B	D1, D0                            ; Send X value to the host
	BSR	writebyte_to_tuber2               ; Write byte to TUBE ULA register 2

	MOVE.B	D2, D0                            ; Send Y value to the host
	BSR	writebyte_to_tuber2               ; Write byte to TUBE ULA register 2

	MOVE.L	(SP)+, D0                         ; Pull D0 from the stack
	BSR	writebyte_to_tuber2               ; Write byte to TUBE ULA register 2

	CMP.B	#$8E, D0                          ; Is it OSBYTE $8E? (Enter language ROM)
	BEQ	SWI_OS_Byte_8E

	CMP.B	#$9D, D0                          ; Is it OSBYTE $9D? (Fast TUBE BPUT)
	BEQ	SWI_OS_Byte_9D

	MOVE.L	D0, -(SP)                         ; Push D0 to the stack

	BSR	readbyte_from_tuber2              ; Wait for data in TUBE ULA Data register 2 and return it in A
	MOVE.W	D0, -(SP)                         ; Push returned Carry flag to stack

	BSR	readbyte_from_tuber2              ; Wait for data in TUBE ULA Data register 2 and return it in A
	MOVE.B	D0, D2                            ; Set D2 to the new Y value received from the host

	BSR	readbyte_from_tuber2              ; Wait for data in TUBE ULA Data register 2 and return it in A
	MOVE.B	D0, D1                            ; Set D1 to the new X value received from the host

	MOVE.L	(SP)+, D0                         ; Pull carry flag from the stack
	ASR.B	#8, D0                            ; Move bit 7 to carry flag
	MOVE.L	(SP)+, D0                         ; Pull D0 from the stack
	RTS

; -----------------------------------------------------------------------------
; SWI &06: OS_Byte $82 handler (Read machine high order address)
; -----------------------------------------------------------------------------
SWI_OS_Byte_82                                    ; SWI &06: OS_Byte $82 handler (Read machine high order address)
	MOVE.W	(hoaddr), D1
	MOVE.L	D1, D2
	ASR.L	#8, D2                            ; D2=D1 DIV 256 (don`t know if this is useful; hoaddr is a 32-bit value)
	RTS

; -----------------------------------------------------------------------------
; SWI &06: OS_Byte $83 handler (Read bottom of user memory)
; -----------------------------------------------------------------------------
SWI_OS_Byte_83                                    ; SWI &06: OS_Byte $83 handler (Read top of operating system RAM address: OSHWM)
	MOVE.L	(oshwm), D1
	MOVE.L	D1, D2
	ASR.L	#8, D2                            ; D2=D1 DIV 256 (don`t know if this is useful; oshwm is a 32-bit value)
	RTS

; -----------------------------------------------------------------------------
; SWI &06: OS_Byte $84 handler (Read top of user memory)
; -----------------------------------------------------------------------------
SWI_OS_Byte_84                                    ; SWI &06: OS_Byte $84 handler (Read bottom of display RAM address: HIMEM)
	MOVE.L	(himem), D1
	MOVE.L	D1, D2
	ASR.L	#8, D2                            ; D2=D1 DIV 256 (don`t know if this is useful; himem is a 32-bit value)
	RTS

; -----------------------------------------------------------------------------
; SWI &06: OS_Byte &8E handler (Enter language ROM)
; -----------------------------------------------------------------------------
SWI_OS_Byte_8E
	MOVE.L	(tubetransfer), A6                ; Set 'Current program'

SWI_OS_Byte_8E_01
	MOVE.B	6(A6), D1                         ; Get ROM type byte
	MOVEQ	#0, D0
	MOVE.B	7(A6), D0
	ADD.L	D0, A6

	TST.B	(A6)+                             ; Check for a copyright string (can`t do CMP.L since it`s not word aligned)
	BNE	SWI_OS_Byte_8E_entercode
	CMPI.B	#'(', (A6)+
	BNE	SWI_OS_Byte_8E_entercode
	CMPI.B	#'C', (A6)+
	BNE	SWI_OS_Byte_8E_entercode
	CMPI.B	#')', (A6)+
	BNE	SWI_OS_Byte_8E_entercode

	ANDI.B	#%00001111, D1                    ; Mask out the processor type bits
	CMPI.B	#%00000011, D1                    ; Is it 68k code?
	BNE	SWI_OS_Byte_8E_cannotrun          ; It`s not the correct type of code

SWI_OS_Byte_8E_entercode
	MOVE.L	(tubetransfer), A6                ; Set 'Current program' again
	MOVE.L	#$00000001, D0
	MOVE.L	#programstarttime, D1
	BSR	SWI_OS_Word                       ; Get program start time

	MOVEQ	#$01, D0                          ; Enter with A=1
	JMP	(A6)
	RTS

SWI_OS_Byte_8E_cannotrun
	MOVE.L	#err_cannot_run_code, D0          ; Point D0 to the ESCAPE error message
	MOVE.L	#0, error_pc
	BRA	SWI_OS_GenerateError              ; SWI OS_GenerateError
	
; -----------------------------------------------------------------------------
; SWI &06: OS_Byte $9D handler (Fast TUBE BPUT)
; -----------------------------------------------------------------------------
SWI_OS_Byte_9D                                    ; SWI &06: OS_Byte $9D handler (Fast TUBE BPUT)
	RTS

; -----------------------------------------------------------------------------
; SWI &07: OS_Word handler
; -----------------------------------------------------------------------------
SWI_OS_Word
	CMP.L	#$000000FF, D0
	BHI	SWI_OS_Word_error

	MOVE.L	A6, -(SP)
	MOVE.L	D0, -(SP)
	MOVE.L	D1, -(SP)
	MOVE.L	D2, -(SP)
	MOVE.L	D1, A6

	TST	D0                                ; Is the reason code $00?
	BNE	SWI_OS_Word_01ff                  ; No, then jump to OSWORD $01-$FF handler
	
	MOVE.L	D3, -(SP)                         ; OSWORD &00 handler
	MOVE.L	D4, -(SP)

	MOVE.W	(hoaddr), D0                      ; Get High Order pointer
	SWAP	D0                                ; Shift to bit 16-31

	MOVE.W	(A6), D0                          ; OS_Word &00 uses only a 16-bit buffer pointer
	MOVEQ	#$00, D1
	MOVE.B	2(A6), D1                         ; Maximum length
	MOVEQ	#$00, D2
	MOVE.B	3(A6), D2                         ; Minimum allowable ASCII value
	MOVEQ	#$00, D3
	MOVE.B	4(A6), D3                         ; Maximum allowable ASCII value
	MOVEQ	#$00, D4                          ; No special flags needed for this call

	BSR	SWI_OS_ReadLine32                 ; Jump to the OS_ReadLine32 handler

	MOVE.L	(SP)+, D4                         ; Clean up stack / restore registers
	MOVE.L	(SP)+, D3
	MOVE.L	(SP)+, D2                         ; D2 isn`t used since on OSWORD $00 exit it will hold the number of bytes in the string
	MOVE.L	D1, D2
	ADDQ	#1, D2                            ; Be sure to include the <CR>
	MOVE.L	(SP)+, D1
	MOVE.L	(SP)+, D0
	MOVE.L	(SP)+, A6
	ANDI	#$FD, CCR                         ; Clear overflow flag
	RTS

SWI_OS_Word_01ff
	MOVEQ	#$00, D1
	MOVEQ	#$00, D2
	CMP.B	#$14, D0                          ; 
	BHI	SWI_OS_Word_15ff

	MOVE.L	#osword_send_table, A0
	ADD.L	D0, A0                            ; Add displacement to A0
	SUBQ	#1, A0
	MOVE.B	(A0), D1                          ; Get the send length of the parameterblock from the table for OSWORD &01-&14
	MOVE.L	#osword_recv_table, A0
	ADD.L	D0, A0                            ; Add displacement to A0
	SUBQ	#1, A0
	MOVE.B	(A0), D2                          ; Get the receive length of the parameterblock from the table for OSWORD &01-&14
	BRA	SWI_OS_Word_send

SWI_OS_Word_15ff
	CMP.B	#$7F, D0
	BHI	SWI_OS_Word_80ff
	MOVEQ	#$10, D1                          ; Number of parameters to send
	MOVEQ	#$10, D2                          ; Number of parameters to be received
	BRA	SWI_OS_Word_send

SWI_OS_Word_80ff
	MOVE.B	(A6), D1                          ; Number of parameters to send
	MOVE.B	1(A6), D2                         ; Number of parameters to be received

SWI_OS_Word_send
	MOVE.L	D0, -(SP)                         ; Push D0 to the stack
	MOVE.B	#$08, D0                          ; Code &08 for OSWORD &01-&FF calls
	BSR	writebyte_to_tuber2               ; Send OSWORD &01-&FF command to the host
	MOVE.L	(SP)+, D0                         ; Pull D0 from the stack
	BSR	writebyte_to_tuber2               ; Send OSWORD reason code to the host
	MOVE.B	D1, D0                            ; 
	BSR	writebyte_to_tuber2               ; Send number of send-parameters to the host
	SUBQ	#1, D1                            ; Replace with a DBxx instruction?
	BMI	SWI_OS_Word_receive

SWI_OS_Word_send_loop
	MOVE.B	(A6, D1), D0                      ; Send the parameter block to the host processor
	BSR	writebyte_to_tuber2               ; Write byte to TUBE ULA register 2
	DBF	D1, SWI_OS_Word_send_loop

SWI_OS_Word_receive
	MOVE.B	D2, D0                            ; 
	BSR	writebyte_to_tuber2               ; Send number of receive-parameters to the host
	SUBQ	#1, D2                            ; Replace with a DBxx instruction?
	BMI	SWI_OS_Word_exit

SWI_OS_Word_receive_loop
	BSR	readbyte_from_tuber2              ; Wait for error number
	MOVE.B	D0, (A6, D2)
	DBF	D2, SWI_OS_Word_receive_loop

SWI_OS_Word_exit
	MOVE.L	(SP)+, D2
	MOVE.L	(SP)+, D1
	MOVE.L	(SP)+, D0
	MOVE.L	(SP)+, A6
	ANDI	#$FD, CCR                         ; Clear overflow flag
	RTS

SWI_OS_Word_error
	ORI	#$02, CCR                         ; Set overflow fag
	RTS

; -----------------------------------------------------------------------------
; SWI &08: OS_File: Read or write a whole file or its attributes
; -----------------------------------------------------------------------------
SWI_OS_File
	MOVE.L	D0, -(SP)                         ; Push D0 to the stack
	MOVE.B	#$14, D0                          ; Code $14 for OSFILE call
	BSR	writebyte_to_tuber2               ; Write byte to TUBE ULA register 2

	MOVE.L	D5, D0                            ; Send attrs/end address
	BSR	writelong_to_tuber2
	MOVE.L	D4, D0                            ; Send length/start address
	BSR	writelong_to_tuber2
	MOVE.L	D3, D0                            ; Send exec address
	BSR	writelong_to_tuber2
	MOVE.L	D2, D0                            ; Send load address
	BSR	writelong_to_tuber2
	MOVE.L	D1, A6
	BSR	writestring_to_tuber2             ; Send string at (A6) through TUBE ULA Data register 2

	MOVE.L	(SP)+, D0                         ; Pull D0 from the stack
	BSR	writebyte_to_tuber2               ; Write byte to TUBE ULA register 2

	BSR	readbyte_from_tuber2              ; Wait for data in TUBE ULA Data register 2 and return it in A
	MOVE.L	D0, -(SP)                         ; Push D0 to the stack (result code)

	BSR	readlong_from_tuber2              ; Read returned attrs
	MOVE.L	D0, D5
	BSR	readlong_from_tuber2              ; Read returned length
	MOVE.L	D0, D4
	BSR	readlong_from_tuber2              ; Read returned exec address
	MOVE.L	D0, D3
	BSR	readlong_from_tuber2              ; Read returned load address
	MOVE.L	D0, D2

	MOVE.L	(SP)+, D0                         ; Pull D0 from the stack
	RTS

; -----------------------------------------------------------------------------
; SWI &09: OS_Args: Read or write a file`s attributes
; -----------------------------------------------------------------------------
SWI_OS_Args
	MOVE.L	D0, -(SP)                         ; Push D0 to the stack
	MOVE.B	#$0C, D0                          ; Code $0C for OSARGS call
	BSR	writebyte_to_tuber2               ; Write byte to TUBE ULA register 2

	MOVE.B	D1, D0                            ; File handle
	BSR	writebyte_to_tuber2               ; Write byte to TUBE ULA register 2

	MOVE.L	D2, D0                            ; Pass data word in D2 to D0
	BSR	writelong_to_tuber2               ; Send 32-bit word from D0

	MOVE.L	(SP)+, D0                         ; Pull D0 from the stack (function)
	BSR	writebyte_to_tuber2               ; Write byte to TUBE ULA register 2

	BSR	readbyte_from_tuber2              ; Wait for data in TUBE ULA Data register 2 and return it in A
	MOVE.L	D0, -(SP)                         ; Push D0 to the stack (result)

	BSR	readlong_from_tuber2              ; Wait for 32-bit word from Tube
	MOVE.L	D0, D2                            ; Pass data word to D2

	MOVE.L	(SP)+, D0                         ; Pull D0 from the stack
	RTS

; -----------------------------------------------------------------------------
; SWI &0A: OS_BGet: Read a single byte from an open file
; -----------------------------------------------------------------------------
SWI_OS_BGet
	MOVE.B	#$0E, D0                          ; Code $0E for BGET call
	JSR	writebyte_to_tuber2               ; Write byte to TUBE ULA register 2
	MOVE.B	D1, D0                            ; File handle
	JSR	writebyte_to_tuber2               ; Write byte to TUBE ULA register 2
	BRA	SWI_OS_ReadC1                     ; Get carry bit and the byte read

; -----------------------------------------------------------------------------
; SWI &0B: OS_BPut: Write a single byte to an open file
; -----------------------------------------------------------------------------
SWI_OS_BPut
	MOVE.L	D0, -(SP)                         ; Push D0 to the stack
	MOVE.B	#$10, D0                          ; Code $10 for OSBPUT call
	BSR	writebyte_to_tuber2               ; Write byte to TUBE ULA register 2
	MOVE.B	D1, D0                            ; File handle
	BSR	writebyte_to_tuber2               ; Write byte to TUBE ULA register 2
	MOVE.L	(SP), D0                          ; Restore D0 from the stack
	BSR	writebyte_to_tuber2               ; Write byte to TUBE ULA register 2
	BSR	readbyte_from_tuber2              ; Wait for data in TUBE ULA Data register 2 and return it in A
	MOVE.L	(SP)+, D0                         ; Pull D0 from the stack
	RTS

; -----------------------------------------------------------------------------
; SWI &0C: OS_GBPB handler
; -----------------------------------------------------------------------------
SWI_OS_GBPB
	MOVE.L	D0, -(SP)                         ; Push D0 to the stack
	MOVE.B	#$16, D0                          ; Code $16 for OSGBPB call
	BSR	writebyte_to_tuber2               ; Write byte to TUBE ULA register 2

	MOVE.L	D4, D0
	BSR	writelong_to_tuber2               ; Send pointer
	MOVE.L	D3, D0
	BSR	writelong_to_tuber2               ; Send count
	MOVE.L	D2, D0
	BSR	writelong_to_tuber2               ; Send address
	MOVE.L	D1, D0
	BSR	writebyte_to_tuber2               ; Send handle
	MOVE.L	(SP)+, D0
	BSR	writelong_to_tuber2               ; Send function

	BSR	readbyte_from_tuber2              ; Read returned pointer
	MOVE.L	D0, D4
	BSR	readlong_from_tuber2              ; Read returned count
	MOVE.L	D0, D3
	BSR	readlong_from_tuber2              ; Read returned address
	MOVE.L	D0, D2
	BSR	readbyte_from_tuber2              ; Read returned cycle/handle
	MOVE.L	D0, D1

	BRA	SWI_OS_ReadC1                     ; Get carry bit and result byte

; -----------------------------------------------------------------------------
; SWI &0D: OS_Find: Open or close a file for random or sequential access
; -----------------------------------------------------------------------------
SWI_OS_Find
	MOVE.L	D0, -(SP)                         ; Push D0 to the stack
	MOVE.B	#$12, D0                          ; Code $12 for OSFIND call
	BSR	writebyte_to_tuber2               ; Write byte to TUBE ULA register 2
	MOVE.L	(SP)+, D0                         ; Pull D0 from the stack
	BSR	writebyte_to_tuber2               ; Write byte to TUBE ULA register 2
	TST	D0                                ; Should the file be closed? (result = $00)
	BNE	SWI_OS_Find2

	MOVE.L	D0, -(SP)                         ; Push D0 to the stack
	MOVE.B	D1, D0                            ; File handle
	BSR	writebyte_to_tuber2               ; Write byte to TUBE ULA register 2
	BSR	readbyte_from_tuber2              ; Wait for data in TUBE ULA Data register 2 and return it in A
	MOVE.L	(SP)+, D0                         ; Pull D0 from the stack
	RTS

SWI_OS_Find2
	BSR	writestring_to_tuber2             ; Send string at (A6) through TUBE ULA Data register 2
	BRA	readbyte_from_tuber2              ; Wait for data in TUBE ULA Data register 2 and return it in A

; -----------------------------------------------------------------------------
; SWI &0E: OS_ReadLine: Read a line from the current input stream
; -----------------------------------------------------------------------------
SWI_OS_ReadLine
	MOVE.L	D0, D4                            ; And put them in D4
	AND.L	#$D0000000, D4                    ; Mask out the OS_ReadLine flags (bit 31-30)
	BRA	SWI_OS_ReadLine32                 ; Jump to _OS_ReadLine32 handler

; -----------------------------------------------------------------------------
; SWI &0F: OS_Control: Read or write address handlers
; -----------------------------------------------------------------------------
SWI_OS_Control
	MOVE.L	D5, -(SP)                         ; Push D0 to the stack
	MOVE.L	D4, -(SP)                         ; Push D0 to the stack
	MOVE.L	D1, -(SP)                         ; Push D0 to the stack
	MOVE.L	D0, -(SP)                         ; Push D0 to the stack

	MOVE.L	D3, D1                            ; First we`re gonna deal with the event handler
	MOVE.L	#10, D0
	BSR	SWI_OS_ChangeEnvironment
	MOVE.L	D1, D4                            ; Temporary register for address of previous event handler

	MOVE.L	D2, D1                            ; Second is the escape state handler
	MOVE.L	#9, D0
	BSR	SWI_OS_ChangeEnvironment
	MOVE.L	D1, D5                            ; Temporary register for previous escape state handler

		                                  ; And finally, the error handler and buffer
	MOVE.L	(SP)+, D1                         ; Pull D1 from the stack (address of error handler)
	MOVE.L	(SP)+, D3                         ; Pull D3 from the stack (address of error handler buffer)

	MOVE.L	#6, D0
	BSR	SWI_OS_ChangeEnvironment
	MOVE.L	D1, D0                            ; On exit, D0 contains address of previous error handler
	MOVE.L	D3, D1                            ; On exit, D1 contains address of previous error handler buffer

	MOVE.L	D4, D3                            ; On Exit, D3 contains address of previous event handler
	MOVE.L	D5, D2                            ; On Exit, D2 contains address of previous escape state handler

	MOVE.L	(SP)+, D4                         ; Pull D4 from the stack (temporary register)
	MOVE.L	(SP)+, D5                         ; Pull D5 from the stack (temporary register)

	ANDI	#$FD, CCR                         ; Clear overflow flag
	RTS

; -----------------------------------------------------------------------------
; SWI &10: OS_GetEnv: Read environment parameters
; -----------------------------------------------------------------------------
SWI_OS_GetEnv
	MOVE.L	#buffer, D0
	MOVE.L	#himem, D1
	MOVE.L	#programstarttime, D2
	RTS

; -----------------------------------------------------------------------------
; SWI &11: OS_Exit: Pass control to the most recent exit handler
; -----------------------------------------------------------------------------
SWI_OS_Exit
	MOVE.L	(exitv), -(SP)
	RTS

; -----------------------------------------------------------------------------
; SWI &12: OS_SetEnv: Set environment parameters
; -----------------------------------------------------------------------------
SWI_OS_SetEnv
	MOVE.L	D3, -(SP)                         ; Push D3 to the stack
	MOVE.L	D2, -(SP)                         ; Push D2 to the stack
	MOVE.L	D1, -(SP)                         ; Push D1 to the stack
	MOVE.L	D0, -(SP)                         ; Push D0 to the stack

	MOVE.L	D7, D1                            ; First we`re gonna deal with the address exception handler
	MOVE.L	#4, D0
	BSR	SWI_OS_ChangeEnvironment
	MOVE.L	D1, D7

	MOVE.L	D6, D1                            ; Data abort handler
	MOVE.L	#3, D0
	BSR	SWI_OS_ChangeEnvironment
	MOVE.L	D1, D6

	MOVE.L	D5, D1                            ; Prefetch abort handler
	MOVE.L	#2, D0
	BSR	SWI_OS_ChangeEnvironment
	MOVE.L	D1, D5

	MOVE.L	D4, D1                            ; Undefined instruction handler
	MOVE.L	#1, D0
	BSR	SWI_OS_ChangeEnvironment
	MOVE.L	D1, D4

	MOVE.L	(SP)+, D1                         ; Exit handler
	MOVE.L	#11, D0
	BSR	SWI_OS_ChangeEnvironment
	MOVE.L	D1, D0                            ; We don`t have to worry about D2 becaouse OS_SetEnv doesn`t use it

	MOVE.L	(SP)+, D1                         ; Memory limit
	MOVE.L	D0, -(SP)
	MOVE.L	#0, D0
	BSR	SWI_OS_ChangeEnvironment
	
	MOVE.L	(SP)+, D0
	MOVE.L	(SP)+, D2
	MOVE.L	(SP)+, D3

	ANDI	#$FD, CCR                         ; Clear overflow flag
	RTS

; -----------------------------------------------------------------------------
; SWI &13: OS_IntOn - Enable interrupts
; -----------------------------------------------------------------------------
SWI_OS_IntOn
	ANDI.W	#$F8FF, SR
	RTS

; -----------------------------------------------------------------------------
; SWI &14: OS_IntOff - Disable interrupts
; -----------------------------------------------------------------------------
SWI_OS_IntOff
	ORI.W	#$0700, SR
	RTS

; -----------------------------------------------------------------------------
; SWI &15: OS_CallBack: Set up the CallBack handler
; -----------------------------------------------------------------------------
SWI_OS_CallBack
	MOVE.L	D3, -(SP)                         ; Push D3 to the stack
	MOVE.L	D2, -(SP)                         ; Push D2 to the stack
	CLR.L	D2
	EXG.L	D1, D3
	MOVE.L	D0, D1
	MOVE.B	#7, D0
	BSR	SWI_OS_ChangeEnvironment
	EXG.L	D1, D0
	EXG.L	D3, D1
	MOVE.L	(SP)+, D2
	MOVE.L	(SP)+, D3
	ANDI	#$FD, CCR                         ; Clear overflow flag
	RTS	

; -----------------------------------------------------------------------------
; SWI &16: OS_EnterOS - Switch to supervisor mode
; -----------------------------------------------------------------------------
SWI_OS_EnterOS
	ORI.W	#$2000, SR
	RTS

; -----------------------------------------------------------------------------
; SWI &18: OS_BreakCtrl: Set up the BreakPoint handler
; -----------------------------------------------------------------------------
SWI_OS_BreakCtrl
	MOVE.L	D3, -(SP)                         ; Push D3 to the stack
	MOVE.L	D2, -(SP)                         ; Push D2 to the stack
	CLR.L	D2
	EXG.L	D1, D3
	MOVE.L	D0, D1
	MOVE.B	#8, D0
	BSR	SWI_OS_ChangeEnvironment
	EXG.L	D1, D0
	EXG.L	D3, D1
	MOVE.L	(SP)+, D2
	MOVE.L	(SP)+, D3
	ANDI	#$FD, CCR                         ; Clear overflow flag
	RTS	

; -----------------------------------------------------------------------------
; SWI &19: OS_UnusedSWI: Read or write handler for unused SWI`s
; -----------------------------------------------------------------------------
SWI_OS_UnusedSWI
	MOVE.L	D3, -(SP)                         ; Push D3 to the stack
	MOVE.L	D2, -(SP)                         ; Push D3 to the stack
	MOVE.L	D1, -(SP)                         ; Push D3 to the stack
	MOVE.L	D0, D1
	MOVE.B	#12, D0
	BSR	SWI_OS_ChangeEnvironment
	MOVE.L	D1, D0
	MOVE.L	(SP)+, D1
	MOVE.L	(SP)+, D2
	MOVE.L	(SP)+, D3
	ANDI	#$FD, CCR                         ; Clear overflow flag
	RTS	

; -----------------------------------------------------------------------------
; SWI &1C: OS_Mouse: Read a mouse state from the buffer
; -----------------------------------------------------------------------------
SWI_OS_Mouse
	BSR	SWI_OS_ReadMonotonicTime          ; Return monotonic time in D0
	MOVE.L	D0, D3

	MOVE.L	#$40, D0                          ; OSWORD &40 call
	MOVE.L	buffer, D1                        ; Place result in buffer
	BSR	SWI_OS_Word

	CLR.L	D0
	CLR.L	D1
	MOVE.W	buffer, D0
	MOVE.W	buffer, D1
	SUBI.L	#640, D0                          ; Make value signed
	SUBI.L	#512, D1
	MULS	#51, D0                           ; D0=D0*51 (32768/(1280/2))
	LSL.L	#6, D1                            ; D1=D1*64 (32768/(1024/2))

	CLR.L	D2
	BTST	#7, buffer+$06                    ; b7=Right/Cancel, b6=Middle/Move, b5=Left/Execute
	BEQ	SWI_OS_Mouse_middle
	BSET	#0, D2

SWI_OS_Mouse_middle
	BTST	#6, buffer+$06
	BEQ	SWI_OS_Mouse_left
	BSET	#1, D2

SWI_OS_Mouse_left
	BTST	#5, buffer+$06
	BEQ	SWI_OS_Mouse_exit
	BSET	#2, D2

SWI_OS_Mouse_exit
	ANDI	#$FD, CCR                         ; Clear overflow flag
	RTS

; The ADVAL/INKEY method:
	MOVE.B	#$80, D0
	MOVE.B	#$07, D1
	MOVE.B	#$00, D2
	BSR	SWI_OS_Byte                       ; Mouse X position in D1=low, D2=high
	MOVE.B	#$80, D0
	MOVE.B	#$08, D1
	MOVE.B	#$00, D2
	BSR	SWI_OS_Byte                       ; Mouse Y position in D1=low, D2=high
	MOVE.B	#$80, D0
	MOVE.B	#$09, D1
	MOVE.B	#$00, D2
	BSR	SWI_OS_Byte                       ; Mouse buttons in %rml, set if pressed

	MOVE.B	#$81, D0
	MOVE.B	#$F6, D1
	MOVE.B	#$FF, D2
	BSR	SWI_OS_Byte                       ; Mouse left button
	MOVE.B	#$81, D0
	MOVE.B	#$F5, D1
	MOVE.B	#$FF, D2
	BSR	SWI_OS_Byte                       ; Mouse middle button
	MOVE.B	#$81, D0
	MOVE.B	#$F4, D1
	MOVE.B	#$FF, D2
	BSR	SWI_OS_Byte                       ; Mouse right button

; -----------------------------------------------------------------------------
; SWI &1E:OS_Module - Perform a module operation
; -----------------------------------------------------------------------------
SWI_OS_Module
	RTS

; -----------------------------------------------------------------------------
; SWI &21:OS_ReadUnsigned - Convert a string to an unsigned number
; -----------------------------------------------------------------------------
SWI_OS_ReadUnsigned
	MOVE.L	A6, -(SP)                         ; Push A6 to the stack
	MOVE.L	D7, -(SP)                         ; Push D7 to the stack
	MOVE.L	D6, -(SP)                         ; Push D6 to the stack
	MOVE.L	D4, -(SP)                         ; Push D4 to the stack
	MOVE.L	D3, -(SP)                         ; Push D3 to the stack
	MOVE.L	D0, -(SP)                         ; Push D0 to the stack

	MOVE.L	#$FFFFFFFF, D7                    ; Put default upper limit in D7
	BTST	#29, D0
	BEQ	SWI_OS_ReadUnsigned3
	MOVE.L	D2, D7                            ; Move supplied upper limit to D7

SWI_OS_ReadUnsigned3
	ANDI.L	#$000000FF, D0
	TST.L	D0
	BNE	SWI_OS_ReadUnsigned4
	MOVE.L	#10, D0                           ; If base is 0 then use base-10 as default

SWI_OS_ReadUnsigned4
	CMP.L	#2, D0
	BLO	SWI_OS_ReadUnsigned_badbase
	CMP.L	#36, D0
	BHI	SWI_OS_ReadUnsigned_badbase
	MOVE.L	D0, D6                            ; Move base to D6
	CLR.L	D2                                ; Clear result register

	MOVE.L	D1, A6
	BSR	skip_spaces
	ADDQ.L	#1, A6
	CMP.B	#'&', D0                          ; Acorn hex sign
	BNE	SWI_OS_ReadUnsigned5
	MOVE.L	#$10, D6                          ; Base is 16
	ADDQ.L	#1, A6
	BRA	SWI_OS_ReadUnsigned_loop

SWI_OS_ReadUnsigned5
	CMP.B	#'$', D0                          ; 68k hex sign
	BNE	SWI_OS_ReadUnsigned_loop
	MOVE.L	#$10, D6                          ; Base is 16
	ADDQ.L	#1, A6

SWI_OS_ReadUnsigned_loop
	CMPI.B	#'9', D0
	BLS	SWI_OS_ReadUnsigned_loop2
	ANDI.B	#$DF, D0                          ; Make uppercase
	SUBI.B	#$07, D0

SWI_OS_ReadUnsigned_loop2
	SUBI.B	#'0', D0
	BMI	SWI_OS_ReadUnsigned_exit
	CMP.B	D6, D0                            ; Check upper base limit
	BHI	SWI_OS_ReadUnsigned_exit
	CMP.L	#$10, D6                          ; Check if the base is 16 (HEX)
	BNE	SWI_OS_ReadUnsigned_loop2a
	LSL.L	#4, D2                            ; Do a quick shift (D2 = D2 * 16)
	ADD.L	D0, D2                            ; Add current digit to result
	MOVE.B	(A6)+, D0                         ; Get next char
	BRA	SWI_OS_ReadUnsigned_loop          ; And branch to main loop

SWI_OS_ReadUnsigned_loop2a
	MOVE.L	D6, D3                            ; Make copy of base so we preserve the original value
	SUBQ.L	#2, D3
	MOVE.L	D2, D4                            ; Remember result before processing this digit

SWI_OS_ReadUnsigned_loop3
	ADD.L	D4, D2                            ; result = result * base
	BCS	SWI_OS_ReadUnsigned_numbtoobig    ; Check for overflow
	DBF	D3, SWI_OS_ReadUnsigned_loop3     ; Multiply by base
	ADD.L	D0, D2                            ; Add current digit to result
	MOVE.B	(A6)+, D0
	BRA	SWI_OS_ReadUnsigned_loop

SWI_OS_ReadUnsigned_exit
	TST.L	D2
	BEQ	SWI_OS_ReadUnsigned_badnumber     ; Jump if no digits were processed
	TST.L	D7                                ; Was an upper limit set?
	BEQ	SWI_OS_ReadUnsigned_exit2         ; If not, then skip upper limit check
	CMP.L	D7, D0
	BHI	SWI_OS_ReadUnsigned_numbtoobig

SWI_OS_ReadUnsigned_exit2
	MOVE.L	A6, D1                            ; D1 = first unused char after value
	SUBQ.L	#1, D1
	MOVE.L	(SP)+, D0                         ; Preserve D0 on exit
	MOVE.L	(SP)+, D3                         ; Preserve D3 on exit
	MOVE.L	(SP)+, D4                         ; Preserve D4 on exit
	MOVE.L	(SP)+, D6                         ; Preserve D6 on exit
	MOVE.L	(SP)+, D7                         ; Preserve D7 on exit
	MOVE.L	(SP)+, A6                         ; Preserve A6 on exit
	ANDI	#$FD, CCR                         ; Clear overflow flag
	RTS

SWI_OS_ReadUnsigned_badbase
	MOVE.L	#err_badbase, D0
	BRA	SWI_OS_ReadUnsigned_errexit

SWI_OS_ReadUnsigned_badnumber
	MOVE.L	#err_badnumber, D0
	BRA	SWI_OS_ReadUnsigned_errexit

SWI_OS_ReadUnsigned_numbtoobig
	MOVE.L	#err_number_too_big, D0

SWI_OS_ReadUnsigned_errexit
	MOVE.L	(SP)+, D3                         ; Discard original value of D0
	MOVE.L	(SP)+, D3                         ; Preserve D3 on exit
	MOVE.L	(SP)+, D4                         ; Preserve D4 on exit
	MOVE.L	(SP)+, D6                         ; Preserve D6 on exit
	MOVE.L	(SP)+, D7                         ; Preserve D7 on exit
	MOVE.L	(SP)+, A6                         ; Preserve A6 on exit
	ORI	#$02, CCR                         ; Set overflow fag
	RTS

; -----------------------------------------------------------------------------
; SWI &28: OS_BinaryToDecimal
; -----------------------------------------------------------------------------
SWI_OS_BinaryToDecimal
	MOVE.L	D0, -(SP)
	MOVE.L	D1, -(SP)
	BSR	SWI_OS_ConvertInteger4
	MOVE.L	D1, D2                            ; Length of string in D2
	MOVE.L	(SP)+, D1                         ; Preserve D1 on exit
	MOVE.L	(SP)+, D0                         ; Preserve D0 on exit
	RTS

; -----------------------------------------------------------------------------
; SWI &29: OS_FSControl: Control the filing system manager and the filing system itself
; -----------------------------------------------------------------------------
SWI_OS_FSControl
	CMP.B	#$3A, D0                          ; Is D0 within the allowed range?
	BHI	SWI_OS_FSControl_error            ; If not, exit with Not Supported error message

	MOVE.L	A6, -(SP)                         ; Push A6 to the stack

	ADD	D0, D0                            ; Multiply D0 by 4 (ADD`s are quicker than MUL`s)
	ADD	D0, D0

	MOVE.L	OS_FSControl_jumptable, A6        ; Optimize this???
	ADD.L	D0, A6
	LEA	(A6), A6                          ; Get vector
	JSR	(A6)                              ; Jump to reason handler

	MOVE.L	(SP)+, A6                         ; Restore A6
	ANDI	#$FD, CCR                         ; Clear overflow flag
	RTS

SWI_OS_FSControl_error
	MOVE.L	#err_bad_fscontrol_call, D0
	ORI	#$02, CCR                         ; Set overflow fag
	RTS

; -----------------------------------------------------------------------------
; SWI &29: OS_FSControl &0A: Set filing system options
; -----------------------------------------------------------------------------
SWI_OS_FSControl0A
	MOVE.B	#$8B, D0                          ; OSBYTE &8B: Select file options
	BSR	SWI_OS_Byte                       ; Do OSBYTE call
	MOVE.B	#$0A, D0                          ; Preserve old value
	RTS

; -----------------------------------------------------------------------------
; SWI &29: OS_FSControl &16: Close all open files
; -----------------------------------------------------------------------------
SWI_OS_FSControl16
	MOVEQ	#$00, D0                          ; OSFILE &00: Close file
	MOVEQ	#$00, D1                          ; File handle = 0 so close all files
	BSR	SWI_OS_File                       ; Do OSFILE call
	MOVE.B	#$16, D0                          ; Preserve old value
	RTS

; -----------------------------------------------------------------------------
; SWI &2B: OS_GenerateError: Generate an error and invoke the error handler
; -----------------------------------------------------------------------------
SWI_OS_GenerateError
;	BTST	#17, D0                           ; Test if X-bit was set -> doesn`t work here since D0 is pointer to error block, not SWI number
;	BNE	SWI_OS_GenerateError_exit
	MOVE.L	(errorv), -(SP)
	RTS

;SWI_OS_GenerateError_exit
;	ORI	#$02, CCR                         ; Set overflow fag
;	RTS


; -----------------------------------------------------------------------------
; SWI &2C: OS_ReadEscapeState: Check whether an escape contition has occurred
; -----------------------------------------------------------------------------
SWI_OS_ReadEscapeState
	BTST.B	#6, escapeflag                    ; Test if the escape flag bit is set
	BNE	SWI_OS_ReadEscapeState_set        ; Jump if the escape flag is set
	ANDI	#$FE, CCR                         ; Clear carry flag
	RTS

SWI_OS_ReadEscapeState_set
	ORI	#$01, CCR                         ; Set Carry flag
	RTS                                       ; Return

; -----------------------------------------------------------------------------
; SWI &2F: OS_ReadPalette: Read the setting of a particular colour
; -----------------------------------------------------------------------------
SWI_OS_ReadPalette
	MOVE.L	D4, -(SP)                         ; Push D4 to the stack
	MOVEQ	#$01, D4                          ; PaletteV entry code &01: PaletteV_ReadEntry
;	MOVEQ	#$23, R9                          ; Vector nr 23

	MOVE.L	A6, -(SP)                         ; Save A6
	MOVE.L	(palettev).L, A6
	JSR	(A6)                              ; Jump to PaletteV
	MOVE.L	(SP)+, A6                         ; Restore A6
	MOVE.L	(SP)+, D4                         ; Restore D4
	RTS

; -----------------------------------------------------------------------------
; SWI &30: OS_ServiceCall: Issue service call to module
; -----------------------------------------------------------------------------
SWI_OS_ServiceCall
	RTS

; -----------------------------------------------------------------------------
; SWI &32: OS_ReadPoint: Returns the colour and tint of a point
; -----------------------------------------------------------------------------
SWI_OS_ReadPoint
	CMP.L	#$000004FF, D0                    ; Is D0 (R0) within the allowed range?
	BHI	SWI_OS_ReadPoint_error            ; If not, exit with Out Of Range error message
	CMP.L	#$000003FF, D1                    ; Is D1 (R1) within the allowed range?
	BHI	SWI_OS_ReadPoint_error            ; If not, exit with Out Of Range error message

	MOVE.L	D0, -(SP)                         ; Push D0 to the stack
	MOVE.L	D1, -(SP)                         ; Push D1 to the stack
	MOVE.W	D0, buffer
	MOVE.W	D1, buffer+2
	MOVE.L	#buffer, D1
	MOVEQ	#$09, D0                          ; OSWORD call 9: Read pixel value
	BSR	SWI_OS_Word
	MOVEQ	#$00, D2
	MOVEQ	#$00, D3
	MOVE.B	buffer+4, D2
	MOVE.L	(SP)+, D1                         ; Pull D1 from the stack
	MOVE.L	(SP)+, D0                         ; Pull D0 from the stack
	CMP.B	#$FF, D2
	BEQ	SWI_OS_ReadPoint_error            ; Jump if point was off screen or non-graphical
	MOVEQ	#$00, D4
	ANDI	#$FD, CCR                         ; Clear overflow flag
	RTS

SWI_OS_ReadPoint_error
	MOVE.L	#err_out_of_range, D0             ; Pointer to error block in D0
	MOVEQ	#$FF, D4                          ; Point is off screen so D4(R4) = -1
	ORI	#$02, CCR                         ; Set overflow fag
	RTS

; -----------------------------------------------------------------------------
; SWI &34: OS_CallAVector: Call a vector directly
; -----------------------------------------------------------------------------
SWI_OS_CallAVector
	CMP.L	#$0000002F, A2                    ; Is A2 (R9) within the allowed range?
	BHI	SWI_OS_CallAVector_error          ; If not, exit with Not Supported error message

	MOVE.L	A2, -(SP)                         ; Push A3 to the stack

	ADD	A2, A2                            ; Multiply A2 by 4 (ADD's are quicker than MUL's)
	ADD	A2, A2

	ADD.L	vector_table, A2                  ; Optimize this???
	LEA	(A2), A2                          ; Get vector
	JSR	(A2)                              ; Jump to reason handler

	MOVE.L	(SP)+, A2                         ; Pull A2 from the stack
	ANDI	#$FD, CCR                         ; Clear overflow flag
	RTS

SWI_OS_CallAVector_error
	MOVE.L	#err_bad_vector_number, D0
	ORI	#$02, CCR                         ; Set overflow fag
	RTS

; -----------------------------------------------------------------------------
; SWI &36: OS_RemoveCursors: Remove the cursors from the screen (VDU 23,1,0;0;0;0;)
; -----------------------------------------------------------------------------
SWI_OS_RemoveCursors
	MOVE.L	D0, -(SP)                         ; Push D0 to the stack
	MOVE.L	D1, -(SP)                         ; Push D1 to the stack
	MOVE.L	#msg_swi_removecursors, D0        ; Location of message in D0
	MOVE.L	#$0B, D1                          ; Length of string
	BSR	SWI_OS_WriteN
	MOVE.L	(SP)+, D1                         ; Pull D0 from the stack
	MOVE.L	(SP)+, D0                         ; Pull D1 from the stack
	ANDI	#$FD, CCR                         ; Clear overflow flag
	RTS

; -----------------------------------------------------------------------------
; SWI &37: OS_RestoreCursors: Restore the cursors from the screen (VDU 23,1,1;0;0;0;)
; -----------------------------------------------------------------------------
SWI_OS_RestoreCursors
	MOVE.L	D0, -(SP)                         ; Push D0 to the stack
	MOVE.L	D1, -(SP)                         ; Push D1 to the stack
	MOVE.L	#msg_swi_restorecursors, D0       ; Location of message in D0
	MOVE.L	#$0B, D1                          ; Length of string
	BSR	SWI_OS_WriteN
	MOVE.L	(SP)+, D1                         ; Pull D0 from the stack
	MOVE.L	(SP)+, D0                         ; Pull D1 from the stack
	ANDI	#$FD, CCR                         ; Clear overflow flag
	RTS

; -----------------------------------------------------------------------------
; SWI &38: OS_SWINumberToString: Convert a SWI number to a SWI name string
; -----------------------------------------------------------------------------
SWI_OS_SWINumberToString
	MOVE.L	A6, -(SP)                         ; Push A6 to the stack
	MOVE.L	A1, -(SP)                         ; Push A1 to the stack
	MOVE.L	D1, -(SP)                         ; Push D1 to the stack
	MOVE.L	D0, -(SP)                         ; Push D0 to the stack
	MOVE.L	D1, A6

	ANDI.L	#XOS_Bit, D0
	BEQ	SWI_OS_SWINumberToString2
	SUBQ.L	#1, D2
	BMI	SWI_OS_SWINumberToString_errorV
	MOVE.B	#'X', (A6)+

SWI_OS_SWINumberToString2
	LEA	SWITable, A1                      ; Point A1 to SWI lookup table

SWI_OS_SWINumberToString_loop
	CMP.L	(A1)+, D0                         ; Check SWI number
	BEQ	SWI_OS_SWINumberToString_found    ; Yes, this is our SWI handler

SWI_OS_SWINumberToString_loop2
	MOVE.L	(A1)+, D1                         ; Get next word
	CMP.B	#$FF, D1                          ; End of SWI-table?
	BEQ	SWI_OS_SWINumberToString_undef    ; Yes, so pass this SWI call to the _UKSWIV
	CMP.B	#$00, D1                          ; Check for end of string marker
	BNE	SWI_OS_SWINumberToString_loop2    ; This loop can probably be optimized, but it works for now
	BRA	SWI_OS_SWINumberToString_loop

SWI_OS_SWINumberToString_found
	MOVE.L	(A1)+, D0                         ; Skip address

SWI_OS_SWINumberToString_found2
	SUBQ.L	#1, D2
	BMI	SWI_OS_SWINumberToString_errorV
	MOVE.B	(A1)+, (A6)+
	BNE	SWI_OS_SWINumberToString_found2

SWI_OS_SWINumberToString_exit
	MOVE.L	(SP)+, D0
	MOVE.L	(SP)+, D1
	MOVE.L	(SP)+, A1
	MOVE.L	(SP)+, A6
	RTS

SWI_OS_SWINumberToString_undef
	CMPI.L	#$0D, D1
	BLO	SWI_OS_SWINumberToString_errorV
	MOVE.L	#'OS_U', (A6)+
	MOVE.L	#'ndef', (A6)+
	MOVE.L	#'ined', (A6)+
	MOVE.B	#$00, (A6)+
	BRA	SWI_OS_SWINumberToString_exit

SWI_OS_SWINumberToString_errorV
	ORI	#$02, CCR                         ; Set overflow fag
	MOVE.L	#err_buffer_overflow, (SP)
	BRA	SWI_OS_SWINumberToString_exit

; -----------------------------------------------------------------------------
; SWI &39: OS_SWINumberFromString: Convert a SWI name string to a SWI number
; -----------------------------------------------------------------------------
SWI_OS_SWINumberFromString
	MOVE.L	A6, -(SP)
	MOVE.L	A5, -(SP)
	MOVE.L	D1, -(SP)                         ; SWI pointer

	LEA	SWITable, A5                      ; Point A1 to SWI lookup table

SWI_OS_SWINumberFromString_loop
	MOVE.L	(SP), A6                          ; Get pointer to SWI name in A6
	MOVE.L	(A5)+, D0                         ; SWI number in D0
	ADDQ.L	#4, A5                            ; Skip address

SWI_OS_SWINumberFromString_loop2
	CMP.L	(A5)+, (A6)+
	BNE	SWI_OS_SWINumberFromString_skip
	TST.B	-1(A5)
	BNE	SWI_OS_SWINumberFromString_loop2

	MOVE.L	(SP)+, D1
	MOVE.L	(SP)+, A5
	MOVE.L	(SP)+, A6
	RTS                                       ; We`ve found our SWI number, so exit

SWI_OS_SWINumberFromString_skip
	MOVE.L	(A5)+, D0
	TST.B	D0
	BNE	SWI_OS_SWINumberFromString_skip
	CMP.B	#$FF, D0
	BNE	SWI_OS_SWINumberFromString_loop

	MOVE.L	(SP)+, D1
	MOVE.L	(SP)+, A5
	MOVE.L	(SP)+, A6
	MOVE.L	#err_swi_name_not_known, D0
	ORI	#$02, CCR                         ; Set overflow fag
	RTS

; -----------------------------------------------------------------------------
; SWI &3A: OS_ValidateAddress: Check that a range of addresses are in logical RAM
; -----------------------------------------------------------------------------
SWI_OS_ValidateAddress
	TST.L	D0                                ; Check minimum address against lower limit of RAM
	BLT	SWI_OS_ValidateAddress_error      ; Jump if it's less than the lower limit
	CMP.L	(ramsize), D1                     ; Check maximum address against upper limit of RAM
	BHI	SWI_OS_ValidateAddress_error      ; Jump if it's more than the lower limit
	
	ANDI	#$FE, CCR                         ; Clear carry flag
	RTS

SWI_OS_ValidateAddress_error
	ORI	#$01, CCR                         ; Set Carry flag
	RTS

; -----------------------------------------------------------------------------
; SWI &3F: SWI_OS_CheckModeValid: Check if it is possible to change to a specified screen mode
; -----------------------------------------------------------------------------
SWI_OS_CheckModeValid
	CMPI.L	#$00000007, D0
	BHI	SWI_OS_CheckModeValid_error
	ANDI	#$FE, CCR                         ; Clear carry flag
	RTS

SWI_OS_CheckModeValid_error
	MOVE.L	#-1, D0                           ; Screen mode is non-existent
	MOVE.L	#-2, D1                           ; Unable to select alternative screen mode
	ORI	#$01, CCR                         ; Set Carry flag
	RTS

; -----------------------------------------------------------------------------
; SWI &40: SWI_OS_ChangeEnvironment: Read or write address handlers
; -----------------------------------------------------------------------------
SWI_OS_ChangeEnvironment
	MOVE.L	(changeenvironmentv), -(SP)
	RTS

; -----------------------------------------------------------------------------
; SWI &42: OS_ReadMonotonicTime: Return the number of centiseconds since the last hard reset
; -----------------------------------------------------------------------------
SWI_OS_ReadMonotonicTime
	MOVE.L	D1, -(SP)
	MOVE.L	#$01, D0
	MOVE.L	#buffer, D1
	BSR	SWI_OS_Word                       ; Get monotomic time
	MOVE.L	buffer, D0                        ; Current time in centiseconds in D0
	SUB.L	osstarttime, D0                   ; Substract OS start time
	MOVE.L	(SP)+, D1
	RTS

; -----------------------------------------------------------------------------
; SWI &45: OS_Plot: Perform a direct PLOT call using VDU
; -----------------------------------------------------------------------------
SWI_OS_Plot
	CMP.L	#$000004FF, D0                    ; Is D0 (R0) within the allowed range?
	BHI	SWI_OS_Plot_error                 ; If not, exit with Out of range error message
	CMP.L	#$000003FF, D1                    ; Is D1 (R1) within the allowed range?
	BHI	SWI_OS_Plot_error                 ; If not, exit with Out of range error message

	MOVE.L	D0, -(SP)                         ; Push D0 to the stack

	MOVEQ	#$19, D0                          ; VDU code for PLOT (VDU 25)
	BSR	SWI_OS_WriteC                     ; Output to host

	MOVE.L	(SP)+, D0                         ; Pull D0 from the stack
	BSR	SWI_OS_WriteC                     ; And output the PLOT command code to host

	MOVE.W	D1, D0
	BSR	SWI_OS_WriteC                     ; Output LSB of X-co-oordinate first
	LSR.L	#8, D0
	BSR	SWI_OS_WriteC                     ; And then MSB of X-co-oordinate

	MOVE.W	D2, D0
	BSR	SWI_OS_WriteC                     ; Output LSB of X-co-oordinate first
	LSR.L	#8, D0
	BSR	SWI_OS_WriteC                     ; And then MSB of X-co-oordinate

	ANDI	#$FD, CCR                         ; Clear overflow flag
	RTS                                       ; Return

SWI_OS_Plot_error
	MOVE.L	#err_out_of_range, D0             ; Pointer to error block in D0
	MOVEQ	#$FF, D4                          ; Point is off screen so D4(R4) = -1
	ORI	#$02, CCR                         ; Set overflow fag
	RTS


; -----------------------------------------------------------------------------
; SWI &46: OS_WriteN - Write the first D1 characters of the string pointed to by D0
; -----------------------------------------------------------------------------
SWI_OS_WriteN
	CMPI.L	#0, D1                            ; Check if size is 0
	BEQ	SWI_OS_WriteN_exit
	SUBQ	#1, D1

	MOVE.L	A0, -(SP)                         ; Save A0
	MOVE.L	D0, -(SP)
	MOVE.L	D1, -(SP)

	MOVE.L	D0, A0

SWI_OS_WriteN_loop
	MOVE.B	(A0)+, D0                         ; Get byte in D0
	BSR	SWI_OS_WriteC                        ; Print byte
	DBF	D1, SWI_OS_WriteN_loop

	MOVE.L	(SP)+, D1                         ; Preserve D1 on exit
	MOVE.L	(SP)+, D0                         ; Preserve D0 on exit
	MOVE.L	(SP)+, A0                         ; Restore A0

SWI_OS_WriteN_exit
	RTS

; -----------------------------------------------------------------------------
; SWI &48: OS_WriteEnv - Set the program environment command string and start time
; -----------------------------------------------------------------------------
SWI_OS_WriteEnv
	MOVE.L	A6, -(SP)                         ; Save A6
	MOVE.L	A5, -(SP)                         ; Save A5
	TST.L	D0
	BEQ	SWI_OS_WriteEnv_time
	MOVE.L	D0, A6
	MOVE.L	#buffer, A5

SWI_OS_WriteEnv_stringloop
	MOVE.B	(A6)+, (A5)+
	BNE	SWI_OS_WriteEnv_stringloop

SWI_OS_WriteEnv_time
	TST.L	D1
	BEQ	SWI_OS_WriteEnv_exit
	
	MOVE.L	D2, -(SP)
	MOVE.L	#4, D2
	MOVE.L	D1, A6
	MOVE.L	#programstarttime, A5

SWI_OS_WriteEnv_timeloop
	MOVE.B	(A6)+, (A5)+
	SUBQ.L	#1, D2
	BPL	SWI_OS_WriteEnv_timeloop
	MOVE.L	(SP)+, D2

SWI_OS_WriteEnv_exit
	MOVE.L	(SP)+, A5
	MOVE.L	(SP)+, A6
	RTS

; -----------------------------------------------------------------------------
; SWI &50: OS_ExitAndDie: Kill a module and pass control to the most recent exit handler
; -----------------------------------------------------------------------------
SWI_OS_ExitAndDie
	MOVE.L	D2, -(SP)
	MOVE.L	D1, -(SP)
	MOVE.L	D0, -(SP)

;	MOVE.L	A2, Curr_Active_Object
	MOVE.L	D3, D1
	MOVE.L	#$04, D0                          ; OS_Module reason &04: Delete module
	BSR	SWI_OS_Module

	MOVE.L	(SP)+, D0
	MOVE.L	(SP)+, D1
	MOVE.L	(SP)+, D2
	BRA	SWI_OS_Exit

; -----------------------------------------------------------------------------
; SWI &55: OS_ReadDefaultHandler: Return the address of the default handler
; -----------------------------------------------------------------------------
SWI_OS_ReadDefaultHandler
	CMP	#16, D0
	BLS	SWI_OS_ReadDefaultHandler2

SWI_OS_ReadDefaultHandlererror
	MOVE.L	#err_bad_environment_number, D0
	ORI	#$02, CCR                         ; Set overflow fag
	RTS

SWI_OS_ReadDefaultHandler2
	LEA	_ChangeEnvironment_table, A0
	LSL.L	#2, D0                            ; D0 = D0 * 4
	ADD.L	D0, A0                            ; A0 = A0+(D0*3)
	ADD.L	D0, A0
	ADD.L	D0, A0
	MOVE.L	(A0)+, D1
	BEQ	_ChangeEnvironmentVerror          ; Vector not implemented
	ADDI.L	#bios_address, D1

	MOVE.L	(A0)+, D2
	BEQ	SWI_OS_ReadDefaultHandler3        ; Skip if no parameter is available
	ADDI.L	#bios_address, D2
	
SWI_OS_ReadDefaultHandler3
	MOVE.L	(A0)+, D3
	BEQ	SWI_OS_ReadDefaultHandler_exit    ; Skip if no parameter is available
	ADDI.L	#bios_address, D3

SWI_OS_ReadDefaultHandler_exit
	RTS

; -----------------------------------------------------------------------------
; SWI &56: OS_SetECFOrigin: Set the origin of the ECF pattern (VDU23,17,6,x;y;0,0,0)
; -----------------------------------------------------------------------------
SWI_OS_SetECFOrigin
	CMP.L	#$000004FF, D0                    ; Is D0 (R0) within the allowed range?
	BHI	SWI_OS_SetECFOrigin_error         ; If not, exit with Not Supported error message
	CMP.L	#$000003FF, D1                    ; Is D1 (R1) within the allowed range?
	BHI	SWI_OS_SetECFOrigin_error         ; If not, exit with Not Supported error message

	MOVE.L	D0, -(SP)                         ; Push D0 to the stack
	MOVE.L	D1, -(SP)
	MOVE.B	#23, D0
	BSR	SWI_OS_WriteC
	MOVE.B	#17, D0
	BSR	SWI_OS_WriteC
	MOVE.B	#6, D0
	BSR	SWI_OS_WriteC
	MOVE.L	(SP)+, D0
	ROR.L	#8, D0
	BSR	SWI_OS_WriteC                     ; X-coord MSB
	ROL.L	#8, D0
	BSR	SWI_OS_writeC                     ; X-coord LSB
	MOVE.L	D1, D0
	ROR.L	#8, D0
	BSR	SWI_OS_WriteC                     ; Y-coord MSB
	ROL.L	#8, D0
	BSR	SWI_OS_writeC                     ; Y-coord LSB
	MOVEQ	#$00, D0
	BSR	SWI_OS_WriteC
	BSR	SWI_OS_WriteC
	BSR	SWI_OS_WriteC
	MOVE.L	(SP)+, D1                         ; Pull D1 from the stack
	MOVE.L	(SP)+, D0                         ; Pull D0 from the stack
	ANDI	#$FE, CCR                         ; Clear carry flag
	RTS

SWI_OS_SetECFOrigin_error
	MOVE.L	#err_out_of_range, D0             ; Pointer to error block in D0
	ORI	#$02, CCR                         ; Set overflow fag
	RTS

; -----------------------------------------------------------------------------
; SWI &59: OS_Confirm: Get a yes or no answer
; -----------------------------------------------------------------------------
SWI_OS_Confirm
	BSR	SWI_OS_ReadC                      ; Read one character from the input stream
	ORI.B	#%00100000, D0                    ; Make character lower-case
	CMP.B	#'y', D0                          ; Is it 'Y'?
	RTS

; -----------------------------------------------------------------------------
; SWI &5B: OS_CRC: Calculate 16-bit CRC value
; -----------------------------------------------------------------------------
SWI_OS_CRC
	MOVE.L	A6, -(SP)                         ; Push A6 to the stack
	MOVE.L	D4, -(SP)                         ; Push D4 to the stack

	MOVE.L	D1, A6

	OR.W	D3, D3                            ; Test for zero size
	BEQ	SWI_OS_CRC_exit

SWI_OS_CRC_Byteloop
	MOVE.B	(A6), D4                          ; Get next byte
	ASL.W	#8, D4                            ; move to high order byte within word
	EOR.W	D4, D0                            ; xor data into current CRC
	MOVEQ	#7, D4                            ; 8 bits in byte - 1 for DBRA

SWI_OS_CRC_Bitloop
	ASL.W	#1, D0                            ; Shift CRC register
	BCC	SWI_CrcBlock_30                   ; Check for high order bit rolling into carry
	EORI.W	#$1021, D0                        ; Apply feedback polynomial

SWI_CrcBlock_30:
	DBRA	D4, SWI_OS_CRC_Bitloop            ; Bit loop
	ADD.W	D3, A6                            ; Increase pointer with D1
	CMP.L	A6, D2                            ; Have we reached the end?
	BLO	SWI_OS_CRC_Byteloop               ; No, process next byte (note: according to the RiscOS documentation this should be a BNE)

SWI_OS_CRC_exit
	MOVE.L	(SP)+, D4                         ; Pull D4 from the stack
	MOVE.L	(SP)+, A6                         ; Pull A6 from the stack
	ANDI	#$FD, CCR                         ; Clear overflow flag
	RTS	                                  ; Return new CRC in D0

; -----------------------------------------------------------------------------
; SWI &5D: OS_PrintChar: Send character to the printer
; -----------------------------------------------------------------------------
SWI_OS_PrintChar
	MOVE.B	D0, D2                            ; Byte to print
	MOVEQ	#$8A, D0                          ; OSWORD &8A (138): Insert value into buffer
	MOVEQ	#$03, D1                          ; Buffer 3: printer
	BSR	SWI_OS_Byte                       ; Call OS_Byte

	                                          ; Carry is set if buffer was full

;	ANDI	#$FD, CCR                         ; Clear overflow flag

	RTS                                       ; Return

; -----------------------------------------------------------------------------
; SWI &7C: OS_LeaveOS - Switch to user mode
; -----------------------------------------------------------------------------
SWI_OS_LeaveOS
	ANDI.W	#$DFFF, SR
	RTS

; -----------------------------------------------------------------------------
; SWI &7D: OS_ReadLine32: Read a line from the current input stream
; -----------------------------------------------------------------------------
SWI_OS_ReadLine32
	IFNE DEBUG
		MOVE.L	D0, A1
		MOVE.B  #2, D0
		TRAP    #15
		MOVE.B	#$0D, (A1, D1.W)
		CMP.B	#$1B, (A1)
		BEQ	DBRL32esc
		ANDI	#$FE, CCR                         ; Clear carry flag
		RTS
DBRL32esc
		ORI	#$01, CCR                         ; Set Carry flag
		RTS
	ENDC
	IFEQ DEBUG

	CMP.L	#$FF, D1                          ; Is buffer size larger than 255 bytes?
	BHI	SWI_OS_ReadLine32_error

	MOVE.L	A0, -(SP)                         ; Push A0 to the stack
	MOVE.L	D0, A0                            ; Put buffer address in A0

	MOVE.B	#$0A, D0                          ; Code &0A for OSWORD &00 call
	BSR	writebyte_to_tuber2               ; Write byte to TUBE ULA register 2

	MOVE.B	D3, D0                            ; Send parameter 6 (Maximum allowable ASCII value)
	BSR	writebyte_to_tuber2               ; Write byte to TUBE ULA register 2
	MOVE.B	D2, D0                            ; Send parameter 5 (Minimum allowable ASCII value)
	BSR	writebyte_to_tuber2               ; Write byte to TUBE ULA register 2
	MOVE.B	D1, D0                            ; Send parameter 4 (Maximum length)
	BSR	writebyte_to_tuber2               ; Write byte to TUBE ULA register 2

	MOVE.B	#$07, D0                          ; MSB of buffer in host (&0700)
	BSR	writebyte_to_tuber2               ; Write byte to TUBE ULA register 2
	MOVE.B	#$00, D0                          ; MSB of buffer in host (&0700)
	BSR	writebyte_to_tuber2               ; Write byte to TUBE ULA register 2

	BSR	readbyte_from_tuber2              ; Get the parameter and store it in the parameterblock
	CMP.B	#$80, D0
	BHS	SWI_OS_ReadLine32_escape

	MOVEQ	#$00, D1                           ; Set 'characters read' to 0

SWI_OS_ReadLine32_loop
	BSR	readbyte_from_tuber2              ; Get the parameter and store it in the parameterblock
	MOVE.B	D0, (A0)+                         ; Store byte in buffer
	ADDQ	#1, D1                            ; Increment line length
	CMP.B	#$0D, D0
	BNE	SWI_OS_ReadLine32_loop

	SUBQ	#1, D1                            ; D1=length of line without <cr>
	MOVE.L	(SP)+, A0                         ; ...and restore A0 and D0

	ANDI	#$FE, CCR                         ; Clear carry flag
	RTS

SWI_OS_ReadLine32_escape                          ; ESCAPE was pressed, so exit with carry set and X = &FF
	MOVE.L	(SP)+, A0                         ; ...and restore A0 and D0
	SUBQ	#1, D1                            ; Length in D1=-1 (ESCAPE was pressed)
	ORI	#$01, CCR                         ; Set Carry flag
	RTS

SWI_OS_ReadLine32_error                           ; Set overflow because buffer is larger than 255 bytes (not compatible with TUBE protocol)
	ORI	#$02, CCR                         ; Set overflow fag
	RTS
	ENDC


;		MOV	#LINE, A0
;.WAITKEY	TST	#0, STATUS
;		BNE	WAITKEY
;		MOVE	DATAIN, D0
;.WAITDISPLAY	TST	#1, STATUS
;		BNE	WAITDISPLAY
;		MOVE	D0, DATAOUT
;		MOVE	D0, (A0)+
;		CMP	#$0D, D0
;		BNE	WAITKEY
;		MOVE	#$0A, DATAOUT

; -----------------------------------------------------------------------------
; SWI &C0: SWI_OS_ConvertStandardDateAndTime
; -----------------------------------------------------------------------------
SWI_OS_ConvertStdDateAndTime
	MOVE.L	D3, -(SP)
	MOVE.L	standarddatetimestring, D3
	BSR	SWI_OS_ConvertDateAndTime
	MOVE.L	(SP)+, D3
	RTS

; -----------------------------------------------------------------------------
; SWI &C1: SWI_OS_ConvertDateAndTime
; -----------------------------------------------------------------------------
SWI_OS_ConvertDateAndTime
	MOVE.L	A6, -(SP)
	MOVE.L	A5, -(SP)
	MOVE.L	D1, A6
	MOVE.L	D3, A5

OS_ConvertDateAndTime_loop
	MOVE.B	(A6)+, D0
	CMP.B	#'%', D0
	BEQ	OS_ConvertDateAndTime_conv
	MOVE.B	D0, (A5)+
	CMP.B	#$00, D0
	BNE	OS_ConvertDateAndTime_loop
	MOVE.L	(SP)+, A5
	MOVE.L	(SP)+, A6
	RTS

OS_ConvertDateAndTime_conv
	MOVE.B	(A6)+, D0
	CMP.B	#'0', D0
	BNE	OS_ConvertDateAndTime_conv2
	MOVE.B	#$00, (A5)+                            ; Insert $00 byte to split string
	BRA	OS_ConvertDateAndTime_loop

OS_ConvertDateAndTime_conv2
	AND.B	#$DF, D0
	CMP.B	#'%', D0
	BNE	OS_ConvertDateAndTime_conv3
	MOVE.B	#'%', (A5)+
	BRA	OS_ConvertDateAndTime_loop

OS_ConvertDateAndTime_conv3
	CMP.B	#'Z', D0
	BNE	OS_ConvertDateAndTime_conv4
	MOVE.B	#'Z', D1                               ; Remove leading zero`s marker

OS_ConvertDateAndTime_conv4
	ROL	#8, D0
	MOVE.B	(A6)+, D0
	AND.W	#$DFDF, D0
	CMP.W	#'CS', D0
	BEQ	OS_ConvertDateAndTime_cs          ; CS: Centiseconds
	CMP.W	#'SE', D0
	BEQ	OS_ConvertDateAndTime_se          ; SE: Seconds
	CMP.W	#'MI', D0
	BEQ	OS_ConvertDateAndTime_mi          ; MI: Minutes
	CMP.W	#'12', D0
	BEQ	OS_ConvertDateAndTime_12          ; 12: Hours
	CMP.W	#'24', D0
	BEQ	OS_ConvertDateAndTime_24          ; 24: Hours
	CMP.W	#'AM', D0
	BEQ	OS_ConvertDateAndTime_ampm        ; 
	CMP.W	#'PM', D0
	BEQ	OS_ConvertDateAndTime_ampm
	CMP.W	#'WE', D0
	BEQ	OS_ConvertDateAndTime_we
	CMP.W	#'W3', D0
	BEQ	OS_ConvertDateAndTime_w3
	CMP.W	#'WN', D0
	BEQ	OS_ConvertDateAndTime_wn
	CMP.W	#'DY', D0
	BEQ	OS_ConvertDateAndTime_dy
	CMP.W	#'ST', D0
	BEQ	OS_ConvertDateAndTime_st          ; Pre-/Suffix nd st rd th th th
	CMP.W	#'MO', D0
	BEQ	OS_ConvertDateAndTime_mo
	CMP.W	#'M3', D0
	BEQ	OS_ConvertDateAndTime_m3
	CMP.W	#'MN', D0
	BEQ	OS_ConvertDateAndTime_mn
	CMP.W	#'CE', D0
	BEQ	OS_ConvertDateAndTime_ce
	CMP.W	#'YR', D0
	BEQ	OS_ConvertDateAndTime_yr
	CMP.W	#'WK', D0
	BEQ	OS_ConvertDateAndTime_wk                     ; Week in the year
	CMP.W	#'DN', D0
	BEQ	OS_ConvertDateAndTime_dn                     ; Day of the year
	CMP.W	#'TZ', D0                                   ; Timezone 3 chars
	BEQ	OS_ConvertDateAndTime_tz

	MOVE.L	(SP)+, A5
	MOVE.L	(SP)+, A6
	MOVE.L	#err_unknown_percent_field, D0
	ORI	#$02, CCR                         ; Set overflow fag
	RTS

OS_ConvertDateAndTime_cs
OS_ConvertDateAndTime_se
OS_ConvertDateAndTime_mi
OS_ConvertDateAndTime_12
OS_ConvertDateAndTime_24
OS_ConvertDateAndTime_ampm
OS_ConvertDateAndTime_we
OS_ConvertDateAndTime_w3
OS_ConvertDateAndTime_wn
OS_ConvertDateAndTime_dy
OS_ConvertDateAndTime_st
OS_ConvertDateAndTime_mo
OS_ConvertDateAndTime_m3
OS_ConvertDateAndTime_mn
OS_ConvertDateAndTime_ce
OS_ConvertDateAndTime_yr
OS_ConvertDateAndTime_wk
OS_ConvertDateAndTime_dn
OS_ConvertDateAndTime_tz
	BRA	OS_ConvertDateAndTime_loop

; -----------------------------------------------------------------------------
; SWI &D0: OS_ConvertHex1 - convert a value into a string of 1 hex character
; -----------------------------------------------------------------------------
SWI_OS_ConvertHex1
	CMP.L	#2, D2                            ; Check if buffer is big enough for 8 chars + terminator byte
	BLE	SWI_BufferOverflow                ; If not, exit with error flag (V) set

	SUB.L	#2, D2                            ; We don`t need D2 (buffer size) anymore, so prepare D2 for exit
	MOVE.L	A6, -(SP)                         ; Push A6 to the stack (used as pointer to string)
	MOVEM.L	D1-D3, -(SP)                      ; Push D1-3 to the stack (used as pointer to string)
	MOVE.W	#$00, D2                          ; Nibbles to do
	ROR.L	#4, D0                            ; Prepare first nibble to process
	BRA	SWI_OS_ConvertHex		

; -----------------------------------------------------------------------------
; SWI &D1: OS_ConvertHex2 - convert a value into a string of 2 hex characters
; -----------------------------------------------------------------------------
SWI_OS_ConvertHex2
	CMP.L	#3, D2                            ; Check if buffer is big enough for 8 chars + terminator byte
	BLE	SWI_BufferOverflow                ; If not, exit with error flag (V) set

	SUB.L	#3, D2                            ; We don`t need D2 (buffer size) anymore, so prepare D2 for exit
	MOVE.L	A6, -(SP)                         ; Push A6 to the stack (used as pointer to string)
	MOVEM.L	D1-D3, -(SP)                      ; Push D1-3 to the stack (used as pointer to string)
	MOVE.W	#$01, D2                          ; Nibbles to do
	ROR.L	#8, D0                            ; Prepare first nibble to process
	BRA	SWI_OS_ConvertHex		

; -----------------------------------------------------------------------------
; SWI &D2: OS_ConvertHex4 - convert a value into a string of 4 hex characters
; -----------------------------------------------------------------------------
SWI_OS_ConvertHex4
	CMP.L	#5, D2                            ; Check if buffer is big enough for 8 chars + terminator byte
	BLE	SWI_BufferOverflow                ; If not, exit with error flag (V) set

	SUB.L	#5, D2                            ; We don`t need D2 (buffer size) anymore, so prepare D2 for exit
	MOVE.L	A6, -(SP)                         ; Push A6 to the stack (used as pointer to string)
	MOVEM.L	D1-D3, -(SP)                      ; Push D1-3 to the stack (used as pointer to string)
	MOVE.W	#$03, D2                          ; Nibbles to do
	ROL.L	#8, D0                            ; Prepare first nibble to process
	ROL.L	#8, D0
	BRA	SWI_OS_ConvertHex		

; -----------------------------------------------------------------------------
; SWI &D3: OS_ConvertHex6 - convert a value into a string of 6 hex characters
; -----------------------------------------------------------------------------
SWI_OS_ConvertHex6
	CMP.L	#7, D2                            ; Check if buffer is big enough for 8 chars + terminator byte
	BLE	SWI_BufferOverflow                ; If not, exit with error flag (V) set

	SUB.L	#7, D2                            ; We don`t need D2 (buffer size) anymore, so prepare D2 for exit
	MOVE.L	A6, -(SP)                         ; Push A6 to the stack (used as pointer to string)
	MOVEM.L	D1-D3, -(SP)                      ; Push D1-3 to the stack (used as pointer to string)
	MOVE.W	#$05, D2                          ; Nibbles to do
	ROR.L	#8, D0                            ; Prepare first nibble to process
	BRA	SWI_OS_ConvertHex		

; -----------------------------------------------------------------------------
; SWI &D4: OS_ConvertHex8 - Convert a value into a string of 8 hex characters
; -----------------------------------------------------------------------------
SWI_OS_ConvertHex8
	CMP.L	#9, D2                            ; Check if buffer is big enough for 8 chars + terminator byte
	BLE	SWI_BufferOverflow                ; If not, exit with error flag (V) set

	SUB.L	#9, D2                            ; We don`t need D2 (buffer size) anymore, so prepare D2 for exit
	MOVE.L	A6, -(SP)                         ; Push A6 to the stack (used as pointer to string)
	MOVEM.L	D1-D3, -(SP)                      ; Push D1-3 to the stack (used as pointer to string)
	MOVE.W	#$07, D2                          ; Nibbles to do

SWI_OS_ConvertHex
	MOVE.L	D1, A6                            ; Pointer to string in A6
	MOVE.L	D0, D1                            ; copy source

SWI_OS_ConvertHex_loop
	ROL.L	#4, D1                            ; Top nibble to bottom
 	MOVE.B	D1, D0                            ; Copy it
	AND.B	#$0F, D0                          ; Mask the nibble
	MOVE.B	#$09, D3                          ; set compare value
 	SUB.B	D0, D3                            ; Set extend for +1 if >9
	ADDI.B	#'0', D0                          ; Add '0' + extend
	CMPI.B	#$3A, D0                          ; Check wether or not it is in the range of A-F
	BLO	SWI_OS_ConvertHex_loop2           ; Jump if it`s not
	ADDI.B	#$07, D0                          ; Make ASCII A-F

SWI_OS_ConvertHex_loop2
	MOVE.B	D0, (A6)+                         ; Store in string
	DBF	D2, SWI_OS_ConvertHex_loop        ; Do next nibble

	MOVE.B	#$00, (A6)                        ; Store termination byte in string

	MOVEM.L	(SP)+, D1-D3                      ; Pull D1-D3 from the stack
	MOVE.L	D1, D0                            ; D0 is pointer to buffer on exit
	MOVE.L	A6, D1                            ; D1 is pointer to terminator on exit
	MOVE.L	(SP)+, A6                         ; Pull A6 from the stack
	ANDI	#$FD, CCR                         ; Clear overflow flag
	RTS

SWI_OS_ConvertHex_error
	ORI	#$02, CCR                         ; Set overflow fag
	RTS

; -----------------------------------------------------------------------------
; SWI &D5: OS_ConvertCardinal1 - convert a value into a unsigned string of decimal characters
; -----------------------------------------------------------------------------
SWI_OS_ConvertCardinal1
	CMP.L	#4, D2                            ; Max string size is 3 characters plus $00 terminator
	BLO	SWI_BufferOverflow
	CMP.L	#$100, D0
	BHS	SWI_OS_ConvertInteger_Error
	MOVEQ.L	#3, D6	                          ; COUNTER (3 decimals max)
	BRA	SWI_OS_ConvertCardinal4_00

; -----------------------------------------------------------------------------
; SWI &D6: OS_ConvertCardinal2 - convert a value into a unsigned string of decimal characters
; -----------------------------------------------------------------------------
SWI_OS_ConvertCardinal2
	CMP.L	#6, D2                            ; Max string size is 5 characters plus $00 terminator
	BLO	SWI_BufferOverflow
	CMP.L	#$10000, D0
	BHS	SWI_OS_ConvertInteger_Error
	MOVEQ.L	#5, D6	                          ; COUNTER (5 decimals max)
	BRA	SWI_OS_ConvertCardinal4_00

; -----------------------------------------------------------------------------
; SWI &D7: OS_ConvertCardinal3 - convert a value into a unsigned string of decimal characters
; -----------------------------------------------------------------------------
SWI_OS_ConvertCardinal3
	CMP.L	#9, D2                            ; Max string size is 9 characters plus $00 terminator
	BLO	SWI_BufferOverflow
	CMP.L	#$1000000, D0
	BHS	SWI_OS_ConvertInteger_Error
	MOVEQ.L	#8, D6	                          ; COUNTER (8 decimals max)
	BRA	SWI_OS_ConvertCardinal4_00

; -----------------------------------------------------------------------------
; SWI &D8: OS_ConvertCardinal4 - convert a value into a unsigned string of decimal characters
; -----------------------------------------------------------------------------
SWI_OS_ConvertCardinal4
	CMP.L	#11, D2                           ; Max string size is 9 characters plus $00 terminator
	BLO	SWI_BufferOverflow
	MOVEQ.L	#10, D6	                          ; COUNTER (10 decimals max)

SWI_OS_ConvertCardinal4_00
	EXG	D1, A5                            ; Put destination in A5
	MOVEM.L	D0-D7, -(SP)                      ; SAVE REGISTERS
 	MOVE.L	D0, D7                            ; SAVE IT HERE
	BEQ	SWI_OS_ConvertCardinal4_57         ; Special case 0
	BRA	SWI_OS_ConvertCardinal4_01

SWI_OS_ConvertCardinal4_01
	CLR.W	D4	                          ; FOR ZERO SURPRESS

SWI_OS_ConvertCardinal4_0
	MOVEQ.L	#1, D2	                          ; VALUE TO SUB
 	MOVE.L	D6, D1	                          ; COUNTER
	SUBQ.L	#1, D1	                          ; ADJUST - FORM POWER OF TEN
	BEQ	SWI_OS_ConvertCardinal4_2          ; IF POWER IS ZERO

SWI_OS_ConvertCardinal4_1
	MOVE.W	D2, D3	                          ; D3=LOWER WORD
	MULU.W	#10, D3
	SWAP.W	D2	                          ; D2=UPPER WORD
	MULU.W	#10, D2
	SWAP.W	D3	                          ; ADD UPPER TO UPPER
	ADD.W	D3, D2
	SWAP.W	D2	                          ; PUT UPPER IN UPPER
	SWAP.W	D3	                          ; PUT LOWER IN LOWER
 	MOVE.W	D3 ,D2	                          ; D2=UPPER & LOWER
	SUBQ.L	#1, D1
	BNE	SWI_OS_ConvertCardinal4_1

SWI_OS_ConvertCardinal4_2
	CLR.L	D0                                ; HOLDS SUB AMT

SWI_OS_ConvertCardinal4_22
	CMP.L	D2, D7
	BLO	SWI_OS_ConvertCardinal4_3          ; IF NO MORE SUB POSSIBLE
	ADDQ.L	#1, D0                            ; BUMP SUBS
	SUB.L	D2, D7                            ; COUNT DOWN BY POWERS OF TEN
	BRA	SWI_OS_ConvertCardinal4_22         ; DO MORE

SWI_OS_ConvertCardinal4_3
	TST.B	D0                                ; ANY VALUE?
	BNE	SWI_OS_ConvertCardinal4_4
	TST.W	D4                                ; ZERO SURPRESS
	BEQ	SWI_OS_ConvertCardinal4_5

SWI_OS_ConvertCardinal4_4
	ADDI.B	#$30, D0                          ; BINARY TO ASCII
	MOVE.B	D0, (A5)+                         ; PUT IN BUFFER
	MOVE.B	D0, D4                            ; MARK AS NON ZERO SURPRESS

SWI_OS_ConvertCardinal4_5
	SUBQ.L	#1, D6                            ; NEXT POWER
	BNE	SWI_OS_ConvertCardinal4_0
	TST.W	D4                                ; SEE IF ANYTHING PRINTED
	BNE	SWI_OS_ConvertCardinal4_6

SWI_OS_ConvertCardinal4_57
	MOVE.B	#'0', (A5)+                       ; PRINT AT LEAST A ZERO

SWI_OS_ConvertCardinal4_6
	MOVE.B	#0, (A5)                          ; PUT TERMINATOR
	MOVEM.L	(SP)+, D0-D7                      ; RESTORE REGISTERS
	EXG	A5, D1                            ; Restore A5
	ANDI	#$FD, CCR                         ; Clear overflow flag
 	RTS                                       ; END OF ROUTINE

; -----------------------------------------------------------------------------
; SWI &D9: OS_ConvertInteger1 - convert a value into a signed string of decimal characters
; -----------------------------------------------------------------------------
SWI_OS_ConvertInteger1
	CMP.L	#5, D2                            ; Max string size is 3 characters plus sign plus $00 terminator
	BLO	SWI_BufferOverflow
	CMP.L	#$100, D0
	BHS	SWI_OS_ConvertInteger_Error
	BTST	#7, D0
	BEQ	SWI_OS_ConvertInteger1_1
	ORI.L	#$FFFFFF00, D0                    ; Make negative

SWI_OS_ConvertInteger1_1
	MOVEQ.L	#3, D6	                          ; COUNTER (3 decimals max)
	BRA	SWI_OS_ConvertInteger4_00

; -----------------------------------------------------------------------------
; SWI &DA: OS_ConvertInteger2 - convert a value into a signed string of decimal characters
; -----------------------------------------------------------------------------
SWI_OS_ConvertInteger2
	CMP.L	#7, D2                            ; Max string size is 5 characters plus sign plus $00 terminator
	BLO	SWI_BufferOverflow
	CMP.L	#$10000, D0
	BHS	SWI_OS_ConvertInteger_Error
	BTST	#15, D0
	BEQ	SWI_OS_ConvertInteger2_1
	ORI.L	#$FFFF0000, D0                    ; Make negative

SWI_OS_ConvertInteger2_1
	MOVEQ.L	#5, D6	                          ; COUNTER (5 decimals max)
	BRA	SWI_OS_ConvertInteger4_00

; -----------------------------------------------------------------------------
; SWI &DB: OS_ConvertInteger3 - convert a value into a signed string of decimal characters
; -----------------------------------------------------------------------------
SWI_OS_ConvertInteger3
	CMP.L	#11, D2                            ; Max string size is 9 characters plus sign plus $00 terminator
	BLO	SWI_BufferOverflow
	CMP.L	#$1000000, D0
	BHS	SWI_OS_ConvertInteger_Error
	BTST	#23, D0
	BEQ	SWI_OS_ConvertInteger3_1
	ORI.L	#$FF000000, D0                    ; Make negative

SWI_OS_ConvertInteger3_1
	MOVEQ.L	#8, D6	                          ; COUNTER (8 decimals max)
	BRA	SWI_OS_ConvertInteger4_00

; -----------------------------------------------------------------------------
; SWI &DC: OS_ConvertInteger4 - convert a value into a signed string of decimal characters
; -----------------------------------------------------------------------------
SWI_OS_ConvertInteger4
	CMP.L	#13, D2                           ; Max string size is 11 characters plus sign plus $00 terminator
	BLO	SWI_BufferOverflow
	MOVEQ.L	#10, D6	                          ; COUNTER (10 decimals max)

SWI_OS_ConvertInteger4_00
	EXG	D1, A5                            ; Put destination in A5
	MOVEM.L	D0-D7, -(SP)                      ; SAVE REGISTERS
 	MOVE.L	D0, D7                            ; SAVE IT HERE
	BPL.S	SWI_OS_ConvertInteger4_01
	NEG.L	D7	                          ; CHANGE TO POSITIVE
	BMI.S	SWI_OS_ConvertInteger4_57         ; SPECIAL CASE (-0)
	MOVE.B	#'-', (A5)+                       ; PUT IN NEG SIGN

SWI_OS_ConvertInteger4_01
	CLR.W	D4	                          ; FOR ZERO SURPRESS

SWI_OS_ConvertInteger4_0
	MOVEQ.L	#1, D5	                          ; VALUE TO SUB
 	MOVE.L	D6, D1	                          ; COUNTER
	SUBQ.L	#1, D1	                          ; ADJUST - FORM POWER OF TEN
	BEQ.S	SWI_OS_ConvertInteger4_2          ; IF POWER IS ZERO

SWI_OS_ConvertInteger4_1
	MOVE.W	D5, D3	                          ; D3=LOWER WORD
	MULU.W	#10, D3
	SWAP.W	D5	                          ; D5=UPPER WORD
	MULU.W	#10, D5
	SWAP.W	D3	                          ; ADD UPPER TO UPPER
	ADD.W	D3, D5
	SWAP.W	D5	                          ; PUT UPPER IN UPPER
	SWAP.W	D3	                          ; PUT LOWER IN LOWER
 	MOVE.W	D3 ,D5	                          ; D5=UPPER & LOWER
	SUBQ.L	#1, D1
	BNE	SWI_OS_ConvertInteger4_1

SWI_OS_ConvertInteger4_2
	CLR.L	D0                                ; HOLDS SUB AMT

SWI_OS_ConvertInteger4_22
	CMP.L	D5, D7
	BLT.S	SWI_OS_ConvertInteger4_3          ; IF NO MORE SUB POSSIBLE
	ADDQ.L	#1, D0                            ; BUMP SUBS
	SUB.L	D5, D7                            ; COUNT DOWN BY POWERS OF TEN
	BRA.S	SWI_OS_ConvertInteger4_22         ; DO MORE

SWI_OS_ConvertInteger4_3
	TST.B	D0                                ; ANY VALUE?
	BNE.S	SWI_OS_ConvertInteger4_4
	TST.W	D4                                ; ZERO SURPRESS
	BEQ.S	SWI_OS_ConvertInteger4_5

SWI_OS_ConvertInteger4_4
	ADDI.B	#$30, D0                          ; BINARY TO ASCII
	MOVE.B	D0, (A5)+                         ; PUT IN BUFFER
	MOVE.B	D0, D4                            ; MARK AS NON ZERO SURPRESS

SWI_OS_ConvertInteger4_5
	SUBQ.L	#1, D6                            ; NEXT POWER
	BNE	SWI_OS_ConvertInteger4_0
	TST.W	D4                                ; SEE IF ANYTHING PRINTED
	BNE	SWI_OS_ConvertInteger4_6

SWI_OS_ConvertInteger4_57
	MOVE.B	#'0', (A5)+                       ; PRINT AT LEAST A ZERO

SWI_OS_ConvertInteger4_6
	MOVE.B	#0, (A5)                          ; PUT TERMINATOR
	MOVEM.L	(SP)+, D0-D7                      ; RESTORE REGISTERS
	EXG	A5, D1                            ; Restore A5
	ANDI	#$FD, CCR                         ; Clear overflow flag
 	RTS                                       ; END OF ROUTINE

SWI_OS_ConvertInteger_Error
	ORI	#$02, CCR                         ; Set overflow fag
	RTS

;		lea	string,A0
;		adda.l	#40,A0
;		move.l	#47110815,D0
;hex2dec_loop:
;		divul.l	#10,D1:D0
;		add.b	#$30,D1
;		move.b	D1,-(A0)
;		cmpi.w	#10,D0
;		bhs.s	hex2dec_loop
;		add.b	#$30,D0
;		move.b	D0,-(A0)
;		move.l	A0,-(SP)
;		move.w	#$09,-(SP)
;		trap	#1
;		addq.l	#6,SP
;		move.w	#8,-(SP)	; warten 
;		trap	#1
;		addq.l	#2,SP
;		clr.w	-(SP)		; ..und tschüß
;		trap	#1
;		BSS
;		string:	DS.L50
;		END

; -----------------------------------------------------------------------------
; SWI &DD: OS_ConvertBinary1
; -----------------------------------------------------------------------------
SWI_OS_ConvertBinary1
	CMP.L	#9, D2                            ; Check if buffer is big enough for 8 chars + terminator byte
	BLE	SWI_BufferOverflow                ; If not, exit with error flag (V) set

	SUB.L	#9, D2                            ; We don`t need D2 (buffer size) anymore, so prepare D2 for exit
	MOVE.L	A6, -(SP)                         ; Push A6 to the stack (used as pointer to string)
	MOVEM.L	D1-D3, -(SP)                      ; Push D1-3 to the stack (used as pointer to string)
	MOVEQ	#7, D2                            ; Result is 8-bit wide
	ROR.L	#8, D0                            ; Prepare first bit to process
	BRA	SWI_OS_ConvertBinary

; -----------------------------------------------------------------------------
; SWI &DE: OS_ConvertBinary2
; -----------------------------------------------------------------------------
SWI_OS_ConvertBinary2
	CMP.L	#17, D2                           ; Check if buffer is big enough for 8 chars + terminator byte
	BLE	SWI_BufferOverflow                ; If not, exit with error flag (V) set

	SUB.L	#17, D2                           ; We don`t need D2 (buffer size) anymore, so prepare D2 for exit
	MOVE.L	A6, -(SP)                         ; Push A6 to the stack (used as pointer to string)
	MOVEM.L	D1-D3, -(SP)                      ; Push D1-3 to the stack (used as pointer to string)
	MOVEQ	#15, D2                           ; Result is 16-bit wide
	ROL.L	#8, D0                            ; Prepare first bit to process
	ROL.L	#8, D0
	BRA	SWI_OS_ConvertBinary

; -----------------------------------------------------------------------------
; SWI &DF: OS_ConvertBinary3
; -----------------------------------------------------------------------------
SWI_OS_ConvertBinary3
	CMP.L	#25, D2                           ; Check if buffer is big enough for 8 chars + terminator byte
	BLE	SWI_BufferOverflow                ; If not, exit with error flag (V) set

	SUB.L	#25, D2                           ; We don`t need D2 (buffer size) anymore, so prepare D2 for exit
	MOVE.L	A6, -(SP)                         ; Push A6 to the stack (used as pointer to string)
	MOVEM.L	D1-D3, -(SP)                      ; Push D1-3 to the stack (used as pointer to string)
	MOVEQ	#23, D2                           ; Result is 24-bit wide
	ROR.L	#8, D0                            ; Prepare first bit to process
	BRA	SWI_OS_ConvertBinary

; -----------------------------------------------------------------------------
; SWI &E0: OS_ConvertBinary4
; -----------------------------------------------------------------------------
SWI_OS_ConvertBinary4
	CMP.L	#33, D2                           ; Check if buffer is big enough for 32 chars + terminator byte
	BLE	SWI_BufferOverflow                ; If not, exit with error flag (V) set

	SUB.L	#33, D2                           ; We don`t need D2 (buffer size) anymore, so prepare D2 for exit
	MOVE.L	A6, -(SP)                         ; Push A6 to the stack (used as pointer to string)
	MOVEM.L	D1-D3, -(SP)                      ; Push D1-3 to the stack (used as pointer to string)
	MOVEQ	#31, D2                           ; Result is 16-bit wide

SWI_OS_ConvertBinary
	MOVE.L	D1, A6                            ; Pointer to buffer in A6
	MOVEQ	#0, D3                            ; Temp register needed for extend bit

SWI_OS_ConvertBinary_loop
	MOVEQ	#$30, D1                          ; ASCII value of '0'
	ASL.L	#1, D0                            ; Shift leftmost bit into carry
	ABCD	D3, D1                            ; Add carry to ASCII value
	MOVE.B	D1, (A6)+                         ; Put character in buffer
	DBF	D2, SWI_OS_ConvertBinary_loop

	MOVE.B	#$00, (A6)                        ; Store termination byte in string

	MOVEM.L	(SP)+, D1-D3                      ; Pull D1-D3 from the stack
	MOVE.L	D1, D0                            ; D0 is pointer to buffer on exit
	MOVE.L	A6, D1                            ; D1 is pointer to terminator on exit
	MOVE.L	(SP)+, A6                         ; Pull A6 from the stack
	ANDI	#$FD, CCR                         ; Clear overflow flag
	RTS

; -----------------------------------------------------------------------------
; SWI &E5: OS_ConvertSpacedInteger1 - convert a value into a signed string of decimal characters
; -----------------------------------------------------------------------------
SWI_OS_ConvertSpacedInteger1
	BSR	SWI_OS_ConvertInteger1
	MOVE.L	D7, -(SP)
	MOVE.L	#5, D7
	BSR	SWI_OS_ConvertSpaced
	MOVE.L	(SP)+, D7
	RTS

; -----------------------------------------------------------------------------
; SWI &E6: OS_ConvertSpacedInteger2 - convert a value into a signed string of decimal characters
; -----------------------------------------------------------------------------
SWI_OS_ConvertSpacedInteger2
	BSR	SWI_OS_ConvertInteger2
	MOVE.L	D7, -(SP)
	MOVE.L	#7, D7
	BSR	SWI_OS_ConvertSpaced
	MOVE.L	(SP)+, D7
	RTS

; -----------------------------------------------------------------------------
; SWI &E5: OS_ConvertSpacedInteger3 - convert a value into a signed string of decimal characters
; -----------------------------------------------------------------------------
SWI_OS_ConvertSpacedInteger3
	BSR	SWI_OS_ConvertInteger3
	MOVE.L	D7, -(SP)
	MOVE.L	#9, D7
	BSR	SWI_OS_ConvertSpaced
	MOVE.L	(SP)+, D7
	RTS

; -----------------------------------------------------------------------------
; SWI &E5: OS_ConvertSpacedInteger4 - convert a value into a signed string of decimal characters
; -----------------------------------------------------------------------------
SWI_OS_ConvertSpacedInteger4
	BSR	SWI_OS_ConvertInteger4
	MOVE.L	D7, -(SP)
	MOVE.L	#12, D7
	BSR	SWI_OS_ConvertSpaced
	MOVE.L	(SP)+, D7
	RTS

; -----------------------------------------------------------------------------
; SWI &EA: OS_ConvertNetStation - Convert from an Econet station/network number pair to a string
; -----------------------------------------------------------------------------
SWI_OS_ConvertNetStation
	MOVE.L	D1, -(SP)
	MOVE.L	D6, -(SP)
	MOVE.L	D7, -(SP)
	MOVE.L	A6, -(SP)

	MOVE.L	D0, A6
	MOVE.L	(A6)+, D6                         ; Station
	MOVE.L	(A6)+, D7                         ; Network
	CMPI.L	#$00000100, D7
	BHS	SWI_OS_ConvertNetStation_badnet
	CMPI.L	#$00000100, D6
	BHS	SWI_OS_ConvertNetStation_badstn

	TST	D7
	BEQ	SWI_OS_ConvertNetStation2
	MOVE.B	D7, D0                            ; Do network number
	BSR	SWI_OS_ConvertCardinal1
	TST	D1                                ; See if there`s still room in the buffer
	BEQ	SWI_BufferOverflow
	MOVE.L	D1, A6
	MOVE.B	#'.', (A6)+
	MOVE.L	A6, D1

SWI_OS_ConvertNetStation2
	MOVE.B	D6, D0                            ; Do station number
	BSR	SWI_OS_ConvertCardinal1

SWI_OS_ConvertNetStationexit
	MOVE.L	(SP)+, A6
	MOVE.L	(SP)+, D7
	MOVE.L	(SP)+, D6
	MOVE.L	(SP)+, D0                         ; On exit, D0 is pointer to buffer
	ANDI	#$FD, CCR                         ; Clear overflow flag
	RTS

SWI_OS_ConvertNetStation_badnet
	MOVE.L	#err_bad_network, 12(SP)
	ORI	#$02, CCR                         ; Set overflow fag
	BRA	SWI_OS_ConvertNetStationexit

SWI_OS_ConvertNetStation_badstn
	MOVE.L	#err_bad_station, 12(SP)
	ORI	#$02, CCR                         ; Set overflow fag
	BRA	SWI_OS_ConvertNetStationexit

; -----------------------------------------------------------------------------
; SWI &EC: OS_ConvertFileSize
; -----------------------------------------------------------------------------
SWI_OS_ConvertFileSize
	MOVE.L	D7, -(SP)                         ; Push D7 to the stack (temp variable)
	MOVE.L	D1, -(SP)                         ; Push D1 to the stack

	MOVE.L	D0, D1
	ANDI.L	#$C0000000, D1                    ; Mask out the GB bits
	BEQ	SWI_OS_ConvertFileSizeM           ; Not in GB range
	LSR.L	#8, D1                            ; Divide by 1024*1024*1024 (=256*256*256*64)
	LSR.L	#8, D1
	LSR.L	#8, D1
	LSR.L	#6, D1
	MOVE.L	D1, D0                            ; Put size in D0
	MOVE.B	'M', D7
	BRA	SWI_OS_ConvertFileSizePrint

SWI_OS_ConvertFileSizeM
	MOVE.L	D0, D1
	ANDI.L	#$FFF00000, D1                    ; Mask out the MB bits
	BEQ	SWI_OS_ConvertFileSizeK           ; Not in MB range
	LSR.L	#8, D1                            ; Divide by 1024*1024 (=256*256*16)
	LSR.L	#8, D1
	LSR.L	#4, D1
	MOVE.L	D1, D0                            ; Put size in D0
	MOVE.B	'K', D7
	BRA	SWI_OS_ConvertFileSizePrint

SWI_OS_ConvertFileSizeK
	MOVE.L	D0, D1
	ANDI.L	#$FFFFFC00, D1                    ; Mask out the KB bits
	BEQ	SWI_OS_ConvertFileSizePrint       ; Not in KB range
	LSR.L	#8, D1                            ; Divide by 1024 (=256*4)
	LSR.L	#2, D1
	MOVE.L	D1, D0                            ; Put size in D0
	MOVE.B	#$00, D7

SWI_OS_ConvertFileSizePrint
	MOVE.L	(SP)+, D1                         ; Restore D1
	BSR	SWI_OS_ConvertCardinal4           ; Convert value in D0 to string in D1
	MOVE.L	D1, A6
	MOVE.B	#$20, (A6)+
	MOVE.B	D7, (A6)+
	MOVE.B	#'b', (A6)+
	MOVE.B	#'y', (A6)+
	MOVE.B	#'t', (A6)+
	MOVE.B	#'e', (A6)+
	MOVE.B	#'s', (A6)+
	MOVE.B	#$00, (A6)+
	ANDI	#$FD, CCR                         ; Clear overflow flag
	RTS


SWI_OS_ConvertSpaced
	MOVE.L	A6, -(SP)
	MOVE.L	D0, -(SP)
	MOVE.L	D1, -(SP)

	MOVE.L	D0, A6
	SUB.L	D0, D1
	MOVE.B	#$00, (A6, D7)
	SUBQ.L	#$01, D7

SWI_OS_ConvertSpaced_loop
	MOVE.B	(A6, D1), (A6, D7)                ; Move converted value to end of buffer
	SUBQ.L	#1, D7
	DBF	D1, SWI_OS_ConvertSpaced_loop
	SUB.L	D7, D2                            ; Decrease free bytes in buffer by number of spaces

SWI_OS_ConvertSpaced_loop2
	MOVE.B	#' ', (A6, D7)
	DBF	D7, SWI_OS_ConvertSpaced_loop2

	MOVE.L	(SP)+, D0
	MOVE.L	(SP)+, D1
	MOVE.L	(SP)+, A6
	RTS


SWI_BufferOverflow
	MOVE.L	#err_buffer_overflow, D0          ; Pointer to error block
	ORI	#$02, CCR                         ; Set overflow fag
	RTS

; -----------------------------------------------------------------------------
; SWI &40380: Debugger_Disassemble
; -----------------------------------------------------------------------------
SWI_Debugger_Disassemble
	MOVE.L	D3, -(SP)                         ; Push D3 to the stack
	MOVE.L	D0, -(SP)                         ; Push D0 to the stack
	ANDI.L	#$00000001, D0                    ; Check if it`s word aligned
	BNE	SWI_Debugger_Disassemble_Error    ; If not, then exit with error
	MOVE.L	(SP)+, D0                         ; Restore D0
	EXG	D0, A0                            ; Put the source address in A0
	EXG	D1, A1                            ; Put the pointer to destination in A1
	MOVE.L	#SWI_Debugger_Disassemble_table, A6

SWI_Debugger_Disassemble_loop
	MOVE.W	(A0), D3                          ; Get fresh copy of opcode
	AND.W	2(A6), D3                         ; Mask out unwanted bits
	CMP.W	(A6), D3                          ; Check if it`s the correct opcode
	BEQ	SWI_Debugger_Disassemble_found
	ADDA.L	#14, A6
	BRA	SWI_Debugger_Disassemble_loop

SWI_Debugger_Disassemble_found                    ; We`ve found the correct opcode
	ADDA.L	#4, A6                            ; Skip AND mask and CMP value

SWI_Debugger_Disassemble_cloop
	MOVE.B	(A6)+, (A1)+
	BNE	SWI_Debugger_Disassemble_cloop
	MOVE.L	(SP)+, D3
	RTS

SWI_Debugger_Disassemble_Error
	MOVE.L	(SP)+, D3                         ; Restore D3
	MOVE.L	#err_unaligned_address, D0        ; Pointer to error block
	ORI	#$02, CCR                         ; Set overflow fag
	RTS

; -----------------------------------------------------------------------------
; SWI &43F40:Joystick_Read - read the state of a joystick
; -----------------------------------------------------------------------------



; -----------------------------------------------------------------------------
; Built-in OS applications
;
; *ERROR
; -----------------------------------------------------------------------------
star_error
	CMP.B	#$0D, (A6)
	BEQ	star_error_help                   ; No parameter, so display help message

	MOVE.L	A6, -(SP)                         ; Push A6 to the stack

;	BSR	get_hex_value                     ; Return hex value of string at (A6) in D1
;	BCC	star_error2                       ; Jump if the parameter was valid

	MOVE.L	#$10, D0
	MOVE.L	A6, D1
	BSR	SWI_OS_ReadUnsigned
	BVC	star_error2                       ; Jump if the parameter was valid

	MOVE.L	#$00000000, errorbuffer           ; No error number was given, so use error nr 0 as default
	MOVE.L	(SP)+, A6                         ; Restore A6
	BRA	star_error3

star_error2
	MOVE.L	D1, A6
	MOVE.L	D2, errorbuffer                   ; Store error number in buffer
	MOVE.L	(SP)+, D2                         ; Clean up stack

star_error3
	BSR	skip_spaces                       ; Loop until (A6) isn`t ASCII value 32 (space)
	BCS	star_error_help
	MOVE.L	#errorbuffer+4, A5

star_error4
	MOVE.B	(A6)+, (A5)
	CMPI.B	#$0D, (A5)+
	BNE	star_error4
	MOVE.B	#$00, -(A5)
	MOVE.L	#errorbuffer, D0
	BSR	SWI_OS_GenerateError
	RTS

star_error_help
	MOVE.L	#msg_star_error_help, D0          ; Location of message in A0
	BSR	SWI_OS_Write0
	RTS

; -----------------------------------------------------------------------------
; *FLASH
; -----------------------------------------------------------------------------
flash
	MOVE.L	A6, -(SP)                         ; Push A6 to the stack
	BSR	skip_spaces                       ; Loop until (A6) isn`t ASCII value 32 (space)
	CMP.B	#$0D, (A6)
	BEQ	flash_error                       ; No parameter, so display help message

flash2
	CMP.B	#$0D, (A6)
	BEQ	flash3
	CMP.B	#' ', (A6)+                       ; Is it ASCII value 32 (space)?
	BNE	flash2                            ; No? Then check next byte
		                                  ; Too many parameters, so generate error
flash_error
	MOVE.L	#msg_flash_error, D0              ; Location of message in A0
	BSR	SWI_OS_Write0

flash_exit
	MOVE.L	(SP)+, A6                         ; Restore A6
	RTS

flash3
	MOVE.L	(SP)+, A6                         ; Restore A6
	MOVE.L	A6, D1                            ; Pointer to file in D1
	MOVE.L	#$00000005, D0                    ; OS_File reason 5: read catalogue information
	BSR	SWI_OS_File
	CMP.L	#biossize, D4                     ; Check if the file has the correct file size
	BNE	flash_wrongfile

	MOVE.L	(oshwm), A5
	ADD.L	#biossize, A5
	ADD.L	#$100, A5
	CMP.L	(ramsize), A5                     ; Check if there`s enough RAM available ($0100 for *FLASH code)
	BLS	flash_noroom

	MOVE.L	A6, D1                            ; Pointer to file in D1
	MOVE.L	#$00000400, D2                    ; Load bios at $00000400
	MOVEQ	#$00, D3
	MOVE.L	#$000000FF, D0                    ; OS_File reason 5: read catalogue information
	BSR	SWI_OS_File

	MOVE.L	#msg_flash_warning, D0            ; Print flash warning
	BSR	SWI_OS_Write0

	MOVEQ	#$15, D0                          ; *FX 21,0 (Flush keyboard buffer)
	MOVEQ	#$00, D1
	BSR	SWI_OS_Byte

	BSR	SWI_OS_Confirm
	BSR	SWI_OS_WriteC
	BNE	flash_exit

; Since the BIOS won`t be available when the flash ROM is switched to command mode, this code must be relocated to RAM
;	MOVE.L	#msg_flash_identify, D0           ; Print ID message
;	BSR	SWI_OS_Write0
;	BSR	flash_identify
	MOVE.L	#buffer, D1                       ; D1 is pointer to buffer
	MOVEQ	#$FF, D2                          ; Size of buffer
;	BSR	SWI_OS_ConvertHex2                ; Print device id
;	BSR	SWI_OS_Write0

	MOVE.L	#msg_flash_start, D0              ; Print flashing sector
	BSR	SWI_OS_Write0
	MOVE.B	D7, D0
	ADD.B	#'0', D0
	BSR	SWI_OS_WriteC
	BSR	SWI_OS_NewLine

	MOVE.L	#msg_flash_finish, D0             ; Location of message in A0
	BSR	SWI_OS_Write0
	BRA	flash_exit

flash_wrongfile
	MOVE.L	#msg_flash_wrongfile, D0          ; Location of message in A0
	BSR	SWI_OS_Write0
	RTS

flash_noroom
	MOVE.L	#msg_flash_noroom, D0          ; Location of message in A0
	BSR	SWI_OS_Write0
	RTS

flash_help
	MOVE.L	#msg_flash_help, D0               ; Location of message in A0
	BSR	SWI_OS_Write0
	RTS

; -----------------------------------------------------------------------------
; *GO
; -----------------------------------------------------------------------------
go
	MOVE.L	#$10, D0
	MOVE.L	A6, D1
	BSR	SWI_OS_ReadUnsigned
	BVS	go_help

;	BSR	get_hex_value                     ; Return hex value of string at (A6) in D1
;	BCS	go_help                           ; Jump if the parameter wasn`t valid

	BSR	skip_spacesd1                     ; Loop until (A6) isn`t ASCII value 32 (space)
	BNE	go_help                           ; Jump if there were more parameters

	MOVE.L	D2, tubetransfer
	BSR	SWI_OS_Byte_8E_01                 ; Check copyright message and ROM type and enter language ROM
	ANDI	#$FE, CCR                         ; Clear the carry-bit and exit
	RTS

go_help
	MOVE.L	#msg_go_help, D0                  ; Location of message in A0
	BSR	SWI_OS_Write0
	RTS

; -----------------------------------------------------------------------------
; *HELP
; -----------------------------------------------------------------------------
help
	MOVE.L	A6, -(SP)                         ; Push A6 to the stack
	CMPI.B	#$0D, (A6)                        ; Is the command terminated with a CR?
	BNE	help_extended
	MOVE.L	#msg_help, D0                     ; Location of message in D0
	BSR	SWI_OS_Write0
	MOVE.L	#msg_help_std, D0                 ; Location of message in D0
	BSR	SWI_OS_Write0
	BRA	help_to_host                      ; Pass the command to the host

help_extended
	ANDI.B	#$DF, (A6)
	CMPI.B	#$54, (A6)+                       ; Is the parameter 'TUBE'?
	BNE	help_swi
	ANDI.B	#$DF, (A6)
	CMPI.B	#$55, (A6)+                       ; Is the parameter 'TUBE'?
	BNE	help_to_host
	ANDI.B	#$DF, (A6)
	CMPI.B	#$42, (A6)+                       ; Is the parameter 'TUBE'?
	BNE	help_to_host
	ANDI.B	#$DF, (A6)
	CMPI.B	#$45, (A6)+                       ; Is the parameter 'TUBE'?
	BNE	help_to_host
	CMPI.B	#$0D, (A6)                        ; Is the command terminated with a CR?
	BNE	help_to_host

	MOVE.L	#msg_help, D0                     ; Location of short help message in D0
	BSR	SWI_OS_Write0
	MOVE.L	#msg_help_extd, D0                ; Location of extended help message in D0
	BSR	SWI_OS_Write0

help_swi
	ANDI.B	#$DF, -(A6)
	CMPI.B	#$53, (A6)+                       ; Is the parameter 'SWI'?
	BNE	help_to_host
	ANDI.B	#$DF, (A6)
	CMPI.B	#$57, (A6)+                       ; Is the parameter 'SWI'?
	BNE	help_to_host
	ANDI.B	#$DF, (A6)
	CMPI.B	#$49, (A6)+                       ; Is the parameter 'SWI'?
	BNE	help_to_host
	CMPI.B	#$0D, (A6)                        ; Is the command terminated with a CR?
	BNE	help_to_host

	MOVE.L	#msg_help, D0                     ; Location of short help message in D0
	BSR	SWI_OS_Write0

	LEA	SWITable, A6

help_swi_loop
	MOVE.B	#$20, D0
	BSR	SWI_OS_WriteC
	BSR	SWI_OS_WriteC
	BSR	SWI_OS_WriteC
	MOVE.L	(A6)+, D0                         ; SWI nr.
	MOVE.L	(A6)+, D0                         ; Jump address
	CMPI.L	#$FFFFFFFF, D0                    ; End of table?
	BEQ	help_to_host

	MOVE.L	A6, D0                            ; Put pointer to SWI string in D0
	BSR	SWI_OS_Write0                     ; Print string
	MOVE.L	D0, A6
	CMPI.B	#$00, -(A6)                       ; Does nothing, only to decrease A0 by 1
	BSR	SWI_OS_NewLine

help_swi_loop2
	CMPI.B	#$FF, (A6)+
	BEQ	help_to_host
	MOVE.L	A6, D0
	ANDI.B	#$03, D0
	BNE	help_swi_loop2
	BRA	help_swi_loop

help_to_host
	MOVE.L	D1, -(SP)
	MOVE.L	#$00000009, D1                    ; Issue a Service_Help call
	BSR	SWI_OS_ServiceCall
	MOVE.L	(SP)+, D1

	MOVE.L	(SP)+, A6                         ; Pop A0 from the stack
	ORI	#$01, CCR                         ; Set the carry bit and exit
	RTS

; -----------------------------------------------------------------------------
; *MON
; -----------------------------------------------------------------------------
mon
	CMPI.B	#$0D, (A6)                        ; Is the command terminated with a CR?
	BNE	monitor_help

	MOVE.L	#msg_monitor, D0                  ; Location of message in A0
	BSR	SWI_OS_Write0

monitor_loop
	BSR	SWI_OS_NewLine
	MOVE.B	#':', D0                          ; : Prompt
	BSR	SWI_OS_WriteC

	MOVE.L	#buffer, D0                       ; Buffer address
	MOVE.L	#$FF, D1                          ; Maximum line length is 255
	MOVE.B	#$20, D2                          ; Minimum acceptable ASCII value
	MOVE.B	#$FF, D3                          ; Maximum acceptable ASCII value
	MOVE.L	#OS_ReadLine32, A0                ; SWI OS_ReadLine32: Read line from input
	TRAP	#SWI
	BCS	monitor_escape                    ; Jump if user pressed ESCAPE

	MOVE.L	#buffer, A6                       ; A6 points to the line read by the OS_ReadLine32 call
	MOVE.B	(A6)+, D0

	CMP.B	#'?', D0                          ; Is it ??
	BEQ	monitor_inhelp                    ; Yes, so jump to (?)Help
	CMP.B	#'*', D0                          ; Is it *?
	BEQ	monitor_star                      ; Yes, so jump to (*) OS command
	ANDI.B	#$DF, D0                          ; Make character upper-case
	CMP.B	#'B', D0                          ; Is it D?
	BEQ	monitor_bytesearch                ; Yes, so jump to (B)yte search
	CMP.B	#'D', D0                          ; Is it D?
	BEQ	monitor_disassemble               ; Yes, so jump to (D)isassemble
	CMP.B	#'E', D0                          ; Is it E?
	BEQ	monitor_edit                      ; Yes, so jump to (E)dit memory
	CMP.B	#'F', D0                          ; Is it F?
	BEQ	monitor_fill                      ; Yes, so jump to (F)ill memory
	CMP.B	#'G', D0                          ; Is it G?
	BEQ	monitor_go                        ; Yes, so jump to (G)o
	CMP.B	#'H', D0                          ; Is it H?
	BEQ	monitor_hexdump                   ; Yes, so jump to (H)ex dump
	CMP.B	#'M', D0                          ; Is it M?
	BEQ	monitor_move                      ; Yes, so jump to (M)ove memory
	CMP.B	#'Q', D0                          ; Is it Q?
	BEQ	monitor_quit                      ; Yes, so jump to (Q)uit
	CMP.B	#'R', D0                          ; Is it R?
	BEQ	monitor_setreg                    ; Yes, so jump to Set (R)egister contents
	CMP.B	#'S', D0                          ; Is it T?
	BEQ	monitor_stringsearch              ; Yes, so jump to (S)tring search
	CMP.B	#'T', D0                          ; Is it T?
	BEQ	monitor_trace                     ; Yes, so jump to (T)race
	CMP.B	#'V', D0                          ; Is it V?
	BEQ	monitor_viewregs                  ; Yes, so jump to (V)iew register contents

monitor_stringsearch
monitor_trace
	MOVE.L	#msg_monitor_unknown_cmd, D0      ; Location of message in A0
	BSR	SWI_OS_Write0
	BRA	monitor_loop

monitor_disassemble
	BSR	skip_spaces                       ; Loop until (A6) isn`t ASCII value 32 (space)

	MOVE.L	#$10, D0
	MOVE.L	A6, D1
	BSR	SWI_OS_ReadUnsigned
	BVS	monitor_inhelp                    ; Jump if the parameter wasn`t valid

;	BSR	get_hex_value                     ; Return hex value of string at (A6) in D1
;	BCS	monitor_inhelp                    ; Jump if the parameter wasn`t valid

	MOVE.L	D1, A6
	MOVE.L	D2, D0
	MOVE.L	#buffer, D1
	BSR	SWI_Debugger_Disassemble

	MOVE.L	D1, D0
	BSR	SWI_OS_Write0
	BSR	SWI_OS_NewLine

	BRA	monitor_loop

monitor_escape
	MOVEQ	#$7E, D0                          ; OSBYTE $7E: Acknowledge detection of an ESCAPE condition
	BSR	SWI_OS_Byte
	BRA	monitor_loop


monitor_bytesearch
	BSR	skip_spaces                       ; Loop until (A6) isn`t ASCII value 32 (space)
	MOVE.L	#$10, D0
	MOVE.L	A6, D1
	BSR	SWI_OS_ReadUnsigned
	BVS	monitor_inhelp                    ; Jump if the parameter wasn`t valid

;	BSR	get_hex_value                     ; Return hex value of string at (A6) in D1
;	BCS	monitor_inhelp                    ; Jump if the parameter wasn`t valid
	MOVE.L	D2, A4                            ; Start address

	BSR	skip_spacesd1                     ; Loop until (A6) isn`t ASCII value 32 (space)
	MOVE.L	#$10, D0
	BSR	SWI_OS_ReadUnsigned
	BVS	monitor_inhelp                    ; Jump if the parameter wasn`t valid
;	BSR	get_hex_value                     ; Return hex value of string at (A6) in D1
;	BCS	monitor_inhelp                    ; Jump if the parameter wasn`t valid
	MOVE.L	D2, A5                            ; End address

	BSR	skip_spacesd1                     ; Loop until (A6) isn`t ASCII value 32 (space)
	MOVE.L	#$10, D0
	BSR	SWI_OS_ReadUnsigned
	BVS	monitor_inhelp                    ; Jump if the parameter wasn`t valid
;	BSR	get_hex_value                     ; Return hex value of string at (A6) in D1
;	BCS	monitor_inhelp                    ; Jump if the parameter wasn`t valid
	MOVE.L	D1, A6
	MOVE.B	D2, D7

monitor_bytesearch_loop
	CMP.B	(A4)+, D7                         ; Fill memory with byte
	BNE	monitor_bytesearch_loop2
	MOVE.L	A4, D0                            ; Put address in D0
	MOVE.L	#buffer, D1                       ; D1 is pointer to buffer
	MOVE.L	#$000000FF, D2                    ; Size of buffer
	BSR	SWI_OS_ConvertHex8                ; Convert to string
	MOVE.L	#$20200000, buffer+$08
	MOVE	#buffer, D0
	BSR	SWI_OS_Write0

monitor_bytesearch_loop2
	CMP.L	A4, A5
	BHS	monitor_bytesearch_loop
	BRA	monitor_loop


monitor_edit
	BSR	skip_spaces                       ; Loop until (A6) isn`t ASCII value 32 (space)
	MOVE.L	#$10, D0
	MOVE.L	A6, D1
	BSR	SWI_OS_ReadUnsigned
	BVS	monitor_inhelp                    ; Jump if the parameter wasn`t valid

;	BSR	get_hex_value                     ; Return hex value of string at (A6) in D1
;	BCS	monitor_inhelp                    ; Jump if the parameter wasn`t valid
	MOVE.L	D2, A4                            ; Start address

	MOVE.B	#$20, buffer+$09                  ; Prepare non-changing characters in the buffer
	MOVE.B	#$20, buffer+$0D
	MOVE.B	#'(', buffer+$0E
	MOVE.L	#$29202000, buffer+$10
;	MOVE.B	#')', buffer+$10
;	MOVE.B	#$20, buffer+$11
;	MOVE.B	#$20, buffer+$12
;	MOVE.B	#$00, buffer+$13

monitor_edit_loop
	MOVE.L	A4, D0                            ; Put address in D0
	MOVE.L	#buffer, D1                       ; D1 is pointer to buffer
	MOVE.L	#$000000FF, D2                    ; Size of buffer
	BSR	SWI_OS_ConvertHex8                ; Convert to string
	MOVE.B	#$20, buffer+$08
	ADDQ	#$02, D1

	MOVE.B	(A4), D0
	MOVE.L	#$000000FF, D2                    ; Size of buffer (not quite $FF but this will do)
	BSR	SWI_OS_ConvertHex2                ; Convert to string
	MOVE.L	D1, A5
	MOVE.B	#$20, (A5)+
	MOVE.L	A4, A6
	BSR	get_ascii_value
	MOVE.B	D0, buffer+$0F

	MOVE.L	#buffer, D0
	BSR	SWI_OS_Write0

	MOVE.L	#buffer+$80, D0                   ; Buffer address
	MOVE.L	#$02, D1                          ; Maximum line length is 2
	MOVE.B	#$20, D2                          ; Minimum acceptable ASCII value
	MOVE.B	#$46, D3                          ; Maximum acceptable ASCII value
	MOVE.L	#OS_ReadLine32, A0                ; SWI OS_ReadLine32: Read line from input
	TRAP	#SWI
	BCS	monitor_edit_escape

	CMPI.B	#$0D, buffer+$80                  ; Empty string?
	BNE	monitor_edit_loop2
	ADDQ	#1, A4                            ; If so, advance one byte
	BRA	monitor_edit_loop

monitor_edit_loop2
	MOVE.L	#buffer+$80, A6
	MOVE.L	#$10, D0
	MOVE.L	A6, D1
	BSR	SWI_OS_ReadUnsigned
	BVS	monitor_edit_loop                 ; Value not valid, so do this address again

;	BSR	get_hex_value
;	BCS	monitor_edit_loop                 ; Value not valid, so do this address again

	MOVE.B	D2, (A4)+
	BRA	monitor_edit_loop

monitor_edit_escape
	MOVEQ	#$7E, D0                          ; OSBYTE $7E: Acknowledge detection of an ESCAPE condition
	BSR	SWI_OS_Byte
	BRA	monitor_loop


monitor_fill
	MOVE.L	A6, D1
	BSR	skip_spacesd1                     ; Loop until (A6) isn`t ASCII value 32 (space)
	MOVE.L	#$10, D0
	BSR	SWI_OS_ReadUnsigned
	BVS	monitor_inhelp                    ; Jump if the parameter wasn`t valid

;	BSR	get_hex_value                     ; Return hex value of string at (A6) in D1
;	BCS	monitor_inhelp                    ; Jump if the parameter wasn`t valid
	MOVE.L	D2, A4                            ; Start address

	BSR	skip_spacesd1                     ; Loop until (A6) isn`t ASCII value 32 (space)
	MOVE.L	#$10, D0
	BSR	SWI_OS_ReadUnsigned
	BVS	monitor_inhelp                    ; Jump if the parameter wasn`t valid
;	BSR	get_hex_value                     ; Return hex value of string at (A6) in D1
;	BCS	monitor_inhelp                    ; Jump if the parameter wasn`t valid
	MOVE.L	D2, A5                            ; End address

	BSR	skip_spacesd1                     ; Loop until (A6) isn`t ASCII value 32 (space)
	MOVE.L	#$10, D0
	BSR	SWI_OS_ReadUnsigned
	BVS	monitor_inhelp                    ; Jump if the parameter wasn`t valid
;	BSR	get_hex_value                     ; Return hex value of string at (A6) in D1
;	BCS	monitor_inhelp                    ; Jump if the parameter wasn`t valid

monitor_fill_loop
	MOVE.B	D2, (A4)+                         ; Fill memory with byte
	CMP.L	A4, A5
	BHS	monitor_fill_loop

	BRA	monitor_loop


monitor_go
	BSR	skip_spaces                       ; Loop until (A6) isn`t ASCII value 32 (space)
	BEQ	monitor_inhelp                    ; Jump if there were more parameters

	MOVE.L	#$10, D0
	MOVE.L	A6, D1
	BSR	SWI_OS_ReadUnsigned
	BVS	monitor_inhelp                    ; Jump if the parameter wasn`t valid
;	BSR	get_hex_value                     ; Return hex value of string at (A6) in D1
;	BCS	monitor_inhelp                    ; Jump if the parameter wasn`t valid

	MOVE.L	D2, A6
	JSR	(A6)
	BRA	monitor_loop


monitor_hexdump
	BSR	skip_spaces                       ; Loop until (A6) isn`t ASCII value 32 (space)
	CMPI.B	#$0D, (A6)                        ; Is the command terminated with a CR?
	BNE	monitor_hexdump1
	CLR.L	D2
	BRA	monitor_hexdump2

monitor_hexdump1
	MOVE.L	#$10, D0
	MOVE.L	A6, D1
	BSR	SWI_OS_ReadUnsigned
	BVS	monitor_inhelp                    ; Jump if the parameter wasn`t valid
;	BSR	get_hex_value                     ; Return hex value of string at (A6) in D1
;	BCS	monitor_inhelp                    ; Jump if the parameter wasn`t valid

	BSR	skip_spacesd1                     ; Loop until (A6) isn`t ASCII value 32 (space)
	BNE	monitor_inhelp                    ; Jump if there were more parameters

monitor_hexdump2
	ANDI.L	#$FFFFFFFC, D2                    ; Mask out uneven bits so the start address is long aligned
	MOVE.L	D2, A6

	MOVE.B	#14, D0
	BSR	SWI_OS_WriteC                     ; Turn auto-paging on

monitor_hexdump_loop
	MOVE.L	A6, D0                            ; Put address in D0
	MOVE.L	#buffer, D1                       ; D1 is pointer to buffer
	MOVE.L	#$000000FF, D2                    ; Size of buffer
	BSR	SWI_OS_ConvertHex8                ; Convert to string
	MOVE.W	#$2020, buffer+$08
	ADDQ	#$02, D1

	MOVEQ	#$0F, D3                          ; Reset byte counter to 16 bytes
	MOVE.L	#buffer+$3B, A4                   ; Reset ASCII pointer

	MOVE.B	#$20, buffer+$3A
	MOVE.B	#$00, buffer+$4B                  ; End of string marker (don`t need to do this in the loop)

monitor_hexdump_innerloop
	MOVE.B	(A6), D0
	MOVE.L	#$000000FF, D2                    ; Size of buffer (not quite $FF but this will do)
	BSR	SWI_OS_ConvertHex2                ; Convert to string
	MOVE.L	D1, A5
	MOVE.B	#$20, (A5)
	ADDQ	#1, D1

	BSR	get_ascii_value
	MOVE.B	D0, (A4)+
	DBF	D3, monitor_hexdump_innerloop

	MOVE	#buffer, D0
	BSR	SWI_OS_Write0
	BSR	SWI_OS_NewLine

	BSR	SWI_OS_ReadEscapeState
	BCC	monitor_hexdump_loop
	MOVEQ	#$7E, D0                          ; OSBYTE $7E: Acknowledge detection of an ESCAPE condition
	BSR	SWI_OS_Byte

	MOVE.B	#15, D0
	BSR	SWI_OS_WriteC                     ; Turn auto-paging off
	BRA	monitor_loop


monitor_inhelp
	MOVE.L	#msg_monitor_help, D0             ; Location of message in A0
	BSR	SWI_OS_Write0
	BRA	monitor_loop


monitor_move
	BSR	skip_spaces                       ; Loop until (A6) isn`t ASCII value 32 (space)
	MOVE.L	#$10, D0
	MOVE.L	A6, D1
	BSR	SWI_OS_ReadUnsigned
	BVS	monitor_inhelp                    ; Jump if the parameter wasn`t valid
;	BSR	get_hex_value                     ; Return hex value of string at (A6) in D1
;	BCS	monitor_inhelp                    ; Jump if the parameter wasn`t valid
	MOVE.L	D2, A4                            ; Start address

	BSR	skip_spacesd1                     ; Loop until (D1) isn`t ASCII value 32 (space)
	MOVE.L	#$10, D0
	BSR	SWI_OS_ReadUnsigned
	BVS	monitor_inhelp                    ; Jump if the parameter wasn`t valid
;	BSR	get_hex_value                     ; Return hex value of string at (A6) in D1
;	BCS	monitor_inhelp                    ; Jump if the parameter wasn`t valid
	MOVE.L	D2, A5                            ; End address

	BSR	skip_spacesd1                     ; Loop until (D1) isn`t ASCII value 32 (space)
	MOVE.L	#$10, D0
	BSR	SWI_OS_ReadUnsigned
	BVS	monitor_inhelp                    ; Jump if the parameter wasn`t valid
;	BSR	get_hex_value                     ; Return hex value of string at (A6) in D1
;	BCS	monitor_inhelp                    ; Jump if the parameter wasn`t valid
	SUBQ.L	#1, D2

monitor_move_loop
	MOVE.B	(A4)+, (A5)+                      ; Move byte
	DBF	D2, monitor_move_loop
	BRA	monitor_loop


monitor_quit
	BSR	SWI_OS_NewLine                    ; Print newline
	RTS                                       ; Exit the monitor


monitor_setreg
	BSR	skip_spaces                       ; Loop until (A6) isn`t ASCII value 32 (space)

	MOVE.L	A5, -(SP)
	MOVE.L	D2, -(SP)
	MOVE.L	D1, -(SP)
	MOVE.L	D0, -(SP)

	CLR.L	D0
	MOVE.B	(A6)+, D0
	ANDI.B	#$DF, D0
	CMPI.B	#'A', D0
	BEQ	monitor_setreg2
	CMPI.B	#'D', D0
	BNE	monitor_inhelp

monitor_setreg2
	ANDI.B	#%10111110, D0                    ; Remaining value will be 0 or 4
	ASL.L	#1, D0                            ; Value is now 0 or 8
	MOVE.B	D0, D2                            ; Temporary value in D2

	MOVE.B	(A6)+, D0
	CMPI.B	#'0', D0
	BLO	monitor_inhelp
	CMPI.B	#'7', D0
	BHI	monitor_inhelp
	SUBI.B	#'0', D0
	ADD.B	D2, D0                            ; Value is now 0-7 for A0-A7 and 8-F for D0-D7
	ASL.L	#2, D0                            ; 
	MOVE.L	#monitor_setreg_a0, A5
	ADD.L	D0, A5

	BSR	skip_spaces                       ; Loop until (A6) isn`t ASCII value 32 (space)
	MOVE.L	#$10, D0
	MOVE.L	A6, D1
	BSR	SWI_OS_ReadUnsigned
	BVS	monitor_inhelp                    ; Jump if the parameter wasn`t valid
;	BSR	get_hex_value                     ; Return hex value of string at (A6) in D1
;	BCS	monitor_inhelp                    ; Jump if the parameter wasn`t valid

	JMP	(A5)

monitor_setreg_exit
	MOVE.L	(SP)+, D0
	MOVE.L	(SP)+, D1
	MOVE.L	(SP)+, D2
	MOVE.L	(SP)+, A5
	BRA	monitor_loop

monitor_setreg_a0
	MOVE.L	D2, A0
	BRA	monitor_setreg_exit

monitor_setreg_a1
	MOVE.L	D2, A1
	BRA	monitor_setreg_exit

monitor_setreg_a2
	MOVE.L	D2, A2
	BRA	monitor_setreg_exit

monitor_setreg_a3
	MOVE.L	D2, A3
	BRA	monitor_setreg_exit

monitor_setreg_a4
	MOVE.L	D2, A4
	BRA	monitor_setreg_exit

monitor_setreg_a5
	MOVE.L	D2, A5
	BRA	monitor_setreg_exit

monitor_setreg_a6
	MOVE.L	D2, A6
	BRA	monitor_setreg_exit

monitor_setreg_a7
	MOVE.L	D2, A7
	BRA	monitor_setreg_exit

monitor_setreg_d0
	MOVE.L	D2, D0
	BRA	monitor_setreg_exit

monitor_setreg_d1
	MOVE.L	D2, D1
	BRA	monitor_setreg_exit

monitor_setreg_d2
	NOP                                       ; Each section must be 4 bytes long
	BRA	monitor_setreg_exit

monitor_setreg_d3
	MOVE.L	D2, D3
	BRA	monitor_setreg_exit

monitor_setreg_d4
	MOVE.L	D2, D4
	BRA	monitor_setreg_exit

monitor_setreg_d5
	MOVE.L	D2, D5
	BRA	monitor_setreg_exit

monitor_setreg_d6
	MOVE.L	D2, D6
	BRA	monitor_setreg_exit

monitor_setreg_d7
	MOVE.L	D2, D7
	BRA	monitor_setreg_exit


monitor_star
	MOVE.L	A6, D0
	BSR	SWI_OS_CLI
	BRA	monitor_loop


monitor_viewregs
	MOVE.B	#$20, D0
	MOVE.W	#$32, D1                          ; Number of spaces

monitor_viewregs2
	BSR	SWI_OS_WriteC
	DBF	D1, monitor_viewregs2

	MOVE.L	#msg_statusregister, D0           ; Location of message in A0
	BSR	SWI_OS_Write0
	BSR	SWI_OS_NewLine

	MOVE.L	#$44303A00, buffer                ; 'D0:' + $00 terminator
	MOVE.L	#buffer+3, D1                     ; D1 is pointer to buffer
	MOVE.L	#$000000FC, D2                    ; Size of buffer
	BSR	SWI_OS_ConvertHex8
	MOVE.B	#$20, buffer+$0B

	MOVE.L	#$44313A00, buffer+$0C            ; 'D1:' + $00 terminator
	MOVE.L	D1, D0
	MOVE.L	#buffer+$0F, D1                   ; D1 is pointer to buffer
	MOVE.L	#$000000F4, D2                    ; Size of buffer
	BSR	SWI_OS_ConvertHex8
	MOVE.B	#$20, buffer+$17

	MOVE.L	#$44323A00, buffer+$18            ; 'D2:' + $00 terminator
	MOVE.L	D2, D0
	MOVE.L	#buffer+$1B, D1                   ; D1 is pointer to buffer
	MOVE.L	#$000000E8, D2                    ; Size of buffer
	BSR	SWI_OS_ConvertHex8
	MOVE.B	#$20, buffer+$23

	MOVE.L	#$44333A00, buffer+$24            ; 'D3:' + $00 terminator
	MOVE.L	D3, D0
	MOVE.L	#buffer+$27, D1                   ; D1 is pointer to buffer
	MOVE.L	#$000000DC, D2                    ; Size of buffer
	BSR	SWI_OS_ConvertHex8
	MOVE.B	#$20, buffer+$2F

	MOVE.L	#$53523A00, buffer+$30            ; 'SR:' + $00 terminator
	MOVE.L	#buffer+$33, D1                   ; D1 is pointer to buffer
	MOVE.L	#$000000CD, D2                    ; Size of buffer
	MOVE.W	SR, D0                            ; Put the status register in D0
	BSR	SWI_OS_ConvertBinary2             ; Prepare string
	MOVE.B	#$20, buffer+$43
	MOVE.L	#$20200A0D, buffer+$44            ; Add some spaces to make it long-word aligned

	MOVE.L	#$44343A00, buffer+$48            ; 'D4:' + $00 terminator
	MOVE.L	D4, D0
	MOVE.L	#buffer+$4B, D1                   ; D1 is pointer to buffer
	MOVE.L	#$000000B8, D2                    ; Size of buffer
	BSR	SWI_OS_ConvertHex8
	MOVE.B	#$20, buffer+$53

	MOVE.L	#$44353A00, buffer+$54            ; 'D5:' + $00 terminator
	MOVE.L	D5, D0
	MOVE.L	#buffer+$57, D1                   ; D1 is pointer to buffer
	MOVE.L	#$000000AC, D2                    ; Size of buffer
	BSR	SWI_OS_ConvertHex8
	MOVE.B	#$20, buffer+$5F

	MOVE.L	#$44363A00, buffer+$60            ; 'D6:' + $00 terminator
	MOVE.L	D6, D0
	MOVE.L	#buffer+$63, D1                   ; D1 is pointer to buffer
	MOVE.L	#$000000A0, D2                    ; Size of buffer
	BSR	SWI_OS_ConvertHex8
	MOVE.B	#$20, buffer+$6B

	MOVE.L	#$44373A00, buffer+$6C            ; 'D7:' + $00 terminator
	MOVE.L	D7, D0
	MOVE.L	#buffer+$6F, D1                   ; D1 is pointer to buffer
	MOVE.L	#$00000094, D2                    ; Size of buffer
	BSR	SWI_OS_ConvertHex8
	MOVE.B	#$20, buffer+$77

	MOVE.L	#$55533A00, buffer+$78            ; 'US:' + $00 terminator
	MOVE.L	USP, A0
	MOVE.L	A0, D0
	MOVE.L	#buffer+$7B, D1                   ; D1 is pointer to buffer
	MOVE.L	#$00000094, D2                    ; Size of buffer
	BSR	SWI_OS_ConvertHex8
	MOVE.B	#$20, buffer+$83
	MOVE.L	#$20200A0D, buffer+$84            ; Add some spaces to make it long-word aligned

	MOVE.L	#$41303A00, buffer+$88            ; 'A0:' + $00 terminator
	MOVE.L	A0, D0
	MOVE.L	#buffer+$8B, D1                   ; D1 is pointer to buffer
	MOVE.L	#$00000094, D2                    ; Size of buffer
	BSR	SWI_OS_ConvertHex8
	MOVE.B	#$20, buffer+$93

	MOVE.L	#$41313A00, buffer+$94            ; 'A1:' + $00 terminator
	MOVE.L	A1, D0
	MOVE.L	#buffer+$97, D1                   ; D1 is pointer to buffer
	MOVE.L	#$00000094, D2                    ; Size of buffer
	BSR	SWI_OS_ConvertHex8
	MOVE.B	#$20, buffer+$9F

	MOVE.L	#$41323A00, buffer+$A0            ; 'A2:' + $00 terminator
	MOVE.L	A2, D0
	MOVE.L	#buffer+$A3, D1                   ; D1 is pointer to buffer
	MOVE.L	#$00000094, D2                    ; Size of buffer
	BSR	SWI_OS_ConvertHex8
	MOVE.B	#$20, buffer+$AB

	MOVE.L	#$41333A00, buffer+$AC            ; 'A3:' + $00 terminator
	MOVE.L	A3, D0
	MOVE.L	#buffer+$AF, D1                   ; D1 is pointer to buffer
	MOVE.L	#$00000094, D2                    ; Size of buffer
	BSR	SWI_OS_ConvertHex8
	MOVE.B	#$20, buffer+$B7

	MOVE.L	#$53533A00, buffer+$B8            ; 'SS:' + $00 terminator
	MOVE.L	SP, D0
	MOVE.L	#buffer+$BB, D1                   ; D1 is pointer to buffer
	MOVE.L	#$00000094, D2                    ; Size of buffer
	BSR	SWI_OS_ConvertHex8
	MOVE.B	#$20, buffer+$C3
	MOVE.L	#$20200A0D, buffer+$C4            ; Add some spaces to make it long-word aligned

	MOVE.L	#$41343A00, buffer+$C8            ; 'A4:' + $00 terminator
	MOVE.L	A4, D0
	MOVE.L	#buffer+$CB, D1                   ; D1 is pointer to buffer
	MOVE.L	#$00000094, D2                    ; Size of buffer
	BSR	SWI_OS_ConvertHex8
	MOVE.B	#$20, buffer+$D3

	MOVE.L	#$41353A00, buffer+$D4            ; 'A5:' + $00 terminator
	MOVE.L	A5, D0
	MOVE.L	#buffer+$D7, D1                   ; D1 is pointer to buffer
	MOVE.L	#$00000094, D2                    ; Size of buffer
	BSR	SWI_OS_ConvertHex8
	MOVE.B	#$20, buffer+$DF

	MOVE.L	#$41363A00, buffer+$E0            ; 'A6:' + $00 terminator
	MOVE.L	A6, D0
	MOVE.L	#buffer+$E3, D1                   ; D1 is pointer to buffer
	MOVE.L	#$00000094, D2                    ; Size of buffer
	BSR	SWI_OS_ConvertHex8
	MOVE.B	#$20, buffer+$EB

	MOVE.L	#$41373A00, buffer+$EC            ; 'A7:' + $00 terminator
	MOVE.L	A7, D0
	MOVE.L	#buffer+$EF, D1                   ; D1 is pointer to buffer
	MOVE.L	#$00000094, D2                    ; Size of buffer
	BSR	SWI_OS_ConvertHex8
	MOVE.B	#$20, buffer+$F7

	MOVE.L	#$50433A00, buffer+$F8            ; 'PC:' + $00 terminator

	MOVE.L	#buffer, D0                       ; D1 is pointer to buffer
	BSR	SWI_OS_Write0                     ; And write it to

	BSR	SWI_OS_NewLine
	BRA	monitor_loop


monitor_help
	MOVE.L	#msg_mon_help, D0                 ; Location of message in A0
	BSR	SWI_OS_Write0
	RTS

; -----------------------------------------------------------------------------
; *QUIT
; -----------------------------------------------------------------------------
quit
	BRA	SWI_OS_Exit

; -----------------------------------------------------------------------------
; *TZAP
; -----------------------------------------------------------------------------
tzap
	BRA	not_supported

; -----------------------------------------------------------------------------
; *XFER
; -----------------------------------------------------------------------------
xfer
	MOVE.L	#$10, D0
	MOVE.L	A6, D1
	BSR	SWI_OS_ReadUnsigned
	BVS	xfer_help                         ; Jump if the parameter wasn`t valid
;	BSR	get_hex_value                     ; Return hex value of string at (A6) in D1
;	BCS	xfer_help                         ; Jump if the parameter wasn't valid
	MOVE.L	D2, D7                            ; Move host address to D7

	BSR	skip_spacesd1                     ; Loop until (A6) isn't ASCII value 32 (space)
	MOVE.L	#$10, D0
	BSR	SWI_OS_ReadUnsigned
	BVS	xfer_help                         ; Jump if the parameter wasn`t valid
;	BSR	get_hex_value                     ; Return hex value of string at (A6) in D1
;	BCS	xfer_help                         ; Jump if the parameter wasn't valid
	MOVE.L	D2, D6                            ; Move parasite address to D6

	BSR	skip_spacesd1                     ; Loop until (A6) isn't ASCII value 32 (space)
	MOVE.L	#$10, D0
	BSR	SWI_OS_ReadUnsigned
	BVS	xfer_help                         ; Jump if the parameter wasn`t valid
;	BSR	get_hex_value                     ; Return hex value of string at (A6) in D1
;	BCS	xfer_help                         ; Jump if the parameter wasn't valid
	MOVE.L	D1, A6
	MOVE.L	D2, D5                            ; Move length to D5

	BSR	skip_spaces                       ; Loop until (A6) isn't ASCII value 32 (space)
	MOVE.B	(A6)+, D0
	ANDI.B	#$DF, D0                          ; Make character upper-case
	CMP.B	#'R', D0                          ; Is it a R(ead)?
	BEQ	xfer2
	CMP.B	#'W', D0                          ; ...or a W(rite)?
	BNE	xfer_help
	MOVE.B	#$06, D4
	BRA	xfer2a
xfer2
	MOVE.B	#$07, D4                          ; Put R/W in D4
xfer2a
	BSR	skip_spaces                       ; Loop until (A6) isn`t ASCII value 32 (space)
	BEQ	xfer2b                            ; End of command string has been reached
	MOVE.B	(A6)+, D0
	ANDI.B	#$DF, D0                          ; Make character upper-case
	CMP.B	#'S', D0                          ; Is it a S(hadow memory)?
	BEQ	xfer3
	CMP.B	#'M', D0                          ; ...or a M(ain memory)?
	BNE	xfer_help
	MOVE.B	#$40, D3                          ; Byte for Main memory
	BRA	xfer3a

xfer2b
	MOVE.B	#$10, D0                          ; Byte for Shadow memory
	BRA	xfer3a

xfer3
	MOVE.B	#$20, D3
xfer3a
	BSR	skip_spaces                       ; Loop until (A6) isn`t ASCII value 32 (space)
	BNE	go_help                           ; Jump if there were more parameters

	MOVE.B	#$0E, buffer                      ; XY+00: Send block length
	MOVE.B	#$10, buffer+1                    ; XY+01: Receive block length
	MOVE.L	D7, buffer+2                      ; XY+02: Host address
	MOVE.L	D6, buffer+6                      ; XY+06: 68k address
	MOVE.W	D5, buffer+10                     ; XY+0A: Length
	MOVE.B	D4, buffer+12                     ; XY+0C: Function (&06 for write, &07 for read)
	MOVE.B	D3, buffer+13                     ; XY+0D: Memory access control

	MOVE.L	#buffer, D1                       ; D1 = pointer to control block
	MOVE.L	#$000000FA, D0                    ; OSWORD &FA call
	BSR	SWI_OS_Word

	CMPI.B	#$06, D4                          ; Is it a read operation?
	BNE	xfer4
	MOVE.L	D7, A5                            ; Source is host address
	MOVE.L	D6, A6                            ; Desrn is copro address
	MOVE.L	D5, D2                            ; Length
	BRA	transferhosttocopro

xfer4
	MOVE.L	D6, A5                            ; Source is host address
	MOVE.L	D7, A6                            ; Desrn is copro address
	MOVE.L	D5, D2                            ; Length
	BRA	transfercoprotohost

xfer_help
	MOVE.L	#msg_xfer_help, D0                ; Location of message in A0
	BSR	SWI_OS_Write0
	RTS



; -----------------------------------------------------------------------------
; Vector handlers
;
; Default vector $01 ErrorV handler
; -----------------------------------------------------------------------------
_errorv
	BSR	SWI_OS_NewLine

	ADD.L	#$04, D0                          ; Ignore error number for now
	BSR	SWI_OS_Write0                     ; Print error message at (D0)

	CMP.L	#$00000000, error_pc
	BEQ	_errorv1
	MOVE.L	#msg_errorv_at, D0                ; Location of message in A0
	BSR	SWI_OS_Write0
	MOVE.L	error_pc, D0
	MOVE.L	#buffer, D1
	MOVE.B	#$FF, D2
	BSR	SWI_OS_ConvertHex8
	BSR	SWI_OS_Write0

_errorv1
	BSR	SWI_OS_NewLine
;	Replace with BRA SWI_OS_Exit
	MOVE.L	(ramsize), A7                     ; Reset stack pointer
	BRA	main_loop

; -----------------------------------------------------------------------------
; Default vector $02 IrqV handler
; -----------------------------------------------------------------------------
_irqv
	MOVE.L	D0, -(SP)                         ; Push D0 to the stack
	MOVE.L	#err_unknown_interrupt, D0        ; Location of message in D0
	MOVE.L	#0, error_pc
	BSR	SWI_OS_GenerateError              ; Print the message
	MOVE.L	(SP)+, D0                         ; Pull D0 from the stack
	RTS

; -----------------------------------------------------------------------------
; Default vector $03 WrchV handler
; -----------------------------------------------------------------------------
_wrchv
	BTST	#6, r1status                      ; Check the NF1 flag of TUBE ULA Status register 1 (1st data register not filled)
	BEQ	_wrchv                            ; Loop until TUBE ULA Data register 2 is empty
	MOVE.B	D0, r1data                        ; ?r1data = D0.B

	IFNE DEBUG
		MOVE.L	D0, -(SP)
		MOVE.L	D1, -(SP)
		MOVE.B	D0, D1
		MOVE.B	#6, D0
		TRAP	#15
		MOVE.L	(SP)+, D1
		MOVE.L	(SP)+, D0
	ENDC

	RTS

; -----------------------------------------------------------------------------
; Default vector $10 EventV handler
; -----------------------------------------------------------------------------
_eventv
	RTS

; -----------------------------------------------------------------------------
; Default vector $18 UKSWIV handler
; -----------------------------------------------------------------------------
_ukswiv
	MOVE.L	D0, -(SP)                         ; Push D0 to the stack
	MOVE.L	#err_no_such_swi, D0              ; Location of message in D0
	BSR	SWI_OS_GenerateError              ; Print the message
	MOVE.L	(SP)+, D0                         ; Pull D0 from the stack
	RTS

; -----------------------------------------------------------------------------
; Default vector $1E ChangeEnvironmentV handler
; -----------------------------------------------------------------------------
_ChangeEnvironmentV
	CMP	#16, D0
	BLS	_ChangeEnvironmentVprocess

_ChangeEnvironmentVerror
	MOVE.L	#err_bad_environment_number, D0
	ORI	#$02, CCR                         ; Set overflow fag
	RTS

_ChangeEnvironmentVprocess
	LEA	_ChangeEnvironment_table, A0
	LSL.L	#2, D0                            ; D0 = D0 * 4
	ADD.L	D0, A0                            ; A0 = A0+(D0*3)
	ADD.L	D0, A0
	ADD.L	D0, A0
	MOVE.L	(A0)+, A1
	CMPA.L	#0, A1
	BEQ	_ChangeEnvironmentVerror          ; Vector not implemented

	MOVE.L	D4, -(SP)                         ; Push D4 to the stack
	MOVE.L	(A0)+, A2
	MOVE.L	(A0)+, A3

	TST.L	D1
	BNE	_ChangeEnvironmentVr1w
	MOVE.L	(A1), D1
	BRA	_ChangeEnvironmentVr2

_ChangeEnvironmentVr1w
	MOVE.L	(A1), D4
	MOVE.L	D1, (A1)
	EXG	D4, D1

_ChangeEnvironmentVr2
	TST.L	D2
	BNE	_ChangeEnvironmentVr2w
	MOVE.L	(A2), D2
	BRA	_ChangeEnvironmentVr3

_ChangeEnvironmentVr2w
	MOVE.L	(A2), D4
	MOVE.L	D2, (A2)
	EXG	D4, D2

_ChangeEnvironmentVr3
	TST.L	D3
	BNE	_ChangeEnvironmentVr3w
	MOVE.L	(A2), D3
	BRA	_ChangeEnvironmentVexit

_ChangeEnvironmentVr3w
	MOVE.L	(A3), D4
	MOVE.L	D1, (A3)
	EXG	D4, D1

_ChangeEnvironmentVexit
	MOVE.L	(SP)+, D4
	RTS


; -----------------------------------------------------------------------------
; Default callback handler (no software vector)
; -----------------------------------------------------------------------------
_callbackv
	BRA	not_supported

; -----------------------------------------------------------------------------
; Default breakpoint handler (no software vector)
; -----------------------------------------------------------------------------
_breakpointv
	BRA	not_supported

; -----------------------------------------------------------------------------
; Default escape handler (no software vector)
; -----------------------------------------------------------------------------
_escapev
	ANDI.B	#$40, D0                          ; Mask out bit 6
	MOVE.B	D0, escapeflag                    ; Set escapeflag to new value
	RTS

; -----------------------------------------------------------------------------
; Default exit handler (no software vector)
; -----------------------------------------------------------------------------
_exitv
	MOVE.L	#0, returncode
	CMP.L	#'ABEX', D1
	BNE	_exitv1
	MOVE.L	D2, returncode
	CMP.L	returncodelimit, D2
	BLS	_exitv1
	MOVE.L	#err_return_code_limit, D0
	BSR	SWI_OS_GenerateError

_exitv1
;	MOVE.L	SExitA, A6
;	MOVE.L	A6, Curr_Active_Object            ; Set currently active object
;	MOVE.L	SExitA_ws, A4                     ; Set workspace pointer
	MOVE.L	(ramsize), A7                     ; Reset supervisor stack
;	                                          ; Set appropiate flags in CCR
;	JMP	(A6)
	BRA	main_loop

; -----------------------------------------------------------------------------
; Default unusedswi handler (no software vector)
; -----------------------------------------------------------------------------
_unusedswiv
	BRA	not_supported

; -----------------------------------------------------------------------------
; Default upcall handler (no software vector)
; -----------------------------------------------------------------------------
_upcallv
	BRA	not_supported


; -----------------------------------------------------------------------------
; Data transfer routines
;
; Transfer data from host memory (A5) to copro memory (A6), length in D2
; -----------------------------------------------------------------------------
transferhosttocopro
	MOVE.L	A5, buffer

transferhosttocopro_loop
	MOVE.L	#buffer, D1
	MOVEQ	#$05, D0                          ; OSWORD &05 call
	BSR	SWI_OS_Word
	MOVE.B	buffer+5, (A6)+
	DBF	D2, transferhosttocopro_loop
	RTS

; -----------------------------------------------------------------------------
; Transfer data from copro memory (A5) to host memory (A6), length in D2
; -----------------------------------------------------------------------------
transfercoprotohost
	MOVE.L	A5, buffer

transfercoprotohost_loop
	MOVE.L	#buffer, D1
	MOVE.B	(A6)+, buffer+5
	MOVEQ	#$06, D0                          ; OSWORD &06 call
	BSR	SWI_OS_Word
	DBF	D2, transfercoprotohost_loop
	RTS

; -----------------------------------------------------------------------------
; Set up the OSWORD &FA handler in the host
; -----------------------------------------------------------------------------
setup_osword_fa
;	ORI.W	#$0400, SR                        ; Disable IRQ's (remmed out since interrupts are already disabled)
	MOVE.L	#osword_fa_hostcode, A5           ; Co-pro address
	MOVE.L	#$FFFF2500, A6                    ; Host address is &2500
	MOVE.L	#$000001FB, D2                    ; Length
	BSR	transfercoprotohost               ; Transfer code to host

	MOVE.L	#$FFFF0200, A5                    ; Host address is &0200
	MOVE.L	#buffer, A6                       ; Co-pro address
	MOVE.L	#$00000002, D2                    ; Just two bytes (original address of wordv handler)
	BSR	transferhosttocopro               ; Get old wordv handler

	MOVE.L	#buffer, A5                       ; Co-pro address
	MOVE.L	#$FFFF2503, A6                    ; Host address is &2503
	MOVE.L	#$00000002, D2                    ; Length
	BSR	transfercoprotohost               ; Save address of old handler in new code

	MOVE.W	#$2500, buffer

	MOVE.L	#buffer, A5                       ; Co-pro address
	MOVE.L	#$FFFF0200, A6                    ; Host address is &0200 (wordv)
	MOVE.L	#$00000002, D2                    ; Length
	BSR	transfercoprotohost               ; Set wordv to new handler

;	ANDI.W	#$F8FF, SR                        ; Enable all interrupts (remmed out)
	RTS
	

; -----------------------------------------------------------------------------
; Various utility functions
;
; Loop until (A6) isn`t ASCII value 32 (space)
; -----------------------------------------------------------------------------
skip_spaces
	CMP.B	#' ', (A6)+                       ; Is it ASCII value 32 (space)?
	BEQ	skip_spaces                       ; No? Then check next byte
	MOVE.B	-(A6), D0                         ; Put the first non-SPACE character in D0
	CMP.B	#$0D, D0                          ; Check if <cr>
	RTS

; -----------------------------------------------------------------------------
; Loop until (D1) isn`t ASCII value 32 (space)
; -----------------------------------------------------------------------------
skip_spacesd1
	EXG	D1, A6

skip_spacesd1a
	CMP.B	#' ', (A6)+                       ; Is it ASCII value 32 (space)?
	BEQ	skip_spacesd1a                    ; No? Then check next byte
	MOVE.B	-(A6), D0                         ; Put the first non-SPACE character in D0
	EXG	D1, A6
	CMP.B	#$0D, D0                          ; Check if <cr>
	RTS

; -----------------------------------------------------------------------------
; Return hex value of string at (A6) in D1
; -----------------------------------------------------------------------------
get_hex_value
	MOVE.L	#$10, D0
	MOVE.L	A6, D1
	BSR	SWI_OS_ReadUnsigned
	BVS	get_hex_value_vset
	
	MOVE.L	D1, A6
	MOVE.L	D2, D1
	ANDI.B	#$FE, CCR                      ; Clear C flag in stacked PSW
	RTS

get_hex_value_vset
	MOVE.L	D1, A6
	MOVE.L	D2, D1
	ORI.B	#$01, CCR                      ; Set Carry in stacked PSW
	RTS

	CLR.L	D1                                ; Clear contents of D1

get_hex_value1
	MOVE.B	(A6)+, D0                         ; Get byte in D0
	MOVE.L	D0, -(SP)                         ; Push D0 to the stack

	CMPI.B	#'0', D0
	BLO	get_hex_value3                    ; Invalid character
	CMPI.B	#'9', D0
	BLS	get_hex_value2                    ; Character is between 0-9, so process it now

	ANDI.B	#%11011111, D0                    ; Make character upper-case
	CMPI.B	#'A', D0
	BLO	get_hex_value3                    ; Invalid character
	CMPI.B	#'F', D0
	BHI	get_hex_value3                    ; Invalid character
	SUBI.B	#$07, D0

get_hex_value2
	ANDI.B	#%00001111, D0                    ; Mask out the highest nibble
	ASL.L	#4, D1                            ; Shift D1 to make room for new nibble
	ADD.B	D0, D1                            ; Add the nibble to the result

	MOVE.L	(SP)+, D0                         ; Pull D0 from the stack (not used; just to clean things up)
	BRA	get_hex_value1

get_hex_value3
	MOVE.L	(SP)+, D0                         ; Pull D0 from the stack

	CMPI.B	#$0D, D0                          ; Is the next character CR?
	BEQ	get_hex_value4                    ; Yes? Then exit with C=0

	CMPI.B	#' ', D0                          ; Is the next character SPACE?
	BEQ	get_hex_value4                    ; Yes? Then exit with C=0

	SUBQ	#1, A6                            ; Optimize?
	ORI	#$01, CCR                         ; Set the carry bit and exit ; 00000160	Bad hex
	RTS

get_hex_value4
	SUBQ	#1, A6                            ; Optimize?
	ANDI	#$FE, CCR                         ; Clear the carry-bit and exit
	RTS

; -----------------------------------------------------------------------------
; Return printable ASCII value of string at (A6) in D0
; -----------------------------------------------------------------------------
get_ascii_value
	MOVE.B	(A6)+, D0
	CMPI.B	#$20, D0
	BLO	get_ascii_value1
	CMPI.B	#$7F, D0
	BLO	get_ascii_value2

get_ascii_value1
	MOVE.B	#'.', D0

get_ascii_value2
	RTS

; -----------------------------------------------------------------------------
; Set interrupt level
; -----------------------------------------------------------------------------
set_interrupt
	ANDI.L	#$7, D0                           ; Mask out other bits
	ASL.W	#8, D0                            ; 

	ANDI.W	#$F8FF, SR                        ; Mask out the ISR bits
;	OR.W	D0, SR                            ; And set the interrupt level

	MOVE.L	(SP)+, D1                         ; Pull A6 from the stack
	RTS


; -----------------------------------------------------------------------------
; Strings and error messages
; -----------------------------------------------------------------------------
startup_message1
	DC.B	$0D, $0A
	DC.B	'Acorn 68', $00

startup_message2
	DC.B	' second processor ', $00

startup_message_cpus
	DC.B	'008000010020030040060070300'

startup_message3
	DC.B	'K', $07, $0D, $0A, $0D, $0A, $00

msg_swi_removecursors
	DC.B	23, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0

msg_swi_restorecursors
	DC.B	23, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0

msg_help
	DC.B	$0A
	DC.B	$0D
;	DC.B	'68030 TUBE ', bios_version, $0A, $0D, $00
	DC.B	'CiscOS v2.02 (13 September 2015)', $0A, $0D, $00

msg_help_std
	DC.B	'   SWI', $0A, $0D
	DC.B	'   TUBE', $0A, $0D, $00

msg_help_extd
	DC.B	'   ERROR (number) <message>', $0A, $0D
	DC.B	'   FLASH <fsp>', $0A, $0D
	DC.B	'   GO <addr>', $0A, $0D
	DC.B	'   MON', $0A, $0D
	DC.B	'   QUIT', $0A, $0D
	DC.B	'   TZAP (addr)', $0A, $0D
	DC.B	'   XFER <io addr.> <addr> <length> (R|W) (S|M)', $0A, $0D, $00

msg_star_error_help
	DC.B	'Syntax: ERROR (number) <message>', $0A, $0D, $00

msg_flash_help
	DC.B	'Syntax: FLASH <fsp>', $0A, $0D, $00

msg_go_help
	DC.B	'Syntax: GO <addr>', $0A, $0D, $00

msg_mon_help
	DC.B	'Syntax: MON', $0A, $0D, $00

msg_tzap_help
	DC.B	'Syntax: TZAP (addr)', $0A, $0D, $00

msg_xfer_help
	DC.B	'Syntax: XFER <io addr.> <addr> <length> (R|W) (S|M)', $0A, $0D, $00

msg_monitor
	DC.B	'CiscOS Monitor', $00

msg_monitor_help
	DC.B	'B  Byte search <start> <end> <byte>', $0A, $0D
	DC.B	'D  Disassemble <addr>', $0A, $0D
	DC.B	'E  Edit memory <addr>', $0A, $0D
	DC.B	'F  Fill <start> <end> <byte>', $0A, $0D
	DC.B	'G  Go <addr>', $0A, $0D
	DC.B	'H  Hex dump {addr}', $0A, $0D
	DC.B	'M  Move memory <source> <destn> <length>', $0A, $0D
	DC.B	'Q  Quit', $0A, $0D
	DC.B	'R  Set register contents <reg> <value>', $0A, $0D
	DC.B	'S  String search <start> <end> <string>', $0A, $0D
	DC.B	'T  Trace', $0A, $0D
	DC.B	'V  View register contents', $0A, $0D
	DC.B	'*  OS command', $0A, $0D
	DC.B	'?  Help', $0A, $0D, $00

msg_monitor_unknown_cmd
	DC.B	'Unknown command, use ? for help.', $0A, $0D, $00

msg_statusregister
	DC.B	'T-S--INT---XNZVC', $00

msg_flash_wrongfile
	DC.B	'File is not a CiscOS file', $0A, $0D, $00

msg_flash_noroom
	DC.B	'No room', $0A, $0D, $00

msg_flash_warning
	DC.B	'WARNING! THIS WILL FLASH THE BIOS', $0A, $0D
	DC.B	'USE AT YOUR OWN RISK!', $0A, $0D, $0A, $0D
	DC.B	'Do you want to continue? (Y/N) : ', $00

msg_flash_identify
	DC.B	'Flash ROM ID=$', $00

msg_flash_start
	DC.B	$0A, $0D
	DC.B	'Flashing sector ', $0A, $0D, $00

msg_flash_finish
	DC.B	'Flash completed successfully', $0A, $0D, $00

msg_flash_error
	DC.B	'Flash error at ', $00

msg_days_short
	DC.B	'MonTueWedThuFriSatSun', $00

msg_months_short
	DC.B	'JanFebMarAprMayJunJulAugSepOctNovDec', $00

msg_bus_error
	DC.B	$0A, $0D
	DC.B	'Bus error'
msg_errorv_at
	DC.B	' at $', $00

msg_address_error
	DC.B	$0A, $0D
	DC.B	'Address error exception at $', $00

msg_exception_mf
	DC.B	' Access type&function:', $00

msg_exception_aa
	DC.B	' Access address      :', $00

msg_exception_ir
	DC.B	' Instruction register:', $00

msg_exception_sr
	DC.B	' Status register     :TRSM-INT---XNZVC', $0A, $0D
	DC.B	'                      ', $00

	ALIGN	4                                 ; Most help and syntax messages go together to save ALIGNing wastage
err_illegal_instruction
	DC.L	$80000100
	DC.B	'Illegal instruction', $00

	ALIGN	4
err_unknown_interrupt
	DC.L	$80000104
	DC.B	'Unknown IRQ at &', $00

	ALIGN	4
err_int_divide_by_zero
	DC.L	$80000169
	DC.B	'Integer divide by zero', $00

	ALIGN	4
err_privilege_violation
	DC.L	$80000008
	DC.B	'Privilege violation', $00

	ALIGN	4
err_out_of_range
	DC.L	$00000001
	DC.B	'Out of range', $00

	ALIGN	4
err_escape
	DC.L	$00000011
	DC.B	'Escape', $00

	ALIGN	4
err_not_a_language
	DC.L	$000000FF
	DC.B	'This is not a language', $00

	ALIGN	4
err_cannot_run_code
	DC.L	$000000FF
	DC.B	'I cannot run this code', $00

	ALIGN	4
err_unknown_exception
	DC.L	$000000FF
	DC.B	'Unknown exception', $00

	ALIGN	4
err_not_supported
	DC.L	$000000FF
	DC.B	'Not supported', $00

	ALIGN	4
err_badbase
	DC.L	$0000016A
	DC.B	'Bad base', $00

	ALIGN	4
err_badnumber
	DC.L	$0000016B
	DC.B	'Bad number', $00

	ALIGN	4
err_number_too_big
	DC.L	$0000016C
	DC.B	'Number too big', $00

	ALIGN	4
err_bad_environment_number
	DC.L	$000001B0
	DC.B	'Bad environment number', $00

	ALIGN	4
err_no_such_swi
	DC.L	$000001E6
	DC.B	'No such SWI', $00

	ALIGN	4
err_bad_vector_number
	DC.L	$000001A0
	DC.B	'Bad vector number', $00

	ALIGN	4
err_return_code_limit
	DC.L	$000001E2
	DC.B	'Return code limit exceeded', $00

	ALIGN	4
err_buffer_overflow
	DC.L	$000001E4
	DC.B	'Buffer overflow', $00

	ALIGN	4
err_swi_name_not_known
	DC.L	$000001E6
	DC.B	'SWI name not known', $00

	ALIGN	4
err_unknown_percent_field
	DC.L	$000002C2
	DC.B	'Unknown ''%'' field', $00

	ALIGN	4
err_bad_station
	DC.L	$00000306
	DC.B	'Bad station number', $00

	ALIGN	4
err_bad_network
	DC.L	$00000307
	DC.B	'Bad network number', $00

	ALIGN	4
err_bad_fscontrol_call
	DC.L	$00000401
	DC.B	'Bad FSControl call', $00

	ALIGN	4
err_unaligned_address
	DC.L	$00000807
	DC.L	'Unaligned address', $00

; -----------------------------------------------------------------------------
; Data
;
; Table which specifies OSWORD call parameter block length
; -----------------------------------------------------------------------------
osword_send_table
	                                          ; Length of parameterblock to be send to the host processor
	DC.B	$00                               ; OSWORD $01: Parameter block length = $00
	DC.B	$05                               ; OSWORD $02: Parameter block length = $05
	DC.B	$00                               ; OSWORD $03: Parameter block length = $00
	DC.B	$05                               ; OSWORD $04: Parameter block length = $05
	DC.B	$02                               ; OSWORD $05: Parameter block length = $02
	DC.B	$05                               ; OSWORD $06: Parameter block length = $05
	DC.B	$08                               ; OSWORD $07: Parameter block length = $08
	DC.B	$0E                               ; OSWORD $08: Parameter block length = $0E
	DC.B	$04                               ; OSWORD $09: Parameter block length = $04
	DC.B	$01                               ; OSWORD $0A: Parameter block length = $01
	DC.B	$01                               ; OSWORD $0B: Parameter block length = $01
	DC.B	$05                               ; OSWORD $0C: Parameter block length = $05
	DC.B	$00                               ; OSWORD $0D: Parameter block length = $00
	DC.B	$01                               ; OSWORD $0E: Parameter block length = $01
	DC.B	$20                               ; OSWORD $0F: Parameter block length = $20
	DC.B	$10                               ; OSWORD &10: Parameter block length = &10
	DC.B	$0D                               ; OSWORD &11: Parameter block length = &0D
	DC.B	$00                               ; OSWORD &12: Parameter block length = &00
	DC.B	$04                               ; OSWORD &13: Parameter block length = &04
	DC.B	$80                               ; OSWORD &14: Parameter block length = &80

osword_recv_table
	                                          ; Length of parameterblock to be received from the host processor
	DC.B	$05                               ; OSWORD &01: Parameter block length = &05
	DC.B	$00                               ; OSWORD &02: Parameter block length = &00
	DC.B	$05                               ; OSWORD &03: Parameter block length = &05
	DC.B	$00                               ; OSWORD &04: Parameter block length = &00
	DC.B	$05                               ; OSWORD &05: Parameter block length = &05
	DC.B	$00                               ; OSWORD &06: Parameter block length = &00
	DC.B	$00                               ; OSWORD &07: Parameter block length = &00
	DC.B	$00                               ; OSWORD &08: Parameter block length = &00
	DC.B	$05                               ; OSWORD &09: Parameter block length = &05
	DC.B	$09                               ; OSWORD &0A: Parameter block length = &09
	DC.B	$05                               ; OSWORD &0B: Parameter block length = &05
	DC.B	$00                               ; OSWORD &0C: Parameter block length = &00
	DC.B	$08                               ; OSWORD &0D: Parameter block length = &08
	DC.B	$18                               ; OSWORD &0E: Parameter block length = &18
	DC.B	$00                               ; OSWORD &0F: Parameter block length = &00
	DC.B	$01                               ; OSWORD &10: Parameter block length = &01
	DC.B	$0D                               ; OSWORD &11: Parameter block length = &0D
	DC.B	$80                               ; OSWORD &12: Parameter block length = &80
	DC.B	$04                               ; OSWORD &13: Parameter block length = &04
	DC.B	$80                               ; OSWORD &14: Parameter block length = &80

; -----------------------------------------------------------------------------
; SWI jump and lookup table
; -----------------------------------------------------------------------------
; Align first entry to long word; SWI string is padded with spaces to align to long word
	ALIGN	4

SWITable
	DC.L	$00000000                         ; SWI number
	DC.L	SWI_OS_WriteC                     ; Pointer to handler
	DC.B	'OS_WriteC', $00, $00, $00        ; SWI name followed by terminator and alignment bytes

	DC.L	$00000001
	DC.L	SWI_OS_WriteS
	DC.B	'OS_WriteS', $00, $00, $00

	DC.L	$00000002
	DC.L	SWI_OS_Write0
	DC.B	'OS_Write0', $00, $00, $00

	DC.L	$00000003
	DC.L	SWI_OS_NewLine
	DC.B	'OS_NewLine', $00, $00

	DC.L	$00000004
	DC.L	readcv
	DC.B	'OS_ReadC', $00, $00, $00, $00

	DC.L	$00000005
	DC.L	cliv
	DC.B	'OS_CLI', $00, $00

	DC.L	$00000006
	DC.L	bytev
	DC.B	'OS_Byte', $00

	DC.L	$00000007
	DC.L	wordv
	DC.B	'OS_Word', $00

	DC.L	$00000008
	DC.L	filev
	DC.B	'OS_File', $00

	DC.L	$00000009
	DC.L	argsv
	DC.B	'OS_Args', $00

	DC.L	$0000000A
	DC.L	bgetv
	DC.B	'OS_BGet', $00

	DC.L	$0000000B
	DC.L	bputv
	DC.B	'OS_BPut', $00

	DC.L	$0000000C
	DC.L	gbpbv
	DC.B	'OS_GBPB', $00

	DC.L	$0000000D
	DC.L	findv
	DC.B	'OS_Find', $00

	DC.L	$0000000E
	DC.L	readlinev
	DC.B	'OS_ReadLine', $00

	DC.L	$0000000F
	DC.L	SWI_OS_Control
	DC.B	'OS_Control', $00, $00

	DC.L	$00000010
	DC.L	SWI_OS_GetEnv
	DC.B	'OS_GetEnv', $00, $00, $00

	DC.L	$00000011
	DC.L	SWI_OS_Exit
	DC.B	'OS_Exit', $00

	DC.L	$00000012
	DC.L	SWI_OS_SetEnv
	DC.B	'OS_SetEnv', $00, $00, $00

	DC.L	$00000013
	DC.L	SWI_OS_IntOn
	DC.B	'OS_IntOn', $00, $00, $00, $00

	DC.L	$00000014
	DC.L	SWI_OS_IntOff
	DC.B	'OS_IntOff', $00, $00, $00

	DC.L	$00000015
	DC.L	SWI_OS_CallBack
	DC.B	'OS_CallBack', $00

	DC.L	$00000016
	DC.L	SWI_OS_EnterOS
	DC.B	'OS_EnterOS', $00, $00

	DC.L	$00000018
	DC.L	SWI_OS_BreakCtrl
	DC.B	'OS_BreakCtrl', $00, $00, $00, $00

	DC.L	$00000019
	DC.L	SWI_OS_UnusedSWI
	DC.B	'OS_UnusedSWI', $00, $00, $00, $00

	DC.L	$0000001C
	DC.L	mousev
	DC.B	'OS_Mouse', $00, $00, $00, $00

	DC.L	$00000021
	DC.L	SWI_OS_ReadUnsigned
	DC.B	'OS_ReadUnsigned', $00

	DC.L	$00000028
	DC.L	SWI_OS_BinaryToDecimal
	DC.B	'OS_BinaryToDecimal', $00, $00

	DC.L	$00000029
	DC.L	fscontrolv
	DC.B	'OS_FSControl', $00, $00, $00, $00

	DC.L	$0000002B
	DC.L	SWI_OS_GenerateError
	DC.B	'OS_GenerateError', $00, $00, $00, $00

	DC.L	$0000002C
	DC.L	SWI_OS_ReadEscapeState
	DC.B	'OS_ReadEscapeState', $00, $00

	DC.L	$0000002F
	DC.L	SWI_OS_ReadPalette
	DC.B	'OS_ReadPalette', $00, $00

	DC.L	$00000032
	DC.L	SWI_OS_ReadPoint
	DC.B	'OS_ReadPoint', $00, $00, $00, $00

	DC.L	$00000034
	DC.L	SWI_OS_CallAVector
	DC.B	'OS_CallAVector', $00, $00

	DC.L	$00000036
	DC.L	SWI_OS_RemoveCursors
	DC.B	'OS_RemoveCursors', $00, $00, $00, $00

	DC.L	$00000037
	DC.L	SWI_OS_RestoreCursors
	DC.B	'OS_RestoreCursors', $00, $00, $00

	DC.L	$00000038
	DC.L	SWI_OS_SWINumberToString
	DC.B	'OS_SWINumberToString', $00, $00, $00, $00

	DC.L	$00000039
	DC.L	SWI_OS_SWINumberFromString
	DC.B	'OS_SWINumberFromString', $00, $00

	DC.L	$0000003A
	DC.L	SWI_OS_ValidateAddress
	DC.B	'OS_ValidateAddress', $00, $00

	DC.L	$0000003F
	DC.L	SWI_OS_CheckModeValid
	DC.B	'OS_CheckModeValid', $00, $00, $00

	DC.L	$00000040
	DC.L	SWI_OS_ChangeEnvironment
	DC.B	'OS_ChangeEnvironment', $00, $00, $00, $00

	DC.L	$00000042
	DC.L	SWI_OS_ReadMonotonicTime
	DC.B	'OS_ReadMonotonicTime', $00, $00, $00, $00

	DC.L	$00000045
	DC.L	SWI_OS_Plot
	DC.B	'OS_Plot', $00

	DC.L	$00000046
	DC.L	SWI_OS_WriteN
	DC.B	'OS_WriteN', $00, $00, $00

	DC.L	$00000048
	DC.L	SWI_OS_WriteEnv
	DC.B	'OS_WriteEnv', $00

	DC.L	$00000050
	DC.L	SWI_OS_ExitAndDie
	DC.B	'OS_ExitAndDie', $00, $00, $00

	DC.L	$00000055
	DC.L	SWI_OS_ReadDefaultHandler
	DC.B	'OS_ReadDefaultHandler', $00, $00, $00

	DC.L	$00000056
	DC.L	SWI_OS_SetECFOrigin
	DC.B	'OS_SetECFOrigin', $00

	DC.L	$0000005D
	DC.L	SWI_OS_PrintChar
	DC.B	'OS_PrintChar', $00, $00, $00, $00

	DC.L	$0000005B
	DC.L	SWI_OS_CRC
	DC.B	'OS_CRC', $00, $00

	DC.L	$00000059
	DC.L	SWI_OS_Confirm
	DC.B	'OS_Confirm', $00, $00

	DC.L	$0000007C
	DC.L	SWI_OS_LeaveOS
	DC.B	'OS_LeaveOS', $00, $00

	DC.L	$0000007D
	DC.L	SWI_OS_ReadLine32
	DC.B	'OS_ReadLine32', $00, $00, $00

	DC.L	$000000D0
	DC.L	SWI_OS_ConvertHex1
	DC.B	'OS_ConvertHex1', $00, $00

	DC.L	$000000D1
	DC.L	SWI_OS_ConvertHex2
	DC.B	'OS_ConvertHex2', $00, $00

	DC.L	$000000D2
	DC.L	SWI_OS_ConvertHex4
	DC.B	'OS_ConvertHex4', $00, $00

	DC.L	$000000D3
	DC.L	SWI_OS_ConvertHex6
	DC.B	'OS_ConvertHex6', $00, $00

	DC.L	$000000D4
	DC.L	SWI_OS_ConvertHex8
	DC.B	'OS_ConvertHex8', $00, $00

	DC.L	$000000D5
	DC.L	SWI_OS_ConvertCardinal1
	DC.B	'OS_ConvertCardinal1', $00

	DC.L	$000000D6
	DC.L	SWI_OS_ConvertCardinal2
	DC.B	'OS_ConvertCardinal2', $00

	DC.L	$000000D7
	DC.L	SWI_OS_ConvertCardinal3
	DC.B	'OS_ConvertCardinal3', $00

	DC.L	$000000D8
	DC.L	SWI_OS_ConvertCardinal4
	DC.B	'OS_ConvertCardinal4', $00

	DC.L	$000000D9
	DC.L	SWI_OS_ConvertInteger1
	DC.B	'OS_ConvertInteger1', $00, $00

	DC.L	$000000DA
	DC.L	SWI_OS_ConvertInteger2
	DC.B	'OS_ConvertInteger2', $00, $00

	DC.L	$000000DB
	DC.L	SWI_OS_ConvertInteger3
	DC.B	'OS_ConvertInteger3', $00, $00

	DC.L	$000000DC
	DC.L	SWI_OS_ConvertInteger4
	DC.B	'OS_ConvertInteger4', $00, $00

	DC.L	$000000DD
	DC.L	SWI_OS_ConvertBinary1
	DC.B	'OS_ConvertBinary1', $00, $00, $00

	DC.L	$000000DE
	DC.L	SWI_OS_ConvertBinary2
	DC.B	'OS_ConvertBinary2', $00, $00, $00

	DC.L	$000000DF
	DC.L	SWI_OS_ConvertBinary3
	DC.B	'OS_ConvertBinary3', $00, $00, $00

	DC.L	$000000E0
	DC.L	SWI_OS_ConvertBinary4
	DC.B	'OS_ConvertBinary4', $00, $00, $00

	DC.L	$000000EA
	DC.L	SWI_OS_ConvertNetStation
	DC.B	'OS_ConvertNetStation', $00, $00, $00, $FF  ; End of table marker


; -----------------------------------------------------------------------------
; Built-in application jump table
; -----------------------------------------------------------------------------

OS_CLI_command_table
	ALIGN	4
	DC.L	star_error
	DC.B	'ERROR  ', $00

	DC.L	flash
	DC.B	'FLASH  ', $00

	DC.L	go
	DC.B	'GO ', $00

	DC.L	help
	DC.B	'HELP   ', $00

	DC.L	mon
	DC.B	'MON', $00

	DC.L	quit
	DC.B	'QUIT   ', $00

	DC.L	tzap
	DC.B	'TZAP   ', $00

	DC.L	xfer
	DC.B	'XFER   ', $00

	DC.L	$FFFFFFFF                         ; End of table marker
	DC.B	$00

; -----------------------------------------------------------------------------
; ChangeEnvironment table
; -----------------------------------------------------------------------------
	ALIGN	4
_ChangeEnvironment_table
	DC.L	ramsize,          $00000000,            $00000000
	DC.L	$00000010,        $00000000,            $00000000
	DC.L	$00000000,        $00000000,            $00000000
	DC.L	$00000000,        $00000000,            $00000000
	DC.L	$0000000C,        $00000000,            $00000000
	DC.L	otherexceptionsv, $00000000,            $00000000
	DC.L	errorv,           error_wkspc_ptr,      error_buffer_ptr
	DC.L	callbackv,        callback_wkspc_ptr,   callback_buffer_ptr
	DC.L	breakpointv,      breakpoint_wkspc_ptr, breakpoint_buffer_ptr
	DC.L	escapev,          escape_wkspc_ptr,     $00000000
	DC.L	eventv,           event_wkspc_ptr,      $00000000
	DC.L	exitv,            exit_wkspc_ptr,       $00000000
	DC.L	ukswiv,           unusedswi_wkspc_ptr,  $00000000
	DC.L	exceptionregs,    $00000000,            $00000000
	DC.L	applicationspace, $00000000,            $00000000
	DC.L	$00000000,        $00000000,            $00000000
	DC.L	upcallv,          upcall_wkspc_ptr,     $00000000


; -----------------------------------------------------------------------------
; OS_FSControl_jumptable
; -----------------------------------------------------------------------------
	ALIGN	4

OS_FSControl_jumptable
	DC.L	not_supported                     ; &00: Set current directory
	DC.L	not_supported                     ; &01: Set library directory
	DC.L	not_supported                     ; &02: Inform of start of new app
	DC.L	not_supported                     ; &03: Run type (internal use only)
	DC.L	not_supported                     ; &04: Run a file
	DC.L	not_supported                     ; &05: Catalogue a directory
	DC.L	not_supported                     ; &06: Examine current directory
	DC.L	not_supported                     ; &07: Catalogue library
	DC.L	not_supported                     ; &08: Examine library
	DC.L	not_supported                     ; &09: Examine objects
	DC.L	SWI_OS_FSControl0A                ; &0A: Set file system options
	DC.L	not_supported                     ; &0B: Set temporary filing system
	DC.L	not_supported                     ; &0C: Add a filing system
	DC.L	not_supported                     ; &0D: Check for filing system
	DC.L	not_supported                     ; &0E: Select filing system
	DC.L	not_supported                     ; &0F: Boot from filing system
	DC.L	not_supported                     ; &10: Remove filing system
	DC.L	not_supported                     ; &11: Add secondary module
	DC.L	not_supported                     ; &12: Convert filetype number to name
	DC.L	not_supported                     ; &13: Restore current filing system
	DC.L	not_supported                     ; &14: Read location of temporary filing system
	DC.L	not_supported                     ; &15: Return a file handle
	DC.L	SWI_OS_FSControl16                ; &16: Close all open files
	DC.L	not_supported                     ; &17: Shutdown filing system
	DC.L	not_supported                     ; &18: Set attributes of objects
	DC.L	not_supported                     ; &19: Rename object
	DC.L	not_supported                     ; &1A: Copy objects
	DC.L	not_supported                     ; &1B: Wipe objects
	DC.L	not_supported                     ; &1C: Count objects
	DC.L	not_supported                     ; &1D: Create handle (internal use only)
	DC.L	not_supported                     ; &1E: Read location of temporary filing system secondary module
	DC.L	not_supported                     ; &1F: Convert filetype name to number
	DC.L	not_supported                     ; &20: Output list of object names & info
	DC.L	not_supported                     ; &21: Convert a filing system number to a name
	DC.L	not_supported                     ; &22: Set contexts (reserved)
	DC.L	not_supported                     ; &23: Add an image filing system
	DC.L	not_supported                     ; &24: Remove an image filing system
	DC.L	not_supported                     ; &25: Canonicalise path
	DC.L	not_supported                     ; &26: Extract filetype from file information
	DC.L	not_supported                     ; &27: Set user root directory
	DC.L	not_supported                     ; &28: Swap current and previous directories
	DC.L	not_supported                     ; &29: Return defect list for an image file
	DC.L	not_supported                     ; &2A: Map out defect from an image file
	DC.L	not_supported                     ; &2B: Unset the current directory
	DC.L	not_supported                     ; &2C: Unset the user root directory
	DC.L	not_supported                     ; &2D: Unset the library directory
	DC.L	not_supported                     ; &2E: Return used space map of image file
	DC.L	not_supported                     ; &2F: Read boot option for disc or image file
	DC.L	not_supported                     ; &30: Write boot option for disc or image file
	DC.L	not_supported                     ; &31: Read free space for disc or image file
	DC.L	not_supported                     ; &32: Rename disc or image file
	DC.L	not_supported                     ; &33: Request update of image stamp
	DC.L	not_supported                     ; &34: Find object at offset within image file
	DC.L	not_supported                     ; &35: Set given directory to path unchecked
	DC.L	not_supported                     ; &36: Read path of given directory
	DC.L	not_supported                     ; &37: Read free space for a large disc or image file
	DC.L	not_supported                     ; &38: Read defect list for a large disc or image file
	DC.L	not_supported                     ; &39: Map out defect from a large disc or image file
	DC.L	not_supported                     ; &3A: Enumerate file handles


; -----------------------------------------------------------------------------
; OSWORD &FA/*XFER handler for the host
; -----------------------------------------------------------------------------
osword_fa_hostcode
	                                          ; tubecontrol        = &0406                                            ; TUBE control (claim/data transfer/release)
	                                          ; osbyte             = &FFF4                                            ; OSBYTE Various OS routines
	                                          ; romsel             = &FE30                                            ; Paged ROM and RAM hardware control
	                                          ; acccon             = &FE34                                            ; RAM access control register
	                                          ; tubedat            = &FEE5                                            ; TUBE ULA data register 3
	                                          ; tubeid             = &F                                               ; When claiming the TUBE, we'll use ID &F

	                                          ; .
	DC.B	$18                               ; 2500  18                 .       CLC
	DC.B	$90, $02                          ; 2501  90 02              ..      BCC &2505
	                                          ; .
	DC.B	$10, $E3                          ; 2503  10 E3              ..      EQUW &E310                 ; 
	                                          ; .
	DC.B	$C9, $FA                          ; 2505  C9 FA              ..      CMP #&FA
	DC.B	$F0, $03                          ; 2507  F0 03              ..      BEQ &250C
	DC.B	$6C, $03, $25                     ; 2509  6C 03 25           l.%     JMP (&2503)
	                                          ; .
	DC.B	$86, $70                          ; 250C  86 70              .p      STX &70
	DC.B	$84, $71                          ; 250E  84 71              .q      STY &71
	DC.B	$48                               ; 2510  48                 H       PHA
	DC.B	$A9, $FB                          ; 2511  A9 FB              ..      LDA #&FB
	DC.B	$A2, $00                          ; 2513  A2 00              ..      LDX #&00
	DC.B	$A0, $FF                          ; 2515  A0 FF              ..      LDY #&FF
	DC.B	$20, $F4, $FF                     ; 2517  20 F4 FF            ..     JSR osbyte
	DC.B	$86, $73                          ; 251A  86 73              .s      STX &73
	DC.B	$AD, $34, $FE                     ; 251C  AD 34 FE           .4.     LDA acccon
	DC.B	$48                               ; 251F  48                 H       PHA
	                                          ; .
	DC.B	$A9, $C7                          ; 2520  A9 C7              ..      LDA #&C0+tubeid                      ; Claim the tube using ID 7
	DC.B	$20, $06, $04                     ; 2522  20 06 04            ..     JSR tubecontrol
	DC.B	$90, $F9                          ; 2525  90 F9              ..      BCC &2520                            ; Repeat if TUBE not successfully claimed
	DC.B	$A0, $00                          ; 2527  A0 00              ..      LDY #&00
	DC.B	$B1, $70                          ; 2529  B1 70              .p      LDA (&70),Y
	DC.B	$C9, $0D                          ; 252B  C9 0D              ..      CMP #&0D
	DC.B	$08                               ; 252D  08                 .       PHP
	DC.B	$A5, $F4                          ; 252E  A5 F4              ..      LDA &F4
	DC.B	$85, $72                          ; 2530  85 72              .r      STA &72
	DC.B	$A0, $0D                          ; 2532  A0 0D              ..      LDY #&0D
	DC.B	$B1, $70                          ; 2534  B1 70              .p      LDA (&70),Y
	DC.B	$AA                               ; 2536  AA                 .       TAX
	DC.B	$A0, $02                          ; 2537  A0 02              ..      LDY #&02
	DC.B	$B1, $70                          ; 2539  B1 70              .p      LDA (&70),Y
	DC.B	$85, $74                          ; 253B  85 74              .t      STA &74
	DC.B	$C8                               ; 253D  C8                 .       INY
	DC.B	$B1, $70                          ; 253E  B1 70              .p      LDA (&70),Y
	DC.B	$85, $75                          ; 2540  85 75              .u      STA &75
	DC.B	$28                               ; 2542  28                 (       PLP
	DC.B	$F0, $40                          ; 2543  F0 40              .@      BEQ &2585
	DC.B	$8A                               ; 2545  8A                 .       TXA
	DC.B	$48                               ; 2546  48                 H       PHA
	DC.B	$29, $40                          ; 2547  29 40              )@      AND #&40
	DC.B	$D0, $13                          ; 2549  D0 13              ..      BNE &255E
	DC.B	$8A                               ; 254B  8A                 .       TXA
	DC.B	$29, $20                          ; 254C  29 20              )       AND #&20
	DC.B	$D0, $04                          ; 254E  D0 04              ..      BNE &2554
		                                  ; .
	DC.B	$A2, $00                          ; 2550  A2 00              ..      LDX #&00
	DC.B	$F0, $02                          ; 2552  F0 02              ..      BEQ &2556
		                                  ; .
	DC.B	$A2, $01                          ; 2554  A2 01              ..      LDX #&01
		                                  ; .
	DC.B	$A9, $6C                          ; 2556  A9 6C              .l      LDA #&6C
	DC.B	$20, $F4, $FF                     ; 2558  20 F4 FF            ..     JSR osbyte
	DC.B	$4C, $77, $25                     ; 255B  4C 77 25           Lw%     JMP &2577
		                                  ; .
	DC.B	$A9, $84                          ; 255E  A9 84              ..      LDA #&84
	DC.B	$20, $F4, $FF                     ; 2560  20 F4 FF            ..     JSR osbyte
	DC.B	$C0, $80                          ; 2563  C0 80              ..      CPY #&80
	DC.B	$D0, $08                          ; 2565  D0 08              ..      BNE &256F
	DC.B	$A9, $01                          ; 2567  A9 01              ..      LDA #&01
	DC.B	$C5, $73                          ; 2569  C5 73              .s      CMP &73
	DC.B	$D0, $E7                          ; 256B  D0 E7              ..      BNE &2554
	DC.B	$F0, $E1                          ; 256D  F0 E1              ..      BEQ &2550
		                                  ; .
	DC.B	$A9, $02                          ; 256F  A9 02              ..      LDA #&02
	DC.B	$C5, $73                          ; 2571  C5 73              .s      CMP &73
	DC.B	$D0, $DB                          ; 2573  D0 DB              ..      BNE &2550
	DC.B	$F0, $DD                          ; 2575  F0 DD              ..      BEQ &2554
		                                  ; .
	DC.B	$68                               ; 2577  68                 h       PLA
	DC.B	$AA                               ; 2578  AA                 .       TAX
	DC.B	$29, $10                          ; 2579  29 10              ).      AND #&10
	DC.B	$D0, $08                          ; 257B  D0 08              ..      BNE &2585
	DC.B	$8A                               ; 257D  8A                 .       TXA
	DC.B	$29, $0F                          ; 257E  29 0F              ).      AND #&0F
	DC.B	$85, $F4                          ; 2580  85 F4              ..      STA &F4
	DC.B	$8D, $30, $FE                     ; 2582  8D 30 FE           .0.     STA romsel
		                                  ; .
	DC.B	$A0, $0A                          ; 2585  A0 0A              ..      LDY #&0A
	DC.B	$B1, $70                          ; 2587  B1 70              .p      LDA (&70),Y
	DC.B	$85, $77                          ; 2589  85 77              .w      STA &77
	DC.B	$C8                               ; 258B  C8                 .       INY
	DC.B	$B1, $70                          ; 258C  B1 70              .p      LDA (&70),Y
	DC.B	$85, $76                          ; 258E  85 76              .v      STA &76
	DC.B	$05, $77                          ; 2590  05 77              .w      ORA &77
	DC.B	$D0, $02                          ; 2592  D0 02              ..      BNE &2596
	DC.B	$F0, $6E                          ; 2594  F0 6E              .n      BEQ &2604
		                                  ; .
	DC.B	$A5, $77                          ; 2596  A5 77              .w      LDA &77
	DC.B	$F0, $02                          ; 2598  F0 02              ..      BEQ &259C
	DC.B	$E6, $76                          ; 259A  E6 76              .v      INC &76
		                                  ; .
	DC.B	$C8                               ; 259C  C8                 .       INY
	DC.B	$B1, $70                          ; 259D  B1 70              .p      LDA (&70),Y
	                                          ; .
	DC.B	$48                               ; 259F  48                 H       PHA
	DC.B	$A5, $77                          ; 25A0  A5 77              .w      LDA &77
	DC.B	$F0, $11                          ; 25A2  F0 11              ..      BEQ &25B5
	DC.B	$A5, $76                          ; 25A4  A5 76              .v      LDA &76
	DC.B	$C9, $01                          ; 25A6  C9 01              ..      CMP #&01
	DC.B	$D0, $0B                          ; 25A8  D0 0B              ..      BNE &25B5
	DC.B	$68                               ; 25AA  68                 h       PLA
	DC.B	$48                               ; 25AB  48                 H       PHA
	DC.B	$C9, $06                          ; 25AC  C9 06              ..      CMP #&06
	DC.B	$90, $05                          ; 25AE  90 05              ..      BCC &25B5
	DC.B	$68                               ; 25B0  68                 h       PLA
	DC.B	$38                               ; 25B1  38                 8       SEC
	DC.B	$E9, $06                          ; 25B2  E9 06              ..      SBC #&06
	DC.B	$48                               ; 25B4  48                 H       PHA
	                                          ; .
	DC.B	$A5, $70                          ; 25B5  A5 70              .p      LDA &70
	DC.B	$18                               ; 25B7  18                 .       CLC
	DC.B	$69, $06                          ; 25B8  69 06              i.      ADC #&06
	DC.B	$AA                               ; 25BA  AA                 .       TAX
	DC.B	$A9, $00                          ; 25BB  A9 00              ..      LDA #&00
	DC.B	$65, $71                          ; 25BD  65 71              eq      ADC &71
	DC.B	$A8                               ; 25BF  A8                 .       TAY
	DC.B	$68                               ; 25C0  68                 h       PLA
	DC.B	$48                               ; 25C1  48                 H       PHA
	DC.B	$20, $06, $04                     ; 25C2  20 06 04            ..     JSR tubecontrol
	DC.B	$A6, $77                          ; 25C5  A6 77              .w      LDX &77
	DC.B	$68                               ; 25C7  68                 h       PLA
	DC.B	$A0, $00                          ; 25C8  A0 00              ..      LDY #&00
	DC.B	$C9, $00                          ; 25CA  C9 00              ..      CMP #&00
	DC.B	$F0, $1E                          ; 25CC  F0 1E              ..      BEQ &25EC
	DC.B	$C9, $01                          ; 25CE  C9 01              ..      CMP #&01
	DC.B	$F0, $35                          ; 25D0  F0 35              .5      BEQ &2607
	DC.B	$C9, $02                          ; 25D2  C9 02              ..      CMP #&02
	DC.B	$F0, $49                          ; 25D4  F0 49              .I      BEQ &261F
	DC.B	$C9, $03                          ; 25D6  C9 03              ..      CMP #&03
	DC.B	$F0, $70                          ; 25D8  F0 70              .p      BEQ &264A
	DC.B	$C9, $06                          ; 25DA  C9 06              ..      CMP #&06
	DC.B	$F0, $08                          ; 25DC  F0 08              ..      BEQ &25E6
	DC.B	$C9, $07                          ; 25DE  C9 07              ..      CMP #&07
	DC.B	$F0, $07                          ; 25E0  F0 07              ..      BEQ &25E9
	DC.B	$A9, $00                          ; 25E2  A9 00              ..      LDA #&00
	DC.B	$F0, $1E                          ; 25E4  F0 1E              ..      BEQ &2604
		                                  ; .
	DC.B	$4C, $75, $26                     ; 25E6  4C 75 26           Lu&     JMP &2675
		                                  ; .
	DC.B	$4C, $A3, $26                     ; 25E9  4C A3 26           L.&     JMP &26A3
		                                  ; .
	DC.B	$20, $F4, $26                     ; 25EC  20 F4 26            .&     JSR &26F4
		                                  ; .
	DC.B	$AD, $E5, $FE                     ; 25EF  AD E5 FE           ...     LDA tubedat
	DC.B	$91, $74                          ; 25F2  91 74              .t      STA (&74),Y
	DC.B	$20, $F4, $26                     ; 25F4  20 F4 26            .&     JSR &26F4
	DC.B	$E6, $74                          ; 25F7  E6 74              .t      INC &74
	DC.B	$D0, $02                          ; 25F9  D0 02              ..      BNE &25FD
	DC.B	$E6, $75                          ; 25FB  E6 75              .u      INC &75
		                                  ; .
	DC.B	$CA                               ; 25FD  CA                 .       DEX
	DC.B	$D0, $EF                          ; 25FE  D0 EF              ..      BNE &25EF
	DC.B	$C6, $76                          ; 2600  C6 76              .v      DEC &76
	DC.B	$D0, $EB                          ; 2602  D0 EB              ..      BNE &25EF
	                                          ; .
	DC.B	$4C, $DA, $26                     ; 2604  4C DA 26           L.&     JMP &26DA
		                                  ; .
	DC.B	$B1, $74                          ; 2607  B1 74              .t      LDA (&74),Y
	DC.B	$8D, $E5, $FE                     ; 2609  8D E5 FE           ...     STA tubedat
	DC.B	$20, $F4, $26                     ; 260C  20 F4 26            .&     JSR &26F4
	DC.B	$E6, $74                          ; 260F  E6 74              .t      INC &74
	DC.B	$D0, $02                          ; 2611  D0 02              ..      BNE &2615
	DC.B	$E6, $75                          ; 2613  E6 75              .u      INC &75
		                                  ; .
	DC.B	$CA                               ; 2615  CA                 .       DEX
	DC.B	$D0, $EF                          ; 2616  D0 EF              ..      BNE &2607
	DC.B	$C6, $76                          ; 2618  C6 76              .v      DEC &76
	DC.B	$D0, $EB                          ; 261A  D0 EB              ..      BNE &2607
	DC.B	$4C, $DA, $26                     ; 261C  4C DA 26           L.&     JMP &26DA
		                                  ; .
	DC.B	$20, $F4, $26                     ; 261F  20 F4 26            .&     JSR &26F4
		                                  ; .
	DC.B	$AD, $E5, $FE                     ; 2622  AD E5 FE           ...     LDA tubedat
	DC.B	$91, $74                          ; 2625  91 74              .t      STA (&74),Y
	DC.B	$E6, $74                          ; 2627  E6 74              .t      INC &74
	DC.B	$D0, $02                          ; 2629  D0 02              ..      BNE &262D
	DC.B	$E6, $75                          ; 262B  E6 75              .u      INC &75
		                                  ; .
	DC.B	$EA                               ; 262D  EA                 .       NOP
	DC.B	$EA                               ; 262E  EA                 .       NOP
	DC.B	$AD, $E5, $FE                     ; 262F  AD E5 FE           ...     LDA tubedat
	DC.B	$91, $74                          ; 2632  91 74              .t      STA (&74),Y
	DC.B	$E6, $74                          ; 2634  E6 74              .t      INC &74
	DC.B	$D0, $02                          ; 2636  D0 02              ..      BNE &263A
	DC.B	$E6, $75                          ; 2638  E6 75              .u      INC &75
		                                  ; .
	DC.B	$20, $F3, $26                     ; 263A  20 F3 26            .&     JSR &26F3
	DC.B	$EA                               ; 263D  EA                 .       NOP
	DC.B	$EA                               ; 263E  EA                 .       NOP
	DC.B	$CA                               ; 263F  CA                 .       DEX
	DC.B	$CA                               ; 2640  CA                 .       DEX
	DC.B	$D0, $DF                          ; 2641  D0 DF              ..      BNE &2622
	DC.B	$C6, $76                          ; 2643  C6 76              .v      DEC &76
	DC.B	$D0, $DB                          ; 2645  D0 DB              ..      BNE &2622
	DC.B	$4C, $DA, $26                     ; 2647  4C DA 26           L.&     JMP &26DA
		                                  ; .
	DC.B	$B1, $74                          ; 264A  B1 74              .t      LDA (&74),Y
	DC.B	$8D, $E5, $FE                     ; 264C  8D E5 FE           ...     STA tubedat
	DC.B	$E6, $74                          ; 264F  E6 74              .t      INC &74
	DC.B	$F0, $03                          ; 2651  F0 03              ..      BEQ &2656
	DC.B	$EA                               ; 2653  EA                 .       NOP
	DC.B	$D0, $02                          ; 2654  D0 02              ..      BNE &2658
		                                  ; .
	DC.B	$E6, $75                          ; 2656  E6 75              .u      INC &75
		                                  ; .
	DC.B	$A5, $73                          ; 2658  A5 73              .s      LDA &73
	DC.B	$B1, $74                          ; 265A  B1 74              .t      LDA (&74),Y
	DC.B	$8D, $E5, $FE                     ; 265C  8D E5 FE           ...     STA tubedat
	DC.B	$E6, $74                          ; 265F  E6 74              .t      INC &74
	DC.B	$F0, $03                          ; 2661  F0 03              ..      BEQ &2666
	DC.B	$EA                               ; 2663  EA                 .       NOP
	DC.B	$D0, $02                          ; 2664  D0 02              ..      BNE &2668
		                                  ; .
	DC.B	$E6, $75                          ; 2666  E6 75              .u      INC &75
		                                  ; .
	DC.B	$20, $F3, $26                     ; 2668  20 F3 26            .&     JSR &26F3
	DC.B	$CA                               ; 266B  CA                 .       DEX
	DC.B	$CA                               ; 266C  CA                 .       DEX
	DC.B	$D0, $DB                          ; 266D  D0 DB              ..      BNE &264A
	DC.B	$C6, $76                          ; 266F  C6 76              .v      DEC &76
	DC.B	$D0, $D7                          ; 2671  D0 D7              ..      BNE &264A
	DC.B	$F0, $65                          ; 2673  F0 65              .e      BEQ &26DA
		                                  ; .
	DC.B	$20, $F4, $26                     ; 2675  20 F4 26            .&     JSR &26F4
		                                  ; .
	DC.B	$AD, $E5, $FE                     ; 2678  AD E5 FE           ...     LDA tubedat
	DC.B	$91, $74                          ; 267B  91 74              .t      STA (&74),Y
	DC.B	$EA                               ; 267D  EA                 .       NOP
	DC.B	$EA                               ; 267E  EA                 .       NOP
	DC.B	$EA                               ; 267F  EA                 .       NOP
	DC.B	$C8                               ; 2680  C8                 .       INY
	DC.B	$D0, $F5                          ; 2681  D0 F5              ..      BNE &2678
	DC.B	$E0, $00                          ; 2683  E0 00              ..      CPX #&00
	DC.B	$D0, $0C                          ; 2685  D0 0C              ..      BNE &2693
	DC.B	$C6, $76                          ; 2687  C6 76              .v      DEC &76
	DC.B	$F0, $4F                          ; 2689  F0 4F              .O      BEQ &26DA
		                                  ; .
	DC.B	$20, $CE, $26                     ; 268B  20 CE 26            .&     JSR &26CE
	DC.B	$A9, $06                          ; 268E  A9 06              ..      LDA #&06
	DC.B	$4C, $9F, $25                     ; 2690  4C 9F 25           L.%     JMP &259F
		                                  ; .
	DC.B	$C6, $76                          ; 2693  C6 76              .v      DEC &76
	DC.B	$A5, $76                          ; 2695  A5 76              .v      LDA &76
	DC.B	$C9, $01                          ; 2697  C9 01              ..      CMP #&01
	DC.B	$D0, $F0                          ; 2699  D0 F0              ..      BNE &268B
	DC.B	$20, $CE, $26                     ; 269B  20 CE 26            .&     JSR &26CE
	DC.B	$A9, $00                          ; 269E  A9 00              ..      LDA #&00
	DC.B	$4C, $9F, $25                     ; 26A0  4C 9F 25           L.%     JMP &259F
		                                  ; .
	DC.B	$B1, $74                          ; 26A3  B1 74              .t      LDA (&74),Y
	DC.B	$8D, $E5, $FE                     ; 26A5  8D E5 FE           ...     STA tubedat
	DC.B	$EA                               ; 26A8  EA                 .       NOP
	DC.B	$EA                               ; 26A9  EA                 .       NOP
	DC.B	$EA                               ; 26AA  EA                 .       NOP
	DC.B	$C8                               ; 26AB  C8                 .       INY
	DC.B	$D0, $F5                          ; 26AC  D0 F5              ..      BNE &26A3
	DC.B	$E0, $00                          ; 26AE  E0 00              ..      CPX #&00
	DC.B	$D0, $0C                          ; 26B0  D0 0C              ..      BNE &26BE
	DC.B	$C6, $76                          ; 26B2  C6 76              .v      DEC &76
	DC.B	$F0, $24                          ; 26B4  F0 24              .$      BEQ &26DA
		                                  ; .
	DC.B	$20, $CE, $26                     ; 26B6  20 CE 26            .&     JSR &26CE
	DC.B	$A9, $07                          ; 26B9  A9 07              ..      LDA #&07
	DC.B	$4C, $9F, $25                     ; 26BB  4C 9F 25           L.%     JMP &259F
		                                  ; .
	DC.B	$C6, $76                          ; 26BE  C6 76              .v      DEC &76
	DC.B	$A5, $76                          ; 26C0  A5 76              .v      LDA &76
	DC.B	$C9, $01                          ; 26C2  C9 01              ..      CMP #&01
	DC.B	$D0, $F0                          ; 26C4  D0 F0              ..      BNE &26B6
	DC.B	$20, $CE, $26                     ; 26C6  20 CE 26            .&     JSR &26CE
	DC.B	$A9, $01                          ; 26C9  A9 01              ..      LDA #&01
	DC.B	$4C, $9F, $25                     ; 26CB  4C 9F 25           L.%     JMP &259F
		                                  ; .
	DC.B	$E6, $75                          ; 26CE  E6 75              .u      INC &75
	DC.B	$A0, $07                          ; 26D0  A0 07              ..      LDY #&07
	DC.B	$B1, $70                          ; 26D2  B1 70              .p      LDA (&70),Y
	DC.B	$18                               ; 26D4  18                 .       CLC
	DC.B	$69, $01                          ; 26D5  69 01              i.      ADC #&01
	DC.B	$91, $70                          ; 26D7  91 70              .p      STA (&70),Y
	DC.B	$60                               ; 26D9  60                 `       RTS
		                                  ; .
	DC.B	$A9, $87                          ; 26DA  A9 87              ..      LDA #&80+tubeid                      ; Release the TUBE using ID 7
	DC.B	$20, $06, $04                     ; 26DC  20 06 04            ..     JSR tubecontrol
	DC.B	$A5, $72                          ; 26DF  A5 72              .r      LDA &72
	DC.B	$C5, $F4                          ; 26E1  C5 F4              ..      CMP &F4
	DC.B	$F0, $05                          ; 26E3  F0 05              ..      BEQ &26EA
	DC.B	$85, $F4                          ; 26E5  85 F4              ..      STA &F4
	DC.B	$8D, $30, $FE                     ; 26E7  8D 30 FE           .0.     STA romsel
		                                  ; .
	DC.B	$68                               ; 26EA  68                 h       PLA
	DC.B	$8D, $34, $FE                     ; 26EB  8D 34 FE           .4.     STA acccon
	DC.B	$A6, $70                          ; 26EE  A6 70              .p      LDX &70
	DC.B	$A4, $71                          ; 26F0  A4 71              .q      LDY &71
	DC.B	$68                               ; 26F2  68                 h       PLA
		                                  ; .
	DC.B	$60                               ; 26F3  60                 `       RTS
		                                  ; .
	DC.B	$20, $F3, $26                     ; 26F4  20 F3 26            .&     JSR &26F3
	DC.B	$20, $F3, $26                     ; 26F7  20 F3 26            .&     JSR &26F3
	DC.B	$60                               ; 26FA  60                 `       RTS



; -----------------------------------------------------------------------------
; SWI_Debugger_Disasseble table
; -----------------------------------------------------------------------------
	ALIGN	4

SWI_Debugger_Disassemble_table
U00
U01
U02
U03
U04
U05
U06
U07
U08
U09
U10
U11
U12
U13
U14
U15
U16
U17
U18
U19
U20
U21
U22
U23
U24
U25
U26
U27
U28
U29AA
U29DA
U29DD
U30
U31
U32
U33
U34
U35
U36
U37
U38
U39
U40
U41
U42
; Instructions with 1st nibble = 0000.

	DC.W	$003C, $FFFF                      ; ORI to CCR. Number of bits in mask = (16)
	DC.B	'ORI  ',0
	DC.L    U09

	DC.W	$007C, $FFFF                      ; ORI to SR (16)
	DC.B	'ORI  ',0
	DC.L	U10

	DC.W	$023C, $FFFF                      ; ANDI to CCR (16)
	DC.B	'ANDI ',0
	DC.L	U09

	DC.W	$027C, $FFFF                      ; ANDI to SR (16)
	DC.B	'ANDI ',0
	DC.L	U10

	DC.W    $0A3C, $FFFF                      ; EORI to CCR (16)
	DC.B    'EORI ',0
	DC.L    U09

	DC.W    $0A7C, $FFFF                      ; EORI to SR (16)
	DC.B    'EORI ',0
	DC.L    U10

	DC.W    $0800, $FFC0                      ; BTST (10)
	DC.B    'BTST ',0
	DC.L    U14

	DC.W    $0840, $FFC0                      ; BCHG (10)
	DC.B    'BCHG ',0
	DC.L    U14

	DC.W    $0880, $FFC0                      ; BCLR (10)
	DC.B    'BCLR ',0
	DC.L    U14

	DC.W    $08C0, $FFC0                      ; BSET (10)
	DC.B    'BSET ',0
	DC.L    U14

	DC.W    $0000, $FF00                      ; Ordinary ORI (8)
	DC.B    'ORI  ',0
	DC.L    U11

	DC.W    $0200, $FF00                      ; Ordinary ANDI (8)
	DC.B    'ANDI ',0
	DC.L    U11

	DC.W    $0400, $FF00                      ; SUBI (8)
	DC.B    'SUBI ',0
	DC.L    U11

	DC.W    $0600, $FF00                      ; ADDI (8)
	DC.B    'ADDI ',0
	DC.L    U11

	DC.W    $0A00, $FF00                      ; Ordinary EORI (8)
	DC.B    'EORI ',0
	DC.L    U11

	DC.W    $0C00, $FF00                      ; CMPI (8)
	DC.B    'CMPI ',0
	DC.L    U11

	DC.W    $0108, $F138                      ; MOVEP (8)
	DC.B    'MOVEP',0
	DC.L    U41

	DC.W    $0100, $F1C0                      ; BTST (7)
	DC.B    'BTST ',0
	DC.L    U15

	DC.W    $0140, $F1C0                      ; BCHG (7)
	DC.B    'BCHG ',0
	DC.L    U15

	DC.W    $0180, $F1C0                      ; BCLR (7)
	DC.B    'BCLR ',0
	DC.L    U15

	DC.W    $01C0, $F1C0                      ; BSET (7)
	DC.B    'BSET ',0
	DC.L    U15

	DC.W    $0040, $C1C0                      ; MOVEA (5)
	DC.B    'MOVEA',0
	DC.L    U17

	DC.W    $000,$C000                        ; MOVE (2)
	DC.B    'MOVE ',0
	DC.L    U16

; Instructions with 1st nibble = 0100
	DC.W    $4AFC, $FFFF                      ; ILLEGAL (16)
	DC.B    'ILLEG',0
	DC.L    U01

	DC.W    $4E70, $FFFF                      ; RESET (16)
	DC.B    'RESET',0
	DC.L    U00

	DC.W    $4E71, $FFFF                      ; NOP (16)
	DC.B    'NOP  ',0
	DC.L    U00

	DC.W    $4E72, $FFFF                      ; STOP (16)
	DC.B    'STOP ',0
	DC.L    U34

	DC.W    $4E73, $FFFF                      ; RTE (16)
	DC.B    'RTE  ',0
	DC.L    U00

	DC.W    $4E75, $FFFF                      ; RTS (16)
	DC.B    'RTS  ',0
	DC.L    U00

	DC.W    $4E76, $FFFF                      ; TRAPV (16)
	DC.B    'TRAPV',0
	DC.L    U00

	DC.W    $4E77, $FFFF                      ; RTR (16)
	DC.B    'RTR  ',0
	DC.L    U00

	DC.W    $4840, $FFF8                      ; SWAP (13)
	DC.B    'SWAP ',0
	DC.L    U23

	DC.W    $4E50, $FFF8                      ; LINK (13)
	DC.B    'LINK ',0
	DC.L    U25

	DC.W    $4E58, $FFF8                      ; UNLK (13)
	DC.B    'UNLK ',0
	DC.L    U24

	DC.W    $4E60, $FFF0                      ; MOVE An <-> USP (12)
	DC.B    'MOVE ',0
	DC.L    U39

	DC.W    $4E40, $FFF0                      ; TRAP (12)
	DC.B    'TRAP ',0
	DC.L    U35

	DC.W    $4E80, $FFC0                      ; JSR (12)
	DC.B    'JSR  ',0
	DC.L    U13

	DC.W    $4EC0, $FFC0                      ; JMP (12)
	DC.B    'JMP  ',0
	DC.L    U13

	DC.W    $4880, $FEB8                      ; EXT (11)
	DC.B    'EXT  ',0
	DC.L    U30

	DC.W    $40C0, $FFC0                      ; MOVE from SR (10)
	DC.B    'MOVE ',0
	DC.L    U37

	DC.W    $44C0, $FFC0                      ; MOVE to CCR (10)
	DC.B    'MOVE ',0
	DC.L    U36

	DC.W    $46C0, $FFC0                      ; MOVE to SR (10)
	DC.B    'MOVE ',0
	DC.L    U38

	DC.W    $4800, $FFC0                      ; NBCD (10)
	DC.B    'NBCD ',0
	DC.L    U32

	DC.W    $4840, $FFC0                      ; PEA (10)
	DC.B    'PEA  ',0
	DC.L    U33

	DC.W    $4AC0, $FFC0                      ; TAS (10)
	DC.B    'TAS  ',0
	DC.L    U22

	DC.W    $4000, $FF00                      ; NEGX (8)
	DC.B    'NEGX ',0
	DC.L    U21

	DC.W    $4200, $FF00                      ; CLR (8)
	DC.B    'CLR  ',0
	DC.L    U21

	DC.W    $4400, $FF00                      ; NEG (8)
	DC.B    'NEG  ',0
	DC.L    U21

	DC.W    $4600, $FF00                      ; NOT (8)
	DC.B    'NOT  ',0
	DC.L    U21

	DC.W    $4A00, $FF00                      ; TST (8)
	DC.B    'TST  ',0
	DC.L    U21

	DC.W    $4880, $FB80                      ; MOVEM (8)
	DC.B    'MOVEM',0
	DC.L    U42

	DC.W    $41C0, $F1C0                      ; LEA (7)
	DC.B    'LEA  ',0
	DC.L    U31

	DC.W    $4000, $F040                      ; CHK (5)
	DC.B    'CHK  ',0
	DC.L    U28

; Instructions with 1st nibble = 0101
	DC.W    $50C8, $F0F8                      ; DBcc (9)
	DC.B    'DB   ',0
	DC.L    U19

	DC.W    $50C0, $F0C0                      ; Scc (6)
	DC.B    'S    ',0
	DC.L    U20

	DC.W    $5000, $F100                      ; ADDQ (5)
	DC.B    'ADDQ ',0
	DC.L    U27

	DC.W    $5100, $F100                      ; SUBQ (5)
	DC.B    'SUBQ ',0
	DC.L    U27

; Instructions with 1st nibble = 0110
	DC.W    $6000, $FF00                      ; BRA (8)
	DC.B    'BRA  ',0
	DC.L    U12

	DC.W    $6100, $FF00                      ; BSR (8)
	DC.B    'BSR  ',0
	DC.L    U12

	DC.W    $6000, $F000                      ; Bcc (4)
	DC.B    'B',0,0,0,0,0
	DC.L    U18

; Instructions with 1st nibble = 0111
	DC.W    $7000, $F100                      ; MOVEQ (5)
	DC.B    'MOVEQ',0
	DC.L    U40

; Instructions with 1st nibble = 1000
	DC.W    $8100, $F1F0                      ; SBCD (9)
	DC.B    'SBCD ',0
	DC.L    U26

	DC.W    $80C0, $F1C0                      ; DIVU (7)
	DC.B    'DIVU ',0
	DC.L    U06

	DC.W    $81C0, $F1C0                      ; DIVS (7)
	DC.B    'DIVS ',0
	DC.L    U06

	DC.W    $8000, $F000                      ; OR (4)
	DC.B    'OR   ',0
	DC.L    U02

; Instructions with 1st nibble = 1001
	DC.W    $9100, $F130                      ; SUBX (7)
	DC.B    'SUBX ',0
	DC.L    U04

	DC.W    $90C0, $F0C0                      ; SUBA (6)
	DC.B    'SUBA ',0
	DC.L    U03

	DC.W    $9000, $F000                      ; SUB (4)
	DC.B    'SUB  ',0
	DC.L    U02

; Instructions with 1st nibble = 1011
	DC.W    $B108, $F138                      ; CMPM (8)
	DC.B    'CMPM ',0
	DC.L    U05

	DC.W    $B0C0, $F0C0                      ; CMPA (6)
	DC.B    'CMPA ',0
	DC.L    U03

	DC.W    $B100, $F100                      ; EOR (5)
	DC.B    'EOR  ',0
	DC.L    U02

	DC.W    $B000, $F000                      ; CMP (4)
	DC.B    'CMP  ',0
	DC.L    U02

; Instructions with 1st nibble = 1100
	DC.W    $C140, $F1F8                      ; EXG  Dn,Dm. (10)
	DC.B    'EXG  ',0
	DC.L    U29DD

	DC.W    $C148, $F1F8                      ; EXG  An,Am. (10)
	DC.B    'EXG  ',0
	DC.L    U29AA

	DC.W    $C188, $F1F8                      ; EXG  Dn,An. (10)
	DC.B    'EXG  ',0
	DC.L    U29DA

	DC.W    $C100, $F1F0                      ; ABCD (9)
	DC.B    'ABCD ',0
	DC.L    U26

	DC.W    $C1C0, $F1C0                      ; MULS (7)
	DC.B    'MULS ',0
	DC.L    U06

	DC.W    $C0C0, $F1C0                      ; MULU (7)
	DC.B    'MULU ',0
	DC.L    U06

	DC.W    $C000, $F000                      ; AND (4)
	DC.B    'AND  ',0
	DC.L    U02

; Instructions with 1st nibble = 1101
	DC.W    $D100, $F130                      ; ADDX (7)
	DC.B    'ADDX ',0
	DC.L    U04

	DC.W    $D0C0, $F0C0                      ; ADDA (6)
	DC.B    'ADDA ',0
	DC.L    U03

	DC.W    $D000, $F000                      ; ADD (4)
	DC.B    'ADD  ',0
	DC.L    U02

; Instructions with 1st nibble = 1110
	DC.W    $E0C0, $FEC0                      ; ASL and ASR mem shifts (9)
	DC.B    'AS   ',0
	DC.L    U07

	DC.W    $E2C0, $FEC0                      ; LSL and LSR mem shifts (9)
	DC.B    'LS   ',0
	DC.L    U07

	DC.W    $E4C0, $FEC0                      ; ROXL and ROXR mem shifts (9)
	DC.B    'ROX  ',0
	DC.L    U07

	DC.W    $E6C0, $FEC0                      ; ROL and ROR mem shifts (9)
	DC.B    'RO   ',0 
	DC.L    U07

	DC.W    $E000, $F018                      ; ASL and ASR reg shifts (6)
	DC.B    'AS   ',0
	DC.L    U08

	DC.W    $E008, $F018                      ; LSL and LSR reg shifts (6)
	DC.B    'LS   ',0
	DC.L    U08

	DC.W    $E010, $F018                      ; ROXL and ROXR reg shifts (6)
	DC.B    'ROX  ',0
	DC.L    U08

	DC.W    $E018, $F018                      ; ROL and ROR reg shifts (6)
	DC.B    'RO   ',0
	DC.L    U08

	DC.W    $0000, $0000                      ; This is the 'I have no idea' entry.
	DC.B    '?????',0
	DC.L    U00


standarddatetimestring                  DC.B	'%24:%mi:%se %dy-%m3-%ce%yr', $00	; SYS$DateFormat https://www.riscosopen.org/viewer/view/castle/RiscOS/Sources/Kernel/s/Arthur2?annotate=4.6.2.10

;MOSdictionary
;                    30:    TokenString  1,"""Syntax: *"",TokenEscapeChar,Token0,0"
;                     31:    TokenString  2,""" the "",0"
;                     32:    TokenString  3,"""director"",0"
;                     33:    TokenString  4,"""filing system"",0"
;                     34:    TokenString  5,"""current"",0"
;                     35:    TokenString  6,""" to a variable. Other types of value can be assigned with *"",0"
;                     36:    TokenString  7,"""file"",0"
;                     37:    TokenString  8,"""default "",0"
;                     38:    TokenString  9,"""tion"",0"
;                     39:    TokenString  10,"""*Configure "",0"
;                     40:    TokenString  11,"""name"",0"
;                     41:    TokenString  12,""" server"",0"
;                     42:    TokenString  13,"""number"",0"
;                     43:    TokenString  14,"TokenEscapeChar,Token1,"" <"",0"
;                     44:    TokenString  15,""" one or more "",TokenEscapeChar,Token7,""s that match"",TokenEscapeChar,Token2,""given wildcard"",0"
;                     45:    TokenString  16,""" and "",0"
;                     46:    TokenString  17,"""relocatable module"",0"
;                     47:    TokenString  18,"13,""C(onfirm)"",9,""Prompt for confirma"",TokenEscapeChar,Token9,"" of each "",0"
;                     48:    TokenString  19,"""sets"",TokenEscapeChar,Token2,0"
;                     49:    TokenString  20,"TokenEscapeChar,Token1,"" [<disc spec.>]"",0"
;                     50:    TokenString  21,"""}"",13,""V(erbose)"",9,""Print informa"",TokenEscapeChar,Token9,"" on each "",TokenEscapeChar,Token7,"" "",0"
;                     51:    TokenString  22, 0
;                     52:    TokenString  23,"TokenEscapeChar,Token31,""Landscape [<XScale> [<YScale> [<Margin> [<Threshold>]]]]]"",0"
;                     53:    TokenString  24,"TokenEscapeChar,Token41,""used"",TokenEscapeChar,Token40,""print a hard copy of"",TokenEscapeChar,Token2,""screen on EPSON-"",0"
;                     54:    TokenString  25,"""."",13,""Op"",TokenEscapeChar,Token9,""s: (use ~"",TokenEscapeChar,Token40,""force off, eg. ~"",0"
;                     55:    TokenString  26,"""printe"",0"
;                     56:    TokenString  27,"TokenEscapeChar,Token14,TokenEscapeChar,Token7,TokenEscapeChar,Token11,"">"",0"
;                     57:    TokenString  28,""" select"",0"
;                     58:    TokenString  29,"""xpression"",0"
;                     59:    TokenString  30,"TokenEscapeChar,Token1,"" ["",0"
;                     60:    TokenString  31,"""sprite"",0"
;                     61:    TokenString  32,""" displays"",0"
;                     62:    TokenString  33,"""free space"",0"
;                     63:    TokenString  34,""" {off}"",0"
;                     64:    TokenString  35,"""library"",0"
;                     65:    TokenString  36,"""parameter"",0"
;                     66:    TokenString  37,"""object"",0"
;                     67:    TokenString  38,""" all "",0"
;                     68:    TokenString  39,"""disc"",0"
;                     69:    TokenString  40,""" to "",0"
;                     70:    TokenString  41,""" is "",0"
;                     71:    =  0,0,0,0

klmloop
	MOVE.L	#$00000000, D6
klmloop1
	ADD.B	#1, D6
	CMP.L	#$00100000, D6
	BNE	klmloop1
	MOVE.B	#prompt, D0                       ; * Prompt
	BSR	SWI_OS_WriteC
	BRA	klmloop	

	ORG     bios_address+$00007FFF-$3B5D
EasterEggImage
	INCBIN	"68000C"
	DC.B	$FF

	END	START

*~Font name~Courier New~
*~Font size~10~
*~Tab type~1~
*~Tab size~4~
