TITLE Forth Interest Group  8086 FORTH
NAME FORTH
PAGE 62,132
.SALL
.XCREF

COMMENT \
		Forth Interest Group  8086 FORTH 

		Version 1.0

		Original implementation by Thomas Newman
		made available by the
			FORTH INTEREST GROUP
			P.O. Box 1105
			San Carlos, CA  94070

		Modified by
			Joe Smith
			U. of Penn./Dept. of Chemistry
			34th & Spruce St.
			Philadelphia, PA  19104
			215 898-4797

		Available through
			SIG/86
			c/o Joseph Boykin
			47-4 Sheridan Drive
			Shrewsbury, MA  01545
			617 845-1074

		Latest revision: June, 1983

This is a revision of fig-FORTH which includes the following changes:

	Source compatible with Microsoft's 8086 Macro Assembler

	Macros for dictionary headers

	Complete interface to MS-DOS, including screen files

	Command line arguments are interpreted

	All i/o is redirectable through execution vectors

\
SUBTTL Assembly switches (TRUE/FALSE) and EQUATES
PAGE


INCLUDE	4TH-OPTS.H		;assembly options

; Version number:

FIGREL		EQU	1	;fig release number
FIGREV		EQU	0	;fig revision number
USRVER		EQU	0	;user version number,0-25,printed as A-Z

; Memory allocation parameters:

EM		EQU	0000		;64K top of memory + 1
NSCR		EQU	8		;No. of 1K block buffers
BUFSIZE		EQU	1024		;size of FORTH's disk buffers
US		EQU	80		;User area size ( in bytes )
RTS		EQU	160		;Return stack/TIB size

BUF1		EQU	EM-(NSCR*(BUFSIZE+4))	;first buffer addr.
INITR0		EQU	BUF1-US		;Start of return stack (R0)
INITS0		EQU	INITR0-RTS	;Start of param. stack (S0)

; ASCII characters used

ANUL		EQU	0		;ASCII NUL
BELL		EQU	7		;ASCII bell: ^G
BSOUT		EQU	8		;output backspace: ^H
LF		EQU	10		;ASCII linefeed
FF		EQU	12		;ASCII form feed
ACR		EQU	13		;ASCII carriage return
BSIN		EQU	127		;input delete char: DEL

SUBTTL Main entry points and COLD start data
PAGE +


INCLUDE	4TH-LIB.MAC		;Required support macros

; Note: FORTH only uses one segment, and runs as a .COM program

MAIN		SEGMENT
		ASSUME	CS:MAIN,DS:MAIN,SS:MAIN,ES:MAIN

		ORG	100H

ORIG: 		NOP
		JMP	CLD		;vector to COLD start
		NOP
		JMP	WRM		;vector to WARM start


		DB	FIGREL		;version # printed by COLD
		DB	FIGREV
		DB	USRVER
		DB	0EH		;version attributes
		DW	LASTNFA		;top word in FORTH vocabulary
		DW	BSIN		;backspace recognised by EXPECT
		DW	INITR0		;initial UP

; COLD start moves the following to USER var's. 3-10
; MUST BE IN SAME ORDER AS USER VARIABLES

		DW	INITS0		;  S0
		DW	INITR0		;  R0
		DW	INITS0		;  TIB
		DW	32		;  WIDTH
		DW	0		;  WARNING
		DW	INITDP		;  FENCE
		DW	INITDP		;  DP
		DW	FORTH+6		;  VOC-LINK

; CPU id printed by COLD

	IF	_ALIGN
		DD	0B3260005H	;"8086" ( in base 36 ! )
	ELSE
		DD	0B3280005H	;"8088" ( in base 36 ! )
	ENDIF

UP 		DW	INITR0		;user area pointer
RPP 		DW	INITR0		;return stack pointer

	$REPORT	<Boot parameters completed>
	$REPORT	<LIMIT	=>,%EM
	$REPORT	<FIRST	=>,%BUF1
	$REPORT	<R0	=>,%INITR0
	$REPORT	<S0	=>,%INITS0

SUBTTL FORTH register usage
PAGE +


COMMENT \

FORTH	8086	Preservation rules
------------------------------------------------------------------------
IP	SI	Interpreter pointer
		Must be preserved across words
		NOTE: Also preserve the direction flag (always UP)!

W	DX	Working register
		Jump to label DPUSH will push contents onto
		the parameter stack before falling into APUSH

SP	SP	Parameter stack pointer
		Must be preserved across words

RP	BP	Return stack pointer
		Must be preserved across words

	AX	General purpose register
		Jump to label APUSH pushes contents onto
		the parameter stack

	CS,DS,SS
		Must be preserved across words

		All other registers are available

\
SUBTTL Comment conventions
PAGE


COMMENT \

==	means	is equal to
:=	means	is assigned the value

name	==	address of name
(name)	==	contents at address name
((name))==	contents at address contained in name

NFA	==	Name Field Address
LFA	==	Link Field Address
CFA	==	Code Field Address
PFA	==	Parameter Field Address

S1,S2	==	parameter stack: top item, next item
R1,R2	==	return stack: top word, next word

LSB	==	Least Significant Bit
MSB	==	Most Significant Bit
LB,LW	==	Low Byte, Low Word
HB,HW	==	High Byte, High Word
\

	IF	_DEBUG
SUBTTL Debugging support
PAGE +

BIP 		DW	0	;breakpoint start address
BIPE 		DW	0	;breakpoint end address

COMMENT \

BIP	BIPE	effect
-----	-----	-------------------------------------------
0	?	trace off
-1	?	trace all NEXT calls
addr1	0	trace addr1 only
addr1	addr2	trace NEXT calls between addr1 and addr2

NOTE: addr1/addr2 can't be CFA's
\

; NEXT with code to trace FORTH word execution

TNEXT: 		PUSHF		;save executing word's data
		PUSH	AX
		MOV	AX,BIP	;addr1
		OR	AX,AX
		JZ	TNEXT2	;no trace if addr1==0
		CMP	AX,-1
		JZ	TNEXT1	;trace all
		CMP	AX,SI
		JZ	TNEXT1	;in range, so trace
		JA	TNEXT2	;not in range
		MOV	AX,BIPE
		OR	AX,AX
		JZ	TNEXT2	;trace addr1 only
		CMP	AX,SI
		JB	TNEXT2	;no longer in range

; Pause on address

TNEXT1: 	POP	AX	;restore executing word's reg's.
		POPF
		INT	3	;Break to DEBUG
BREAK: 		JMP	SHORT TNEXT3	;continue

; No pause, restore registers

TNEXT2: 	POP	AX
		POPF
TNEXT3: 	LODSW		;AX:=(IP)
		MOV	BX,AX
		JMP	SHORT NEXT1

	$REPORT	<Debug trace included>
	ENDIF
SUBTTL Inner interpreter, DPUSH, APUSH entry points
PAGE +


DPUSH: 		PUSH	DX	;common entry point; DX, AX to S2, S1
APUSH: 		PUSH	AX	;common entry point, AX to S1

NEXT:
	IF	_DEBUG
		JMP	TNEXT
	ELSE
		LODSW			; AX:=(IP), IP:=IP+1
		MOV	BX,AX
	ENDIF

NEXT1: 		MOV	DX,BX
		INC	DX		; W:=(IP)+1
		JMP	WORD PTR [BX]	;to CFA
SUBTTL FORTH dictionary 
PAGE +


;=C   LIT	push an inline literal			-- n

		$CODE	83H,LI,T,LIT
		LODSW
		JMP	APUSH

;=C   EXECUTE	executes the word at CFA		CFA -- ?

		$CODE	87H,EXECUT,E,EXEC
		POP	BX
		JMP	NEXT1

;=C   BRANCH	adds an inline offset to IP		--

		$CODE	86H,BRANC,H,BRAN
BRAN1:		ADD	SI,[SI]		; IP:=IP+(IP)
		JMP	NEXT

;=C   0BRANCH	branch if f is zero			f --

		$CODE	87H,0BRANC,H,ZBRAN
		POP	AX
		OR	AX,AX
		JZ	BRAN1		;f==0, so branch
		INC	SI		;point IP to next word
		INC	SI
		JMP	NEXT

;=C   (LOOP)	execution time loop code		--

		$CODE	86H,(LOOP,),XLOOP
		MOV	BX,1
XLOO1: 		ADD	[BP],BX		;R1:=R1+1
		MOV	AX,[BP]
		SUB	AX,2[BP]	;compare new index to limit
		XOR	AX,BX
		JS	BRAN1		;branch - keep looping

		ADD	BP,4		;end of loop, drop R1, R2
		INC	SI		;skip branch offset
		INC	SI
		JMP	NEXT

;=C   (+LOOP)	(LOOP) with increment on S1		n --

		$CODE	87H,(+LOOP,),XPLOO
		POP	BX
		JMP	XLOO1

;=C   (DO)	run-time loop initialization		n2 n1 --

		$CODE	84H,(DO,),XDO
		POP	DX		;index
		POP	AX		;limit
		XCHG	BP,SP		;put them on the return stack
		PUSH	AX		;R2:=S2
		PUSH	DX		;R1:=S2
		XCHG	BP,SP
		JMP	NEXT

;=C   I		leave index value			-- n

		$CODE	81H,,I,IDO
		MOV	AX,[BP]		;AX:=R1 (index)
		JMP	APUSH

;=C   DIGIT	convert c to binary using base n1	c n1 -- [n2] f

		$CODE	85H,DIGI,T,DIGIT
		POP	DX		;base
		POP	AX		;ASCII char
		SUB	AL,'0'
		JB	DIGI2		;error if c < '0'
		CMP	AL,9
		JBE	DIGI1		;number 0-9
		SUB	AL,7
		CMP	AL,10		;number A-Z?
		JB	DIGI2		;no, error
DIGI1: 		CMP	AL,DL
		JAE	DIGI2		;error if digit > base
		SUB	DX,DX
		MOV	DL,AL		;new binary number
		MOV	AL,1		;f==TRUE if OK
		JMP	DPUSH
