; -*- Mode:MIDAS -*- 

TITLE	MTBOOT - Create KS10 bootload tape or file.
	;CStacy,  21 July 1984
	;(Munged by Alan a great deal since then.)

; The 8080 front-end reads a tape starting with an optional 
; microcode file, and EOF, and a 512 word bootload program
; which is loaded at 1000 and started.
;
; MTBOOT writes a file (to be copied onto a KS10 boot tape after the
; microcode file) containing the SBLK-bootstrap loader followed by SBLK
; files concatenated.  Usually the first one is DDT and the second is
; some client program.
;
; OR
;
; MTBOOT will directly write a tape containing a microcode and the boot
; file.

;;; MTBOOT gets DDT from the file DSK:KSHACK;DDT BIN
;;; MTBOOT gets microcode from the file DSK:KSHACK;GOOD RAM

IFNDEF $$DBG, $$DBG==0		;Set for debugging version of bootloader.
IFNDEF $$TPDBG, $$TPDBG==0	;Set for debugging tape handling
IFNDEF $$SBDBG, $$SBDBG==0	;Set for debugging SBLK stuff


SUBTTL	Definitions

X=0		;Super temporary.
A=1		;A-E general purpose.
B=2
C=3
D=4
E=5
BP=6		;Buffer pointer.
F=7		;Flags.
RETRY=10	;Count disk ops.
Q=11		;Checksum.
T=12		;Temporary ACs.
TT=13
P=17		;Stack pointer.

; I/O channels for MTBOOT

DSKI==1		;Disk input
OUTCH==2	;Disk or tape output
TYIC==3		;Typein
TYOC==4		;Typeout

CALL==:<PUSHJ P,>
RET==:<POPJ P,>
NOP=:<TRN>

;System call macro
DEFINE SYSCAL OP,ARGS
	.CALL [ SETZ ? SIXBIT /OP/ ? ARGS ((SETZ)) ]
TERMIN


;Canonical information macro.
DEFINE INFORM A,B
IF1,[	PRINTX /A = B
/]
TERMIN

;Type out an ascii string.
DEFINE TSTYPE &STRING
	MOVEI T,<.LENGTH STRING>
	MOVE TT,[440700,,[ASCII STRING]]
	SYSCAL SIOT,[%CLIMM,,TYOC ? TT ? T]
	 .LOSE %LSFIL
TERMIN

;Type string from BP until null encountered.
DEFINE TYPEBP BPTR
	MOVE T,BPTR
	ILDB TT,T
	JUMPE TT,.+3
	.IOT TYOC,TT
	JRST .-3
TERMIN


;Decrement ASCII byte pointer.
DEFINE DECBP C			   ;Decrement byte pointer.
	ADD C,[70000,,]		   ;Back up the byte pointer.
	SKIPGE C		   ;Did we cross a word boundary?
	  SUB C,[430000,,1]	   ; then fix it.
TERMIN



SUBTTL	Main Program and Data

SYSLOS:	.VALUE [ASCIZ ":Losage."]
	JRST .-1

POPJ1:	AOS (P)				;Canonical Skip
CPOPJ:	POPJ P,				;Return.
DIE:	.LOGOUT 1,			;JRST here to die.

MTBOOT:	MOVE P,[-PDLLEN,,PDL-1]		;Init our stack.
	PUSHJ P,RFN"RMNAME		;Find name of this machine.
	SYSCAL OPEN,[%CLBIT,,<.UAO+%TJDIS> ? %CLIMM,,TYOC ? [SIXBIT /TTY/]]
	  .LOSE %LSFIL
	SYSCAL OPEN,[%CLBIT,,.UAI ? %CLIMM,,TYIC ? [SIXBIT /TTY/]]
	  .LOSE %LSFIL
	SYSCAL CNSGET,[%CLIMM,,TYIC ? %CLOUT,,X ? %CLOUT,,X	;Get TTY caps.
		       %CLOUT,,X ? %CLOUT,,X ? %CLOUT,,TTYOPT]
	  .LOSE %LSFIL
	.SUSET [.RSNAME,,A]
	MOVEM A,INFILE+3
	MOVEM A,KSBOOT+3
	TSTYPE "AKS10 ITS Bootload Generator."
	SETZM MAGP
	TSTYPE "AWrite a tape? "
	PUSHJ P,YORNP
	 JRST NOTAPE
	SETOM MAGP
	TSTYPE "ARewind tape first? "
	PUSHJ P,YORNP
	 JRST NOWIND
	SYSCAL OPEN,[	[.BII,,OUTCH]	; Can only rewind in input mode...
			[SIXBIT /MT0/]]
	 .LOSE %LSFIL 
	MOVE A,[OUTCH,,[1,,1]]	; rewind once
	.MTAPE A,
	 .LOSE %LSSYS
