; > HostIO
; Interface to Host system
; ------------------------
; NOTE: This module uses a lot of absolute addresses, whereas BASIC itself
; is carefully written to be position independant. When this module is
; executing it knows it's running on UNIX, so by definition, the code is
; loaded into memory at &0000, so absolute addresses are usable.

; 08-Feb-2008: RDCH/WRCH use direct TRAP calls
; 09-Feb-2008: CLI checks for *Quit, seperate ostty and mytty settings
; 10-Feb-2008: Vectors explicity set on startup, calls chain through to
;              BBC calls if BBC environment available.
; 22-Aug-2008: Set up unix handlers, ESCFLG set on SIGINT.
; 25-Feb-2009: Working on SIGINT handler and cooked/raw tty settings
; 27-Feb-2009: Some problems with read() vs SIGINT/SIGQUIT. If RDCH is
;              wrapped in tty_raw/tty_mine calls, A%=GET never returns;
;              if RDCH is not wrapped in tty_raw/tty_mine calls, SIGINT
;              and SIGQUIT don't terminate RDCH. Will need to investigate
;              deeper.
;              QUIT has to send some output before calling tty_host. Is
;              this generic? Is there a flush() call usable instead?
;              Using ioctl() fixes the problem, but ioctl() isn't available
;              on v6.
;              All output delays turned off, crmod turned off, INT/QUIT
;              keys restored on quit
; Try to call ioctrl() via indir to catch unsupported calls on v6


; Initialise Host I/O system
; ==========================
; On entry, r5=&0BBC for BBC environment or <>&0BBC otherwise
;           r6=>top of memory-2, bottom of stack, startup parameters
;               stacked parameters end with -1 or 0 (documented as 0, actually -1)
; On exit,  r0=bottom of memory
;           r1=top of memory
; Could combine this with IO_CommandLine and recover space used by parameters.
; Keeping parameters means still have startup command available.
;
.IO_Init
adr IO_UNIX,r0		; Default to UNIX TRAP calls
mov 6(sp),r4		; Address of first parameter
beq IO_Init2		; =0, no parameters, use UNIX I/O calls
inc r4			; Test for -1
beq IO_Init2		; =-1, no parameters, use UNIX I/O calls
dec r4			; Restore r4
movb (r4)+,r1		; Get first char of first param
cmp r1,#ASC"-"		; Is it a switch?
bne IO_Init2		; No, use UNIX I/O calls - ERROR - IO_Init2 checks same char for 'u'
movb (r4),r1		; Get first char of first param
bis #&20,r1		; Ensure lower case
cmp r1,#ASC"b"		; Is it "-bbc"?
bne IO_Init2		; No, use UNIX I/O calls
adr IO_BBC,r0		; Force use of BBC I/O calls
.IO_Init2
adr IO_BBC,r2		; Use BBC I/O fall-through calls
cmp r1,#ASC"u"		; Is it "-unix"?
beq IO_Init25		; Yes, jump to use only UNIX I/Ocalls
cmp r5,#&0BBC		; Is BBC environment available?
beq IO_Init3		; Yes, use BBC calls
.IO_Init25
mov #0,r5		; Prevent BBC I/O calls
adr IO_NUL,r2		; Fall-through to nulls
.IO_Init3
adr QuitV,r1		; Point to vectors
adr BBCQUITV,r3
mov #16,r4		; 16 entries to fill in
.IO_InitLp1
mov (r0)+,(r1)+		; Copy to vector tables
mov (r2)+,(r3)+
dec  r4
bne  IO_InitLp1		; Loop for 16 entries

; Set BBC handlers
; ----------------
cmp  r5,#&0BBC		; Is BBC environment available?
bne  IO_InitSignals	; No, jump to set up signals
bisb #2,SV_SYS		; Flag that BBC calls available
mov  #&FFFE,r0		; -2 = Escape handler
clr  r1			; Keep default handler routine
adr  SV_ESCFLG,r2	; Set handler buffer address
emt  14			; Set Escape flag
mov  #&FFFD,r0		; -3 = Error handler
adr  ErrorHandler,r1	; Set handler routine
clr  r2			; Keep default buffer address
emt  14			; Set Error handler

