**********************************************************************
*
* VTL-2 Source Re-Creation
*   This source file was created by (unknown) by keying in the
*   source code provided in the VTL-2 manual. This required
*   translating the unusual syntax of the cross-assembler used
*   by the original authors into a more conventional Motorola
*   assembler format. The output of this assembly then found its
*   way to many Altair 680 web archives as "the" S-Record file
*   for VTL-2. 
*
*   However, in June of 2022, it was discovered that this source
*   file contained two errors:
* 
*     1) The operand of the suba instruction at label eval5
*        should have been #'= instead of '=. This error caused
*	 most relational operations to fail.
*
*     2) The operand of the cmpb instruction in the evalu routine
*	 should have been #'$ instead of #$. This caused direct
*	 ASCII output through the $ device to fail.
*
*   These bugs were found, fixed, and the source file cleaned up
*   by Mike Douglas in June of 2022. The output of this source
*   file now exactly matches the hex bytes in the listing provided
*   in the VTL-2 manual.
*
**********************************************************************

* VTL-2
* v-3.6
* 9-23-76
* By Gary Shannon
* & Frank McCoy
* Copyright 1976, The Computer Store

* Define locations in monitor

INCH	equ	$FF00
POLCAT	equ	$FF24
OUTCH	equ	$FF81

* Misc defines

LINLEN	equ	72		input line length
CR	equ	$0D
LF	equ	$0A

* Set aside four bytes for user defined
*   interrupt routine if needed

	org	0
zero	rmb	4		interrupt vector
at	rmb	2		cancel & cr

* General purpose storage

vars	rmb	52		variables (A-Z)
brak	rmb	2		[ open bracket
save10	rmb	2		\ backslash
brik	rmb	2		] close bracket
up	rmb	2		^ up arrow
save11	rmb	2		_ underscore
save14	rmb	2		space
excl	rmb	2		! bang (return address)
quote	rmb	2		" double quote (string literals)
dolr	rmb	2		# pound sign (line number)
dollar	rmb	2		$ dollar sign (char i/o)
remn	rmb	2		% percent (remainder after divide)
ampr	rmb	2		& ampersand (end of program)
quite	rmb	2		' single quote (random number)
paren	rmb	2		( open paren
parin	rmb	2		) close paren
star	rmb	2		* asterisk (end of memory)
plus	rmb	2		+ plus sign
coma	rmb	2		, comma
mins	rmb	2		- minus
perd	rmb	2		. period
slash	rmb	2		/ forward slash
save0	rmb	2		0 zero
save1	rmb	2		1 one
save2	rmb	2		2 two
save3	rmb	2		3 three
save4	rmb	2		4 four
save5	rmb	2		5 five
save6	rmb	2		6 six
save7	rmb	2		7 seven
save8	rmb	2		8 eight
save9	rmb	2		9 nine
coln	rmb	2		: colon (array operator)
semi	rmb	2		; semi-colon (no cr/lf on string print)
less	rmb	2		< less than
eqal	rmb	2		= equal sign
grat	rmb	2		> greater than or equal

decbuf	rmb	4
lastd	rmb	1
delim	rmb	1
linbuf	rmb	LINLEN+1	reserve line length + 1 bytes

	org	$F1
stack	rmb	15		space for monitor
mi	rmb	4		monitor interrupt vectors
nmi	rmb	4
prgm	equ	*		user program starts here

	org	$FC00 
start	lds	#stack		entry point
	clra
	ldx	#okm
	bsr	strgt

loop	clra
	staa	dolr
	staa	dolr+1
	jsr	cvtln		returns line # in b:a
	bcc	stmnt		no line # then exec
	bsr	exec
	beq	start

loop2	bsr	find		find line
eqstrt	beq	start		if end then stop
	ldx	0,x		load real line #
	stx	dolr		save it
	ldx	save11		get line
	inx			bump past line #
	inx
	inx
	bsr	exec		execute it
	beq	loop3		if zero continue
	ldx	save11		find line #
	ldx	0,x		get it
	cpx	dolr		has it changed?
	beq	loop3		if not get nexr

	inx			increment old line #
	stx	excl		save for return
	bra	loop2		continue
loop3	bsr	fnd3		find next line
	bra	eqstrt		continue

exec	stx	save7		execute line
	jsr	var2
	inx
skip	ldaa	0,x		get first term
	bsr	evil
outx	ldx	dolr
	rts