DIGI2: 		SUB	AX,AX
		JMP	APUSH		;f==FALSE if error

PAGE


;=C*  (FIND)	dictionary search primtive		a1 NFA -- [PFA b] f

		$CODE	86H,(FIND,),PFIND
		MOV	AX,DS
		MOV	ES,AX		;DI defaults to ES
		POP	BX		;BX:=NFA
		POP	CX		;CX:=a1 ( search string )

PFIN1: 		MOV	DI,CX		;get addr
		MOV	AL,[BX]		;get word length
		MOV	DL,AL
		XOR	AL,[DI]
		AND	AL,3FH		;check lengths+smudge bit
		JNZ	PFIN5		;lengths differ

PFIN2: 		INC	BX		;length matches, check chars
		INC	DI
		MOV	AL,[BX]
		XOR	AL,[DI]
		ADD	AL,AL		;this checks bit 8
		JNZ	PFIN5		;chars differ
		JNB	PFIN2		;OK so far

	IF	_ALIGN
		ADD	BX,6		;Compute PFA ( could be 5 or 6)
		AND	BX,0FFFEH	;Clear LSB to align
	ELSE
		ADD	BX,5
	ENDIF
		;end of word (bit 8 set), a match

		PUSH	BX		;S3:=PFA
		MOV	AX,1		;f:=TRUE
		SUB	DH,DH		;DX:=length byte
		JMP	DPUSH		;S2:=f, S1:=l

		; No match, try the next dictionary entry

PFIN5: 		INC	BX		;advance BX to LFA
		JB	PFIN6		;bit 8 set - must be the end
		MOV	AL,[BX]
		ADD	AL,AL
		JMP	PFIN5
PFIN6:

	IF	_ALIGN
		INC	BX		;This could be one too many...
		AND	BX,0FFFEH	;Clear LSB to align
	ENDIF

		MOV	BX,[BX]		;BX:=(LFA)
		OR	BX,BX		;start of dictionary?
		JNZ	PFIN1		;no, keep looking
		MOV	AX,0		;no match, f:=FALSE
		JMP	APUSH		;S1:=f

PAGE


;=C   ENCLOSE	text scanning primitive			a1 c -- a1 n1 n2 n3

		$CODE	87H,ENCLOS,E,ENCL
		POP	AX		;delimiter c
		POP	BX		;text addr
		PUSH	BX		;S4:=text addr
		MOV	AH,0
		MOV	DX,-1		;DX is counter
		DEC	BX		;BX points to text

		; Scan to first non-delimiter

ENCL1: 		INC	BX		;next char
		INC	DX		;count it
		CMP	AL,[BX]		;delimiter found?
		JZ	ENCL1		;not yet, keep looking
		PUSH	DX		;yes, S3:=count
		CMP	AH,[BX]		;found NUL char?
		JNZ	ENCL2		;no...
		MOV	AX,DX		;yes, n2:=n3
		INC	DX		;n3:=n3+1
		JMP	DPUSH		;exit

		; Enclose text to first delimiter

ENCL2: 		INC	BX
		INC	DX
		CMP	AL,[BX]
		JZ	ENCL4		;found it...
		CMP	AH,[BX]		;NUL?
		JNZ	ENCL2		;no, keep looking

		; Found NUL at end of text

ENCL3: 		MOV	AX,DX
		JMP	DPUSH

		; Found delimiter

ENCL4: 		MOV	AX,DX		;count to delimiter
		INC	AX		;count to first > delimiter
		JMP	DPUSH		;S2, S1

SUBTTL Input/output primitives
PAGE


;=:*  EMIT	char output				c --

		$COLON	84H,EMI,T,EMIT
		DW	TICKEMIT,	AT,	EXEC
		DW	ONE,OUTT
		DW	PSTOR,SEMIS

;=:*  KEY	char input				-- c

		$COLON	83H,KE,Y,KEY
		DW	TICKEY,	AT,	EXEC,	SEMIS

;=C   ?TERMINAL	console status				-- f

		$CODE	89H,?TERMINA,L,QTERM
		JMP	PQTER

;=:*  CR	output carriage return/line feed	--

		$COLON 82H,C,R,CR
		DW	TICKCR,	AT,	EXEC,	SEMIS

SUBTTL
PAGE


;=C   CMOVE	byte block move				a1 a2 n --

		$CODE	85H,CMOV,E,CMOVE
		CLD			;count up
		MOV	BX,SI		;save IP
		POP	CX		;move count
		POP	DI		;a2 ( destination )
		POP	SI		;a1 ( source )
		MOV	AX,DS
		MOV	ES,AX		;intrasegment only
	REP	MOVSB			;all that for this?
		MOV	SI,BX
		JMP	NEXT

;=C   U*	unsigned mixed multiply			u1 u2 -- ud

		$CODE	82H,U,*,USTAR
		POP	AX
		POP	BX
		MUL	BX
		XCHG	AX,DX		;S1:=MSW, S2:=LSW
		JMP	DPUSH

;=C   U/	unsigned mixed divide			ud u -- urem uquot

		$CODE	82H,U,/,USLAS
		POP	BX		;BX:=divisor
		POP	DX		;DX:=MSW of dividend
		POP	AX		;AX:=LSW
		CMP	DX,BX		;0?
		JNB	DZERO
		DIV	BX
		JMP	DPUSH
DZERO: 		MOV	AX,-1		;divide by zero! leave -1
		MOV	DX,AX
		JMP	DPUSH

;=C   AND	bitwise AND				n n -- n

		$CODE	83H,AN,D,ANDD
		POP	AX
		POP	BX
		AND	AX,BX
		JMP	APUSH

;=C   OR	bitwise OR				n n -- n

		$CODE	82H,O,R,ORR
		POP	AX
		POP	BX
		OR	AX,BX
		JMP	APUSH

;=C   XOR	bitwise exclusive OR			n n -- n

		$CODE	83H,XO,R,XORR
		POP	AX
		POP	BX
		XOR	AX,BX
		JMP	APUSH

;=C   SP@	push current parameter stack pointer	-- SP

		$CODE	83H,SP,@,SPAT
		MOV	AX,SP
		JMP	APUSH

;=C   SP!	reset parameter stack			? --

		$CODE	83H,SP,!!!!,SPSTO
		MOV	BX,UP		;USER variable base addr
		MOV	SP,6[BX]	;S0 is 6 bytes above base
		JMP	NEXT

;=C   RP@	push current RP onto parameter stack	-- RP

		$CODE	83H,RP,@,RPAT
		MOV	AX,BP
		JMP	APUSH

;=C   RP!	reset return stack			? --

		$CODE	83H,RP,!!!!,RPSTO
		MOV	BX,UP		;USER variable base addr
		MOV	BP,8[BX]	;offset of R0 is 8
		JMP	NEXT

;=C   ;S	end of screen or run time colon word	--

		$CODE	82H,!!!;,S,SEMIS
		MOV	SI,[BP]		;IP:=R1 - pop return stack
		INC	BP		;adjust RP
		INC	BP
		JMP	NEXT

;=C   LEAVE	force loop exit				--

		$CODE	85H,LEAV,E,LEAVE
		MOV	AX,[BP]
		MOV	2[BP],AX	;limit:=index
		JMP	NEXT

;=C   >R	push parm. stack to return stack	n --

		_NFA	= $
		DB	82H,'>','R'+80H		;macro can't handle it!
		$LINKS	$+2,TOR

		POP	BX		;BX:=S1
		DEC	BP		;adjust RP
		DEC	BP
		MOV	[BP],BX		;push it
		JMP	NEXT

;=C   R>	pop return stack to parm. stack		-- n

		$CODE	82H,R,!!!>,FROMR
		MOV	AX,[BP]		;AX:=R1
		INC	BP		;adjust RP
		INC	BP
		JMP	APUSH

;=C   R		top of return stack to parm. stack	-- n

		$NAME	81H,,R
		$LINKS	IDO+2,RR	;synonym for I

;=C   0=	test top of stack for zero		n -- f

		$CODE	82H,0,=,ZEQU
		POP	AX
		OR	AX,AX
		MOV	AX,1
		JZ	ZEQU1
		DEC	AX
ZEQU1:		JMP	APUSH

;=C   0<	test top of stack for negative value	n -- f

		$CODE	82H,0,!!!<,ZLESS
		POP	AX
		OR	AX,AX
		MOV	AX,1
		JS	ZLESS1
		DEC	AX
ZLESS1:		JMP	APUSH

;=C   +		16-bit addition				n1 n2 -- nsum

		$CODE	81H,,+,PLUS
		POP	AX
		POP	BX
		ADD	AX,BX
		JMP	APUSH

;=C   D+	32-bit addition				d1 d2 -- dsum

		$CODE	82H,D,+,DPLUS
		POP	AX		;AX:=d2 MSW
		POP	DX		;DX:=d2 LSW
		POP	BX		;BX:=d1 MSW
		POP	CX		;CX:=d1 LSW
		ADD	DX,CX		;add low words
		ADC	AX,BX		;add high words with carry
		JMP	DPUSH

;=C   MINUS	16-bit two's complement			n -- -n

		$CODE	85H,MINU,S,MINUS
		POP	AX
		NEG	AX
		JMP	APUSH

;=C   DMINUS	32-bit two's complement			d -- -d

		$CODE	86H,DMINU,S,DMINU
		POP	BX		;MSW
		POP	CX		;LSW
		SUB	AX,AX
		MOV	DX,AX
		SUB	DX,CX		;subtract from 0
		SBB	AX,BX		;again for high word
		JMP	DPUSH

;=C   OVER	copy second stack item to top		n1 n2 -- n1 n2 n1

		$CODE	84H,OVE,R,OVER
		POP	DX
		POP	AX
		PUSH	AX
		JMP	DPUSH