; Catch system signals
; --------------------
.IO_InitSignals
jsr pc,SetupSIGINT	; Catch user interupts (Escape)
;jsr pc,SetupSIGEMT	; Catch EMTs
jsr pc,SetupSIGSYS	; Catch bad SYS (TRAP) calls
trap 48			; Catch program termination
equw 3			; SIGQUIT - Program quit (Ctrl-@)
equw CatchSIGQUIT	; Quit tidily

; Set up tty and keep copy to restore and to use on I/O calls
; -----------------------------------------------------------
trap 0				; Indirect system call
equw io_rdctrl			; Point to ioctrl(stdin,TIOCGETP,SV_OSIOCTL)
bcs  IO_InitTTY			; ioctrl() not available
bisb #1,SV_SYS			; Set flag that ioctrl() available
mov  SV_OSIOCTL+0,SV_MYIOCTL+0	; Copy to myioctl settings
mov  SV_OSIOCTL+2,SV_MYIOCTL+2
mov  SV_OSIOCTL+4,SV_MYIOCTL+4
;
mov  #27,SV_MYIOCTL+0		; Change SIGINT to CHR$27, SIGQUIT to CHR$0
trap 54				; ioctrl()
equw 0				; stdin
equb 17,"t"			; TIOCSETP
equw SV_MYIOCTL			; Write settings on stdin
;;trap 0			; Indirect system call
;;equw io_wrctrl		; Point to ioctrl(stdin,TIOCSETP,SV_OSIOCTL)
;
.IO_InitTTY
clr  r0				; 0=STDIN
trap 32				; gtty()
equw SV_OSTTY			; Read host TTY setting
mov  SV_OSTTY+0,SV_MYTTY+0	; Copy to mytty settings
mov  SV_OSTTY+2,SV_MYTTY+2
jsr  pc,tty_mine		; Set up my TTY settings

; Return memory limits
; --------------------
adr  BasicEnd,r0	; r0=bottom of memory
mov  sp,r1
add  #2,r1		; r1=top of memory
rts  pc

.io_rdctrl
trap 54			; ioctrl()
equw 0			; stdin
equb 18,"t"		; TIOCGETP
equw SV_OSIOCTL		; Read settings on stdin

;;.io_wrctrl
;;trap 54			; ioctrl()
;;equw 0			; stdin
;;equb 17,"t"		; TIOCSETP
;;equw SV_MYIOCTL		; Write settings on stdin

; Set TTY settings for outside or inside operation
; ------------------------------------------------
.tty_mine
mov  SV_OSTTY+4,r0		; Get host tty_flags
bic  #&FF00+32+16+8+2,r0	; Raw+CRMod+Echo+CBreak off, no delays
bis  #2,r0			; CBreak on -- raw, but with INT and QUIT working
;;bis  #32,r0			; CBreak on -- raw, but with INT and QUIT working
.tty_set
mov  r0,SV_MYTTY+4		; Store my tty_flags
bitb #1,SV_SYS			; Is ioctrl() available?
beq  tty_mineTTY		; No, use stty()
trap 54				; ioctrl()
equw 0				; stdin
equb 9,"t"			; TIOCSETP
equw SV_MYTTY			; Write settings on stdin
rts  pc
.tty_mineTTY
clr  r0				; 0=STDIN
trap 31				; stty()
equw SV_MYTTY			; Set my TTY setting
rts  pc

;.tty_raw
;mov  SV_OSTTY+4,r0		; Get host tty_flags
;bic  #&FF00+32+16+8+2,r0	; Raw+CRMod+Echo+CBreak off, no delays
;bis  #32,r0			; Raw on -- allow SIGINT and SIGQUIT through
;br   tty_set

.tty_host
; using stty() causes hangs on quit, using ioctrl() works correctly
bitb #1,SV_SYS		; Is ioctrl() available?
beq  tty_hostTTY	; No, use stty()
trap 54			; ioctrl()
equw 0			; stdin
equb 9,"t"		; TIOCSETP
equw SV_OSTTY		; Write settings on stdin
rts  pc
.tty_hostTTY
clr  r0			; 0=stdin
trap 31			; stty()
equw SV_OSTTY		; Set host TTY setting
rts  pc


