	.Z80
	.SFCOND
	PAGE	64

FALSE	EQU	0
TRUE	EQU	0FFH

T2732	EQU	FALSE
T2716	EQU	TRUE


;
	IF	T2732
	TITLE	PROGRAMMER, 2732
	ENDIF

	IF	T2716
	TITLE	PROGRAMMER, 2716
	ENDIF
;
; This routine reads a CP/M .COM file of maximum size 4k bytes
; and burns it in a 2732 installed in U80 of BIGBOARD II.
; Or into a 2716 installed in U81.
; The 2732/2716 is 1st checked against the code to be burned in
; to be sure no '0' levels are to be programmed to '1'.
; Note that the 2732/2716 need not be blank.
; To achieve maximum speed, only those locations needing to be
; programmed actually receive the 50 ms programming pulse.
; Following programming, the 2732/2716 is verified,
; and any errors reported. The program can possibly be modified
; to burn other PROMS, but the reader should proceed with caution.
; Programming requirements vary considerably.
;
; jumpering for U-80 (2732) is as follows:
;
;	pin 18 to REC5
;	pin 20 to /OE/VPP5
;	pin 21 TO RA11
;
;	
; D. H. DURLAND
; 663 Georgia Ave.
; Palo Alto, CA 94306
;
; edit 12-8-82 remove phone #.  You are welcome to write.  Include
;  stamped, self addressed envelope.
; edit 11-1-82 to remove reference to 2716's
; edit 10-21-82 to include jumper information
;
; the program is intended to be assembled using MACRO-80
; .phase/.dephase commands work well to get code to 100h for .com file 
;
; Instructions for use:
;	Your code should be stored in a CP/M .COM file.
;	To program, for example, EXAMPROG.COM
;
;	Turn on your programming power supply.
;	Insert the PROM to be programmed in U-80 or U81
;	Boot up CP/M to access PROGRAM.COM and EXAMPROG.COM
;	(the usual drive access rules apply)
;	Type '<x:>PROGRAM <y:>EXAMPROG.COM'<CR>(the .COM is optional)
;	(The program will bounce if it doesn't find a .com file)
;
;	The rest is automatic
;
;
;********************************************************
;							*
; 2716 Entry's included 26/06/83			*
;							*
; by	L.Koopman					*
;	Waarbekenplein 13				*
;	7553 KK	Hengelo (o)				*
;	Tel. 074-913022					*
;	Holland						*
;							*
; jumpering for U-81 (2716) is as follows:		*
;							*
;	pin 18 to PGM					*
;	pin 20 to RECX					*
;	pin 21 to /OE/VPP4				*
;							*
; pin 2 of U44 must be lifted for programming and	*
; verify of a 2716 eprom.				*
;							*
;********************************************************


BOOT	EQU	0
FCB	EQU	5CH
BDOS	EQU	5
CR	EQU	0DH
LF	EQU	0AH
R2	EQU	7FH
SYS1	EQU	0C8H
PROG	EQU	0C0H
CTCB3	EQU	08BH
SRCMEM	EQU	9000H		; park source here
STACK	EQU	SRCMEM
ON	EQU	00001000B
OFF	EQU	00000000B

	IF	T2732
ROMSIZ	EQU	4096		; size of a 2732
	ENDIF

	IF	T2716
ROMSIZ	EQU	2048		; size of a 2716
	ENDIF

MAXREC	EQU	ROMSIZ/128
PRAM	EQU	8000H		; where some of this will run

	IF	T2716
ROMLOC	EQU	4000H		; ROM LOCATION
	ENDIF

	IF	T2732
ROMLOC	EQU	5000H		; ROM LOCATION
		ENDIF

ROMCPY	EQU	0A000H		; PROM copied here
ENDCK	EQU	HIGH (SRCMEM+ROMSIZ)
;
	ASEG
	org	100h
;
;
PROGRM:	LD	SP,STACK	; Underneath code to be burned
;
; 1st check to be sure a name has been entered.
;
	LD	HL,FCB+1	; 1 past drive
	LD	A,(HL)
	CP	' '		; is there a letter?
	JP	Z,BUMFIL	; if not, go report no file
;
; now check for no type spec or .COM
;
	LD	DE,65H		; 1st type in FCB
	LD	HL,COMTBL
	LD	BC,3
;
COM0:
	LD	A,(DE)		; get type
	CP	' '
	JR	Z,COM1		; space OK
;
	CP	(HL)		; ck letter
	JP	NZ,BUMFIL	; insist on space or correct letter
;
COM1:
	LDI			; move a letter
	JP	PE,COM0		; until COM moved in
;
	JR	OPNFIL		; go open it
;
COMTBL:
	DEFM	'COM'
;
OPNFIL:
	LD	C,15		; open file
	LD	DE,FCB
	CALL	BDOS
	OR	A		; set flags
	JP	M,BUMFIL	; if can't find it
;
	LD	C,35		; compute file size
	LD	DE,FCB
	CALL	BDOS
	LD	HL,R2		; point to high virtual size byte
	LD	A,(HL)
	DEC	HL
	OR	(HL)		; middle byte
	JP	NZ,TOOBIG	; both high bytes must be 0
;
	DEC	HL
	LD	A,MAXREC
	CP	(HL)		; least significant byte
	JP	C,TOOBIG	; MAXREC records maximum
;
; fill with FF 1st
;
	LD	HL,SRCMEM
	LD	DE,SRCMEM+1
	LD	(HL),0FFH
	LD	BC,ROMSIZ	; byte count
	LDIR			; do it
;
; now the actual read
;
	LD	DE,SRCMEM-128
RDLP:
	LD	HL,128
	ADD	HL,DE		; update DMA ADDR
	EX	DE,HL
	PUSH	DE		; save DMA ADDR
	LD	C,26		; set DMA ADDR
	CALL	BDOS
;
	LD	C,20		; read sequential
	LD	DE,FCB
	CALL	BDOS		; read a record
	POP	DE		; recover DMA ADDR
	OR	A		; successful?
	JR	Z,RDLP		; if not past end of file
;
	CP	1		; end of file?
	JP	NZ,BUMRD	; anything else is an error
;
; now we move the next section up to 8000 and jump to it,
; as we are going to bank switch in the PROMS and can't operate
; from CP/M
;
	LD	DE,BURNIT
	LD	HL,BURNLO
	LD	BC,BRNEND-BURNIT
	LDIR			; move code up
	JP	BURNIT		; and go to it
;
BURNLO	EQU	$
;
	.PHASE	PRAM		; out of bank switched area
;
BURNIT:
	DI
	LD	A,0
	OUT	(SYS1),A	; switch in the PROMS
	EI

;
; 1st we check the PROM for 0-1 transitions
;
	LD	HL,SRCMEM	; source code
	LD	DE,ROMLOC	; PROM address
	LD	A,TRUE
	LD	(BITSOK),A	; initialize assuming OK
;
CKLOOP:
	LD	A,(DE)		; get a PROM byte
	OR	(HL)
	LD	B,A		; save with (possibly) extra bits
	LD	A,(DE)		; get PROM again
	CP	B
	JR	NC,CKADUP	; if no bits went up
;
	LD	A,FALSE
	LD	(BITSOK),A	; flag for message at end
	JP	ROMOUT		; go back to CP/M
;
CKADUP:	INC	HL
	INC	DE
	LD	A,H
	CP	ENDCK		; 1 past end
	JR	C,CKLOOP	; for 2k or 4k bytes
;
; at this point we know that the PROM is at least theoretically
; programmable.  Copy it into ROMCPY for reference.
;
	LD	HL,ROMLOC	; PROM
	LD	DE,ROMCPY	; copy destination
	LD	BC,ROMSIZ	; byte count
	LDIR			; move it
;
; here is the actual burn
;
	LD	B,3
	LD	C,PROG
	LD	HL,BRNTBL	; table of output words
	OTIR			; get set
;
	LD	HL,SRCMEM	; source code
	LD	DE,ROMLOC	; PROM address
	LD	BC,ROMCPY	; copy address
	JR	BURNLP		; and do it
BRNTBL:
	DEFB	00000000B+ON	; to disable PROM outs, enable U-57 outs
	DEFB	00000001B+ON	; to disable PROM /CS lines
	DEFB	00000100B+ON	; to turn on program voltage
;
BURNLP:
	LD	A,(BC)		; PROM copy
	CP	(HL)		; same as source?
	JR	Z,BURN9		; skip burn if so (save time)
;
	LD	A,(HL)		; get source
	LD	(DE),A		; latch it to PROM for burn
;
	IF	T2732
	LD	A,00000001B+OFF
	OUT	(PROG),A	; /DECODE low thus /CS low
	ENDIF
	
	IF	T2716
	LD	A,00000011B+ON	; pgm on
	OUT	(PROG),A	; PROGRAM PULSE ON
	ENDIF
;
	PUSH	BC		; save copy address
	LD	B,50		; millisecond count
CNTMS:
	IN	A,(CTCB3)	; get current count
	LD	C,A		; it becomes reference
MSCHG:
	IN	A,(CTCB3)
	CP	C		; change?
	JR	Z,MSCHG		; until a change
;
	DJNZ	CNTMS		; do 50x 1 millisec
	POP	BC		; retrieve copy address
;
	IF	T2732
	LD	A,00000001B+ON
	OUT	(PROG),A	; /DECODE high thus /CS high
	ENDIF

	IF	T2716
	LD	A,00000011B+OFF
	OUT	(PROG),A	; pgm off
	ENDIF
;
BURN9:				; can get here if PROM=source
				;  (see BURNLP+2)
;
	INC	HL
	INC	DE
	INC	BC
	LD	A,H
	CP	ENDCK		; 1 past end
	JR	C,BURNLP	; for 4k bytes
;
; PROM is now burned.  Time to verify it.
;
	LD	B,3
	LD	C,PROG
	LD	HL,NRMTBL	; table to go back to normal
	OTIR			; go back
;
	JR	VERIF1		; and verify
NRMTBL:
	DEFB	00000100B+OFF	; to turn off program voltage
	DEFB	00000001B+OFF	; to enable chip set decoder
	DEFB	00000000B+OFF	; to turn off out buff and enable PROM
;
VERIF1:
;
; 1st we copy the burned PROM into ROMCPY
;
	LD	HL,ROMLOC	; PROM
	LD	DE,ROMCPY	; copy destination
	LD	BC,ROMSIZ	; byte count
	LDIR			; move it

;
; Now switch out the PROMS and go back to CP/M for verification.
;
ROMOUT:
	DI
	LD	A,8
	OUT	(SYS1),A	; switch out the PROMS
	EI
	JP	VERIFY		; go do the verification
;
BRNEND	EQU	$
;
BITSOK:	DEFS	1		; goes false on 0 to 1 transition request
ROMOK:	DEFS	1		; goes false on bad verify
;
	.DEPHASE
;
VERIFY:
	LD	A,(BITSOK)
	OR	A
	JP	Z,BITNG		; go report no try
;
	LD	DE,CRLF		; else do the verification
	CALL	PMSG		; put crlf
;
	LD	A,TRUE
	LD	(ROMOK),A	; assume ok
	LD	HL,SRCMEM	; source start
	LD	DE,ROMCPY	; PROM copy
;
VLP:
	LD	A,(DE)		; get a PROM byte
	CP	(HL)		; match?
	CALL	NZ,REPORT	; if not
	INC	HL
	INC	DE
	LD	A,H
	CP	ENDCK		; 1 past end
	JR	C,VLP		; catch all bytes
;
	LD	A,(ROMOK)
	OR	A
	JP	Z,FINIS		; if not ok, no reporting to be done
;
	LD	DE,VERMSG	; else report success, and quit
	CALL	PMSG
	JP	FINIS
;
; Report receives DE pointing to the bad PROM byte and HL pointing
;  to the source byte.  HL is a relative address.
;
REPORT:	PUSH	DE
	PUSH	HL
	CALL	MOVE4		; move address into message
	LD	A,(DE)		; get bad PROM byte
	LD	DE,ERRMS4
	CALL	MOVE2		; move bad PROM byte to message
	LD	A,(HL)		; get source byte
	LD	DE,ERRMS6
	CALL	MOVE2		; move to message
	LD	DE,ERRMS1
	CALL	PMSG		; print the error message
	POP	HL
	POP	DE
	LD	A,FALSE
	LD	(ROMOK),A	; if we get here at all, we have a problem
	RET
;
; MOVE4 converts the address to ASCII and moves it to the message area
;
MOVE4:                   
	PUSH	DE
	LD	DE,ERRMS2
	LD	A,H
	RES	7,A		; modulo 4k		     
	CALL	MOVE2		; move H to message area
	LD	A,L
	CALL	MOVE2		; and L
	POP 	DE
	RET
;
; MOVE2 converts a HEX byte to two ASCII characters and moves
;  them into the message area
;
MOVE2:
	PUSH	AF
	RRA
	RRA
	RRA
	RRA			; get high nibble into low
	CALL	MOVNIB		; and move it
	POP	AF		; restore entire byte
MOVNIB:
	AND	0FH		; only low part of interest
	ADD	A,90H
	DAA
	ADC	A,40H
	DAA			; convert to ASCII
	LD	(DE),A		; put it in the message area
	INC	DE		; advance to next slot
	RET
;
; this area contains abort routines and messages
;
BITNG:
	LD	DE,BITMSG
	CALL	PMSG
	JP	FINIS
BITMSG:	
	DEFM 	CR,LF,'Bits not all blank.  Not programmable.'
	DEFM	' Aborting',CR,LF,'$'
;
BUMFIL:	
	LD	DE,FILMSG
	CALL	PMSG
	JP	FINIS
FILMSG:
	DEFM	CR,LF,'Improper file specification',CR,LF,'$'
;
TOOBIG:
	LD	DE,BIGMSG
	CALL	PMSG
	JP	FINIS
BIGMSG:
	DEFM	CR,LF,'Too big for PROM',CR,LF,'$'
;
BUMRD:
	LD	DE,RDMSG
	CALL	PMSG
	JP	FINIS
RDMSG:
	DEFM	CR,LF,'Bad read, aborting',CR,LF,'$'
;
PMSG:
	LD	C,9
	CALL	BDOS
	RET
;
ERRMS1:
	DEFM	'Relative '
ERRMS2:
	DEFS	4		; will hold address
ERRMS3:
	DEFM	'='
ERRMS4:
	DEFS	2		; will hold bad PROM byte
ERRMS5:
	DEFM	' should='
ERRMS6:
	DEFS	2		; will hold source byte
CRLF:
	DEFM	CR,LF,'$'
VERMSG:
	DEFM	'PROM verifies OK',CR,LF,'$'
;
FINIS:
	JP	BOOT
;
	END
;
