  	.title 	'Fox PROM Monitor'
	.sbttl	'PROM.ASM'
version	==	4  ;version for fox 3/4/82
revision==	14
;----------
; DSC-3, DSC-4 PROM Monitor
;
; Features of the DSC/3:
;
;    Z-80 at 4MHz
;    64K Dynamic RAM
;    1K PROM
;    4 Ports - 3 RS-232
;              1 RS-422  (optionally RS-232)
;    Real time clock
;    Optional floppy disk controller
;    2 8-bit parallel ports
;
; The PROM Monitor occupies the 1K PROM on the DSC/3
; and the DSC/4.  It can execute these commands:
;
; Set <addr>
;   set memory locations, starting at <addr>
;
; Dump [ <addr1> [<addr2>] ]
;   dump memory from <addr1> to <addr2>
;
; Fill <addr1> <addr2> <byte>
;   fill memory with <byte> from <addr1> to <addr2>
;
; Go <addr>
;   jump to <addr>
;
; In <port>
;   input from Z-80 <port>
;
; Out <port> <byte>
;   output <byte> to Z-80 <port>
;
; Test <addr1> <addr2>
;   test memory from <addr1> to <addr2>
;
; Boot <device> [<combuf>]
;   read and execute program from floppy, network, 
;   harddisk, test floppy, or tape
;
	.page
	.pabs
	.phex
;----------
;    Data and address definitions:
;
RAM	==	09000h	; beginning of RAM
BOOTloc	==	RAM	; beginning of bootstrap
stack	==	RAM+400h; top of RAM
Daddr	==	RAM+3E0h; Dump address
resbuf	==	RAM+380h; Floppy result buffer
homeF	==	RAM+390h; home command
readF	==	RAM+393h; read command
cr	==	0Dh
lf	==	0Ah
RxRDY	==	0	; receiver ready status bit
TxRDY	==	2	; transmitter ready status bit
;
;    Port definitions:
;
DMA	==	38h	; DMA chip
CTC0	==	30h	; CTC channel 0 (port 0)
SIO1AC	==	2Ah	; SIO-1 channel A, control 
SIO1AD	==	28h	; SIO-1 channel A, data -port 0
SIO1BĂ	=˝	2Bh	; SIO-1 channel B, control
SIO1BD	==	29h	; SIO-1 channel B, data -port 1
PIOAC	==	0Ah	; PIO channel A, control
PIOAD	==	08h	; PIO channel A, data
PIOBC	==	0Bh	; PIO channel B, control
PIOBD	==	09h	; PIO channel B, data
FLOPSR	==	10h	; Floppy status register
FLOPDR	==	11h	; Floppy data register
HARDP	==	01h	; Hard disk parallel port
SETMAP	==	03h	; Set memory map register
STOPFLOP==	03h	; Stop floppy controller
PARADATA==	02H	; J4 PARALLEL PORT
PARASTAT==	08H	; PIO CHAN A DATA
;----------
; Come here on master reset
	.loc	00h	; RST 0
	lxi	SP,stack; you always need a stack
	jmp	initial	; intialize the PIO and SIO1
;
; Use these two bytes to store the DMA vector
DMAvect:.word	DMARdone; interrupt on DMA done
;----------
; Update history:
;
; 1.07 (09/01/80) Initial release
; 1.08  (10/01)   Changed autoboot jumpers
; 1.09  (10/27)   Changed autoboot jumpers (AGAIN!)
;	          Boot from any floppy drive
;		  Boot from hard disk
; 1.09T 06/21/81  Boot from tape (option)
; 4.09            version for fox
	.page
;----------
; Utility routines
;
; Callable by an RST instruction:
;
; RST 1 - in0:     Input a character from port 0
; RST 2 - out0:    Output a character to port 0
; RST 3 - outst0:  Output a string to port 0
; RST 4 - crlf:    Output <return>, <linefeed> to port0
; RST 5 - space:   Output <space> to port 0
; RST 6 - getbyt:  Input a byte from port 0
; RST 7 - restart: Restart the PROM monitor
;
; Callable through jump vector at top of ROM
;
; cmdHARD: Send a command string to hard disk
; resHARD: Get a result string from hard disk
; sendHARD:Send byte to hard disk
; recHARD: Get bytes from hard disk
; command: Output a command string to the floppy contlr
; result:  Input a result string from the floppy contlr
; ioerr:   Output an I/O error message on port 0
;
; Jump vector table:
numvec	=	7
	.loc	3FCh-3*numvec
	jmp	cmdHARD
	jmp	resHARD
	jmp	sendHARD
	jmp	recHARD
	jmp	command
	jmp	result
	jmp	ioerr