; Signal handlers
; ===============
.SetupSIGINT
trap 48			; signal()
equw 2			; SIGINT - User interupt (Escape)
equw CatchSIGINT
rts  pc
.CatchSIGINT
jsr  pc,SetupSIGINT	; Reconnect handler
movb #&FF,SV_ESCFLG	; Set local Escape flag
rti

;.SetupSIGEMT
;trap 48		; signal()
;equw 7			; SIGEMT - EMT call
;equw CatchSIGEMT
;rts  pc
;.CatchSIGEMT
;jsr  pc,SetupSIGEMT	; Reconnect handler
;rti

.SetupSIGSYS
trap 48		; signal()
equw 12		; SIGSYS - unknown SYS (TRAP) call
equw CatchSIGSYS
rts  pc
.CatchSIGSYS
jsr pc,PrintInline
equs "SIGSYS",13,0
align
jsr  pc,SetupSIGSYS	; Reconnect handler
bis  #1,2(sp)		; Set returned carry flag
rti


; Copy any command line to string buffer
; ======================================
; sp=>retaddr, argn, arg[0], arg[1], ... 0
;
.IO_CommandLine
mov sp,r3		; Point to stack frame
add #6,r3		; Point to first parameter
adr SV_STRING,r1	; Point to string buffer
.IO_CmdSkip
mov (r3)+,r2		; Get address of parameter
beq IO_CmdEnd		; =0 - end of parameters
inc r2
beq IO_CmdEnd		; =-1 - end of parameters
dec r2
movb (r2),r0		; Check this parameter
cmpb r0,#ASC"-"		; Is it an option to BASIC?
beq IO_CmdSkip		; Skip BASIC options
sub #2,r3		; Adjust for following increment
.IO_CmdNext
mov (r3)+,r2		; Get address of parameter
beq IO_CmdEnd		; End of parameters
.IO_CmdCopy
movb (r2)+,(r1)+	; Copy bytes from parameter to string buffer
bne IO_CmdCopy		; Loop until zero byte
movb #32,&FFFF(r1)	; Replace zero byte with space
br  IO_CmdNext		; Jump back for next parameter
.IO_CmdEnd
movb #13,(r1)		; Store terminating <cr>
adr SV_STRING,r4	; r4=>command line
movb (r4),r0		; Get first byte from string
cmp r0,#13		; Is it null string - no parameters?
rts pc			; Return EQ=no command line, NE=command line found


; IO jump block entries for Unix environment
; ------------------------------------------
.IO_UNIX
equw UNIX_QUIT
equw UNIX_CLI
equw UNIX_BYTE
equw UNIX_WORD
equw UNIX_WRCH
equw UNIX_NEWL
equw UNIX_RDCH
equw UNIX_FILE
equw UNIX_ARGS
equw UNIX_BGET
equw UNIX_BPUT
equw UNIX_GBPB
equw UNIX_FIND
equw UNIX_SYS1
equw UNIX_SYS2
equw UNIX_ERROR

; IO jump block entries for BBC environment
; -----------------------------------------
.IO_BBC
equw BBC_QUIT
equw BBC_CLI
equw BBC_BYTE
equw BBC_WORD
equw BBC_WRCH
equw BBC_NEWL
equw BBC_RDCH
equw BBC_FILE
equw BBC_ARGS
equw BBC_BGET
equw BBC_BPUT
equw BBC_GBPB
equw BBC_FIND
equw BBC_SYS1
equw BBC_SYS2
equw BBC_ERROR

; IO jump block entries for null returns
; --------------------------------------
.IO_NUL
equw NUL_QUIT
equw NUL_CLI
equw NUL_BYTE
equw NUL_WORD
equw NUL_WRCH
equw NUL_NEWL
equw NUL_RDCH
equw NUL_FILE
equw NUL_ARGS
equw NUL_BGET
equw NUL_BPUT
equw NUL_GBPB
equw NUL_FIND
equw NUL_SYS1
equw NUL_SYS2
equw NUL_ERROR


