; GENGRAF.ASM
; -----------
;
; GSX-80 - GENGRAF.COM
;
; Disassembled by:
;
; ROCHE Emmanuel
; 8 rue HERLUISON
; 10000 TROYES
; FRANCE
; ------
;
;--------------------------------
;
	PAGE	0		; Listing without page breaks
;
	ORG	0100H		; Standard CP/M-80 COMmand file
;
;--------------------------------
; List of ASCII characters used
;
lf	equ	0AH		; Line Feed
cr	equ	0DH		; Carriage Return
ctrlZ	equ	1AH		; = End Of File
;
;--------------------------------
; List of BDOS functions used
;
BDOS	equ	0005H		; Basic Disk Operating System
;
sysres	equ	 0		; System reset
conout	equ	 2		; Console output
pstring	equ	 9		; Print string
openf	equ	15		; Open file
closef	equ	16		; Close file
deletef	equ	19		; Delete file
readf	equ	20		; Read sequential
writef	equ	21		; Write sequential
makef	equ	22		; Make file
renamef	equ	23		; Rename file
setDMA	equ	26		; Set DMA address
filsiz	equ	35		; Compute file size
;
;--------------------------------
; List of page zero locations used
;
reboot	EQU	0000H		; Warm start
dskuse	EQU	0004H		; Current disk and user number
topTPA	EQU	0006H		; Address of top TPA
I$0010	EQU	0010H		; ----I
I$0020	EQU	0020H		; ----I
FCB1	EQU	005CH		; Default File Control Block 1
ZERtyp	EQU	0065H		; First char of filetype in page zero
ZERcr	EQU	007CH		; Current record position in page zero
ZERrrn	EQU	007DH		; Random record number in page zero
DBUF	EQU	0080H		; Default 128-byte disk buffer
;
C$CD02	EQU	0CD02H		; -C---
I$CDF9	EQU	0CDF9H		; ----I
I$FFF3	EQU	0FFF3H		; ----I
;
;--------------------------------
; List of offset inside Default FCB 1
;
FCBtyp	equ	0009H		; First char of filetype in FCB
FCBex	equ	000CH		; Current extent number  in FCB
;
;======================================================================
; Start of first program
;
start1:	DB	0C3H		; Jump opcode
;
word1:	DW	start2		; Point to start of program
;
retone:	DB	0C9H		; Return opcode
;
word2:	DW	0000H		; ?
;
start3:	LXI	H,0001H		; HL = 1 (point to BIOS entry?)
	SPHL			; Stack = above
	CALL	chkASG		; Check is ASSIGN.SYS is on disk
	CALL	readA		; Read ASSIGN.SYS file
	MVI	A,05H		; Number of drivers to try to load
	PUSH	PSW		; 
	LXI	H,DMAbuf	; DMA buffer (source)
	LXI	D,DDnumb	; DD number  (destination)
getbyt:	MOV	A,M		; Get a byte from ASSIGN.SYS
	CPI	ctrlZ		; = EOF?
	JZ	close3		; Then Close ASSIGN.SYS
	CPI	31H		; Is it a number?
	JNC	dozen		; 
	XRA	A		; If < 1 then set to 0
	JMP	digit		; 
;
;--------------------------------
;
dozen:	SUI	30H		; Convert to binary number
	ADD	A		; (Multiplied by 10?)
	MOV	B,A		; 
	ADD	A		; 
	ADD	A		; 
	ADD	B		; 
digit:	MOV	B,A		; 
	INX	H		; 
	MOV	A,M		; Get a byte from ASSIGN.SYS
	SUI	30H		; Convert to binary number
	ADD	B		; 
	STAX	D		; Store it in DD number
	XRA	A		; Reset Reg-A to zero
	INX	D		; 
	STAX	D		; 2nd byte of DD number = zero
	INX	D		; 
	INX	H		; (Space separator in ASSIGN.SYS)
	INX	H		; (Point to drive letter)
	CALL	upper		; Convert to upper case
	SUI	40H		; Convert to binary number
	STAX	D		; Store in DD list
	INX	D		; Point to next char in destination
	INX	H		; Point to next char in source
	MVI	C,08H		; 8 chars of device driver
