;*****
;
; Resident 8080 Altair/IMSAI/Poly 88 FDOS III Version 1.0
;  (Recreated by Mike Douglas, Feb 2024, from automated
;   disassembly and source listing in the FDOS manual)
;
;*****
;
; Entry Addresses
;	Power Up = C3E7 hex
;	Re-Entry = C3E4 hex
;
PROM	equ	0C000h

DATAO	equ	0C1h
DATAI	equ	0C0h
CNTRL	equ	0C0h
CCTRL	equ	0		;console control port
CDATA	equ	1		;console data port
CRRDY	equ	1		;console data ready
CTRDY	equ	80h		;console xmit ready

SCTCH	equ	0C400H		;scratch RAM
VCTRS	equ	SCTCH		;I/O vectors
HIGH	equ	SCTCH+21h
BASE	equ	SCTCH+30h
STACK	equ	SCTCH+7Fh

PASS	equ	BASE
OFILE   equ	BASE+1
OUNIT	equ	BASE+2
IUNIT   equ	BASE+3
ISIZE	equ	BASE+4
ITRK	equ	BASE+6
ISCTR	equ	BASE+7
ICNTR	equ	BASE+8
OSIZE	equ	BASE+9
OTRK	equ	BASE+11
OSCTR	equ	BASE+12
OCNTR	equ	BASE+13
TITRK	equ	BASE-1
TISIZE	equ	BASE+14

ASMB	equ	VCTRS+24
START	equ	VCTRS+27
UPDTX	equ	VCTRS+30

CR	equ	13
LF	equ	10

; Entry point when Q is typed in monitor.
; Loads FDOS and branches to FDOS start address.
;
	ORG	 PROM				

	jmp	fdos
ci	jmp	VCTRS			;keyboard input vector
co	jmp	VCTRS+3			;console output vector
rdrIn	jmp	VCTRS+6			;reader input vector
lo	jmp	VCTRS+9			;list output vector
po	jmp	VCTRS+12		;punch output vector
mntr	jmp	VCTRS+15		;system monitor vector

fdos	lxi	sp,STACK
	call	fdos1
	jmp	start

rstV	jmp	reset
xusV	jmp	xus
xxUsv	jmp	xxus
seekV	jmp	seek+1
rFlgV	jmp	rFlag
loopV	jmp	loop
restrV	jmp	restr
riV	jmp	ri
wrtV	jmp	wrt
passV	jmp	iPass			;ASMB interpass function

assem	call	redx
	call	restr
	jmp	asmb

update	lxi	sp,STACK
	call	fdos1
	jmp	updtX

prog	call	redx
	jmp	mntr

reset	mvi	a,81H
	call	loop
	mvi	a,0DH
	jmp	loop

fdos1	call	reset
	lxi	h,0			;set bias=0
	push	h
	lxi	h,105
	shld	ISIZE
	lxi	h,ITRK
	mvi	m,1			;track=1
	inr	l
	mvi	m,0			;sector=0
	inr	l			;read buffer empty
	mvi	m,0
	call	redx
	ret				;go to FDOS

restr	lhld	TISIZE			;restore IFILE pointers
	shld	ISIZE
	lda	tITRK
	sta	ITRK
	lda	IUNIT
	rrc
	rrc
	sta	ISCTR
	sub	a
	sta	ICNTR
	ret

; Subroutine to read a hex file into memory.
; Starts with routine redo, uses all registers.

redx	pop	h			;swap bias & return
	xthl
	push	h

redo	pop	h			;get bias
	push	h
	call	rix			;get char into a
	mvi	b,':'
	sub	b
	jnz	redo

	mov	d,a
	call	byte
	jz	red2

	mov	e,a
	call	byte
	push	psw
	call	byte
	pop	b
	mov	c,a
	dad	b
	call	byte

red1	call	byte
	mov	m,a
	inx	h
	dcr	e
	jnz	red1

	call	byte
	jnz	ler
	jmp	redo

red2	call	byte
	mov	h,a
	call	byte
	mov	l,a
	ora	h
	jz	red3
	pchl

red3	pop	h
	ret

byte	call	rix
	call	nbl
	rlc
	rlc
	rlc
	rlc
	mov	c,a
	call	rix
	call	nbl
	ora	c
	mov	c,a
	add	d
	mov	d,a
	mov	a,c
	ret

; Subroutine to convert two hex characters to one byte

nbl	sui	'0'
	rc
	adi	0E9H
	rc
	adi	6
	jp	nIo
	adi	7
	rc

nIo	adi	10
	ora	a
	ret

; Subroutine to read a byte from disk
; Places char in A-reg. Entry at ri reads 8 bits.
; Entry at riX reads 7 bits.

rix	call	ri
	jc	mntr
	ani	07FH
	ret