; IO entry points
; ===============
.CatchSIGQUIT	JSR PC,IO_NEWL
.IO_QUIT0	MOV #0,R0	; Quit with status=0
.IO_QUIT	JSR PC,@QuitV	; Quit
		BVS IO_Error
		RTS PC
.IO_CLI		JSR PC,@CLIV	; Execute command
		BVS IO_Error
		RTS PC
.IO_BYTE	JSR PC,@BYTEV	; Byte operation
		BVS IO_Error
		RTS PC
.IO_WORD	JSR PC,@WORDV	; Control block operation
		BVS IO_Error
		RTS PC
.IO_WRCR	MOV #13,R0	; Print CHR$13
		BR  IO_WRCH
.IO_ASCI	CMP R0,#13	; Print ASCII character
		BEQ IO_NEWL
.IO_WRCH	JSR PC,@WRCHV	; Send char to output stream
		BVS IO_Error
		RTS PC
.IO_NEWL	JSR PC,@NEWLV	; Send NEWLINE to output stream
		BVS IO_Error
		RTS PC
.IO_RDCH	JSR PC,@RDCHV	; Read char from input stream
		BVS IO_Error
		RTS PC
.IO_FILE	JSR PC,@FILEV	; Whole file operations
		BVS IO_Error
		RTS PC
.IO_ARGS	JSR PC,@ARGSV	; Information on open files
		BVS IO_Error
		RTS PC
.IO_BGET	JSR PC,@BGETV	; Get byte from channel
		BVS IO_Error
		RTS PC
.IO_BPUT	JSR PC,@BPUTV	; Put byte to channel
		BVS IO_Error
		RTS PC
.IO_GBPB	JSR PC,@GBPBV	; Block read/write
		BVS IO_Error
		RTS PC
.IO_FIND	JSR PC,@FINDV	; Open or close file
		BVS IO_Error
		RTS PC
.IO_SYS1	JSR PC,@sys1V
		BVS IO_Error
		RTS PC
.IO_SYS2	JSR PC,@sys2V
		BVS IO_Error
		RTS PC
.IO_ERROR	JSR PC,@ERRV	; Generate an error
		BVS IO_Error
		RTS PC

.IO_Error			; R0=>error block byte,string,zero byte
clv
mov r0,-(sp)
jmp Error


; NUL returns
; ===========
.NUL_QUIT
.NUL_CLI
.NUL_BYTE
.NUL_WORD
.NUL_WRCH
.NUL_NEWL
.NUL_RDCH
.NUL_FILE
.NUL_ARGS
.NUL_BGET
.NUL_BPUT
.NUL_GBPB
.NUL_FIND
.NUL_SYS1
.NUL_SYS2
.NUL_ERROR
		clv
		rts pc


; Direct calls to BBC MOS I/O calls
; =================================
.BBC_QUIT	mov r0,-(sp)	; Save return value
		mov #2,r0
		emt 13		; Set default handlers
		mov (sp)+,r0	; Get return value back
		emt 0		; Won't actually get back!
		rts pc
.BBC_CLI	emt 1		; r0=>command string
		rts pc
.BBC_BYTE	emt 2		; Osbyte r0,r1,r2
		rts pc
.BBC_WORD	emt 3		; Osword r0,r1=>block
		rts pc
.BBC_WRCH	emt 4		; Oswrch r0=char
		rts pc
.BBC_NEWL	emt 5		; Print NEWLINE
		rts pc
.BBC_RDCH	emt 6		; Osrdch r0=char
		rts pc
.BBC_FILE	emt 7		; Osfile r0=action, r1=>block
		rts pc
.BBC_ARGS	emt 8		; Osargs r0=action, r1=>block, r2=handle
		rts pc
.BBC_BGET	emt 9		; Osbget r1=handle
		rts pc
.BBC_BPUT	emt 10		; Osbput r0=byte, r1=handle
		rts pc
.BBC_GBPB	emt 11		; Osgbpb r0=action, r1=>block
		rts pc