;
; Version, revision, and serial number
	.byte	version
	.byte	revision
	.word	0FFFFh	; serial number
	.page
;----------
; Input a character from port 0
;  Regs in:   none
;  Regs out:  A = input character
	.loc	08h	; RST 1
in0:
waiti:	in	PARASTAT  ; read status
	ANI	40H     ; check for receiver ready
	jrz	waiti	; wait until ready      
	IN	PARADATA; read the char
;----------
; Output a character to port 0
;  Regs in:   A = output character
;  Regs out:  none
	.loc	10h	; RST 2
out0:
	ani	7Fh	; strip parity bit
	push	PSW	; save output char
	jmpr	outc	; continue elsewhere
;----------
; Flush an input character from port 0
;  (jumped to from 'out')
flush:	in	PARADATA; flush the input char
	rst	restart/8 ; restart the monitor
;----------
; Output a string to port 0
;  Regs in:   HL = address of string (ended by null)
;  Regs out:  none
;  Destroyed: A, HL
	.loc	18h	; RST 3
outst0:
	mov	A,M	; get next output char
	ora	A	; string terminated by null
	rz
	rst	out0/8	; output this char
	inx	H	; point to next char
	jmpr	outst0	; repeat until null found
;----------
; Output <return>, <linefeed> to port 0
;  Regs in:   none
;  Regs out:  none
;  Destroyed: A
	.loc	20h	; RST 4
crlf:
	mvi	A,cr
	rst	out0/8
	mvi	A,lf
	jmpr	out0	; return from out0
;----------
; Output <space> to port 0
;  Regs in:   none
;  Regs out:  none
;  Destroyed: A
	.loc	28h	; RST 5
space:
	mvi	A,' '
	jmpr	out0	; return from out0
;----------
; Handle an input error
;  Regs in:   none
;  Regs out:  none
error:	mvi	A,'?'
	rst	out0/8	; type '?' on input error
	rst	restart/8 ; restart the monitor
;--------
; Input a byte from port 0
;  Regs in:   none
;  Regs out:  A = byte read
;	      B = 1 if number was typed, 0 otherwise
;  Destroyed: DE
	.loc	30h	; RST 6
getbyt:
	push	H	; save HL (courtesy to caller)
	call	getadr	; let 'getadr' do the work
	mov	A,L	; result in low byte of HL
	pop	H	; restore HL
	ret
;----------
; Restart the main monitor loop
	.loc	38h	; RST 7
restart:
	jmp	prompt	; jump here to restart monitor
;----------
; Output a byte to port 0
;  (jumped to from 'out0')
outc:
wait0:	in	PARASTAT; read status
	BIT	5,A	; check for transmitter ready
	jrNz	wait0	; wait until ready
	bit	6,A	; check for receiver ready
	jrnz	flush	; jump if interrupted by user
	pop	PSW	; restore output char
	out	PARADATA; write the char
;
; Convert lowercase to uppercase
	cpi	'a'	; return if less than 'a'
	rm
	cpi	'z'+1	; return if greater than 'z'
	rp
	sui	'a'-'A'	; convert lower to upper case
	ret
;----------
; Input an address from port 0
;  Regs in:   none
;  Regs out:  HL = address read
;	      B  = 1 if number was typed, 0 otherwise
;  Destroyed: A, DE
;
; Note:  An address contains zero or more spaces, 
;	 followed by one or more HEX digits, and
;	 terminated by a <space> or <return>
getadr:
	lxi	H,0	; HL = 0
	mov	B,H	; B = 0
	mov	D,H	; D = 0
get0:	rst	in0/8	; skip leading spaces
	cpi	' '
	jrz	get0
get1:	cpi	cr	; terminate if <return>
	rz
	cpi	'G'
	jrnc	error	; jump if digit > F
	cpi	'A'
	jrc	num	; jump if digit < A
	sui	'A'-('9'+1) ; partially convert A..F
	cpi	'9'+1	
	jrc	error	; jump if 9 < digit < A