NOWIND:	SYSCAL OPEN,[	[1000+.BIO,,OUTCH]	; 1000 word records
			[SIXBIT /MT0/]]
	 .LOSE %LSFIL 
	TSTYPE "AWriting microcode from "
	MOVEI B,RAMFIL
	MOVE D,[440700,,TYPEIN]
	PUSHJ P,RFN"PFN
	MOVE D,[440700,,TYPEIN]
	TYPEBP D
	PUSHJ P,COPY
	MOVE A,[OUTCH,,[1,,5]]	; EOF once
	.MTAPE A,
	 .LOSE %LSSYS
NOTAPE:	TSTYPE "AInclude DDT? "
	SETOM DDTP			;Normally we write DDT
	SETOM PRGP			;and some other program.
	PUSHJ P,YORNP
	 SETZM DDTP			;Say not to include DDT.
	TSTYPE "AInput file (just press Return if none)? "
	PUSHJ P,READER			;Read file name string.
	 CAIA
	JRST [	MOVE D,[440700,,TYPEIN]	;Bp to the filename string.
		MOVEI B,INFILE		;Ptr to file block.
		PUSHJ P,RFN"RFN		;Parse the file name.
		JRST MERGE ]
	SETZM PRGP
	SKIPN DDTP
	 JRST [	TSTYPE "AWriting just the loader is useless!"
		JRST DIE ]
MERGE:	SKIPE MAGP
	 JRST MERGE0
	MOVEI A,KSBOOT			;Open the output file.
	SYSCAL OPEN,[%CLBIT,,.BIO ? %CLIMM,,OUTCH ? 0(A) ? 1(A) ? 2(A) ? 3(A)]
	 .LOSE %LSFIL
MERGE0:	TSTYPE "AWriting 512 word bootstrap loader."
	MOVE A,[-1000,,PREBOOT]		;Pointer to bootload program.
	.IOT OUTCH,A			;Write out 512 words.
	SKIPN DDTP
	 JRST [	CALL MNSBLK
		JRST MERGE1]
	TSTYPE "AWriting DDT from "
	MOVEI B,DDTBIN
	MOVE D,[440700,,TYPEIN]
	PUSHJ P,RFN"PFN
	MOVE D,[440700,,TYPEIN]
	TYPEBP D
	PUSHJ P,COPY			;Write out DDT.
MERGE1:	SKIPN PRGP
	 JRST [	CALL MNSBLK
		JRST MERGE2]
	SETOM CLIENP
	TSTYPE "AWriting SBLK program from "
	MOVEI B,INFILE
	MOVE D,[440700,,TYPEIN]
	PUSHJ P,RFN"PFN
	MOVE D,[440700,,TYPEIN]
	TYPEBP D
	PUSHJ P,COPY			;Write out program.
MERGE2:	SKIPE MAGP
	 JRST MERGE3
	SYSCAL RFNAME,[%CLIMM,,OUTCH ? %CLOUT,,KSBOOT
			%CLOUT,,KSBOOT+1 ? %CLOUT,,KSBOOT+2 ? %CLOUT,,KSBOOT+3]
	 .LOSE %LSFIL
	TSTYPE "AWrote file "
	MOVEI B,KSBOOT
	MOVE D,[440700,,TYPEIN]
	PUSHJ P,RFN"PFN
	MOVE D,[440700,,TYPEIN]
	TYPEBP D
MERGE3:	.CLOSE OUTCH,
	JRST DIE

;;; Open, gobble, and write out the file specified by B.
COPY:	PUSH P,A
	PUSH P,B
	PUSH P,C
	SYSCAL OPEN,[%CLBIT,,.BII ? %CLIMM,,DSKI ? 0(B) ? 1(B) ? 2(B) ? 3(B)]
	 .LOSE %LSFIL
	JRST COPY1

COPY2:	MOVE B,[-1000,,BUFFER]
	.IOT OUTCH,B			;Copy out buffer.