.BBC_FIND	emt 12		; Osfind r0=action, r1=>filename or handle
		rts pc
.BBC_SYS1	emt 13
		rts pc
.BBC_SYS2	emt 14
		rts pc
.BBC_ERROR	emt 15		; Generate inline error
		rts pc


; Calls translated to UNIX TRAPs
; ==============================

; OSNEWL - Output newline to output stream
; ========================================
.UNIX_NEWL		; Print NEWLINE
mov  #10,r0
jsr  pc,IO_WRCH
.UNIX_WRCR		; Print CR
mov  #13,r0

; OSWRCH - Output character to output stream
; ==========================================
; On entry, R0=character
; On exit,  all registers preserved
;
.UNIX_WRCH
mov  r0,MOS_BUF		; Store char in buffer
mov  #1,r0		; STDOUT=1
trap 4			; write()
equw MOS_BUF		; address=buffer
equw 1			; count=1
mov  MOS_BUF,r0		; Restore r0
clv			; Clear error state
rts  pc


; OSRDCH - Wait for character from input stream
; =============================================
; On exit,  R0=character
;           CC=not escape, CS=escape
;
.UNIX_RDCH
clr  r0			; STDIN=0
trap 3			; read()
equw MOS_BUF		; address=buffer
equw 1			; count=1
movb MOS_BUF,r0		; Fetch char from buffer
cmp  r0,#27		; Escape character?
clv			; No error
beq  UNIX_RDCH_ESC
clc			; Not Escape
rts  pc
.UNIX_RDCH_ESC
sec			; Escape character
rts  pc


; OSQUIT - Quit execution
; =======================
; On entry, R0=exit status
;
.UNIX_QUIT
mov  r0,-(sp)		; Save exit status
bitb #1,SV_SYS
beq  UNIX_QUITtty
trap 54			; ioctrl()
equw 0			; stdin
equb 17,"t"		; TIOCSETP
equw SV_OSIOCTL		; Restore host TTY characters
.UNIX_QUITtty
jsr  pc,tty_host	; Restore host TTY settings
;trap 48		; signal(SIGSYS,0)
;equw 12
;equw 0
;trap 48		; signal(SIGEMT,0)
;equw 7
;equw 0
trap 48			; signal(SIGQUIT,0)
equw 3
equw 0
trap 48			; signal(SIGINT,0)
equw 2
equw 0
mov  (sp)+,r0		; Get exit status back
trap 1			; exit(r0)
clv			; Clear error state
rts  pc			; Just in case we get back!


; OSWORD - Host calls with parameters in control block
; ====================================================
; On entry, R0=action
;           R1=>control block
; On exit,  All registers undefined
;
.UNIX_WORD
; 0 - Read line
; 1 - Read TIME
; 2 - Write TIME
; 3 - Read SYSTIME
; 4 - Write SYSTIME
; 5 - Read from memory
; 6 - Write to memory
; 7 - SOUND
; 8 - ENVELOPE
; 9 - POINT
; 10 - Character definition
; 11 - Read palette
; 12 - Write palette
; 13 - Read graphics positions
; 14 - Read TIME$
; 15 - Write TIME$
tst r0
beq UNIX_WORD0		; OSWORD 0 - Read Line
cmp r0,#1
beq UNIX_WORD1		; OSWORD 1 - Read TIME
jmp @BBCWORDV		; Fall through to BBC call