num:	sui	'0'	; convert ASCII to HEX
	jrc	error	; jump if digit < 0
	dad	H	; shift HL left 4 bits
	dad	H
	dad	H
	dad	H
	mov	E,A	; DE = current HEX digit
	dad	D	; add current digit to addr
	mvi	B,1	; set 'number typed' flag
	rst	in0/8
	cpi	' '	; terminate if <space>
	rz
	jmpr	get1	; continue collecting chars
;----------
; Output an address to port 0
;  Regs in:   HL = address to be printed
;  Regs out:  none
;  Destroyed: A
prtadr:
	mov	A,H
	call	prtbyt
	mov	A,L
;----------
; Output a byte to port 0
;  Regs in:   A = byte to be printed
;  Regs out:  none
;  Destroyed: A
prtbyt:
	push	PSW
	rrc		; print high nibble of A
	rrc
	rrc
	rrc
	call	prtnbl	; print low nibble of A
	pop	PSW
prtnbl:	ani	0Fh	; mask lower nibble
	adi	'0'	; convert to ASCII
	cpi	'9'+1
	jc	out0	; jump if 0..9
	adi	'A'-('9'+1) ; convert A..F to ASCII
	jmp	out0	; use return from out0
;----------
; Send a command string to the floppy controller
;  Regs in:   HL = address of command string
;  Regs out:  none
;  Destroyed: A, HL
command:
	mov	A,M	; get a command byte
	cpi	endcom	; check if end-of-string
	rz		; return if all bytes sent
	call	waitdr	; wait for data register
	cc	ioerr	; I/O error if wrong direction
	mov	A,M	; get the command byte
	out	FLOPDR	; write to data register
	inx	H	; point to next command byte
	jmpr	command
;----------
; Collect result string from the floppy controller
;  Regs in:   none
;  Regs out:  none
;  Destroyed: A, HL
result:
	lxi	H,resbuf; point to result buffer
readDR:	call	waitdr	; wait from data register
	rnc		; return if all bytes received
	in	FLOPDR	; get the result byte
	mov	M,A	; store it in 'flopbuf'
	inx	H	; point to next result byte
	jmpr	readDR
;----------
; Wait until floppy data register is ready
;  Regs in:   none
;  Regs out:  A = status register, rotated left by 1
waitdr:
	in	FLOPSR	; read floppy status register
	rlc
	jrnc	waitdr	; bit 7 = 1 if ready
	rlc		; bit 6 = 1 if CPU receiving
	ret		; 	  0 if CPU sending
;----------
; Output an I/O error message
;  Regs in:   none
;  Regs out:  none
errmsg:	.asciz	[cr][lf]'I/O error '
ioerr:	lxi	H,errmsg
	rst	outst0/8 ; output a message
	pop	H	; get the caller's address
	call	prtadr	; print the caller's address
	rst	restart/8 ; restart the monitor
	.page
;----------
; Initialization code - executed on master reset
;
; Initialize the PIO chip
initial:
	LXI	H,0	;MOVE TO RAM, REL ROM
	LXI	D,8000H
	LXI	B,800H
	LDIR
	JMP	MOVBAK+8000H
MOVBAK:	IN	2	;RELEASE ROM
	LXI	H,8000H
	LXI	D,0
	LXI	B,800H
	LDIR
	JMP	CONTIN
CONTIN:	mvi	A,0CFh					
	out	PIOAC	; reset PIO channel A
	mvi	A,0F8h	;  top    5 lines = input
	out	PIOAC	;  bottom 3 lines = output
	mvi	A,3
	out	PIOAC	; disable interrupts
	mvi	A,0CFh
	out	PIOBC	; reset PIO channel B
	mvi	A,0C0h	;  top    2 lines = input
	out	PIOBC	;  bottom 6 lines = output
	mvi	A,3
	out	PIOBC	; disable interrupts
;
; Do a little house cleaning
	mvi	A,0
	out	PIOBD	; unload the floppy head
	mvi	A,0C3h
	out	DMA	; reset the DMA chip