DDname:	CALL	upper		; Convert to upper case
	CPI	';'		; Start of comments? (end of DD name)
	JZ	fill1		; 
	CPI	cr		; End of line?
	JNZ	fill2		; 
fill1:	MVI	A,' '		; Space for filling DD filename
	DCX	H		; Decrement counter
fill2:	STAX	D		; Put space in DD table
	INX	D		; 
	DCR	C		; = 0?
	JNZ	DDname		; No: loop
	MVI	A,lf		; Yes: we must have reached the Line Feed
fill3:	CMP	M		; Isn't it?
	INX	H		; 
	JNZ	fill3		; 
	POP	PSW		; 
	DCR	A		; Loop 5 times
	PUSH	PSW		; 
	JNZ	getbyt		; Get another byte from ASSIGN.SYS
close3:	POP	PSW		; 
	CALL	closeA		; Close ASSIGN.SYS
	LHLD	topTPA		; Load address of top of TPA from page zero
	SHLD	savtop		; Save address of top of TPA
	LXI	D,DDlist	; Source: List of 5 DD filenames
	LXI	H,ASSIGN	; Destin: ASSIGN.SYS file spec
	MVI	C,09H		; 9 bytes (drive code + DD filename)
	CALL	copyDH		; Copy one file specification
	MVI	M,50H		; "P" (add PRL filetype)
	INX	H		; 
	MVI	M,52H		; "R"
	INX	H		; 
	MVI	M,4CH		; "L"
	CALL	C0278		; 
	LHLD	LOMEM		; New top of TPA after DD is loaded
	SHLD	savtop		; Save address of top of TPA
	LXI	D,GSXSYS	; Source: GDOS file specification
	LXI	H,ASSIGN	; Destin: ASSIGN.SYS file spec
	MVI	C,0CH		; 12 bytes (drive code + FILENAME.TYP)
	CALL	copyDH		; Copy one file specification
	CALL	C0278		; 
	LHLD	LOMEM		; Destin: New top of TPA after DD is loaded
	PUSH	H		; 
	LXI	B,dskuse	; Current disk and user number
	DAD	B		; 
	LXI	D,topTPA	; Source: Load address of top TPA
	MVI	C,02H		; 2 bytes
	CALL	copyDH		; Copy it in LOMEM
	LXI	D,DDnumb	; Source: 
	MVI	C,02H		; 2 bytes
	CALL	copyDH		; Copy it in DDnumb
	DCX	D		; 
	DCX	D		; Source: 
	MVI	C,37H		; 55 bytes (5 times 11 bytes)
	CALL	copyDH		; Copy 5 file specifications
	XCHG			; 
	INX	D		; 
	INX	D		; 
	MVI	C,pstring	; Print string
	CALL	BDOS		; 
	LHLD	word2		; Load what?
	POP	D		; 
	DAD	D		; 
	JNC	ninofm		; 'not enough memory$'
	XCHG			; 
	SHLD	topTPA		; Store address of top TPA
	MVI	C,setDMA	; Set DMA address
	LXI	D,DBUF		; Default 128-bytes disk buffer
	CALL	BDOS		; 
	LXI	D,reloc		; Source: Put RELOC address in Reg-DE
	LHLD	LOMEM		; Destin: New top of TPA after DD is loaded
	LXI	B,I$FFF3	; Length of GSX.SYS (GDOS) ?
	DAD	B		; 
	PUSH	H		; 
	SHLD	GDOSb		; GDOS base
	MVI	C,0DH		; 13 bytes
	CALL	copyDH		; Copy a string in TPA
	LXI	H,border	; Limit between 1st and 2nd program
	POP	D		; 
	PUSH	D		; 
	MOV	A,E		; 
	SUB	L		; 
	MOV	C,A		; 
	MOV	A,D		; 
	SBB	H		; 
	MOV	B,A		; 
	LXI	D,start1	; Start of first program
	JMP	retone		; Return opcode