; Read line of text
; -----------------
; On entry, R1=>address of memory to read string to
; On exit,  R2=length of string
;           CC=ok, CS=Escape pressed
;
.UNIX_WORD0
mov  r1,-(sp)		; Save pointer to control block
mov  r3,-(sp)		; Save R3
mov  (r1),r1		; Get pointer to buffer
clr  r2			; Zero number of characters read
.RdLnLoop
jsr  pc,IO_RDCH		; Get a character
bcs  RdLnEsc		; Escape state
cmp  r0,#13
beq  RdLnCR		; <CR> - End of line
cmp  r0,#10
beq  RdLnCR		; <LF> - End of line
cmp  r0,#21
beq  RdLnU		; Ctrl-U - delete line
cmp  r0,#127
beq  RdLnDel		; <DEL> - del a character
cmp  r0,#8
beq  RdLnDel		; <BS> - del a character
cmp  r0,#ASC" "
bcs  RdLnLoop		; Ignore other control characters
cmp  r2,#240
bcc  RdLnLoop		; No more room for characters
movb r0,(r1)+		; Put character into memory
inc r2			; Inc. number of characters
jsr  pc,IO_WRCH		; Output the character
br   RdLnLoop		; Go back for another
;
.RdLnU
mov  r2,r3		; We want to delete all characters
br   RdLnDelete
.RdLnDel
mov  #1,r3		; We only want to delete one char
.RdLnDelete
tst  r2			; Check line length
beq  RdLnLoop		; Length=0, jump back to main loop
mov  #8,r0		; Output <DEL> by backspacing
jsr  pc,IO_WRCH
mov  #32,r0
jsr  pc,IO_WRCH
mov  #8,r0
jsr  pc,IO_WRCH
dec  r1			; Back address pointer
dec  r2			; Dec character counter
;sob  r3,RdLnDelete	; Loop for each to delete
dec  r3
bne  RdLnDelete		; Loop for each to delete
br   RdLnLoop		; Go back into ReadLine loop
;
.RdLnEsc
jsr  pc,IO_NEWL		; Print newline
clr  r2			; Length = 0
mov  (sp)+,r3		; Restore R3
mov  (sp)+,r1		; Get buffer address back
movb r0,(r1)		; Put <CR> terminator in
sec			; Set carry - escape
rts  pc
;
.RdLnCR
mov  #13,r0		; Convert <LF> to <CR>
movb r0,(r1)+		; Put <CR> terminator in
jsr  pc,IO_NEWL		; Returns with r0=<cr>
clc			; Clear carry - ok
.RdLnEnd
mov  (sp)+,r3		; Restore R3
mov  (sp)+,r1		; Get buffer address back
clr  r0			; Restore R0
rts  pc			; r0=0, r1=buffer, r2=length

; Read TIME
; ---------
.UNIX_WORD1
; On entry, R1=>block to read time to
; On exit,  R0=corrupted
;
mov  r4,-(sp)		; Save some registers
mov  r3,-(sp)
mov  r2,-(sp)
mov  r1,-(sp)		; Save buffer pointer
TRAP 13			; Read one-second time to r1:r0
mov r1,r4
mov r0,r3
jsr pc,EvalTimes10
jsr pc,EvalTimes10	; Multiply by 100
mov  (sp),r2		; Get buffer pointer back
movb r4,(r2)+		; Store returned time*100
swab r4
movb r4,(r2)+
movb r3,(r2)+
swab r3
movb r3,(r2)
mov  (sp)+,r1		; Restore registers
mov  (sp)+,r2
mov  (sp)+,r3
mov  (sp)+,r4
rts  pc			; r0 corrupted


; OSCLI - Execute command
; =======================
; Initially, just checks for *Quit
.UNIX_CLI		; r0=>command string
mov r1,-(sp)
mov r0,-(sp)
mov r0,r1
.CLI_lp1
movb (r1)+,r0
cmp r0,#ASC"*"
beq CLI_lp1		; Skip spaces
cmp r0,#ASC" "
beq CLI_lp1
mov r1,-(sp)		; Save address after '*'s and ' 's
bic #32,r0
cmp r0,#ASC"Q"
bne CLI_not
movb (r1)+,r0
bic #32,r0
cmp r0,#ASC"U"
bne CLI_not
movb (r1)+,r0
bic #32,r0
cmp r0,#ASC"I"
bne CLI_not
movb (r1)+,r0
bic #32,r0
cmp r0,#ASC"T"
bne CLI_not
movb (r1),r0
cmp r0,#ASC"!"
bcc CLI_not
add #6,sp		; Balance stack just in case QUIT returns ;) ;) ;)
jmp IO_QUIT0
.CLI_not
mov (sp)+,r1		; Get command line address back
;
			; (pc+0)=>name
			; (pc+2)=argv