COPY1:	SETZM BUFFER			;Freshen buffer.
	MOVE C,[BUFFER,,BUFFER+1]
	BLT C,BUFFER+1000
	MOVE A,[-1000,,BUFFER]		;Pointer to input buffer
	.IOT DSKI,A			;Read max 512 words from file.
	CAME A,[-1000,,BUFFER]	; Stop at EOF
	 JRST COPY2
	.CLOSE DSKI,
	POP P,C
	POP P,B
	POP P,A
	RET

;;; Write minimum SBLK file:
MNSBLK:	PUSH P,A
	MOVE A,[-3,,[
		JRST 1
		JRST 4,17
		JRST 4,17
		]]
	.IOT OUTCH,A
	SETZM BUFFER
	MOVE A,[BUFFER,,BUFFER+1]
	BLT A,BUFFER+1000
	MOVE A,[-775,,BUFFER]
	.IOT OUTCH,A
	POP P,A
	RET

;;; Read from TYIC with minimal rubout handling (displays only).
;;; Uses TYPEIN buffer and skips if read something; returns count in A.

READER:	MOVE BP,[440700,,TYPEIN]
	SETZM TYPEIN			;Clear typein buffer.
	MOVE A,[TYPEIN,,TYPEIN+1]
	BLT A,TYPEIN+LTYPEI
	SETZ A,				;Keep count in A.
READ1:	.IOT TYIC,T
	CAIN T,177			;Rubout deletes chars.
	 JRST RUBOUT
	CAIN T,^D			;^D rubs out a line.
	 JRST RUBALL
	CAIE T,^C			;^C and ^M finish input.
	 CAIN T,^M
	 JRST [	MOVEI T,0
		IDPB T,BP		;Tie off ASCIZ string.
		SKIPE A			;If we read something
		 AOS (P)		; Skip
		POPJ P, ]		;  Return.
	AOS A				;Keep count of chars read.
	CAILE C,LTYPEI*5.		;Avoid overflowing the buffer.
	 JRST RUBALL
	IDPB T,BP			;Stuff it.
	CAIGE T,40			;No random ctl chars allowed!
	 JRST [ .IOT TYOC,[^G]
		JRST RUBOUT ]
	JRST READ1			;Get another.
RUBALL:	TSTYPE " XXX?"
	JRST READER			;Flush entire line.

RUBOUT:	SKIPN A				;Something to rubout?
	 JRST [	.IOT TYOC,[^G]		; No, just beep.
		JRST READ1 ]
	MOVE T,TTYOPT			;Examine terminal.
	TLNE T,%TOERS
	 JRST [ TSTYPE "X"		;If able, erase from screen
		JRST RUBOU1 ]
	LDB T,BP			;Else just echo deleted char.
	.IOT TYOC,T
RUBOU1:	DECBP BP
	SOS A
	JRST READ1


;;; Y-OR-N-P, skips for Yes.
YORNP:	TSTYPE / (Y or N) /
	.IOT TYIC,T
	CAIN T,40			;A [SPACE] means yes.
	 JRST POPJ1
	CAIN T,177			;A [RUBOUT] means no.
	 POPJ P,
	CAIL T,140
	 SUBI T,40			;Y or N mean the obvious.
	CAIN T,"Y
	 JRST POPJ1
	CAIN T,"N
	 POPJ P,
	.IOT TYOC,[^G]
	JRST YORNP			;Maybe obvious not to everybody????



$$RFN==1
$$PFN==1
$$MNAME==1
.INSRT DSK:SYSENG;RFN

RSIXTP::				;Filename parser routines.
PSIXTP:	POPJ P,				;No special character processing.


;;; Data

PDLLEN==200
LTYPEI==20.
LBUFFE==1001

TTYOPT:	0				;TTYOPT word.
MAGP:	0				;-1 if writing a tape.
DDTP:	0				;-1 if DDT being written too.
PRGP:	0				;-1 if program to "merge" with DDT.
CLIENP:	0			   	;-1 if hacking client now.
MNAME:	0				;Name of this ITS.

PDL:	BLOCK PDLLEN			;Stack.
BUFFER:	BLOCK 1001			;Disk buffer.
TYPEIN:	BLOCK LTYPEI+1			;Typein buffer.

;;; File names.

KSBOOT:	SIXBIT /DSK/
	SIXBIT /KSBOOT/
	SIXBIT />/
	0

INFILE:	SIXBIT /DSK/
	SIXBIT /FOO/
	SIXBIT /BIN/
	0

DDTBIN:	SIXBIT /DSK/
	SIXBIT /DDT/
	SIXBIT /BIN/
	SIXBIT /KSHACK/

