; 
;       INIT4TH Version 1.0 as of December 13, 1981
; 
;                By: Kelly Smith, CP/M-Net
; 
;      The purpose of INIT4TH,  came about from the flagrant 
; destruction  of Fig-Forth screens that were co-resident on 
; my CP/M diskettes...I would forget that the screens DO NOT 
; appear  in the CP/M directory,  and as such are  prone  to 
; eminent  destruction (due totally to my stupidity) by  the 
; CP/M "PIP" command.  What to do? Well, I also got tired of 
; clearing  out  screens  that  were  full  of  "e5's"  from 
; formatting,  and  decided  to  kill  two  birds  with  one 
; stone...
; 
;      INIT4TH  will  allow retention of all  relevant  CP/M 
; files (such as FORTH itself) on a CP/M and FORTH diskette, 
; initialize  all sectors NOT occupied by the resident  CP/M 
; files, and RESERVE all remaining sectors as available disk 
; area  for FORTH screens.  How is it  done?  Well,  INIT4TH 
; creats  one  "super  file"  called  RESERVED.4TH  that  is 
; nothing  but  blanks  (actually ASCII "space"  code)  that 
; aquires all CP/M groups remaining after the resident  CP/M 
; files...once    your   quasi   CP/M-FORTH   diskette    is 
; initialized,  it's  FULL  as far as CP/M is concerned  for 
; further PIPing,  and ready for whatever you want to  place 
; into  the  available  Fig-Forth screen  area  (my  version 
; starts  with a blank screen number 17,  up to  249).  It's 
; best,  if you PIP all the CP/M files to a blank  formatted 
; diskette first to make them contiguous on the diskette (no 
; "holes"),  and  then  run INIT4TH on it  to  "take-up-the-
; slack".
; 
;      But  WARNING...do  not  run this on a  diskette  that 
; already  has screens that you want to  preserve...this  is 
; ONLY  for diskette INITIALIZATION of FORTH  screens...copy 
; from  another  diskette as you normally do to  place  your 
; "treasured" screens on it.
; 
;      A  conditional assembly equate "SYS" is used to  make 
; RESERVED.4TH  invisible  in the directory (if you want  it 
; that way).
; 
;      I  hope this is of some use to you,  and if you  make 
; any  changes,  I  would appreciate it,  if you  modem  the 
; program to CP/M-Net (805) 527-9321 as INIT4TH.NEW...
; 
;      P.S.  I have learned many new WORDs using FORTH,  but 
; none are repeatable here...
; 
;                         Best regards: Kelly Smith CP/M-Net
;
;
;
; define TRUE/FALSE assembly parameters
;
true	equ	-1	; define TRUE
false	equ	not true; define FALSE
sys	equ	true	; define SYS (make RESERVED.4TH a $SYS file)
;
;
; BDOS entry point and function codes
; 
base	equ	0	; base address of "standard" CP/M system
bdos	equ	base+5	; CP/M BDOS entry address
msgfc	equ	9	; message function
resdsk	equ	13	; reset disk system
offc	equ	15	; open file
cffc	equ	16	; close file
wrfc	equ	21	; write record
mffc	equ	22	; make file
sdma	equ	26	; set dma address
; 
; secondary FCB field definitions
; 
fn	equ	1	; file name field (rel)
ft	equ	9	; file type field (rel)
ex	equ	12	; file extent field (rel)
frc	equ	15	; file record count (rel)
nr	equ	32	; next record field (rel)
; 
; ASCII control characters
; 
cr	equ	0dh	; carriage return
lf	equ	0ah	; line feed
bel	equ	07h	; bell signal
;
;
	org	base+100h
;
	lxi	h,0	; save old stack pointer
	dad	sp
	shld	oldstk
	lxi	sp,stack; make a new stack pointer
	lxi	d,initmsg	; Forth Screen initialization in progress
	mvi	c,msgfc
	call	bdos
	call	reset	; reset disk in case it's R/O
init4th:call	open	; attempt to open RESERVED.4TH
	inr	a	; check CP/M return code
	jnz	makeok	; RESERVED.4TH already exist?
	call	make	; make new file
	inr	a	; check CP/M return code
	jnz	makeok
	lxi	d,dirful; oops...disk directory is full
exit:	mvi	c,msgfc
	call	bdos
	lhld	oldstk	; get old CP/M stack pointer
	sphl
	ret
;
; RESERVED.4TH exists, so set the FCB entry for next append to file
;
makeok:		
;
	lxi	d,active; indicate disk activity with "."
	mvi	c,msgfc
	call	bdos
	call	setdma	; set dma for record to write
	call	write	; write it out...
	push	psw	; save possible error code
	lda	fcb+frc	; get record count
	sta	fcb+nr	; make next record
	pop	psw	; get possible error code
	ora	a	; disk full yet, all available records?
	jz	makeok	; do more records, if not
	call	close	; close-up shop, and go home
	lxi	d,dskful; Forth Screens are now initialized...
	jmp	exit	; exit to CP/M
; 
;  reset - reset disk
;
reset:		
	push	h
	push	d
	push	b
	mvi	c,resdsk
	call	bdos
	pop	b
	pop	d
	pop	h
	ret
; 
; open - open disk file
; 
open:		
	push	h
	push	d
	push	b
	lxi	d,fcb
	mvi	c,offc
	call	bdos
	pop	b
	pop	d
	pop	h
	ret
;
; setdma - set dma for record
;
setdma:
	push	h
	push	d
	push	b
	lxi	d,dbuf
	mvi	c,sdma
	call	bdos
	pop	b
	pop	d
	pop	h
	ret
;
; write - write record
;
write:
	push	h
	push	d
	push	b
	lxi	d,fcb
	mvi	c,wrfc
	call	bdos
	pop	b
	pop	d
	pop	h
	ret
; 
; close - close disk file
; 
close:		
	push	h
	push	d
	push	b
	lxi	d,fcb
	mvi	c,cffc
	call	bdos
	pop	b
	pop	d
	pop	h
	ret
; 
; make - make new disk file
; 
make:		
	push	h
	push	d
	push	b
	lxi	d,fcb
	mvi	c,mffc
	call	bdos
	pop	b
	pop	d
	pop	h
	ret
;

initmsg:db	cr,lf,'Forth Screen initialization in progress',cr,lf,'$'
;
active:	db	'.$'
;
dirful:	db	cr,lf,'Oops, this diskette is already full!$'
;
dskful:	db	cr,lf,lf,'Forth Screen initialization completed'

	if	SYS
	db	' as (RESERVED.4TH)$'
	endif		; SYS

	if	not SYS
	db	' as RESERVED.4TH$'
	endif		; SYS

;
fcb:	db	2	; initialize diskette in B: drive

	if	SYS
	db	'RESERVED4','T'+80H,'H'
	endif		; SYS

	if	not SYS
	db	'RESERVED4TH'
	endif		; SYS

	db	0,0,0,0,0,0,0,0,0,0
;
; data area
; 
	ds	128	; 64 level stack
stack	equ	$	;local stack
;
oldstk		
	ds	2	; storage for old CP/M stack pointer
;
dbuf:	db	'                '	; use blanks for initialization data
	db	'                '
	db	'                '
	db	'                '
	db	'                '
	db	'                '
	db	'                '
	db	'                '
;
	end