;=C   DROP	throw out top stack item		n --

		$CODE	84H,DRO,P,DROP
		POP	AX
		JMP	NEXT

;=C   SWAP	exchange top two stack items		n1 n2 -- n2 n1

		$CODE	84H,SWA,P,SWAP
		POP	DX
		POP	AX
		JMP	DPUSH

;=C   DUP	duplicate the top stack item		n -- n n

		$CODE	83H,DU,P,DUPP
		POP	AX
		PUSH	AX
		JMP	APUSH

;=C   2DUP	duplicate the top two stack items	n1 n2 -- n1 n2 n1 n2

		$CODE	84H,2DU,P,TDUP
		POP	AX
		POP	DX
		PUSH	DX
		PUSH	AX
		JMP	DPUSH

;=C   +!	add to a memory location		n addr --

		$CODE	82H,+,!!!!,PSTOR
		POP	BX
		POP	AX
		ADD	[BX],AX
		JMP	NEXT

;=C   TOGGLE	toggle bits at a memory location	n addr --

		$CODE	86H,TOGGL,E,TOGGL
		POP	AX
		POP	BX
		XOR	[BX],AL
		JMP	NEXT

;=C   @		push memory location to stack		addr -- n

		$CODE	81H,,@,AT
		POP	BX
		MOV	AX,[BX]
		JMP	APUSH

;=C   C@	push byte location to stack		addr -- b

		$CODE	82H,C,@,CAT
		POP	BX
		MOV	AL,[BX]
		SUB	AH,AH
		JMP	APUSH

;=C   2@	fetch 32-bit number			addr -- d

		$CODE	82H,2,@,TAT
		POP	BX
		MOV	AX,[BX]		;LSW at addr
		MOV	DX,[BX+2]	;MSW at addr+2
		JMP	DPUSH

;=C   !		pop stack to memory - "store"		n addr --

		$CODE	81H,,!!!!,STORE
		POP	BX
		POP	AX
		MOV	[BX],AX
		JMP	NEXT

;=C   C!	byte store - "see-store"		b addr --

		$CODE	82H,C,!!!!,CSTOR
		POP	BX
		POP	AX
		MOV	[BX],AL
		JMP	NEXT

;=C   2!	32-bit store				d addr --

		$CODE	82H,2,!!!!,TSTOR
		POP	BX
		POP	AX
		MOV	[BX],AX		;move LSW to addr
		POP	AX
		MOV	2[BX],AX	;move MSW to addr+2
		JMP	NEXT
SUBTTL Defining words
PAGE


;=C   :		begin colon definition			--

		$COLON	0C1H,,:
		DW	QEXEC,	SCSP	;compile time code
		DW	CURR,	AT
		DW	CONT,	STORE
		DW	CREAT,	RBRAC
		DW	PSCOD
					;run time code
DOCOL: 		INC	DX		;W:=W+1
		DEC	BP
		DEC	BP		;RP:=RP-2
		MOV	[BP],SI		;push IP onto return stack
		MOV	SI,DX		;IP:=W
		JMP	NEXT

;=:   ;		end colon definition			--

		$COLON	0C1H,,!!!;
		DW	QCSP,	COMP
		DW	SEMIS,	SMUDG
		DW	LBRAC,	SEMIS

;=:   NOOP	do nothing - no operation		--

		$COLON	84H,NOO,P,NOOP
		DW	SEMIS

;=:   CONSTANT	define a symbolic constant		n --

		$COLON	88H,CONSTAN,T,CON
		DW	CREAT,	SMUDG	;compile time code
		DW	COMMA,	PSCOD
					;run time code
DOCON: 		INC	DX		;point W to PFA
		MOV	BX,DX
		MOV	AX,[BX]		;get data at PFA
		JMP	APUSH		;here it is!

;=:   VARIABLE	define a symbolic variable		n --

		$COLON	88H,VARIABL,E
		DW	CON,	PSCOD	;compile time code
					;run time code
DOVAR: 		INC	DX		;point W to PFA
		PUSH	DX		;return PFA
		JMP	NEXT

;=:   USER	define a user variable			n --

		$COLON	84H,USE,R
		DW	CON,	PSCOD	;compile time code
					;run time code
DOUSE: 		INC	DX		;point W to PFA
		MOV	BX,DX		;BX:=(PFA)   offset
		MOV	BL,[BX]		;BX:=(PFA)  offset<256
		SUB	BH,BH		;just to be safe...
		MOV	DI,UP		;DI:=UP  (user area base addr)
		LEA	AX,[BX+DI]	;load effective address
		JMP	APUSH		;push address to stack

	$REPORT	<Code-level kernel completed>

SUBTTL Constants and USER variables
PAGE +


;=#   0		zero					-- 0

		$CONST	81H,,0,ZERO
		DW	0

;=#   1		one					-- 1

		$CONST	81H,,1,ONE
		DW	1

;=#   2		two					-- 2

		$CONST	81H,,2,TWO
		DW	2

;=#   3		three					-- 3

		$CONST	81H,,3,THREE
		DW	3

;=#   BL	ASCII blank				-- 32

		$CONST	82H,B,L,BLS
		DW	20H

;=#   C/L	characters per line			-- 64

		$CONST	83H,C/,L,CSLL
		DW	64

;=#   FIRST	address of lowest disk buffer		-- addr

		$CONST	85H,FIRS,T,FIRST
		DW	BUF1

;=#   LIMIT	last available memory address + 1	-- addr

		$CONST	85H,LIMI,T,LIMIT
		DW	EM

;=#   B/BUF	size of disk buffers in bytes		-- 1024

		$CONST	85H,B/BU,F,BBUF
		DW	BUFSIZE

;=#   B/SCR	number of disk buffers per screen	-- 1

		$CONST	85H,B/SC,R,BSCR
		DW	1
SUBTTL
PAGE +


;=:   +ORIGIN	word for accessing data in low memory	n -- addr

		$COLON	87H,+ORIGI,N,PORIG
		DW	LIT,	ORIG
		DW	PLUS,	SEMIS

SUBTTL USER variables
PAGE +


;=U   S0	parameter stack base			-- addr

		$USER	82H,S,0,SZERO
		DW	6		;offset in user area

;=U   R0	return stack base			-- addr

		$USER	82H,R,0,RZERO
		DW	8

;=U   TIB	Terminal Input Buffer address		-- addr

		$USER	83H,TI,B,TIB
		DW	10

;=U   WIDTH	maximum length of word names		-- addr

		$USER	85H,WIDT,H,NWIDTH
		DW	12

;=U   WARNING	switch for error processing: 0, 1, -1	-- addr

		$USER	87H,WARNIN,G,WARN
		DW	14

;=U   FENCE	pointer to protected dictionary		-- addr

		$USER	85H,FENC,E,FENCE
		DW	16

;=U   DP	top address used in dictionary		-- addr

		$USER	82H,D,P,DP
		DW	18

;=U   VOC-LINK	pointer to top vocabulary		-- addr

		$USER	88H,VOC-LIN,K,VOCL
		DW	20

;The following user variables hold CFA's for their
;respective logical functions


;=U+  @KEY	CFA of function to do character input	-- addr

		$USER	84H,@KE,Y,TICKEY
		DW	22

;=U+  @EMIT	CFA of function to do character output	-- addr

		$USER	85H,@EMI,T,TICKEMIT
		DW	24

;=U+  @CR	CFA of function to output newline	-- addr

		$USER	83H,@C,R,TICKCR
		DW	58

;=U+  @BLKRD	CFA of function to read one block	-- addr

		$USER	86H,@BLKR,D,TICKBRD
		DW	26

;=U+  @BLKWRT	CFA of function to write one block	-- addr

		$USER	87H,@BLKWR,T,TICKBWRT
		DW	28

;=U   BLK	current block, 0 if terminal		-- addr

		$USER	83H,BL,K,BLK
		DW	30

;=U   IN	current character in input stream	-- addr

		$USER	82H,I,N,INN
		DW	32

;=U   OUT	count of characters output		-- addr

		$USER	83H,OU,T,OUTT
		DW	34

;=U   SCR	current screen				-- addr

		$USER	83H,SC,R,SCR
		DW	36

;=U   OFFSET	number of lowest block to be used	-- addr

		$USER	86H,OFFSE,T,OFSET
		DW	38

;=U   CONTEXT	current vocabulary for execution	-- addr

		$USER	87H,CONTEX,T,CONT
		DW	40

;=U   CURRENT	current vocabulary for definitions	-- addr

		$USER	87H,CURREN,T,CURR
		DW	42

;=U   STATE	current interpreter state		-- addr

		$USER	85H,STAT,E,STATE
		DW	44

;=U   BASE	current number base for i/o		-- addr

		$USER	84H,BAS,E,BASE
		DW	46

;=U   DPL	Decimal Point Locator 			-- addr

		$USER	83H,DP,L,DPL
		DW	48

;=U   CSP	temporary storage for Current SP	-- addr

		$USER	83H,CS,P,CSPP
		DW	52

;=U   R#	current editing cursor location		-- addr

		$USER	82H,R,#,RNUM
		DW	54

;=U   HLD	text pointer used in number formatting	-- addr

		$USER	83H,HL,D,HLD
		DW	56

	$REPORT	<Constants and user variables completed>

SUBTTL FORTH definitions
PAGE +


;=C   1+	increment the top stack item		n -- n+1

		$CODE	82H,1,+,ONEP
		POP	AX
		INC	AX
		JMP	APUSH

;=C   2+	add 2 to the top stack item		n -- n+2

		$CODE	82H,2,+,TWOP
		POP	AX
		INC	AX
		INC	AX
		JMP	APUSH

;=C+  1-	decrement the top stack item		n -- n-1

		$CODE	82H,1,-,ONEM
		POP	AX
		DEC	AX
		JMP	APUSH

;=C+  2-	subtract 2 from the top stack item	n -- n-2

		$CODE	82H,2,-,TWOM
		POP	AX
		DEC	AX
		DEC	AX
		JMP	APUSH