;
;--------------------------------
; HL source
; DE destination
; BC count
;
reloc:	MOV	A,M		; Get a byte
	STAX	D		; Put it in destination
	INX	H		; 
	INX	D		; 
	DCX	B		; Decrement 16 bit counter
	MOV	A,B		; 
	ORA	C		; If finished, then jump to GDOS
	DB	0C2H		; JNZ opcode
GDOSb:	DW	0000H		; GDOS base
	JMP	start1		; Else: Start of first program
;
;--------------------------------
; Test if lower cases.
; If so, convert to upper cases.
;
upper:	MOV	A,M		; Get a byte
	INX	H		; 
	CPI	'a'		; Beginning of lower cases?
	RC			; 
	CPI	'z'+1		; End of lower cases?
	RNC			; 
	SUI	20H		; Convert to upper cases
	RET			; 
;
;--------------------------------
; Copy a string in TPA from DE (source) to HL (destination)
;
; DE = source
; HL = destination
;  C = number of bytes
;
copyDH:	LDAX	D		; Get a byte from source
	MOV	M,A		; Put it in TPA at destination HL
	INX	D		; 
	INX	H		; 
	DCR	C		; Decrement counter
	JNZ	copyDH		; 
	RET			; 
;
;--------------------------------
;
ninofm:	LXI	D,notmem	; 'Not enough memory$'
	JMP	bak2CPM		; 
;
;--------------------------------
;
notmem:	DB	'Not enough memory$'
;
GSXSYS:	DB	00H		; Default drive
	DB	'GSX     SYS'	; GDOS file specification
;
;--------------------------------
; Table of DDs
;
; Format:
; DW 0FFFFH is replaced by DD number (HI = DD number, LO = 00H)
; DB 00H    is replaced by the drive number
; DS 8      is replaced by the DD filename
;
DDnumb:	DW	0FFFFH
DDlist:	DB	00H
	DB	'        '	; First DD filename
;
	DW	0FFFFH
	DB	00H
	DB	'        '	; Second DD filename
;
	DW	0FFFFH
	DB	00H
	DB	'        '	; Third DD filename
;
	DW	0FFFFH
	DB	00H
	DB	'        '	; Fourth DD filename
;
	DW	0FFFFH
	DB	00H
	DB	'        '	; Fifth DD filename
;
;--------------------------------
;
C0278:	CALL	chkASG		; Check if ASSIGN.SYS is on disk
	CALL	readA		; Read ASSIGN.SYS file
	LHLD	DMA2nd		; DMA buffer 2nd byte (PRL program size)
	PUSH	H		; 
	XCHG			; 
	LHLD	savtop		; Load address of top of TPA
	MOV	A,L		; 
	SUB	E		; 
	MOV	A,H		; Compute HIMEM - PRL program size
	SBB	D		; 
	MOV	H,A		; 
	MVI	L,00H		; Page boundary
	SHLD	LOMEM		; Store address of new top of TPA
	PUSH	H		; 
	PUSH	H		; 
	PUSH	D		; 
	CALL	readA		; Read ASSIGN.SYS file
	POP	B		; 
	POP	H		; 
J$0298:	CALL	C02C8		; 
	MOV	M,A		; 
	INX	H		; 
	DCX	B		; 
	MOV	A,C		; 
	ORA	B		; 
	JNZ	J$0298		; 
	POP	H		; 
	MOV	B,H		; 
	DCR	B		; 
	POP	D		; 
J$02A7:	MVI	C,08H		; 8 
	CALL	C02C8		; 
J$02AC:	RLC			; 
	PUSH	PSW		; 
	JNC	J$02B4		; 
	MOV	A,B		; 
	ADD	M		; 
	MOV	M,A		; 