ri	push	b			;save reg D-L
	push	h
	lxi	h,ICNTR
	mov	a,m
	ana	a			;cnt=0?
	jnz	ri10			;no

ri5	mvi	l,ISCTR and 0FFh	;yes-incr disk address
	call	incDa
	lhld	ISIZE
	dcx	h
	shld	ISIZE
	mov	a,l
	ana	a
	jnz	ri3

	mov	a,h
	ana	a
	jnz	ri3

	inx	h
	shld	ISIZE
	lxi	h,ICNTR
	mvi	m,0
	stc				;set EOF

ri2	pop	h			;restore D-L
	pop	b
	ret

ri3	lxi	h,ISCTR			;xmit unit/sector
	call	xus
	call	chk			;make sure a disk
	inr	l			;set counter=128
	mvi	m,128
	mvi	c,5			;set try cnt=5
	mvi	l,ITRK and 0FFh		;seek track
	call	seek

ri6	mvi	a,e			;read data
	call	loop
	in	DATAI			;DD mark?
	ani	80h
	jz	ri4			;no
	call	rFlag
	jmp	ri5

ri4	in	DATAI			;CRC error
	ani	08h
	jz	ri10			;no
	call	rFlag
	dcr	c			;decrement retry count
	jnz	ri6
	mvi	a,001H
	jmp	chk1

ri10	mvi	a,40h			;read byte into A
	out	CNTRL
	in	DATAI
	mov	c,a
	mvi	a,41h			;strobe buffer
	call	loop
	mvi	l,ICNTR and 0FFh	;decrement read counter
	dcr	m
	mov	a,c
	ora	a
	jmp	ri2

; Routine to increment disk address

incDa	inr	m
	mov	a,m
	ani	1Fh
	cpi	27
	jz	incDb
	dcr	l
	ret

incDb	mov	a,m
	ani	0C1h
	mov	m,a
	dcr	l
	inr	m
	ret

; Subroutine to write a byte to disk
; Expects char to be in C-reg

wrt	mov	a,c
	push	h
	out	DATAO			;output char
	mvi	a,31h
	call	loop
	lxi	h,oCntr
	inr	m			;increment buffer count
	mov	a,m
	cpi	128			;=128?
	jnz	wrt4			;no
	mvi	m,0			;clear count

wrt1	lxi	h,osCtr			;xmit unit/sector
	call	xus
	call	chk			;makke sure a disk
	mvi	c,5			;set try count=5
	dcr	l			;seek track
	call	seek

wrt2	mvi	a,5			;write data
	call	loop
	mvi	a,7			;read forCRC
	call	loop		
	in	DATAI			;CRC error?
	ani	08h
	jz	wrt3			;no
	call	rFlag
	dcr	c			;decrement retry count
	jnz	wrt2
	mvi	a,0Fh			;write as DD
	call	loop
	call	wrtN			;increment disk addr, check size
	jmp	wrt1

wrt3	call	wrtN			;increment disk addr, check size
wrt4	pop	h
	ret

; Subroutine to transmit unit/sector byte

xus	mov	a,m
	ani	1Fh			;extract logical sector
	push	h
	lxi	h,tbl-1			;get table pointer
	add	l			;make sector pointer
	mov	l,a
	mov	c,m			;get physical sector
	pop	h
	mov	a,m
	ani	0C0H
	ora	c			;merge unit and sector

xxus	out	DATAO
	mvi	a,21h
	jmp	loop

; Subroutine to seek track in A

seek	mov	a,m
	out	DATAO
	mvi	a,11h
	call	loop
	mvi	a,09h
	jmp	loop

; Subroutine to reset flag

rFlag	mvi	a,0Bh

; Subroutine to issue command & loop on busy

loop	out	CNTRL
	sub	a
	out	CNTRL

loop1	in	DATAI
	rar
	jc	loop1
	ret

; Subroutine to increment disk address and check file soize

wrtN	mvi	l,OSCTR and 0FFh
	call	incDa

wrtN2	lhld	oSize
	dcx	h
	shld	oSize
	mov	a,l
	ana	a
	rnz
	mov	a,h
	ana	a
	rnz
	mvi	a,2
	jmp	chk1

; Subroutine to check if a disk, else error 3

chk	in	DATAI
	ani	20h
	rz
	mvi	a,3

; Routine to print error

chk1	ori	'0'			;convert to ASCII
	mov	c,a
	call	co
	jmp	mntr

; Interpass functions
; if bit 0 of (pass) is equal to 1, then bit 0 of
; (pass) is set to 0 and '1' is returned in
; A-reg. If bit 0 of (pass) is equal to 0, then (pass)
; is set to 0 and '0' plus (pass) shifted right
; 1 bit position is returned in A-reg. If (pass)
; is equal to zero, a jump to update occurs

iPass	lda	base
	rar
	jnc	pass2
	lda	base
	dcr	a
	sta	base
	mvi	a,1
	jmp	pass3