evil	cmpa	#'"		double quote
	bne	evalu
	inx
strgt	jmp	strng		to print it

* Insert line into program, new line # in b:a

stmnt	stx	save8		save line #
	staa	dolr
	stab	dolr+1
	ldx	dolr
	bne	skp2		if line # > 0

* List program

	ldx	#prgm		list program
lst2	cpx	ampr		end of program
	beq	eqstrt
	stx	save11		line # for cvdec
	ldaa	0,x
	ldab	1,x
	jsr	prnt2
	ldx	save11
	inx
	inx
	jsr	pntmsg
	jsr	crlf
	bra	lst2

nxtxt	ldx	save11		get pointer
	inx			bump past line#
lookag	inx	find		end of line
	tst	0,x
	bne	lookag
	inx
	rts

find	ldx	#prgm		find line #
fnd2	stx	save11
	cpx	ampr
	beq	rts1
	ldaa	1,x
	suba	dolr+1
	ldaa	0,x
	sbca	dolr
	bcc	set
fnd3	bsr	nxtxt
	bra	fnd2

set	ldaa	#$FF		set not equal
rts1	rts

evalu	jsr	eval		evaluate line
	pshb
	psha
	ldx	save7
	jsr	convp
	pula
	cmpb	#'$		string?
	bne	ar1
	pulb
	jmp	OUTCH		then print it

ar1	subb	#'?		print?
	beq	prnt		then do it
	incb			machine language?
	pulb
	bne	ar2
	swi			then interrupt

ar2	staa	0,x		store new value
	stab	1,x
	addb	quite		randomizer
	adca	quite+1
	staa	quite
	stab	quite+1
	rts

* Continue inserting line into program, new line # in x

skp2	bsr	find		find line
	beq	insrt		if not there
	ldx	0,x		then insert
	cpx	dolr		new line
	bne	insrt

	bsr	nxtxt		setup registers
	lds	save11		for delete

delt	cpx	ampr		delete old line
	beq	fitit
	ldaa	0,x
	psha
	inx
	ins
	ins
	bra	delt

fitit	sts	ampr		store new end
insrt	ldx	save8		count new line length
	ldab	#3
	tst	0,x
	beq	gotit		if no line then stop
cntln	incb
	inx
	tst	0,x
	bne	cntln

open	clra			calculate new end
	addb	ampr+1
	adca	ampr
	staa	save10
	stab	save10+1
	subb	star+1
	sbca	star
	bcc	rstrt		if too big then stop
	ldx	ampr
	lds	save10
	sts	ampr

	inx
slide	dex
	ldab	0,x
	pshb
	cpx	save11
	bne	slide

don	lds	dolr		store line #
	sts	0,x
	lds	save8		get new line
	des
movl	inx
	pulb
	stab	1,x
	bne	movl

gotit	lds	#stack
	jmp	loop

rstrt	jmp	start

prnt	pulb			print decimal
prnt2	ldx	#decbuf		convert to decimal
	stx	save4
	ldx	#pwrs10
cvd1	stx	save5
	ldx	0,x
	stx	save6
	ldx	#save6
	jsr	divide
	psha
	ldx	save4
	ldaa	save2+1
	adda	#'0
	staa	0,x
	inx
	stx	save4
	ldx	save5
	pula
	inx
	inx
	tst	1,x
	bne	cvd1
	
	ldx	#decbuf-1
	com	5,x		zero suppress
zrsup	inx
	ldab	0,x
	cmpb	#'0
	beq	zrsup
	com	lastd

pntmsg	clra			zero for delim
strtms	staa	delim		store delimiter

outmsg	ldab	0,x		general purpose print
	inx
	cmpb	delim
	beq	ctlc
	jsr	OUTCH
	bra	outmsg

ctlc	jsr	POLCAT		poll for character
	bcc	rts2
	bsr	inch2
	cmpb	#3		ctrl-c?
	beq	rstrt

inch2	jmp	INCH

strng	bsr	strtms		print string literal
	ldaa	0,x
	cmpa	#';
	beq	outd
crlf2	jmp	crlf

eval	bsr	getval		evaluate expression

nxtrm	psha
	ldaa	0,x		end of line?
	beq	outn
	cmpa	#')
outn	pula
	beq	outd
	bsr	term
	ldx	save0
	bra	nxtrm