J$02B4:	INX	H		; 
	DCX	D		; 
	MOV	A,D		; 
	ORA	E		; 
	JZ	close2		; Close ASSIGN.SYS
	POP	PSW		; 
	DCR	C		; 
	JNZ	J$02AC		; 
	JMP	J$02A7		; 
;
;--------------------------------
;
close2:	POP	PSW		; 
	CALL	closeA		; Close ASSIGN.SYS
	RET			; 
;
;--------------------------------
;
C02C8:	PUSH	H		; 
	PUSH	D		; 
	LHLD	D03B6		; 
	INR	L		; 
	JP	J$02D9		; 
	PUSH	B		; 
	CALL	readA		; Read ASSIGN.SYS file
	POP	B		; 
	LXI	H,0000H		; 
J$02D9:	SHLD	D03B6		; 
	LXI	D,DMAbuf	; DMA buffer
	DAD	D		; 
	MOV	A,M		; 
	POP	D		; 
	POP	H		; 
	RET			; 
;
;--------------------------------
; Check if file is on disk
;
chkASG:	LXI	D,ASSIGN	; ASSIGN.SYS file spec
chkfil:	PUSH	D		; 
	LXI	H,FCBex		; Point to current extent number
	DAD	D		; 
	MVI	M,00H		; 
	INX	H		; 
	INX	H		; 
	MVI	M,00H		; 
	MVI	A,80H		; 
	STA	D03B6		; 
	MVI	C,openf		; Open file
	CALL	BDOS		; 
	POP	D		; 
	LXI	H,I$0020	; 
	DAD	D		; 
	MVI	M,00H		; 
badchk:	ORA	A		; Successful open/close?
	RP			; Yes: return
	CALL	showFN		; No: Display filename on console
	LXI	D,notfnd	; ' not found$'
	JMP	bak2CPM		; 
;
;--------------------------------
;
closeA:	LXI	D,ASSIGN	; ASSIGN.SYS file spec
	MVI	C,closef	; Close file
	CALL	BDOS		; 
	JMP	badchk		; Cf. above
;
;--------------------------------
; Display filename on console
;
showFN:	XCHG			; 
	MOV	A,M		; Get drive code
	ORA	A		; 
	JZ	nodriv		; 
	ADI	40H		; Convert drive code in letter
	MOV	E,A		; 
	CALL	showit		; 
	MVI	E,':'		; Drive separator
	CALL	showit		; 
nodriv:	INX	H		; 
	MVI	A,8+1		; Filename
	CALL	loopri		; 
	MVI	E,'.'		; Filename separator
	CALL	showit		; 
	MVI	A,3+1		; Filetype
	CALL	loopri		; 
	RET			; 
;
;--------------------------------
; Display a char on console
;
showit:	PUSH	H		; 
	MVI	C,conout	; Console output
	CALL	BDOS		; 
	POP	H		; 
	RET			; 
;
;--------------------------------
; Display n-1 chars on console
;
loopri:	DCR	A		; Done?
	RZ			; 
	MOV	E,M		; Get char
	INX	H		; Ready next char
	PUSH	PSW		; 
	CALL	showit		; Display the char on console
	POP	PSW		; 
	JMP	loopri		; Loop until done
;
;--------------------------------
; Read ASSIGN.SYS file
;
readA:	LXI	D,DMAbuf	; DMA buffer
	MVI	C,setDMA	; Set DMA address
	CALL	BDOS		; 
	LXI	D,ASSIGN	; ASSIGN.SYS file spec
	PUSH	D		; 
	MVI	C,readf		; Read sequential
	CALL	BDOS		; 
	POP	D		; 
	ORA	A		; Successful read?
	RZ			; Yes: return
	CALL	showFN		; No: Display filename on console
	LXI	D,whyEOF	; ':  unexpected EOF$'
bak2CPM:MVI	C,pstring	; Print string
	CALL	BDOS		; 
	JMP	reboot		; Warm start