;=:   HERE	next available dictionary location	-- addr

		$COLON	84H,HER,E,HERE
		DW	DP,	AT,	SEMIS

;=:   ALLOT	reserve n bytes in the dictionary	n --

		$COLON	85H,ALLO,T,ALLOT
		DW	DP,	PSTOR,	SEMIS

;=:   ,		compile n into the dictionary		n --

		$COLON	81H,,!!!,,COMMA
		DW	HERE,	STORE
		DW	TWO,	ALLOT,	SEMIS

;=:   C,	compile a byte into the dictionary	b --

		$COLON	82H,C,!!!,,CCOMM
		DW	HERE,	CSTOR
		DW	ONE,	ALLOT,	SEMIS

;=C   -		16-bit subtraction			n1 n2 -- n1-n2

		$CODE	81H,,-,SUBB
		POP	DX
		POP	AX
		SUB	AX,DX
		JMP	APUSH

;=:   =		test top two items for equality		n1 n2 -- f

		$COLON	81H,,=,EQUAL
		DW	SUBB,	ZEQU,	SEMIS

;=C   <		test for top number > second number	n1 n2 -- f

		$CODE	81H,,!!!<,LESS
		POP	DX
		POP	AX
		MOV	BX,DX
		XOR	BX,AX
		JS	LES1		;signs different
		SUB	AX,DX
LES1: 		OR	AX,AX		;test sign bit
		MOV	AX,0		;assume false
		JNS	LES2		;not less than
		INC	AX		;return true (1)
LES2: 		JMP	APUSH

;=:   U<	unsigned test for top > next item	u1 u2 -- f

		$COLON	82H,U,!!!<,ULESS
		DW	TDUP,	XORR,	ZLESS
			$GO?0	ULES1
		DW	DROP,	ZLESS,	ZEQU
			$GOTO	ULES2
ULES1: 		DW	SUBB,	ZLESS
ULES2: 		DW	SEMIS

;=:   >		test for second item > top of stack	n1 n2 -- f

		$COLON	81H,,!!!>,GREAT
		DW	SWAP,	LESS,	SEMIS

;=C   ROT	bring the third stack item to top	n1 n2 n3 -- n2 n3 n1

		$CODE	83H,RO,T,ROT
		POP	DX
		POP	BX
		POP	AX
		PUSH	BX
		JMP	DPUSH

;=:   SPACE	output a blank				--

		$COLON	85H,SPAC,E,SPACE
		DW	BLS,	EMIT,	SEMIS

;=:   -DUP	duplicate the top number if it isn't 0	n -- n [n]

		$COLON	84H,-DU,P,DDUP
		DW	DUPP
			$GO?0	DDUP1
		DW	DUPP
DDUP1: 		DW	SEMIS

;=:   TRAVERSE	move across a fig-FORTH name field	addr1 n -- addr2

		$COLON	88H,TRAVERS,E,TRAV
		DW	SWAP
TRAV1: 		DW	OVER,	PLUS
		DW	LIT,	7FH
		DW	OVER,	CAT,	LESS
			$GO?0	TRAV1
		DW	SWAP,	DROP,	SEMIS

;=:   LATEST	return the top NFA in CURRENT		-- NFA

		$COLON	86H,LATES,T,LATES
		DW	CURR,	AT,	AT,	SEMIS

;=:   LFA	convert a PFA to LFA			PFA -- LFA

		$COLON	83H,LF,A,LFA
		DW	LIT,	4
		DW	SUBB,	SEMIS

;=:   CFA	convert a PFA to CFA			PFA -- CFA

		$COLON	83H,CF,A,CFA
		DW	TWO,	SUBB,	SEMIS

;=:*  NFA	convert a PFA to NFA			PFA -- NFA

		$COLON	83H,NF,A,NFA
		DW	LIT,	5
		DW	SUBB

	IF	_ALIGN
		DW	DUPP,	CAT
		DW	LIT,	90H,	EQUAL	;90H==NOP!
			$GO?0	NFA1
		DW	ONEM
NFA1:
	ENDIF

		DW	LIT,	-1
		DW	TRAV,	SEMIS

;=:*  PFA	convert a NFA to PFA			NFA -- PFA

		$COLON	83H,PF,A,PFA
		DW	ONE,	TRAV
	IF	_ALIGN
		DW	LIT,	6,	PLUS
		DW	LIT,	-2,	ANDD
	ELSE
		DW	LIT,	5,	PLUS
	ENDIF
		DW	SEMIS

;=:   !CSP	save SP at CSP				--

		$COLON	84H,!!!!CS,P,SCSP
		DW	SPAT,	CSPP
		DW	STORE,	SEMIS

;=:   ?ERROR	issue error message m if f is TRUE	f m --

		$COLON	86H,?ERRO,R,QERR
		DW	SWAP
			$GO?0	QERR1
		DW	ERROR
			$GOTO	QERR2
QERR1: 		DW	DROP
QERR2: 		DW	SEMIS

;=:   ?COMP	issue a message if not compiling	--

		$COLON	85H,?COM,P,QCOMP
		DW	STATE,	AT
		DW	ZEQU,	LIT,	17
		DW	QERR,	SEMIS

;=:   ?EXEC	issue a message if not executing	--

		$COLON	85H,?EXE,C,QEXEC
		DW	STATE,	AT
		DW	LIT,	18
		DW	QERR,	SEMIS

;=:   ?PAIRS	issue a message if n1 <> n2		n1 n2 --

		$COLON	86H,?PAIR,S,QPAIR
		DW	SUBB
		DW	LIT,	19
		DW	QERR,	SEMIS

;=:   ?CSP	issue a message if SP <> (CSP)		--

		$COLON	84H,?CS,P,QCSP
		DW	SPAT,	CSPP,	AT,	SUBB
		DW	LIT,	20
		DW	QERR,	SEMIS

;=:   ?LOADING	issue a message if not loading		--

		$COLON	88H,?LOADIN,G,QLOAD
		DW	BLK,	AT,	ZEQU
		DW	LIT,	22
		DW	QERR,	SEMIS

;=:   COMPILE	compile the following word at run time	--

		$COLON	87H,COMPIL,E,COMP
		DW	QCOMP
		DW	FROMR,	DUPP,	TWOP,	TOR
		DW	AT,	COMMA,	SEMIS