term	psha			get value
	pshb
	ldaa	0,x
	psha
	inx
	bsr	getval
	staa	save3
	stab	save3+1
	stx	save0
	ldx	#save3
	pula
	pulb

	cmpa	#'*		see if *
	bne	eval2
	pula	multiply
multip	staa	save2
	stab	save2+1		2's complement
	ldab	#16
	stab	save1
	clra
	clrb

mult	lsr	save2
	ror	save2+1
	bcc	noad
multi	bsr	add
noad	asl	1,x
	rol	0,x
	dec	save1
	bne	mult		loop till done
rts2	rts

getval	jsr	cvbin		get value
	bcc	outv
	cmpb	#'?		of literal
	bne	var
	stx	save9		or input
	jsr	inln
	bsr	eval
	ldx	save9
outd	inx
outv	rts

var	cmpb	#'$		or string
	bne	var1
	bsr	inch2
	clra
	inx
	rts

var1	cmpb	#'(
	bne	var2
	inx
	bra	eval

var2	bsr	convp		or variable
	ldaa	0,x		or array element
	ldab	1,x
	ldx	save6		load old index
	rts

array	bsr	eval		locate array element
	aslb
	rola
	addb	ampr+1
	adca	ampr
	bra	pack
	
convp	ldab	0,x		get location
	inx
	pshb
	cmpb	#':
	beq	array		of variable or
	clra
	andb	#$3F
	addb	#2
	aslb

pack	stx	save6		store old index
	staa	save4
	stab	save4+1
	ldx	save4		load new index
	pulb
	rts

eval2	cmpa	#'+		addition
	bne	eval3
	pula
add	addb	1,x
	adca	0,x
	rts

eval3	cmpa	#'-		subtraction
	bne	eval4
	pula
subtr	subb	1,x
	sbca	0,x
	rts

eval4	cmpa	#'/		see if it's divide
	bne	eval5
	pula
	bsr	divide
	staa	remn
	stab	remn+1
	ldaa	save2
	ldab	save2+1
	rts

eval5	suba	#'=		see if equal test
	bne	eval6
	pula
	bsr	subtr
	bne	noteq
	tstb
	beq	eql
noteq	ldab	#$FF
eql	bra	combout

eval6	deca			see if less than test
	pula
	beq	eval7

sub2	bsr	subtr
	rolb
comout	clra
	andb	#1
	rts
	
eval7	bsr	sub2		gt test
combout	comb
	bra	comout

pwrs10	fdb	10000,1000,100,10,1

* Divide a:b by *x, result in save2, remainder in a:b

divide	clr	save1		divide 16-bits
got	inc	save1
	asl	1,x	
	rol	0,x
	bcc	got
	ror	0,x
	ror	1,x
	clr	save2
	clr	save2+1
div2	bsr	subtr		a:b := a:b - *x
	bcc	ok
	bsr	add		a:b := a:b + *x
	clc
	fcb	$9C		cpx trick
ok	sec
	rol	save2+1
	rol	save2
	dec	save1
	beq	done
	lsr	0,x
	ror	1,x
	bra	div2

tstn	ldab	0,x		test for numeric
	cmpb	#'9+1
	bpl	notdec
	cmpb	#'0
	bge	done
notdec	sec
	rts
done	clc
dun	rts

cvtln	bsr	inln

cvbin	bsr	tstn		convert to binary
	bcs	dun
cont	clra
	clrb
cbloop	addb	0,x
	adca	#0
	subb	#'0
	sbca	#0
	staa	save1
	stab	save1+1
	inx
	pshb
	bsr	tstn
	pulb
	bcs	done
	aslb
	rola
	aslb
	rola
	addb	save1+1
	adca	save1
	aslb
	rola
	bra	cbloop

inln6	cmpb	#'@		cancel
	beq	newlin
	inx
	cpx	#LINLEN+2	reach end?
	bne	inln2
newlin	bsr	crlf

inln	ldx	#2		input line from terminal
inln5	dex
	beq	newlin

inln2	jsr	INCH		input character
	stab	linbuf-1,x	store it
	cmpb	#'_		backspace?
	beq	inln5

inln3	cmpb	#CR		carriage return
	bmi	inln2
	bne	inln6
inln4	clr	linbuf-1,x	clear last char
	ldx	#linbuf
	bra	linefd

crlf	ldab	#CR		cr
	bsr	outch2
linefd	ldab	#LF		lf
outch2	jmp	OUTCH

okm	fcb	CR,LF
	fcc	'OK'
	fcb	0

	end