;
;--------------------------------
;
whyEOF:	DB	':  unexpected EOF$'
;
notfnd:	DB	' not found$'
;
ASSIGN:	DB	00H		; Default drive
	DB	'ASSIGN  SYS'	; File specification
	DS	24		; Rest of FCB definition
;
savtop:	DW	0000H		; Save area for top of TPA
;
LOMEM:	DW	0000H		; Save area for new top of TPA,
				;   after a DD is loaded in TPA
;
D03B6:	DW	0000H		; ?
;
DMAbuf:	DB	00H		; DMA buffer first byte
;
DMA2nd:	DB	00H		; DMA buffer second byte (PRL program size)
;
	DS	126		; Rest of 128-bytes buffer
;
;
;======================================================================
; Start of second program
;
start2:	LXI	D,copyr		; Copyright message
	MVI	C,pstring	; Print string
	CALL	BDOS		; 
	LXI	H,ZERtyp	; First char of filetype in page zero
	MVI	M,43H		; "C"  (add COM filetype)
	INX	H		; 
	MVI	M,4FH		; "O"
	INX	H		; 
	MVI	M,4DH		; "M"
	LXI	D,FCB1		; Default FCB in page zero
	MVI	C,filsiz	; Compute file size
	CALL	BDOS		; 
	LHLD	ZERrrn		; Random record number in page zero
	DAD	H		; 
	DAD	H		; 
	DAD	H		; 
	DAD	H		; 
	DAD	H		; 
	DAD	H		; 
	DAD	H		; 
	LXI	D,I$048D	; 
	DAD	D		; 
	MOV	A,L		; 
	CMA			; 
	MOV	L,A		; 
	MOV	A,H		; 
	CMA			; 
	MOV	H,A		; 
	INX	H		; 
	SHLD	word2		; Save what?
	XRA	A		; 
	STA	ZERcr		; Current record position set to zero
	LXI	H,FCB1		; Source: Default FCB in page zero
	LXI	D,FCBseq	; Destin: FCB for read/write seq
	PUSH	D		; 
	MVI	C,24H		; 36 bytes
	CALL	copyHD		; 
	POP	D		; 
	PUSH	D		; 
	LXI	H,FCBtyp	; Point to first char of filetype
;
border:		; +++ Limit between 1st and 2nd program +++
;
	DAD	D		; 
	MVI	M,24H		; "$" (temporary file)
	INX	H		; 
	MVI	M,24H		; "$"
	INX	H		; 
	MVI	M,24H		; "$"
	MVI	C,deletef	; Delete file
	CALL	BDOS		; 

I$048D	EQU	$-1		; ???

	POP	D		; 
	MVI	C,makef		; Make file
	CALL	BDOS		; 
	INR	A		; 
	JZ	nodspc		; Display 'no dir space' on console
	LXI	H,start3	; Relocate start of program
	SHLD	word1		; Point to start of program
	LXI	D,start1	; Start of first program
J$04A1:	PUSH	D		; 
	MVI	C,setDMA	; Set DMA address
	CALL	BDOS		; 
	LXI	D,FCBseq	; FCB for read/write seq
	MVI	C,writef	; Write sequential
	CALL	BDOS		; 
	POP	D		; 
	LXI	H,DBUF		; Default 128-bytes disk buffer
	DAD	D		; 
	XCHG			; 
	LXI	H,start2	; Start of second program
	MOV	A,E		; 
	SUB	L		; 
	MOV	A,D		; 
	SBB	H		; 
	JC	J$04A1		; 
	LXI	D,FCB1		; Default FCB in page zero
	CALL	chkfil		; Check if file is on disk
J$04C5:	MVI	C,80H		; 
	LXI	D,copyr		; 