;
; Initialize port 0 to be a standard CRT at 9600 baud
	mvi	A,45h	; set counter mode
	out	CTC0	; next byte is time constant
	mvi	A,13	; 13 = 2Mhz/(16*baudrate)
	out	CTC0	; port 0 is 9600 baud
	lxi	H,rs232	; port 0 is RS-232
	lxi	B,rs232$<8+SIO1AC 
	outir
;
; Enter monitor if front-panel switch is on
	in	PIOAD
	bit	7,A	; check front-panel switch
	jrnz	Monitor	
;
; Check for auto-boot
	in	SIO1AC	;  DCD  STS
	bit	3,A	;  ---  ---
	jnz	Network ;   1    -   Network boot
	bit	5,A	;   0    0   Floppy boot
	jnz	Harddisk;   0    1   Harddisk boot
	jmp	Floppy
;
; RS-232 SIO command - for complete explanation,
; 		       see Zilog Data Book, page 56
rs232:  .byte	18h	      ; channel reset
	.byte	14h,01001100b ; 2 stops bits, no parity
	.byte	 3 ,11000001b ; receiver enable
	.byte	 5 ,11101010b ; transmitter enable
	.byte	11h,00000000b ; no interrupts
rs232$	==	.-rs232	  ; length of SIO command string
;----------
; Main monitor loop
;
; Wait for a command character, then jump to the
; appropriate routine to handle the command
;
PROMmsg:.ascii  [cr][lf]'PROM Monitor '
	.byte	version+'0','.'
	.byte	revision/10+'0',revision@10+'0',0
Monitor:
	lxi	H,PROMmsg
	rst	outst0/8 ; print a boot-up message
prompt:
	lxi	SP,stack ; start with a fresh stack
	rst	crlf/8	; on a fresh line
	mvi	A,':'	; output the command prompt
	rst	out0/8
	rst	in0/8	; input a command
	cpi	'S'
	jrz	Set	; Set memory
	cpi	'D'
	jz	Dump	; Dump memory
	cpi	'G'
	jz	Go	; Go to a program
	CPI	'E'	; ECHO (EMULATE DUMB CRT)
	JZ	EMULATE
	cpi	'F'
	jz	Fill	; Fill memory
	cpi	'I'
	jz	In	; Input from a port
	cpi	'O'
	jz	Out	; Output to a port
	cpi	'T'
	jz	Test	; Test memory
	cpi	'B'
	jz	Boot	; Boot
	cpi	cr
	jrz	Dumpcr	; <cr> - dump memory
	jmp	error
	.page
;----------
; Set memory
;
; S <addr>
Set:
	call	getadr	; address is in HL
Set1:	rst	crlf/8
	call	prtadr	; print HL
	rst	space/8
	mov	A,M	; get old byte from memory
	call	prtbyt	; print it
	rst	space/8
	rst	getbyt/8 ; get new byte from CRT
	bit	0,B	; test if number entered
	jrz	Set2    ; jump if no number entered
	mov	M,A	; replace byte in memory
Set2:	inx	H	; point to next byte
	jmpr	Set1
;----------
; Dump memory
;
; D  [ <addr1> [<addr2] ]
Dumpcr:
	lxi	H,RAM	; default starting address
	shld	Daddr
	jmpr	default
Dump:
	call	getadr	; get starting address
	bit	0,B
	jrnz	Daddr1	; jump if number entered
	lhld	Daddr	; resume from previous dump
	jmpr	default
Daddr1: shld	Daddr	; store starting address
	cpi	cr	; see if <return> was typed
	jrz	default	; jump if no end addr entered
	call 	getadr	; get ending address
	jmpr	Daddr2
default:lxi	D,128	; default dump range
	dad	D
Daddr2:	xchg		; DE = ending address
;
; Top of dump loop - print dump address
Dump0:	lhld	Daddr
	rst	crlf/8
	call	prtadr
;
; Dump 16 bytes in hexadecimal format
Dump1:	rst	space/8
	mov	A,M	; get a byte
	call	prtbyt	; print it in hexadecimal
	inx	H	; point to next byte
	mov	A,L	; check if multiple of 16
	ani	0Fh
	jrnz	Dump1	; jump if not
;
; Dump 16 bytes in ASCII format
	rst	space/8
	lhld	Daddr