RAMFIL:	SIXBIT /DSK/
	SIXBIT /GOOD/
	SIXBIT /RAM/
	SIXBIT /KSHACK/

CONSTANTS


SUBTTL	SBLK Bootstrap Loader

.INSRT KSHACK;KSDEFS

MEMSIZ=1000000		;The size of memory.
DDT=MEMSIZ-4000		;Address of DDT.
JOBSYM=DDT-1		;-1 if following is invalid.
;      DDT-2		;All symbols ptr. 
KILC=  DDT-3		;Initial symbols ptr.
STARTA=DDT-4		;Start address.

;Print a string
DEFINE	TYPE &STRING
	MOVEI T,[ASCIZ STRING]
	CALL TYPOUT
TERMIN

;Type a SIXBIT value
DEFINE	6TYPE LOC
	MOVEI T,LOC
	CALL TYPSIX
TERMIN

;Type a number.
DEFINE	8TYPE LOC
	MOVE T,LOC
	CALL OCTPNT
TERMIN

;Type a CRLF (sugar macro).
DEFINE	TYPECR
	CALL CRLF
TERMIN

; Type character immediate.
DEFINE	CTYPE CHAR
	MOVEI TT,CHAR
	CALL TYO
TERMIN

;Fatal error macro.
DEFINE	ERROR &MSG
	JRST [	MOVEI T,[ASCIZ MSG]
		JSR BARF ]
TERMIN

; 1000  --- Start Program
; 1001  --- Lossage PC stored here.
; LOSE  --- Horrible PC here.

IFNDEF ORG, ORG==:1000	;Location of this bootload program in core (PREBOOT).

PREBOOT:	
OFFSET ORG-.
	JRST GO			;Go for it!.

BARF:	0			;Errors JSR here
	TYPECR
	CALL TYPOUT
	TYPECR
	JRST 4,@BARF

LOSE:	0			   ;Really awful errors JSR here.
	JRST 4,@LOSE

IFN 0,[
	IORD X,MTCS1		   ;Store some I/O info in 103-113.
	MOVEM X,103		   ;MTCS1.
	IORD X,MTCS2
	MOVEM X,104		   ;MTCS2.
	IORD X,MTDS
	MOVEM X,105		   ;MTDS.
	IORD X,MTER
	MOVEM X,106		   ;MTER1.
	SETZM 107		   ;Not used.
	SETZM 110		   ;Not used.
	IORD X,IOPAGR
	MOVEM X,111		   ;UBA page RAM loc 0.
	IORD X,IOSTAT
	MOVEM X,112		   ;UBA status register.
	MOVE X,VERSUN
	MOVEM X,113		   ;Version of this bootloader.
];IFN 0

GO:	;; Clear core above and below the loader.  Be careful about 8RHBAS
	;; through 8BOOTP.
	SETZM ORG+1000
	MOVE A,[ORG+1000,,ORG+1001]
	BLT A,777677		; Don't clobber DSKDMP bootstrap
	SETZM 8BOOTP+1
	MOVE A,[8BOOTP+1,,8BOOTP+2]
	BLT A,ORG-1
	SETZM 20
	MOVE A,[20,,21]
	BLT A,8RHBAS-1
	;; Clear all AC's and select block 0
CLRACS:	WRUBR ACBLK+0		; A in block 0 contains count.
	MOVEI A,7		; Start with block 7.
CLRACL:	WRUBR ACBLK(A)		; Select next block
	SETZI 0,
	MOVEI 17,1
	BLT 17,17		; Clears A iff A already contained 0.
	WRUBR ACBLK+0		; Select block 0 again
	SOJGE A,CLRACL		; Go do next?
	MOVE P,[-LBOOPD,,BOOPDL-1] ;Init our stack.
MAKIOT:	SKIPN A,8RHBAS		   ;Find 19 bit base addr of tape boot device.
	 ERROR "RH11 base?"
	HLLM A,IOPAGR		   ;UBA pager this bus.
	HLLM A,IOSTAT		   ;UBA status this bus.
	MOVE B,[-NIOWDS,,MTCS1]		   ;AOBJN to IO words.
MAKIO1:	MOVEM A,(B)		   ;Store unibus addr of tape control register.
	ADDI A,2		   ;Compute next one.
	AOBJN B,MAKIO1		   ;Go store them all.
HERALD:	TYPE "ITS MTBOOT."
	6TYPE VERSUN
	SETZI BP,		; Buffer starts empty.
	CALL LODCOD
	MOVEM A,START
	JRST LOAD3