;
mov (sp)+,r0		; Restore registers
mov (sp)+,r1
jmp @BBCCLIV		; Fall through to BBC call


; OSBYTE - Host calls with byte parameters
; ========================================
.UNIX_BYTE
tst  r0
beq  UNIX_BYTE0
;cmp  r0,#&7F
;beq  UX_EOF
jmp  @BBCBYTEV		; Osbyte r0,r1,r2

; Read host system type
; ---------------------
.UNIX_BYTE0
mov  #8,r1		; r1=8 for Unix
bitb #2,SV_SYS		; Are BBC calls available?
beq  UNIX_BYTE0ok	; No, exit with r1=8
emt 2			; Ask host for host type
.UNIX_BYTE0ok
rts  pc

; Read EOF status
; ---------------
;.UX_EOF
;rts pc

; OSFIND - Open/close a file
; ==========================
; On entry, R0=0, R1=handle     - close
;           R0<>0, R1=>filename - open
; On exit,  R0=handle
;
.UNIX_FIND
tst  r0
bne  UX_OPEN
mov  r1,r0		; r0=handle
trap 6			; close()
rts  pc
.UX_OPEN
;jsr  pc,UX_GetString	; Get zero-terminated string
mov  #&8905,MOS_BUF	; trap 5 - open()
mov  r1,MOS_BUF+2	; filename
bic  #&FF3F,r0
rol  r0
rol  r0
swab r0			; r0=1/2/3
dec  r0			; r0=0/1/2
mov  r0,MOS_BUF+4	; action
trap 0			; indir()
equw MOS_BUF		; open(filename,action)
rts  pc

; OSBGET - Read a single byte
; ===========================
; On entry, R1=handle
; On exit,  R0=byte read
;
.UNIX_BGET
mov  r1,r0		; r0=handle
trap 3			; read()
equw MOS_BUF		; address=buffer
equw 1			; count=1
movb MOS_BUF,r0		; Fetch char from buffer
rts  pc			; read() sets Cy if at EOF

; OSBPUT - Read a single byte
; ===========================
; On entry, R0=byte to write
;           R1=handle
; On exit,  R0=byte read
;
.UNIX_BPUT
mov  r0,MOS_BUF		; Store char in buffer
mov  r1,r0		; r0=handle
trap 4			; write()
equw MOS_BUF		; address=buffer
equw 1			; count=1
mov  MOS_BUF,r0		; Restore r0
rts  pc

; OSARGS - Read/write open file information
; =========================================
; On entry, R0=action
;           R1=>control block
; On exit,  Control block updated
;
.UNIX_ARGS
tst  r0
bne  UX_ARGS
tst  r1
bne  UX_ARGS
mov  #24,r0		; r0=24 for UnixFS
bitb #2,SV_SYS		; Are BBC calls available?
beq  UX_FSok		; No, exit with r0=24
clr  r0
emt 8			; Ask host for host type
.UX_FSok
rts  pc

.UX_ARGS
;; tst r0
;; beq UX_RdPTR
;; cmp r0,#1
;; beq UX_WrPTR
;; cmp r0,#2
;; beq UX_RdEXT
;; cmp r0,#3
;; beq UX_WrEXT
jmp @BBCARGSV	; Osargs r0=action, r1=>block, r2=handle
;; 
;; 
;; mov #&8913,MOS_BUF+16	; trap 19 - lseek()
;; 
;; 
;; 
;; clr MOS_BUF+18		; offset.lo=0
;; clr MOS_BUF+20		; offset.hi=0
;; mov #1,MOS_BUF+22	; ptr=ptr+offset
;; tst r0
;; beq RX_RdPtr		; r0=0, jump to read PTR
;; mov #2,MOS_BUF+22	; ptr=ext+offset
;; 
;; mov (r2)+,MOS_BUF+18	; offset.lo
;; mov (r2)+,MOS_BUF+20	; offset.hi
;; mov #0,MOS_BUF+22	; whence
;; tst r0
;; beq UX_RdPTR
;; 
;; mov -(r2),r1
;; mov -(r2),r0
;; rts pc