Dump2:	mov	A,M	; get a byte
	ani	7Fh	; mask out parity bit
	cpi	20h	; printable?
	jrnc	.+4	; skip next instr if printable
	mvi	A,'.'	; print <dot> if unprintable
	rst	out0/8	; print it in ASCII
	inx	H	; point to next byte
	mov	A,L	; check if multiple of 16
	ani	0Fh
	jrnz	Dump2	; jump if not
;
; Check if dump is finished
	shld	Daddr
	ora	A	; clear carry flag
	dsbc	D	; clear carry flag if done
	jrc	Dump0	; jump if not done
	rst	restart/8
;----------
; Go to a memory location
; 
; G <addr>
Go:
	call	getadr	; address is in HL
	pchl		; jump to address in HL
;----------
; Fill memory
;
; F <addr1> <addr2> <byte>
Fill:
	call	getadr	; starting address
	push	H
	call	getadr	; ending address
	rst	getbyt/8 ; fill char
	pop	D	; begin addr in DE
	ora	A	; clear carry
	dsbc	D	; HL = HL - DE
	mov	C,L	; BC = byte count
	mov	B,H	
	mov	L,E	; HL = source address
	mov	H,D
	mov	M,A	; put fill char in memory
	inx	D	; DE = destination address
	ldir
	rst	restart/8
;----------
; Input from a port
;
; I <port>
In:
	rst	getbyt/8
	mov	C,A	; C = port number
	rst	crlf/8
	inp	A	; input byte to A
	call	prtbyt	; print the byte
	rst	restart/8
;----------
; Output to a port
;
; O <port> <byte>
Out:
	rst	getbyt/8
	push	PSW	; save port number
	rst	getbyt/8 ; get output byte
	pop	B	; restore port number
	mov	C,B	; C = port number
	outp	A	; output byte from A
	rst	restart/8
;----------
; Test memory
;
; T <addr1> <addr2>
;
; Repetitively write an increasing data pattern,
; and read it back for verification. 
;
; For each error detected , the address, byte written,
; and byte read are displayed.
pattern	=	0FFh	; initial pattern offset
Test:
	call	getadr	; read starting address
	push	H
	call	getadr	; read ending address
	pop	D	; DE = start, HL = end
	mvi	B,pattern
	rst	crlf/8
retry:	push	H	; save ending address
	push	H
fillmem:mov	A,L
	add	H
	add	B
	mov	M,A	; fill memory with H+L+pattern
	ora	A	; clear carry bit
	dsbc	D	; set Z flag if done
	dad	D	; restore HL
	dcx	H	; go to next location
	jrnz	fillmem
	pop	H	; restore ending address
testmem:mov	A,L
	add	H
	add	B
	cmp	M
	cnz	memerr	; call if memory error
	ora	A
	dsbc	D
	dad	D
	dcx	H
	jrnz	testmem
	dcr	B	; use another pattern
	mvi	A,'.'	; tell user we're still alive
	rst	out0/8
	pop	H
	jmp	retry
memerr:	push	PSW	; save what was written
	rst	crlf/8
	call	prtadr	; print address of error
	rst	space/8
	pop	PSW
	call	prtbyt	; byte written
	rst	space/8
	mov	A,M
	jmp	prtbyt	; byte read
	.page
;----------
; Boot from floppy, network, harddisk, or tape.
;
; B <device> [<combuf>]
;
; Read a bootstrap program from a device into RAM.
; If successful, jump to RAM.  If the device is 'T',
; then test the floppy disk controller.
Boot:
	rst	in0/8	; get device name
	cpi	'H'
	jz	Harddisk; Boot from harddisk
	cpi	'N'
	jz	Network	; Boot from network
	cpi	'F'
	jrz	Floppy	; Boot from floppy unit 0
	cpi	'T'
	jrz	Testflop; Test floppy
;
; Check for boot from specified floppy unit
	sui	'0'	; unit must be >= 0
	jm	error
	cpi	7+1	; unit must be <= 7
	jp	error
	jmpr	goflop
;----------
; Floppy boot
;
; Read single density, track 0, sectors 1-2
; from drive 0, and jump to RAM
Floppy:
	sub	A