LOAD4:	CALL LODSKP
LOAD3:	CALL MTIOT
	JUMPL A,LOAD4
	CAME A,START
	 ERROR "Start instruction mismatch"
	CALL LODCOD
	EXCH A,START		; Consider running second program
	CAMN A,[JRST 4,17]	; Was first file the minimal SBLK file?
	 JRST DONE		; Yes:  Run second program
	EXCH A,START		; OK, so run first program
	MOVE B,JOBSYM
	CAIE B,DDT-2		; Does it look like DDT?
	 JRST DONE		; No:  Just go run it
	MOVEM A,STARTA		; This must be DDT, set starting address
	TLO B,400000
	MOVEM B,JOBSYM		; and mark symbol table as clobbered
	JRST LOAD5

LOAD6:	CALL LODSYM
LOAD5:	CALL MTIOT
	JUMPL A,LOAD6
	CAME A,STARTA
	 ERROR "Start instruction mismatch"
DONE:	;; Clear out loader and start him up.
	SETZM ORG
	MOVE 15,[ORG,,ORG+1]	; Load AC for BLT.
	MOVE 16,[BLT 15,ORG+1777]	; This instruction does the work.
	MOVE 17,START		; This is the start instruction.
	JRST 16			; Do it.

;;; Load a symbol table block or other information block.  Enter with first
;;; word already in A.
;;; Clobbers A, B, C and Q.
LODSYM:	HRRZ C,A		; C: type of block
	JUMPN C,LODSKP
	HLRE B,A
	ADD B,A
	ADDB B,@JOBSYM
	HLL B,A
	JRST LODBK1

;;; Skip over an information block.  Enter with first word already in A.
;;; Clobbers A, B and Q.
LODSKP:	MOVE B,A		; B: aobjn into hyperspace
	MOVE Q,A		; Q: checksum
SKPLUP:	ROT Q,1
	CALL MTIOT
	ADD Q,A
	AOBJN B,SKPLUP
	JRST CHKSUM

;;; Load the code from an SBLK file, returns start instruction in A.
;;; Clobbers A, B, C and Q.
LODCOD:	CALL MTIOT		; Get a word
	CAME A,[JRST 1]		; End of RDIN cruft?
	 JRST LODCOD		; No: keep looking.
	JRST LODCD1

LODCD2:	CALL LODBLK		; Loop loading SBLKs
LODCD1:	CALL MTIOT
	JUMPL A,LODCD2		; Until start instruction
	RET

;;; Load an SBLK into memory.  Enter with first word already in A.
;;; Clobbers A, B, C and Q.
LODBLK:	MOVE B,A		; B: aobjn into core
LODBK1:	MOVE Q,A		; Q: checksum
LODLUP:	ROT Q,1
	HRRZ C,B		; C: destination address
	CAIL C,8SWIT0		; Smashing 8080 area?
	 CAILE C,8QNUM
	  CAIA
	   ERROR "Overwriting 8080 area"
	CAIGE C,20		; Smashing ACs?
	 ERROR "Overwriting ACs"
	CAIL C,ORG		; Smashing loader?
	 CAILE C,ORG+1777
	  CAIA
	   ERROR "Overwriting loader"
	CALL MTIOT		   ;Get word.
	MOVEM A,(B)		   ;Store it.
	ADD Q,A			   ;Do sum checking.
	AOBJN B,LODLUP
CHKSUM:	CALL MTIOT		   ;Read checksum.
	CAME A,Q		   ;Match?
	 ERROR "Checksum error"
	RET

; Get word from tape (or refill buffer) into A.
MTIOT:	JUMPL BP,MTIOT1		   ;Jump if buffer contains data
	IFN $$TPDBG,CTYPE "%
	MOVEI RETRY,20.		   ;Retry count
READ:	CALL MTHAK		   ;Init tape.
	MOVEI A,40001+<org/1000>   ;Page after loader, UBA valid.
	IOWR A,IOPAGR		   ;Map Unibus locations 0-1777 to KS10 mem.
	SETZ A,
	IOWR A,MTBA
	MOVNI A,2000		   ;2000 18-bit words = 1000 36-bit words.
	IOWR A,MTWC
	MOVEI A,71		   ;Read forward
	IOWR A,MTCS1
	CALL IOWAIT
	TRNE A,4		   ;Premature tape mark?
	 ERROR "Unexpected EOF"	   ; Lose.
	IORD A,MTER
	TRNE A,176777		   ;Tape error--retry
	 JRST [	SOJL RETRY,[ ERROR "Tape err" ]
		CALL MTHAK
		MOVNI A,1	   ;Backspace one record.
		IOWR A,MTFC
		MOVEI A,33
		IOWR A,MTCS1
		CALL IOWAIT
		JRST READ ]
	MOVSI BP,-1000		   ;Buffer contains data now
	IFN $$TPDBG,CTYPE "$
