; > Startup
; BBC BASIC for the pdp11
; (C)J.G.Harston 1988, 1989, 2005, 2006, 2008, 2009
; Program header and BASIC startup, etc.

; 24-May-2006 v0.10 Added skeleton error handler
; 28-Jan-2008 v0.11
; 25-Feb-2009 v0.13
; 25-Oct-2009 JGH: Places zero word at top of stack so 2(sp) can be examined


; This source uses the 'ADR label,dst' pseudo-opcode
; The assembler needs to expand this into:
;   MOV pc,dst // ADD #label-$,dst


ORG 0				; Position independant code

EQUW &0107			; Magic number &o000407, also branch to Startup
EQUW CodeEnd-Startup		; size of text
EQUW &0000			; size of initialised data
EQUW BasicEnd-CodeEnd		; size of uninitialised data
EQUW &0000			; size of symbol data
EQUW &0000			; entry point
EQUW &0000			; not used
EQUW &0001			; no relocation info
;
ORG 0				; Position independant code
.Startup
; On entry, R0-R5=0, SP=>stack, R7=Startup
; Environment: R7=>Bottom of memory
;              R6=>Top of memory
; When run on Unix,
;              R6=>pointers to command line parameter strings,
;                  terminated with 0
;                  parameter strings
; When run in BBC environment,
;              R5=&0BBC
;
; Normally, header will not have been loaded
; and memory will be mapped so Startup=&0000
;
; Loader clears system variables. This means that
; CALL Startup does not replicate running the code.
; For CALL Startup (CALL 0) to re-enter BASIC as
; though run from disk, Startup needs to clear system
; variables, as done by the system loader.
;
;ADR  SV_VARS,r0		; r0=>start of system variable area
;MOV  #(SV_SIZE-2)/2,r1		; Size of system variable area
;MOV  #&090A,(r0)+		; @%=&90A
; Loader clears data area
;.StartClear
;MOV  #&0000,(r0)+		; Clear system variable area
;DEC  r1			; Clears all resident and dynamic variables
;BNE  StartClear		; r0=bottom of memory
;ADR  BasicEnd,r0		; r0=bottom of memory
;MOV  sp,r1			; r1=top of memory
jsr  PC,IO_Init			; Initialise I/O, find memory limits
mov  r0,SV_MEMBOT		; Initialise bottom of memory
mov  r0,SV_PAGE			; Put initial PAGE at bottom of memory
mov  #&FF0D,(r0)+		; 'NEW' the program
mov  r0,SV_TOP			; TOP=end of empty program
mov  r0,SV_LOMEM		; LOMEM=TOP
mov  r0,SV_VAREND		; VAREND=TOP
mov  r1,SV_MEMTOP		; Initialise top of memory
mov  r1,SV_HIMEM		; Put initial HIMEM at top of memory
mov  r1,SV_STACK		; Clear BASIC's stack
mov  r1,sp			; Put stack at top of memory
mov  #&090A,SV_VARS		; @%=&90A
adr  StartupCopyright-1,r0	; Get location of (C) message
mov  r0,SV_FAULT		; Point REPORT to it
movb #&FF,SV_OPTIONS		; Set options to &FF
jsr  pc,IO_CommandLine		; any command line params? eg filename
beq  StartupNull		; LEN(filename)=0, quiet startup
jmp  ChainStartup		; Jump to do CHAIN "filename"
.StartupNull
jsr pc,PrintInline
;
.StartupMessage
EQUS "PDP11 BBC BASIC IV Version 0.13 [Integer only]",13
.StartupCopyright
EQUS "(C) Copyright J.G.Harston 1989,2005-2009",13
EQUB 0
ALIGN
;
; Immediate mode
; --------------
.Immediate
clr SV_AUTO			; Clear AUTO line
.ImmediateLoop
mov SV_HIMEM,SP			; Put system stack at top of memory
jsr pc,IO_AckEsc		; Ack. any pending Escape
mov #ASC">",r0
jsr pc,IO_WRCH			; Print ">" prompt
clr SV_ONERR			; Cancel ON ERROR
mov SV_AUTO,SV_LINE		; Get current line to AUTO line
beq ImmNotAuto			; No AUTO line
mov r0,-(sp)
jsr pc,PrintLineNumber		; Output r0 as line number
mov (sp),r0
mov SV_STEP,r1			; Get AUTO STEP
bic #&FF00,r1			; Ensure 8-bit value
add r1,r0			; Add STEP to AUTO line
bcs errTooBig			; Run out of line numbers
mov r0,SV_AUTO			; Store updated AUTO line
mov #ASC" ",r0
jsr pc,IO_WRCH			; Print a space
.ImmNotAuto
ADR SV_STRING,r1		; Point to string buffer
JSR PC,IO_ReadLine		; Read a line of input
clrb SV_COUNT			; Zero COUNT
adr SV_STRING,r5		; Point to string buffer
jsr pc,ReadLineNumber		; r4=line number (CC) or zero (CS)
bcs ImmNoLineNum		; No line number entered
mov r4,SV_LINE			; Set current input line number
.ImmNoLineNum			; r5=>start or line or after line number

; Tokenise entered line
; ---------------------
adr SV_INPUT,r4			; r4=>dest in input buffer
jsr pc,Tokenise			; Tokenise from r5 to r4
; On exit, r0,r1,r2,r3=corrupted, r4=>dest <cr>, r5=>source <cr>
inc r4				; Step past <cr>
movb #&FF,(r4)			; Put &FF after <cr>
adr SV_INPUT,r5			; Point BASIC pointer to line
sub r5,r4			; r4=line length inc. <cr>
mov SV_LINE,r1			; Get line number
bne ImmLineNum			; Line number, enter line
mov #0,-(sp)			; Push zero word at top of stack
jmp Execute			; Execute immediate line
; jsr pc,Execute		; No line number, execute line
; jmp Immediate			; Non-zero word at top of stack -> executing from immediate mode

.ImmLineNum
; Line entered for entry into program
; r1=line number
; r4=line length
; r5=line start
movb (r5)+,r0
dec  r4
cmpb r0,#ASC" "
beq  ImmLineNum			; Skip any leading spaces
dec  r5
inc  r4				; Point back to first non-space character
clr r3
jsr pc,LineFind			; Find line number
; r1=><cr> at point to insert
; NE=no line, EQ=line found
;; movb 1(r1),r0
;; cmpb r0,#&FF	; End of program?
;; beq  ...
;; 
;; ...
;; 
;; movb r4,2(r1)	; Store line number high byte
;; swab r4
;; movb r4,1(r1)	; Store line number low byte
;; 
;; .ImmLineNumLp
;; movb (r5)+,r0
;; movb (r1)+,r0
;; inc  r2
;; cmpb r0,#13
;; bne  ImmLineNumLp
;; movb r2,3(r1)
;; 
;; 
;;
;
jsr pc,PrintInline
equs "Insert line",13,0
align
;
; save various registers
;jsr pc,FindTOP			; Check for Bad Program
;jsr pc,LineFind			; Find where to put line number
;bne ImmLineEnter
;jsr pc,LineDelete		; Delete existing line
;.ImmLineEnter
; restore various registers
;beq ImmediateLoop		; No line to enter, jump back for another
;add #4,r2			; r2=line length+<cr>+<numlo>+<numhi>+<len>
; Check if enough room
; insert space for new line
; insert new line
;jsr pc,SetTOP			; Put program terminator at end
br ImmediateLoop		; Go back for another line

.errTooBig
jsr pc,Error
equb 20,"Too big",0
align