goflop:
	lxi	H,homeFLOP; setup home, read commands
	lxi	D,homeF	; must move to RAM so that
	lxi	B,13	; unitno can be selected
	ldir
	sta	homeF+1	; put unitno in home, read
	sta	readF+1
	set	2,A	; turn on drive select bit
	out	PIOBD	; select drive
	sub	A
	out	PIOAD	; multiplex Floppy to DMA
	call	result	; flush the floppy controller
	lxi	H,specFLOP
	call	command ; specify timing info
reseek: lxi	H,homeF
	call	command	; recalibrate drive 0
sense:	lxi	H,IsenseFLOP
	call	command	; sense interrupt status
	call	result	; 2 result bytes returned
	lda	resbuf	; get first status byte
	bit	3,A	
	jrnz	reseek	; retry if not ready
	bit	5,A
	jrz	sense	; retry until seek done
	ani	0D0h	; check if seek successful
	cnz	ioerr
;
; This code is very timing sensitive.
; For 5 inch floppy, each data byte must be read from
; the floppy controller within 27 microsecs, or else it
; will be lost, and the read operation will terminate
; prematurely.
	lxi	H,readF
	call	command	; read data
	lxi	H,BOOTloc ; boot address
       	lxi	B,256<8+FLOPDR
..read:	call	waitdr	; wait for next byte available
	ini		; get and store a byte
	jrnz	..read	; continue until 1 sector read
	in	STOPFLOP; stop the floppy controller
;
; Check result status
	call	result	; 7 result bytes returned
	lxi	h,resbuf; get first result byte
	mov	a,m
	ani	0C0h	; top 2 bits should be zero
	jz	BOOTloc	; jump to boot code
	lxi	d,9070h	; mov result buf
	lxi	b,10h	;  to to 9070 for display
	ldir
	lxi	h,9000h	; display result if err
	mvi	a,cr
	jmp	daddr1	; into display routine
;----------
; Test floppy
;
; Get command buffer address, and then
; perform a floppy command and result phase
Testflop:
	call	getadr	; get command buffer address
	call	command ; do a command phase
	call	result	; do a result phase
	rst	restart/8
 	.page
;----------
; Floppy command strings - see NEC765 chip description
;			   for explanation
drive	=	0	; boot drive number
track	=	0	; boot track number
sector	=	1	; first boot sector
endcom	=	0FFh	; end-of-command character
specFLOP:
	.byte	3	; 'specify' command
	.byte	0cfh	; seek rate = 8 ms
			; head unload time = 256ms
	.byte	81h	; head load time = 256ms
			; non-DMA mode
	.byte	endcom
IsenseFLOP:
	.byte	8	; 'sense interrupt status'
	.byte	endcom
homeFLOP:
	.byte	7	; 'recalibrate' command
	.byte	drive	; drive select
	.byte	endcom
readFLOP:
	.byte	46h	; 'read' command
	.byte	drive	; head, drive select
	.byte	track	; track number
	.byte	00h	; head address
	.byte	sector	; sector number
	.byte	01h	; 256 byte sector
	.byte	10h	; last sector number
	.byte	0eh	; gap length (in bytes)
	.byte	0	; sector size
	.byte	endcom
	.page
;----------
; Network boot
Network:
	sub	A	; DMA vector stored in low core
	stai
	im2		; setup interrupt mode
	mvi	A,1
	out	PIOAD	; multiplex SIO1B to DMA
	lxi	H,DMANprog
	lxi	B,DMAN$<8+DMA
	outir		; program the DMA chip
	lxi	H,RECprog
	lxi	B,REC$<8+SIO1BC
	outir		; program the SIO1B chip
..wait:
	in	SIO1BC	; wait for data addressed to us
	ani	1<RxRDY
	jrz	..wait
	in	SIO1BD	; throw away the user number
	mvi	A,87h	; enable DMA
	out	DMA
	ei
	hlt		; wait for DMA done interrupt
	jmp	BOOTloc	; execute the bootstrap
;
; Process interrupt on DMA done
DMARdone:
	push	PSW
	mvi	A,0C3h	; reset DMA chip
	out	DMA
	mvi	A,18h	; reset the SIO1B chip
	out	SIO1BC
	pop	PSW
	ret
	.page