;=:   [		suspend compilation to do calculations	--

		$COLON	0C1H,,[,LBRAC
		DW	ZERO,	STATE,	STORE,	SEMIS

;=:   ]		resume compilation after [		--

		$COLON	81H,,],RBRAC
		DW	LIT,	0C0H
		DW	STATE,	STORE,	SEMIS

;=:   SMUDGE	make the latest definition unFINDable	--

		$COLON	86H,SMUDG,E,SMUDG
		DW	LATES
		DW	LIT,	20H
		DW	TOGGL,	SEMIS

;=:   HEX	set the current number base to 16	--

		$COLON	83H,HE,X
		DW	LIT,	16
		DW	BASE,	STORE,	SEMIS

;=:   DECIMAL	set the current number base to 10	--

		$COLON	87H,DECIMA,L,DECA
		DW	LIT,	10
		DW	BASE,	STORE,	SEMIS

;=:   (;CODE)	run time code for ;CODE			--

		$COLON	87H,(!!!;CODE,),PSCOD
		DW	FROMR,	LATES,	PFA
		DW	CFA,	STORE,	SEMIS

;=:   ;CODE	end colon compilation, start CODE	--

		$COLON	0C5H,!!!;COD,E,SEMIC
		DW	QCSP
		DW	COMP,	PSCOD,	LBRAC
SEMI1		DW	NOOP	; (ASSEMBLER)
		DW	SEMIS

;=:   <BUILDS	define compile time behavior		--

		$COLON	87H,!!!<BUILD,S,BUILD
		DW	ZERO,	CON,	SEMIS

;=:   DOES>	define run time behavior		--

		$COLON	85H,DOES,!!!>,DOES
		DW	FROMR,	LATES,	PFA,	STORE
		DW	PSCOD

DODOE: 		XCHG	BP,SP		;get RP
		PUSH	SI		;RP:=IP
		XCHG	BP,SP
		INC	DX		;point W to PFA
		MOV	BX,DX
		MOV	SI,[BX]		;IP:=(PFA)
		INC	DX
		INC	DX		;W points to PFA
		PUSH	DX
		JMP	NEXT

;=:   COUNT	prepare to type a string		addr -- addr+1 n

		$COLON	85H,COUN,T,COUNT
		DW	DUPP,	ONEP,	SWAP,	CAT,	SEMIS

;=:   TYPE	output n characters beginning at addr	addr n --

		$COLON	84H,TYP,E,TYPES
		DW	DDUP
			$GO?0	TYPE1
		DW	OVER,	PLUS
		DW	SWAP,	XDO
TYPE2: 		DW	IDO,	CAT,	EMIT
			$LOOP	TYPE2
			$GOTO	TYPE3
TYPE1: 		DW	DROP
TYPE3: 		DW	SEMIS

;=:   -TRAILING	adjust addr/n to avoid trailing blanks	addr n1 -- addr n2

		$COLON	89H,-TRAILIN,G,DTRAI
		DW	DUPP,	ZERO,	XDO
DTRA1: 		DW	OVER,	OVER,	PLUS
		DW	ONE,	SUBB,	CAT
		DW	BLS,	SUBB
			$GO?0	DTRA2
		DW	LEAVE
			$GOTO	DTRA3
DTRA2: 		DW	ONE,	SUBB
DTRA3: 			$LOOP	DTRA1
		DW	SEMIS

;=:   (.")	run time code for ."			--

		$COLON	84H,(.!!!",),PDOTQ
		DW	RR
		DW	COUNT,	DUPP,	ONEP
		DW	FROMR,	PLUS,	TOR
		DW	TYPES,	SEMIS

;=:   ."	print the following string		--

		$COLON	0C2H,.,!!!",DOTQ
		DW	LIT,	'"'
		DW	STATE,	AT
			$GO?0	DOTQ1
		DW	COMP
		DW	PDOTQ,	WORDS,	HERE
		DW	CAT,	ONEP,	ALLOT
			$GOTO	DOTQ2
DOTQ1: 		DW	WORDS,	HERE,	COUNT,	TYPES
DOTQ2: 		DW	SEMIS

;=:   EXPECT	input up to n characters to addr	addr n --

		$COLON	86H,EXPEC,T,EXPEC
		DW	OVER,	PLUS,	OVER
		DW	XDO
EXPE1: 		DW	KEY,	DUPP
		DW	LIT,	0EH
		DW	PORIG,	AT,	EQUAL
			$GO?0	EXPE2
		DW	DROP,	DUPP,	IDO
		DW	EQUAL,	DUPP,	FROMR
		DW	TWO,	SUBB,	PLUS
		DW	TOR
			$GO?0	EXPE6
		DW	LIT,	BELL
			$GOTO	EXPE7
EXPE6: 		DW	LIT,	BSOUT,	EMIT
		DW	BLS,	EMIT
		DW	LIT,	BSOUT
EXPE7: 			$GOTO	EXPE3
EXPE2: 		DW	DUPP,	LIT,	ACR
		DW	EQUAL
			$GO?0	EXPE4
		DW	LEAVE,	DROP,	BLS,	ZERO
			$GOTO	EXPE5
EXPE4: 		DW	DUPP
EXPE5: 		DW	IDO
		DW	CSTOR,	ZERO,	IDO,	ONEP
		DW	STORE
EXPE3: 		DW	EMIT
			$LOOP	EXPE1
		DW	DROP,	SEMIS

;=:   QUERY	EXPECT 80 characters to TIB		--

		$COLON	85H,QUER,Y,QUERY
		DW	TIB,	AT
		DW	LIT,	80,	EXPEC
		DW	ZERO,	INN,	STORE,	SEMIS

;=:   <nul>	0 in input: resets interpreter		--

		_NFA	= $
		DB	0C1H,80H	;zero header
		$LINKS	DOCOL

		DW	BLK,	AT
			$GO?0	NULL1
		DW	ONE,	BLK,	PSTOR
		DW	ZERO,	INN,	STORE
		DW	BLK,	AT
		DW	BSCR,	ONE,	SUBB,	ANDD
		DW	ZEQU
			$GO?0	NULL2
		DW	QEXEC,	FROMR,	DROP
NULL2: 			$GOTO	NULL3
NULL1: 		DW	FROMR,	DROP
NULL3: 		DW	SEMIS

;=C   FILL	fill n bytes at address with c		addr n c --

		$CODE	84H,FIL,L,FILL
		POP	AX		;fill char
		POP	CX		;fill count
		POP	DI		;destination address
		MOV	BX,DS
		MOV	ES,BX		;same segment
		CLD			;fill toward higher address
	REP	STOSB			;GO!
		JMP	NEXT

;=:   ERASE	fill n bytes at addr with 0's		addr n --

		$COLON	85H,ERAS,E,ERASEE
		DW	ZERO,	FILL,	SEMIS

;=:   BLANKS	fill n bytes at addr with blanks	addr n --

		$COLON	86H,BLANK,S,BLANK
		DW	BLS,	FILL,	SEMIS

;=:   HOLD	insert char in formatted output		c --

		$COLON	84H,HOL,D,HOLD
		DW	LIT,	-1
		DW	HLD,	PSTOR
		DW	HLD,	AT,	CSTOR,	SEMIS

;=:   PAD	returns addr of the text output buffer	-- addr

		$COLON	83H,PA,D,PAD
		DW	HERE,	LIT,	68,	PLUS,	SEMIS
		DW	PLUS,	SEMIS

;=:   WORD	get a word delimited by char to HERE	c --

		$COLON	84H,WOR,D,WORDS
		DW	BLK,	AT
			$GO?0	WORD1
		DW	BLK,	AT,	BLOCK
			$GOTO	WORD2
WORD1: 		DW	TIB,	AT
WORD2: 		DW	INN,	AT,	PLUS,	SWAP
		DW	ENCL,	HERE
		DW	LIT,	34
		DW	BLANK,	INN,	PSTOR
		DW	OVER,	SUBB,	TOR
		DW	RR,	HERE,	CSTOR
		DW	PLUS,	HERE,	ONEP
		DW	FROMR,	CMOVE,	SEMIS

;=:   (NUMBER)	ASCII to binary conversion primitive	d1 addr1 -- d2 addr2

		$COLON	88H,(NUMBER,),PNUMB
PNUM1: 		DW	ONEP
		DW	DUPP,	TOR
		DW	CAT,	BASE,	AT,	DIGIT
			$GO?0	PNUM2
		DW	SWAP,	BASE,	AT,	USTAR
		DW	DROP,	ROT,	BASE,	AT
		DW	USTAR,	DPLUS
		DW	DPL,	AT,	ONEP
			$GO?0	PNUM3
		DW	ONE,	DPL,	PSTOR
PNUM3: 		DW	FROMR
			$GOTO	PNUM1
PNUM2: 		DW	FROMR,	SEMIS

;=:   NUMBER	convert string at addr to 32-bit number	addr -- d

		$COLON	86H,NUMBE,R,NUMB
		DW	ZERO,	ZERO
		DW	ROT,	DUPP,	ONEP,	CAT
		DW	LIT,	"-",	EQUAL
		DW	DUPP,	TOR,	PLUS
		DW	LIT,	-1
NUMB1: 		DW	DPL,	STORE
		DW	PNUMB
		DW	DUPP,	CAT,	BLS,	SUBB
			$GO?0	NUMB2
		DW	DUPP,	CAT
		DW	LIT,	".",	SUBB
		DW	ZERO,	QERR,	ZERO
			$GOTO	NUMB1
NUMB2: 		DW	DROP,	FROMR
			$GO?0	NUMB3
		DW	DMINU
NUMB3: 		DW	SEMIS

;=:   -FIND	search dictionary for next input word	-- [PFA b] f

		$COLON	85H,-FIN,D,DFIND
		DW	BLS,	WORDS
		DW	HERE,	CONT,	AT,	AT
		DW	PFIND,	DUPP,	ZEQU
			$GO?0	DFIN1
		DW	DROP
		DW	HERE,	LATES,	PFIND
DFIN1: 		DW	SEMIS

;=:   (ABORT)	error function when WARNING is -1	--

		$COLON	87H,(ABORT,),PABOR
		DW	ABORT,	SEMIS

;=:   ERROR	system error handler - n is line no.	n -- [IN BLK]

		$COLON	85H,ERRO,R,ERROR
		DW	WARN,	AT,	ZLESS
			$GO?0	ERRO1
		DW	PABOR
ERRO1: 		DW	HERE,	COUNT,	TYPES
		DW	PDOTQ
		DB	2,"? "
		DW	MESS
		DW	SPSTO
		DW	BLK,	AT,	DDUP
			$GO?0	ERRO2
		DW	INN,	AT,	SWAP
ERRO2: 		DW	QUIT

;=:   ID.	print dictionary name field		NFA --

		$COLON	83H,ID,.,IDDOT
		DW	PAD
		DW	LIT,	32
		DW	LIT,	'_'
		DW	FILL
		DW	DUPP,	PFA,	LFA
		DW	OVER,	SUBB
		DW	PAD,	SWAP,	CMOVE
		DW	PAD,	COUNT
		DW	LIT,	1FH	;use low 5 bits of length

; ID. was changed to clear the MSB of the last char in the name

		DW	ANDD,	DUPP,	PAD,	PLUS
		DW	LIT,	80H,	TOGGL	;Zero the MSB
		DW	TYPES,	SPACE,	SEMIS

;=:*  CREATE	create a dictionary header		--

		$COLON	86H,CREAT,E,CREAT
		DW	DFIND
			$GO?0	CREA1
		DW	DROP,	NFA,	IDDOT
		DW	LIT,	4,	MESS	;"not unique"
		DW	SPACE
CREA1: 		DW	HERE,	DUPP,	CAT
		DW	NWIDTH,	AT,	MIN
		DW	ONEP,	ALLOT
		DW	DUPP
		DW	LIT,	0A0H
		DW	TOGGL			;smudge it
		DW	HERE,	ONE,	SUBB
		DW	LIT,	80H
		DW	TOGGL			;last char has bit 8 set

	IF	_ALIGN
;This section of code forces the body of a compiled FORTH word to
;lie on even addresses.  This allows the threaded CFA's to be
;fetched by the inner interpreter in one bus cycle.  For the 8088
;this means nothing, and the extra space required for alignment
;should be saved by setting _ALIGN to FALSE.  The literal 90H is
;used because MASM uses NOP's to align words.  NFA expects
;90H to be used also.
		DW	LIT,	90H,	CCOMM
		DW	DP,	AT
		DW	LIT,	-2,	ANDD
		DW	DP,	STORE
	ENDIF
		DW	LATES,	COMMA		;compile LFA
		DW	CURR,	AT,	STORE	;update vocabulary
		DW	HERE,	TWOP,	COMMA,	SEMIS	;CFA:=PFA

;=:   [COMPILE]	compile an otherwise immediate word	--

		$COLON	0C9H,[COMPILE,]
		DW	DFIND
		DW	ZEQU,	ZERO,	QERR
		DW	DROP,	CFA,	COMMA,	SEMIS

;=:   LITERAL	compile n to be used at run time	n --

		$COLON	0C7H,LITERA,L,LITER
		DW	STATE,	AT
			$GO?0	LITE1
		DW	COMP,	LIT,	COMMA
LITE1: 		DW	SEMIS

;=:   DLITERAL	compile d to be used at run time	d --

		$COLON	0C8H,DLITERA,L,DLITE
		DW	STATE,	AT
			$GO?0	DLIT1
		DW	SWAP,	LITER,	LITER
DLIT1:		DW	SEMIS

;=:   ?STACK	check if the stack is out of bounds	--

		$COLON	86H,?STAC,K,QSTAC
		DW	SPAT,	SZERO,	AT
		DW	SWAP,	ULESS,	ONE,	QERR	;underflow
		DW	SPAT,	HERE
		DW	LIT,	80H
		DW	PLUS,	ULESS
		DW	LIT,	7
		DW	QERR				;overflow
		DW	SEMIS

;=:   INTERPRET	outer text interpreter			--

		$COLON	89H,INTERPRE,T,INTER
INTE1: 		DW	DFIND			;begin
			$GO?0	INTE2
		DW	STATE,	 AT,	LESS
			$GO?0	INTE3
		DW	CFA,	COMMA		;compile it
			$GOTO	INTE4
INTE3: 		DW	CFA,	EXEC		;execute it
INTE4: 		DW	QSTAC
			$GOTO	INTE5
INTE2: 		DW	HERE,	NUMB,	DPL,	AT,	ONEP
			$GO?0	INTE6
		DW	DLITE			;32-bit number
			$GOTO	INTE7
INTE6: 		DW	DROP,	LITER		;16-bit number
INTE7:		DW	QSTAC
INTE5:			$GOTO	INTE1		;repeat forever

;=:   IMMEDIATE	mark the latest word to be executed	--

		$COLON	89H,IMMEDIAT,E
		DW	LATES
		DW	LIT,	40H	;bit 7 is precedence
		DW	TOGGL,	SEMIS

;=:   VOCABULARY	define a new vocabulary		--

		$COLON	8AH,VOCABULAR,Y
		DW	BUILD
		DW	LIT,	0A081H
		DW	COMMA
		DW	CURR,	AT
		DW	CFA,	COMMA,	HERE,	VOCL
		DW	AT,	COMMA,	VOCL,	STORE
		DW	DOES
DOVOC: 		DW	TWOP,	CONT,	STORE,	SEMIS

;=:   FORTH	FORTH vocabulary header			--

		$DOES	0C5H,FORT,H,FORTH
		DW	DOVOC
		DW	0A081H		;fake a null name field!
		DW	LASTNFA		;link changes as def's are added
		DW	0		;end of voc list

;=:   DEFINITIONS	set CURRENT to CONTEXT		--

		$COLON	8BH,DEFINITION,S,DEFIN
		DW	CONT,	AT
		DW	CURR,	STORE,	SEMIS

;=:   (		begin a comment ended by ')'		--

		$COLON	0C1H,,(
		DW	LIT,	')',	WORDS,	SEMIS

;=:   QUIT	halt execution, reset interpreter	--

		$COLON	84H,QUI,T,QUIT
		DW	ZERO,	BLK,	STORE
		DW	LBRAC
QUIT1: 		DW	RPSTO,	CR,	QUERY
		DW	INTER
		DW	STATE,	AT,	ZEQU
			$GO?0	QUIT2
		DW	PDOTQ
		DB	2,"ok"
QUIT2: 			$GOTO	QUIT1

;=:   ABORT	clear stacks and begin execution	--

		$COLON	85H,ABOR,T,ABORT
		DW	SPSTO,	DECA,	QSTAC,	CR
		DW	DOTCPU,	PDOTQ
		DB	16H,'Fig-FORTH  Version '
		DB	FIGREL+30H, '.', FIGREV+30H
		DW	LIT,	10,	PORIG,	CAT
		DW	LIT,	41H,	PLUS,	EMIT
		DW	FORTH,	DEFIN
		DW	LIT,	0,	PRTER,	STORE	;Reset echo

; The following lines add command line interpretation.
; Any text at 80H is copied to the TIB and interpreted.
; This code should probably go somewhere else, but I never bothered
; to move it...

		DW	LIT,	80H,	COUNT,	DUPP	;anyone here?
			$GO?0	AB1			;no...
		DW	ZERO,	LIT,	80H,	CSTOR	;don't do twice
		DW	TIB,	AT,	DUPP
		DW	LIT,	64,	ERASEE		;ensure NUL end
		DW	SWAP,	CMOVE			;move it
		DW	ZERO,	INN,	STORE
		DW	ZERO,	BLK,	STORE,	LBRAC
		DW	CR,	CR,	INTER		;interpret it
			$GOTO AB2
AB1:		DW	DROP,	DROP			;nothing to do
AB2:		DW	QUIT				;back to normal

; Warm start vector comes here

WRM: 		MOV	SI,OFFSET WRM1
		JMP	NEXT
WRM1		DW	WARM

;=:   WARM	empty disk buffers and abort		--

		$COLON	84H,WAR,M,WARM
		DW	MTBUF,	ABORT

; Cold start vector comes here

CLD: 		MOV	SI,OFFSET CLD1		;initialize IP
		MOV	AX,CS
		MOV	DS,AX			;all in one segment
		MOV	SP,12H[ORIG]		;initialize SP
		MOV	SS,AX
		MOV	ES,AX
		CLD				;SI gets incremented
		MOV	BP,RPP			;init RP

		CALL NEAR PTR SYSINIT	;system dependent initialization

		JMP	NEXT

CLD1 		DW	COLD

;=:*  COLD	full initialization and restart		--

		$COLON	84H,COL,D,COLD
		DW	DRZER,	MTBUF
		DW	FIRST,	USE,	STORE
		DW	FIRST,	PREV,	STORE
		DW	LIT,	ORIG+12H
		DW	LIT,	UP,	AT
		DW	LIT,	6,	PLUS
		DW	LIT,	16,	CMOVE	;USER variables
		DW	LIT,	ORIG+12,AT
		DW	LIT,	FORTH+6,STORE	;vocabulary link

; Initialize i/o vectors

		DW	LIT,	PKEY,	TICKEY,		STORE
		DW	LIT,	PEMIT,	TICKEMIT,	STORE
		DW	LIT,	PCR,	TICKCR,		STORE
		DW	LIT,	BLKRD,	TICKBRD,	STORE
		DW	LIT,	BLKWRT,	TICKBWRT,	STORE

		DW	ABORT

;=C   S->D	convert a 16-bit number to 32-bits	n -- d

		_NFA	= $
		DB	84H,'S->','D'+80H
		$LINKS	$+2,STOD

		POP	DX		;n, becomes LSW of result
		SUB	AX,AX
		OR	DX,DX		;is n negative?
		JNS	STOD1		;no, MSW:=AX=0
		DEC	AX		;yes, MSW:=-1
STOD1: 		JMP	DPUSH		;S1=MSW, S2=LSW

;=:   +-	apply the sign of n2 to n1		n1 n2 -- n3

		$COLON	82H,+,-,PM
		DW	ZLESS
			$GO?0	PM1
		DW	MINUS
PM1: 		DW	SEMIS

;=:   D+-	apply the sign of n to d1		d1 n -- d2

		$COLON	83H,D+,-,DPM
		DW	ZLESS
			$GO?0	DPM1
		DW	DMINU
DPM1: 		DW	SEMIS

;=:   ABS	take the absolute value of n1		n1 -- n2

		$COLON	83H,AB,S,ABBS
		DW	DUPP,	PM,	SEMIS

;=:   DABS	take the absolute value of d1		d1 -- d2

		$COLON	84H,DAB,S,DABS
		DW	DUPP,	DPM,	SEMIS

;=:   MIN	return the smaller of n1 and n2		n1 n2 -- n

		$COLON	83H,MI,N,MIN
		DW	TDUP,	GREAT
			$GO?0	MIN1
		DW	SWAP
MIN1: 		DW	DROP,	SEMIS
;=:   MAX	return the larger of two numbers	n1 n2 -- n

		$COLON	83H,MA,X,MAX
		DW	TDUP,	LESS
			$GO?0	MAX1
		DW	SWAP
MAX1: 		DW	DROP,	SEMIS

;=:   M*	mixed multiplication			n1 n2 -- d

		$COLON	82H,M,*,MSTAR
		DW	TDUP,	XORR,	TOR
		DW	ABBS
		DW	SWAP,	ABBS,	USTAR
		DW	FROMR,	DPM,	SEMIS

;=:   M/	mixed division				d n1 -- nrem nquot

		$COLON	82H,M,/,MSLAS
		DW	OVER,	TOR,	TOR
		DW	DABS
		DW	RR,	ABBS,	USLAS
		DW	FROMR,	RR,	XORR
		DW	PM,	SWAP,	FROMR
		DW	PM,	SWAP,	SEMIS

;=:   *		16-bit signed multipication		n1 n2 -- n1*n2

		$COLON	81H,,*,STAR
		DW	MSTAR,	DROP,	SEMIS

;=:   /MOD	16-bit signed division with remainder	n1 n2 -- nrem nquot

		$COLON	84H,/MO,D,SLMOD
		DW	TOR,	STOD,	FROMR
		DW	MSLAS,	SEMIS

;=:   /		16-bit signed division			n1 n2 -- nquot

		$COLON	81H,,/,SLASH
		DW	SLMOD,	SWAP,	DROP,	SEMIS

;=:   MOD	16-bit modulo division			n1 n2 -- nrem

		$COLON	83H,MO,D,MODD
		DW	SLMOD,	DROP,	SEMIS

;=:   */MOD	scale n1 by the ratio of n2 to n3	n1 n2 n3 -- nrem nquot

		$COLON	85H,*/MO,D,SSMOD
		DW	TOR,	MSTAR,	FROMR
		DW	MSLAS,	SEMIS

;=:   */	scale n1 by the ratio of n2 to n3	n1 n2 n3 -- nquot

		$COLON	82H,*,/,SSLA
		DW	SSMOD,	SWAP,	DROP,	SEMIS

;=:   M/MOD	mixed unsigned scaler			ud1 u -- urem udquot

		$COLON	85H,M/MO,D,MSMOD
		DW	TOR,	ZERO,	RR,	USLAS
		DW	FROMR,	SWAP,	TOR
		DW	USLAS,	FROMR,	SEMIS

;=:   (LINE)	convert a line/screen to addr/count	l s -- addr count

		$COLON	86H,(LINE,),PLINE
		DW	TOR
		DW	LIT,	64
		DW	BBUF,	SSMOD
		DW	FROMR,	BSCR,	STAR
		DW	PLUS
		DW	BLOCK,	PLUS
		DW	LIT,	64,	SEMIS

;=:   .LINE	type line n1 in screen n2		n1 n2 --

		$COLON	85H,.LIN,E,DLINE
		DW	PLINE,	DTRAI,	TYPES,	SEMIS

;=:   MESSAGE	type error message n			n --

		$COLON	87H,MESSAG,E,MESS
		DW	WARN,	AT
			$GO?0	MESS1
		DW	DDUP
			$GO?0	MESS2
		DW	LIT,	4
		DW	OFSET,	AT,	BSCR,	SLASH
		DW	SUBB,	DLINE,	SPACE
MESS2: 			$GOTO	MESS3
MESS1: 		DW	PDOTQ
		DB	6,"MSG # "
		DW	DOT
MESS3: 		DW	SEMIS

	$REPORT	<FORTH kernel completed>

INCLUDE	4TH-SYSD.ASM			;System dependent code

SUBTTL Disk interface words
PAGE +

;=?   DRIVE	disk drive last accessed		-- addr

		$VAR	85H,DRIV,E,DRIVE
		DW	0

;=?+  RECORD	disk record last accessed		-- addr

		$VAR	86H,RECOR,D,REC
		DW	0

;=?+  DTA	disk transfer address last used		-- addr

		$VAR	83H,DT,A,DTA
		DW	FIRST

;=?   USE	pointer to disk buffer to use next	-- addr

		$VAR	83H,US,E,USE
		DW	BUF1

;=?   PREV	pointer to disk buffer last accessed	-- addr

		$VAR	84H,PRE,V,PREV
		DW	BUF1

;=#   #BUFF	total number of block buffers		-- n

		$CONST	85H,#BUF,F,NOBUF
		DW	NSCR

;=?   DISK-ERROR	status of last disk operation	-- addr

		$VAR	8AH,DISK-ERRO,R,DSKERR
		DW	0

;=?*  PRINTER	flag controlling printer		-- addr

		$VAR	87H,PRINTE,R,PRTER
		DW	0

;Block read/write words modified to use execution vectors.
;The functions called by BLOCK-READ/-WRITE have the following stack
;effect: ( addr blk -- ) and set DISK-ERROR accordingly.

;=:+  BLOCK-READ	read one block to addr		addr blk --

		$COLON	8AH,BLOCK-REA,D,BLOCKRD
		DW	TICKBRD,	AT,	EXEC,	SEMIS

;=:+  BLOCK-WRITE	write one block from addr	addr blk --

		$COLON	8BH,BLOCK-WRIT,E,BLOCKWRT
		DW	TICKBWRT,	AT,	EXEC,	SEMIS

;=:*  +BUF	advance addr to next buffer		addr1 -- addr2

		$COLON	84H,+BU,F,PBUF
		DW	BBUF,	TWOP,	TWOP	;B/BUF+4
		DW	PLUS,	DUPP,	LIMIT,	EQUAL
			$GO?0	PBUF1
		DW	DROP,	FIRST
PBUF1: 		DW	DUPP,	PREV,	AT
		DW	SUBB,	SEMIS

;=:   UPDATE	mark PREV buffer to be saved		--

		$COLON	86H,UPDAT,E,UPDAT
		DW	PREV,	AT,	AT
		DW	LIT,	8000H
		DW	ORR
		DW	PREV,	AT,	STORE,	SEMIS

;=:*  EMPTY-BUFFERS	wipe out disk buffers		--

		$COLON	8DH,EMPTY-BUFFER,S,MTBUF
		DW	FIRST,	LIMIT,	OVER
		DW	SUBB,	ERASEE
;Modified so that emptied buffers won't look like block 0:
;instead, they're all assigned to block 32767.  If you want to
;use FORTH on a disk that big - TOO BAD!
		DW	LIT,	7FFFH
		DW	NOBUF,	ONEP,	ZERO,	XDO
MTBUF1:		DW	DUPP,	BUFFE,	DROP
			$LOOP	MTBUF1
		DW	DROP,	SEMIS

;Words added to save buffers:

;=:+  SAVBUF	saves buffer at addr if updated		addr --

		$COLON	86H,SAVBU,F,SAVBUF
		DW	DUPP,	TOR,	AT,	ZLESS
			$GO?0	SVBF1		;not updated, return
		DW	RR,	TWOP,	RR,	AT
		DW	LIT,	7FFFH,	ANDD	;15-bits only!
		DW	ZERO,	RSLW		;write it
		DW	DSKERR,	AT,	ZEQU
			$GO?0	SVBF1		;don't un-update if error
		DW	RR,	ONEP		;high byte!
		DW	LIT,	80H,	TOGGL	;un-update buffer
SVBF1:		DW	FROMR,	DROP,	SEMIS

;=:+  SAVE-BUFFERS	flush buffers but don't empty	--

		$COLON	8CH,SAVE-BUFFER,S,SAVBUFS
		DW	PREV,	AT
SVBFS1:		DW	PBUF,	OVER,	SAVBUF,	ZEQU
			$GO?0	SVBFS1
		DW	DROP,	SEMIS

;=:*  BUFFER	assign an available buffer to block n	n -- addr

;BUFFER changed to write out ALL dirty buffers when one is found.

		$COLON	86H,BUFFE,R,BUFFE
		DW	USE,	AT,	DUPP,	TOR
BUFF1: 		DW	PBUF
			$GO?0	BUFF1		;dont use PREV
		DW	USE,	STORE		;use this one NEXT!
		DW	RR,	AT,	ZLESS	;found a dirty one?
			$GO?0	BUFF2		;no
		DW	SAVBUFS			;yes, save ALL
BUFF2:		DW	RR,	STORE		;set header to n
		DW	RR,	PREV,	STORE	;this is now PREV
		DW	FROMR,	TWOP,	SEMIS	;leave data addr

;=:*  BLOCK	get block n				n -- addr

		$COLON	85H,BLOC,K,BLOCK
		DW	OFSET,	AT,	PLUS,	TOR	;get n+offset
		DW	PREV,	AT,	DUPP		;look in PREV first
		DW	AT,	RR,	SUBB
		DW	DUPP,	PLUS			;throw out high bit
			$GO?0	BLOC1			;n is in PREV
BLOC2: 		DW	PBUF,	ZEQU			;check next buffer
			$GO?0	BLOC3			;found it
		DW	DROP,	RR			;not in buffer
		DW	BUFFE,	DUPP			;get a buffer
		DW	RR,	ONE,	RSLW		;read blk
		DW	TWO,	SUBB			;leave buffer addr
BLOC3: 		DW	DUPP,	AT,	RR,	SUBB	;check the buffer
		DW	DUPP,	PLUS,	ZEQU
			$GO?0	BLOC2
		DW	DUPP,	PREV,	STORE		;either found it or read it
BLOC1: 		DW	FROMR,	DROP			;return
		DW	TWOP,	SEMIS

;T&SCALC now done by D&RCALC in SYSD.ASM file...

;=:*  R/W	block read/write, f=1=write, f=2=read	addr blk f --

		$COLON	83H,R/,W,RSLW
;Modified to simply pass the address and blk to the R/W functions
			$GO?0	RSLW1
		DW	BLOCKRD
			$GOTO	RSLW2
RSLW1:		DW	BLOCKWRT
RSLW2:		DW	DSKERR,	AT,	DDUP
			$GO?0	RSLW5		;OK
		DW	ZLESS
			$GO?0	RSLW3
		DW	LIT,	9		;Write error
			$GOTO	RSLW4
RSLW3:		DW	LIT,	8		;Read error
RSLW4:		DW	LIT,	7FFFH		;Set buffer to 32767
		DW	PREV,	AT,	STORE	; to mark as bad
		DW	WARN,	AT,	ZLESS	;If WARNING<0 then
			$GO?0 RSLW6		;assume he can handle it
			$GOTO RSLW7		;otherwise,
RSLW6:		DW	ZERO,	WARN,	STORE	;don't try to read!
RSLW7:		DW	QERR
RSLW5:		DW	SEMIS

;=:*  FLUSH	empty buffers, saving changed ones	--

		$COLON	85H,FLUS,H,FLUSH
		DW	NOBUF,	ONEP
		DW	ZERO,	XDO
FLUS1: 		DW	LIT,	7FFFH,	BUFFE,	DROP
			$LOOP	FLUS1
		DW	SEMIS

;=:   LOAD	interpret screen n			n --

		$COLON	84H,LOA,D
		DW	BLK,	AT,	TOR
		DW	INN,	AT,	TOR
		DW	ZERO,	INN,	STORE
		DW	BSCR,	STAR,	BLK,	STORE
		DW	INTER
		DW	FROMR,	INN,	STORE
		DW	FROMR,	BLK,	STORE
		DW	SEMIS

;=:   -->	continue with next screen		--

		$COLON	0C3H,--,!!!>
		DW	QLOAD
		DW	ZERO,	INN,	STORE
		DW	BSCR,	BLK,	AT
		DW	OVER,	MODD,	SUBB
		DW	BLK,	PSTOR,	SEMIS
SUBTTL
PAGE +


;=:   '		find next input word in dictionary	-- PFA

		_NFA	= $
		DB	0C1H,"'"+80H
		$LINKS	DOCOL,TICK

		DW	DFIND,	ZEQU
		DW	ZERO,	QERR
		DW	DROP,	LITER,	SEMIS

;=:*  FORGET	chop off the top of the dictionary	--

		$COLON	86H,FORGE,T
		DW	CURR,	AT
		DW	CONT,	AT
		DW	SUBB
		DW	LIT,	24,	QERR	;"declare vocabulary"
		DW	TICK,	DUPP
		DW	FENCE,	AT,	ULESS	;note change from fig
		DW	LIT,	21,	QERR	;"in protected dictionary"
		DW	DUPP
		DW	NFA,	DP,	STORE
		DW	LFA,	AT
		DW	CONT,	AT,	STORE,	SEMIS
SUBTTL Control flow structures
PAGE

;=:   BACK	compile a backward branch offset	target --

		$COLON	84H,BAC,K,BACK
		DW	HERE,	SUBB
		DW	COMMA,	SEMIS

;=:   BEGIN	starting point of looping structures	-- HERE 1

		$COLON	0C5H,BEGI,N
		DW	QCOMP
		DW	HERE,	ONE,	SEMIS

;=:   ENDIF	end of IF..ELSE..THEN structure		addr 2 --

		$COLON	0C5H,ENDI,F,ENDIFF
		DW	QCOMP
		DW	TWO,	QPAIR
		DW	HERE,	OVER,	SUBB
		DW	SWAP,	STORE,	SEMIS

;=:   THEN	synonym for ENDIF			addr 2 --

		$COLON	0C4H,THE,N
		DW	ENDIFF,	SEMIS

;=:   DO	start of DO..LOOP structure		-- HERE 3

		$COLON	0C2H,D,O
		DW	COMP,	XDO
		DW	HERE,	THREE,	SEMIS

;=:   LOOP	end of DO..LOOP structure		addr 3 --

		$COLON	0C4H,LOO,P
		DW	THREE,	QPAIR
		DW	COMP,	XLOOP
		DW	BACK,	SEMIS

;=:   +LOOP	end of DO..+LOOP structure		addr 3 --

		$COLON	0C5H,+LOO,P
		DW	THREE,	QPAIR
		DW	COMP,	XPLOO
		DW	BACK,	SEMIS

;=:   UNTIL	end of BEGIN..UNTIL loop		addr 1 --

		$COLON	0C5H,UNTI,L,UNTIL
		DW	ONE,	QPAIR
		DW	COMP,	ZBRAN
		DW	BACK,	SEMIS

;=:   END	synonym for UNTIL			addr 1 --

		$COLON	0C3H,EN,D
		DW	UNTIL,	SEMIS

;=:   AGAIN	end of BEGIN..AGAIN infinite loop	addr 1 --

		$COLON	0C5H,AGAI,N,AGAIN
		DW	ONE,	QPAIR
		DW	COMP,	BRAN
		DW	BACK,	SEMIS

;=:   REPEAT	end of BEGIN..WHILE..REPEAT structure	addr 1 --

		$COLON	0C6H,REPEA,T
		DW	TOR,	TOR
		DW	AGAIN
		DW	FROMR,	FROMR
		DW	TWO,	SUBB
		DW	ENDIFF,	SEMIS

;=:   IF	conditional branch structure		-- 2

		$COLON	0C2H,I,F,IFF
		DW	COMP,	ZBRAN
		DW	HERE,	ZERO,	COMMA
		DW	TWO,	SEMIS

;=:   ELSE	optional part of IF..ELSE..THEN		addr 2 -- HERE 2

		$COLON	0C4H,ELS,E
		DW	TWO,	QPAIR
		DW	COMP,	BRAN
		DW	HERE,	ZERO,	COMMA
		DW	SWAP
		DW	TWO,	ENDIFF,	TWO
		DW	SEMIS

;=:   WHILE	conditional loop BEGIN..WHILE..REPEAT	addr 2 -- HERE 4

		$COLON	0C5H,WHIL,E
		DW	IFF,	TWOP,	SEMIS
SUBTTL Output formatting words
PAGE +


;=:   SPACES	type n spaces				n --

		$COLON	86H,SPACE,S,SPACS
		DW	ZERO,	MAX
		DW	DDUP
			$GO?0	SPAX1
		DW	ZERO,	XDO
SPAX2: 		DW	SPACE
			$LOOP	SPAX2
SPAX1: 		DW	SEMIS

;=:   <#	begin number formatting			--

		$COLON	82H,!!!<,#,BDIGS
		DW	PAD,	HLD,	STORE
		DW	SEMIS

;=:   #>	end number formatting			d -- addr count

		$COLON	82H,#,!!!>,EDIGS
		DW	DROP,	DROP
		DW	HLD,	AT
		DW	PAD
		DW	OVER,	SUBB,	SEMIS

;=:   SIGN	places a '-' in output if n < 0		n d -- d

		$COLON	84H,SIG,N,SIGN
		DW	ROT,	ZLESS
			$GO?0	SIGN1
		DW	LIT,	'-',	HOLD
SIGN1: 		DW	SEMIS

;=:   #		convert one digit of d1 to ASCII	d1 -- d2

		$COLON	81H,,#,DIG
		DW	BASE,	AT,	MSMOD
		DW	ROT
		DW	LIT,	9
		DW	OVER,	LESS
			$GO?0	DIG1
		DW	LIT,	7,	PLUS
DIG1: 		DW	LIT,	'0',	PLUS
		DW	HOLD,	SEMIS

;=:   #S	process all significant digits of d1	d1 -- 0.

		$COLON	82H,#,S,DIGS
DIGS1: 		DW	DIG
		DW	OVER,	OVER
		DW	ORR,	ZEQU
			$GO?0	DIGS1
		DW	SEMIS

;=:   D.R	print d right-aligned in n columns	d n --

		$COLON	83H,D.,R,DDOTR
		DW	TOR,	SWAP,	OVER
		DW	DABS
		DW	BDIGS
		DW	DIGS,	SIGN
		DW	EDIGS
		DW	FROMR,	OVER,	SUBB
		DW	SPACS,	TYPES,	SEMIS

;=:   .R	print n1 right-aligned in n2 columns	n1 n2 --

		$COLON	82H,.,R,DOTR
		DW	TOR
		DW	STOD,	FROMR,	DDOTR,	SEMIS

;=:   D.	print a 32-bit number			d --

		$COLON	82H,D,.,DDOT
		DW	ZERO
		DW	DDOTR,	SPACE,	SEMIS

;=:   .		print a 16-bit number			n --

		$COLON	81H,,.,DOT
		DW	STOD,	DDOT,	SEMIS

;=:   ?		print the value at addr			addr --

		$COLON	81H,,?,QUES
		DW	AT,	DOT,	SEMIS

;=:   U.	print an unsigned 16-bit number		u --

		$COLON	82H,U,.,UDOT
		DW	ZERO,	DDOT,	SEMIS

;=:   VLIST	print the words in CONTEXT vocabulary	--

		$COLON	85H,VLIS,T
		DW	LIT,	80H
		DW	OUTT,	STORE
		DW	CONT,	AT,	AT
VLIS1: 		DW	OUTT,	AT
		DW	CSLL,	GREAT
			$GO?0	VLIS2
		DW	CR
		DW	ZERO,	OUTT,	STORE
VLIS2: 		DW	DUPP
		DW	IDDOT
		DW	SPACE,	SPACE
		DW	PFA,	LFA,	AT
		DW	DUPP,	ZEQU
		DW	QTERM,	ORR
			$GO?0	VLIS1
		DW	DROP,	SEMIS

;=:   LIST	list screen n, as 16 lines of 64 chars	n --

		$COLON	84H,LIS,T,LISTC
		DW	DUPP,	BLOCK	,DROP	;added 7-9-83
		DW	DECA,	CR
		DW	DUPP,	SCR,	STORE
		DW	PDOTQ
		DB	6,"SCR # "
		DW	DOT
		DW	LIT,	16,	ZERO,	XDO
LIST1: 		DW	CR,	IDO
		DW	LIT,	3,	DOTR,	SPACE
		DW	IDO,	SCR,	AT,	DLINE
		DW	QTERM
			$GO?0	LIST2
		DW	LEAVE
LIST2: 			$LOOP	LIST1
		DW	CR,	SEMIS

;=:   INDEX	print line 0 of screens n1 thru n2	n1 n2 --

		$COLON	85H,INDE,X
		DW	LIT,	FF,	EMIT,	CR
		DW	ONEP,	SWAP,	XDO
INDE1: 		DW	CR,	IDO
		DW	LIT,	3,	DOTR,	SPACE
		DW	ZERO,	IDO,	DLINE
		DW	QTERM
			$GO?0	INDE2
		DW	LEAVE
INDE2: 			$LOOP	INDE1
		DW	SEMIS

;=:   TRIAD	list screens in groups of three		n1 n2 --

		$COLON	85H,TRIA,D
		DW	LIT,	FF,	EMIT
		DW	LIT,	3,	SLASH
		DW	LIT,	3,	STAR
		DW	LIT,	3,	OVER
		DW	PLUS,	SWAP,	XDO
TRIA1: 		DW	CR,	IDO,	LISTC
		DW	QTERM
			$GO?0	TRIA2
		DW	LEAVE
TRIA2: 			$LOOP	TRIA1
		DW	CR
		DW	LIT,	15,	MESS,	CR
		DW	SEMIS
;
		$COLON	84H,.CP,U,DOTCPU
		DW	BASE,	AT
		DW	LIT,	36,	BASE,	STORE
		DW	LIT,	22H,	PORIG,	TAT
		DW	DDOT
		DW	BASE,	STORE,	SEMIS

IF	_EXTEND
INCLUDE	4TH-XTNS.ASM
ENDIF

	$REPORT	<FORTH definitions completed>

SUBTTL End of FORTH dictionary
PAGE



;=:   TASK	word to mark the end of the dictionary	--

LASTNFA:
		$COLON	84H,TAS,K,TASK
		DW	SEMIS
;
INITDP		EQU	$
MAIN		ENDS

	$REPORT	<End of assembly source>

		END	ORIG
ragment  which,  on  receiving
                  control after you  hit  ^C,  examines  t