; OSGBPB - Read/write multiple bytes
; ==================================
; On entry, R0=action
;           R1=>control block
; On exit,  Control block updated
;
.UNIX_GBPB
tst  r0
beq  UX_GBPBbbc
cmp  r0,#5
bcc  UX_GBPBbbc
mov  r3,-(sp)
mov  r2,-(sp)
mov  r1,-(sp)
mov  r0,-(sp)
bit  #1,r0
beq  UX_NoPtr
movb (r1),r0		; r0=handle
mov  #&8913,MOS_BUF+16	; trap 19 - lseek()
movb 9(r1),r2
bic  #&FF00,r2		; r2=ptr.lo
movb 10(r1),r3
bic  #&FF00,r3		; r3=ptr.lo
swab r3
bis  r3,r2
mov  r2,MOS_BUF+18	; offset.lo
movb 11(r1),r2
bic  #&FF00,r2		; r2=ptr.hi
movb 12(r1),r3
bic  #&FF00,r3		; r3=ptr.hi
swab r3
bis  r3,r2
mov  r2,MOS_BUF+20	; offset.hi
clr  MOS_BUF+22		; whence=0
trap 0			; indir()
equw MOS_BUF+16		; lseek(handle,offset.lo,offset.hi.whence)
.UX_NoPtr
mov  (sp)+,r0		; Get action back
mov  #&8903,r1		; r1=trap 3 - read()
cmp  r0,#2
bcc  UX_RdWr
inc  r1			; r1=trap 4 - write()
.UX_RdWr
mov  r1,MOS_BUF+16	; trap 3/4
mov  (sp),r1		; Get control block back
movb (r1),r0		; r0=handle
movb 1(r1),r2
bic  #&FF00,r2		; r2=addr.lo
movb 2(r1),r3
bic  #&FF00,r3		; r3=addr.lo
swab r3
bis  r3,r2
mov  r2,MOS_BUF+18	; store address
movb 5(r1),r2
bic  #&FF00,r2		; r2=num.lo
movb 6(r1),r3
bic  #&FF00,r3		; r3=num.lo
swab r3
bis  r3,r2
mov  r2,MOS_BUF+20	; store count
trap 0			; indir()
equw MOS_BUF+16		; read/write(buffer,count)
mov  r1,-(sp)
mov  r2,-(sp)
mov  r3,-(sp)
clr  r0
rts  pc
.UX_GBPBbbc
jmp @BBCGBPBV		; Osgbpb r0=action, r1=>block


; OSFILE - Load/Save file
; =======================
; On entry, R0=action
;           R1=>control block
; On exit,  Control block updated
;
.UNIX_FILE
incb r0
beq  UX_LOAD		; r0=&FF - load file
decb r0
beq  UX_SAVE		; r0=&00 - save file
.UX_SAVE
.UX_FILEbbc
jmp @BBCFILEV		; Osfile r0=action, r1=>block
.UX_LOAD
; (r1)=>filename
; 2(r1)=>load address
; 6(r1)=>load flag
movb (r1),r0
movb 1(r1),r2
bic  #&FF00,r0
bic  #&FF00,r2
swab r2
bis  r2,r0		; r0=>filename
jsr  pc,UX_GetString	; Ensure zero-string
movb 2(r1),r2
movb 3(r1),r3
bic  #&FF00,r2
bic  #&FF00,r3
swab r3
bis  r3,r2		; r2=load address


rts  pc


; Fall through to BBC calls
; =========================
.UNIX_SYS1	jmp @BBCSYS1V
.UNIX_SYS2	jmp @BBCSYS2V
.UNIX_ERROR	jmp @BBCERRV	; Generate error


; Copy ctrl-string at r0 to string buffer and add zero terminator
; ===============================================================
.UX_GetString
mov  r1,-(sp)
adr  SV_STRING,r1
.UX_GetStrLp
movb (r0)+,(r1)+
cmp  -1(r1),#ASC" "
bcc  UX_GetStrLp
movb #0,(r1)
adr  SV_STRING,r0
mov  (sp)+,r1
rts  pc