;----------
; SDLC command strings
lenBOOT	==	380h	; length of network boot code
BOOTusr	==	254	; boot pseudo user number
RECprog:
	.byte	    00011000b ; channel reset
	.byte	  4,00100000b ; SDLC mode
	.byte	15h,10000000b ; transmit disable
	.byte	  3,11111100b ; receiver info
	.byte	  6,BOOTusr   ; user number
	.byte	  7,01111110b ; flag byte
	.byte	11h,11100100b ; interrupt control
	.byte	23h,11111101b ; enable receiver
REC$	==	.-RECprog
;
DMANprog:
	.byte	0C3h	; master reset		    2D
	.byte	0C7h	; reset port A	 	    2D
	.byte	0CBh	; reset port B		    2D
	.byte	7Dh	; read from port B
	.word	BOOTloc	; DMA address
	.word	lenBOOT-1; DMA length - 1
	.byte	14h	; port A inc, memory	    1B
	.byte	28h	; port B fixed, I/O	    1B
	.byte	95h	; byte mode		    2B
	.byte	SIO1BD	; port B
	.byte	12h	; interrupt at end of block
	.byte	DMAvect&0FFh ; interrupt vector
	.byte	92h	; stop at end of block
	.byte	0CFh	; load starting address	    2C
	.byte	1	; read
	.byte	0CFh	; load starting address	    1A
	.byte	0ABh	; enable interrupts
DMAN$	==	.-DMANprog
	.LOC	400H	;SECOND HALF OF ROM
;----------
; Harddisk boot
;
; Read logical unit 0, track 2, sector 1
Harddisk:
	lxi	H,selHARD
	call	cmdHARD	; select unit 0
	lxi	H,readHARD
	call	cmdHARD	; read 1 sector
	call	resHARD	; get result status
	lxi	H,BOOTloc
	mvi	B,128
	call	recHARD	; get data bytes
	jmp	BOOTloc
;----------
; Send command to the hard disk
;  Regs in:   HL = address of command string
;  Regs out:  none
;  Destroyed: A, BC, HL
cmdHARD:
..1:	in	HARDP	; clear status
	in	PIOAD	; wait for HDC receive
	bit	3,A
	jrnz	..1
	mvi	A,51h	; "request to send"
	out	HARDP
..2:	in	PIOAD	; wait for HDC send
	bit	4,A
	jrz	..2
	in	HARDP	; check if "clear to send"
	cpi	52h
	jrnz	..1	; if not, retry
	mvi	B,8
	jmpr	sendHARD
;----------
; Receive status from hard disk controller
;  Regs in:   none
;  Regs out:  none
;  Destroyed: A, BC, HL
resHARD:
	lxi	H,resbuf; put result bytes here
	mvi	B,8	; always get 8 result bytes
	call	recHARD
	lda	resbuf+7; check error status
	ora	A
	cnz	ioerr	; abort on any error
	ret
;----------
; Send data bytes to the hard disk
;  Regs in:   HL = block address
;	      B  = byte count
;  Regs out:  none
;  Destroyed: A, BC, HL
sendHARD:
	mvi	C,HARDP
..1:	in	PIOAD
	bit	3,A
	jrnz	..1
	outi
	jrnz	..1
	ret
;----------
; Receive data bytes from the hard disk
;  Regs in:   HL = block address
;	      B  = byte count
;  Regs out:  none
;  Destroyed: A, BC, HL
recHARD:
	mvi	C,HARDP
..1:	in	PIOAD
	bit	4,A
	jrz	..1
	ini
	jrnz	..1
	ret
;----------
; Hard disk commands
selHARD:
	.byte	13h	; select
	.byte	0	; unit
readHARD:
	.byte	11h	; read
	.byte	1	; secotr
	.byte	2	; track
	.byte	0
	.byte	0
	.byte	0
	.byte	10	; retries
	.byte	0
EMULATE:
	rst	4	;crlf
..4:	IN	SIO1AC
	BIT	RXRDY,A
	JRNZ	..GOTHOST
	IN	PARASTAT
	BIT	6,A
	JRZ	..4
	IN	PARADATA
	PUSH	PSW
..2:	IN	SIO1AC
	BIT	TXRDY,A
	JRZ	..2
	POP	PSW
	OUT	SIO1AD
	JMPR	..4
..GOTHOST:
	IN	SIO1AD
	PUSH	PSW
..3:	IN	PARASTAT
	BIT	5,A
	JRNZ	..3
	POP	PSW
	OUT	PARADATA
	JMPR	..4
	.end