J$04CA:	PUSH	D		; 
	PUSH	B		; 
	MVI	C,setDMA	; Set DMA address
	CALL	BDOS		; 
	LXI	D,FCB1		; Default FCB in page zero
	MVI	C,readf		; Read sequential
	CALL	BDOS		; 
	STA	errcod		; Error code (Read sequential)
	ORA	A		; 
	POP	B		; 
	POP	D		; 
	JNZ	J04EE		; 
	DCR	C		; 
	JZ	J04EE		; 
	LXI	H,DBUF		; Default 128-bytes disk buffer
	DAD	D		; 
	XCHG			; 
	JMP	J$04CA		; 
;
;--------------------------------
;
J04EE:	MVI	A,80H		; 
	SUB	C		; 
	MOV	C,A		; 
	LXI	D,copyr		; 
J$04F5:	PUSH	B		; 
	PUSH	D		; 
	MVI	C,setDMA	; Set DMA address
	CALL	BDOS		; 
	LXI	D,FCBseq	; FCB for read/write seq
	MVI	C,writef	; Write sequential
	CALL	BDOS		; 
	ORA	A		; 
	POP	D		; 
	POP	B		; 
	JNZ	werror		; Display 'write error$' on console
	DCR	C		; 
	JZ	J$0516		; 
	LXI	H,DBUF		; Default 128-bytes disk buffer
	DAD	D		; 
	XCHG			; 
	JMP	J$04F5		; 
;
;--------------------------------
;
J$0516:	LDA	errcod		; Error code (Read sequential)
	ORA	A		; 
	JZ	J$04C5		; 
	LXI	D,FCBseq	; FCB for read/write seq
	MVI	C,closef	; Close file
	CALL	BDOS		; 
	LXI	D,FCB1		; 
	MVI	C,deletef	; Delete file
	CALL	BDOS		; 
	LXI	D,FCBseq	; FCB for read/write seq
	LXI	H,I$0010	; 
	DAD	D		; 
	MVI	C,10H		; 16 bytes
	XCHG			; 
	CALL	copyHD		; 
	LXI	H,rentyp	; 
	MVI	M,43H		; "C" (add COM filetype)
	INX	H		; 
	MVI	M,4FH		; "O"
	INX	H		; 
	MVI	M,4DH		; "M"
	MVI	C,renamef	; Rename file
	LXI	D,FCBseq	; FCB for read/write seq
	CALL	BDOS		; 
	MVI	C,sysres	; System reset
	JMP	BDOS		; 
;
;--------------------------------
; HL = source
; DE = destination
;  C = count
;
copyHD:	MOV	A,M		; Get a byte
	STAX	D		; Put it in destination DE
	INX	H		; 
	INX	D		; 
	DCR	C		; Decrement count
	JNZ	copyHD		; 
	RET			; 
;
;--------------------------------
;
werror:	LXI	D,wrierr	; 'Write Error.$'
	JMP	bak2CPM		; 
;
;--------------------------------
;
nodspc:	LXI	D,nodirs	; 'No Directory Space.$'
	JMP	bak2CPM		; 
;
;--------------------------------
;
errcod:	DB	00H		; Error code (Read sequential)
;
	DB	00H		; (Byte added by linker?)
;
FCBseq:	DB	00H		; FCB for read/write seq
	DB	00H,00H,00H,00H,00H,00H,00H,00H
	DB	00H,00H,00H,00H,00H,00H,00H,00H
	DB	00H,00H,00H,00H,00H,00H,00H,00H
;
rentyp:	DB	00H,00H,00H	; Filetype for renaming filename.COM
	DB	00H,00H,00H,00H,00H,00H,00H,00H
;
;--------------------------------
;
wrierr:	DB	'Write Error.$'
;
nodirs:	DB	'No Directory Space.$'
;
copyr:	DB	'---------------------------------------------------', cr, lf
	DB	'GENGRAF 1.0  15 Nov 82   Serial No 5000-1232-654321', cr, lf
	DB	'Copyright (C) 1982                                 ', cr, lf
	DB	'Digital Research, Inc.          All Rights Reserved', cr, lf
	DB	'---------------------------------------------------', cr, lf, '$'
;
;--------------------------------
;
	END	100H		; Standard CP/M-80 COMmand file