pass2	ana	a
	jz	update
	call	restr
	lda	base
	rar
	push	psw
	sub	a
	sta	base
	pop	psw

pass3	adi	'0'
	ret

; Physical sector table. Indexed by logical sector number.

tbl	db	1,10,19,2,11,20,3,12,21,4,13,22,5
	db	14,23,6,15,24,7,16,25,8,17,26,9,18
	db	0,0,0

; Console input routine

cix	in	00h			;this is for 88-SIO
	ani	01h
	jnz	cix
	in	01h
	ani	7Fh
	ret

crLf	mvi	c,CR
	call	co
	mvi	c,LF
	jmp	co

; Console output routine

cox	in	00h			;this is for 88-SIO
	ani	80h
	jnz	cox
	mov	a,c
	out	01h
	ret

; Copy vector table from PROM to RAM

init	lxi	b,JMP*256+NUMVEC	;B=JMP inst, C=vector count
	lxi	h,VCTRS
	lxi	d,VECTR

init1	mov	m,b
	inx	h
	ldax	d
	mov	m,a
	inx	h
	inx	d
	ldax	d
	mov	m,a
	inx	h
	inx	d
	dcr	c
	jnz	init1

mntRx	lxi	sp,STACK
	call	crLf
	mvi	c,'>'
	call	co
	call	cEcho
	cpi	'T'
	jz	tstM
	cpi	'M'
	jz	mem
	cpi	'G'
	jz	go

ler	mvi	c,'?'
	call	co
	jmp	mntRx

cEcho	call	ci
	mov	c,a
	call	co
	ret

go	call	param
	call	crLf
	pchl

param	lxi	h,0
parm1	call	cEcho
	cpi	CR
	rz
	cpi	','
	rz

	dad	h
	dad	h
	dad	h
	dad	h
	jc	ler

	call	nbl
	jc	ler

	ora	l
	mov	l,a
	jmp	parm1

byteC	call	cEcho
byteC1	call	nbl
	rlc
	rlc
	rlc
	rlc
	push	psw
	call	cEcho
	call	nbl
	pop	b
	ora	b
	ret

byteO	push	psw
	call	byteO1
	mov	c,a
	call	co
	pop	psw
	call	byteO2
	mov	c,a
	jmp	co

byteO1	rrc
	rrc
	rrc
	rrc

byteO2	ani	0Fh
	cpi	10
	jm	byteO3

	adi	7
byteO3	adi	'0'
	ret

hlco	call	crLf
	mov	a,h
	call	byteO
	mov	a,l
	call	byteO
	ret

dspyM	call	hlco
	mvi	c,'='
	call	co
	mov	a,m
	call	byteO
	mvi	c,' '
	call	co
	ret

mem	call	param
mem1	call	dspyM
	call	cEcho
	cpi	CR
	jz	mntRx
	cpi	' '
	jz	mem9
	call	byteC1
	mov	m,a

mem9	inx	h
	jmp	mem1

kbInt	in	00h			;this is for 88-SIO
	ani	01h
	rnz
	in	01h
	cpi	03h
	jz	mntr
	ret

tstM	call	param
	push	h
	xchg
	call	param
	shld	HIGH
	xchg
	call	crLf

tstM2	mvi	m,0
	mov	a,e
	cmp	l
	jnz	tstM3
	mov	a,d
	cmp	h
	jz	tstM4

tstM3	inx	h
	jmp	tstM2

tstM4	mvi	e,1

tstM7	pop	h
	push	h

tstM1	inr	m
	mov	a,e
	cmp	m
	cnz	tstM6
	lda	HIGH
	cmp	l
	jnz	tstM5

	lda	HIGH+1
	cmp	h
	jnz	tstM5

	inr	e
	call	kbInt
	jmp	tstM7

tstM5	inx	h
	jmp	tstM1

tstM6	call	dspyM
	mov	a,e
	call	byteO
	jmp	crLf

rdix	jmp	ci
lox	jmp	co
pox	jmp	co

; Duplicate PROM content

	db	0D2h,0E0h,013h,00Eh,02Bh,0CDh,0ACh,001h
	db	0C3h,0E5h,013h,00Eh,020h,0CDh,0ACh

; I/O Vector Table

	org	prom+3E4h

	jmp	mntrx			;monitor re-entry
	jmp	init			;monitor start address

vectr	dw	cix			;console in
	dw	cox			;console out
	dw	rdix			;reader in
	dw	lox			;line printer out
	dw	pox			;punch out
	dw	mntrx			;monitor re-entry
	dw	ri			;read disk
	dw	wrt			;write disk
	dw	40h			;assem/edit vector
	dw	40h			;executive vector
	dw	43h			;update vector

NUMVEC	equ	($-vectr)/2		;number of vectors

	end