MTIOT1:	MOVE A,2000(BP)		   ;Get next word from buffer
	AOBJN BP,.+1		   ;Advance buffer pointer
IFN $$SBDBG,[
	TYPE "...  "
	8TYPE A
	MOVEI B,40000.		;Pause about 1/4 sec.
	SOJG B,.
]; $$SBDBG
	RET

MTHAK:	IFN $$TPDBG,CTYPE "#
	MOVEI A,40		   ;Hack the tape drive.
	IOWR A,MTCS2
	MOVE A,8QNUM
	IOWR A,MTCS2
	MOVE A,8BOOTP
	IOWR A,MTTC
	SETZ A,
	IOWR A,MTFC
	RET

IOWAIT:	IORD A,MTDS		   ;Wait for IO completion.
	TRNN A,20000		   ;Wait if positioning in progress
	 TRNN A,200		   ;Wait until drive ready
	  JRST IOWAIT
	RET

;Hand TT to 8080 for printing.
TYO:	ANDI TT,177		;Remove crap.
	TRO TT,400		;Set CTY-character-pending
	MOVEM TT,8CTYOT		;Store in comm area
	CONI TT			;Read 8080
	TRO TT,80INT		;Hey you! Get this!
	CONO (TT)		;Interrupt 8080
	SKIPE 8CTYOT		;Wait for completion
	 JRST .-1
	RET

IFN 0,[
;Wait for console char TT from the 8080.
TYI:	SKIPN TT,8CTYIN		   ;Chars stored here by 8080.
	 RET
	SETZM 8CTYIN		   ;Remember to clear it.
	ANDI TT,177		   ;Remove crap.
	RET
]; 0

;Type Newline.
CRLF:	MOVEI TT,15
	CALL TYO
	MOVEI TT,12
	CALL TYO
	RET

;Type SIXBIT from T.
TYPSIX:	HRLI T,440600
	MOVEI X,6
TYPSI1:	ILDB TT,T
	JUMPE TT,TYPSIZ
	ADDI TT,40
	CALL TYO
	SOJG X,TYPSI1
TYPSIZ:	RET

;Type ASCIZ from T.
TYPOUT:	HRLI T,440700
TYPOUL:	ILDB TT,T
	JUMPE TT,TYPOUZ
	CALL TYO
	JRST TYPOUL
TYPOUZ:	RET

;Type octal number from T.
OCTPNT:	SETZ TT,
	LSHC T,-3		   ;shift instead of IDIVI, don't forget
	LSH TT,-41		   ;negative! 
	PUSH P,TT		   ;push remainder
	SKIPE T			   ;done?
	  CALL OCTPNT		   ;no compute next one
OCTPN1:	POP P,TT		   ;yes, take out in opposite order
	ADDI TT,60		   ;make ascii
	CALL TYO
	RET			   ;and return for the next one.

;;; WRUBR ACBLK+N selects AC block N as current and previous.
ACBLK:	REPEAT 8, <400000+<1100*.RPCNT>>,,0

; Data
LBOOPD==20.

VERSUN:	.FNAM2			; Loader version.
BOOPDL:	BLOCK LBOOPD		; The stack.
START:	0			; Start instruction.

;;; Table of I/O addresses
MTCS1:	0
MTWC:	0
MTBA:	0
MTFC:	0
MTCS2:	0
MTDS:	0
MTER:	0
MTAS:	0
MTCK:	0
MTDB:	0
MTMR:	0
MTDT:	0
MTSN:	0
MTTC:	0
NIOWDS==:.-MTCS1

IOPAGR:	UBAPAG
IOSTAT:	UBASTA

VARIABLES
CONSTANTS

IF1,[	PRINTX /
Bootstrap loader /
	.TYO6 .FNAM2 ]
INFORM [, length]\.-1000
IFG .-2000, .FATAL Bootstrap loader doesn't fit in 512 words.

BLOCK 1000			   ;Pad the loader.
	-1			   ;Force core to exist.

OFFSET 0

END MTBOOT
