	title	'DDT86 1.1  10/2/81'
;
;	modified  5/14/81  R. Silberstein
;	modified  6/15/81  R. Silberstein
;	modified  8/12/81  R. Silberstein
;	modified  9/6/81   R. Silberstein
;	modified  9/16/81  R. Silberstein
;	modified  10/1/81  R. Silberstein
;
;
;	*****************************************
;	*					*
;	*	D D T  8 0 8 6 - 8 0 8 8	*
;	*					*
;	*****************************************	
;
debug		equ	00h	;if set, use direct bios calls for console io
;
ddt_org		equ	100h		;origin of this module
lasmorg		equ	ddt_org+1300h	;origin of disassembler
asmorg		equ	ddt_org+2200h	;origin of assembler
;
		cseg
;
		org	005ch
fcb		rb	10h
fcb2		rb	14h
buff		rb	80h
;
		org	lasmorg
disem:		mov	ax,0
		ret	4	;remove parameters from stack
;
		org	asmorg
assem:		mov	ax,0
		ret	4	;remove parameters from stack
;
		org	ddt_org

		jmp	ddt86	;ccp transfers control here	
		jmp	conin
		jmp	plmconout
		jmp	plmgetline
		jmp	asment	;get here on error in assem (pl/m)
		jmp	plmset	;assembler link to ddt set/verify
;
bdosint:	int	bdosi	;this is only here for user to patch
				;actual bdos link gets set from here
bdosintloc	equ	offset bdosint
bdosintnum	equ	offset bdosint+1
;
bdosi		equ	224	;bdos interrupt number
stsize		equ	96	;stack size
nbps		equ	2	;number of breakpoints
;
ifmask16	equ	0200h	;16-bit IF mask
ifmask8		equ	02h	;8-bit IF mask
;
lf		equ	0ah	;line feed
cr		equ	0dh	;carriage return
eol		equ	cr
ctls		equ	13h	;ascii ctl-s
;
;	*******************************************
;	*					  *
;	*           m e s s a g e s		  *
;	*					  *
;	*******************************************
;
copyright	db	' COPYRIGHT (C) 1981, DIGITAL RESEARCH '
;
signon		db	'DDT86 1.','1' or 80h
;
DATE		DB	' 10/02/81 '
regname		db	'A','X' or 80h
		db	'B','X' or 80h
		db	'C','X' or 80h
		db	'D','X' or 80h
		db	'S','P' or 80h
		db	'B','P' or 80h
		db	'S','I' or 80h
		db	'D','I' or 80h
segreg		db	'C','S' or 80h
		db	'D','S' or 80h
		db	'S','S' or 80h
		db	'E','S' or 80h
		db	'I','P' or 80h
;
flagname	db	'ODITSZAPC'
flagbits	db	5,6,7,8,9,10,12,14,16
;
segnames	db	'C','S' or 80h
		db	'D','S' or 80h
		db	'E','S' or 80h
		db	'S','S' or 80h
		db	'X','1' or 80h
		db	'X','2' or 80h
		db	'X','3' or 80h
		db	'X','4' or 80h
;
closem		db	cr,lf,'CANNOT CLOS','E' or 80h
loadm		db	cr,lf,'INSUFFICIENT MEMOR','Y' or 80h
makem		db	cr,lf,'NO SPAC','E' or 80h
memm		db	cr,lf,'MEMORY REQUEST DENIE','D' or 80h
openm		db	cr,lf,'NO FIL','E' or 80h
readm		db	'  START      EN','D' or 80h
verm		db	cr,lf,'VERIFY ERROR AT',' ' or 80h
writem		db	cr,lf,'DISK WRITE ERRO','R' or 80h
;
;	****************************************************
;	*						   *
;	*	    i n i t i a l i z a t i o n		   *
;	*						   *
;	****************************************************
;
setbdosint:			;copy vector at 0:bdosi*4 to (bdosi+1)*4
	mov	al,byte ptr .bdosintnum	;get bdos interrupt #
	inc	al
	mov	byte ptr .ddtbdosintnum,al	;ddt uses the next interrupt internally
	sub	ah,ah
	shl	ax,1
	shl	ax,1		;bdos int # * 4
	mov	di,ax		;[di] points to new bdos interrupt vector
	mov	si,ax
	sub	si,4		;[si] points to actual bdos interrupt vector
	push	ds		;save ds
	sub	ax,ax
	mov	es,ax		;set es and ds to 0 to move interrupt vectors
	mov	ds,ax
	mov	cx,4
rep	movs	al,al		;copy bdos interrupt vector to next int vector
	pop	ds		;restore ds
	ret
;
checkcmdtail:			;if command tail not empty, assume E command
	mov	si,offset buff
	mov	ah,0
	lods	al		;get count from command tail
	or	al,al
	jz	cctret		;nothing to do if tail empty
	cmp	al,conbuffmax
	jbe	movcom
	mov	al,conbuffmax	;truncate, if needed
movcom:
	mov	cx,ax		;count to [cx]
	mov	di,offset conbuff
	push	ds
	pop	es		;point destination to ddt seg
rep	movs	al,al		;copy command tail into ddt command buff
	mov	al,eol
	stos	al		;store terminator
	call	execute		;command tail is assumed E command
cctret:
	ret
;
ddt86:
	cld
	MOV	CCPSS,SS
	MOV	CCPSP,SP	;SAVE CCP STACK POINTER
	MOV	USERSS,SS
	MOV	USERSP,SP	;INITIALIZE USER'S MACHINE STATE TO CCP STACK
;
	pushf
	pop	ax		;get flags
	and	ax,ifmask16	;mask to IF bit
	mov	sysif,ah	;save system IF state
	mov	userfl,ax	;initialize user's flags to sysif
;
	mov	ax,cs
	cli			;entering critical region
	mov	ss,ax		;set ss = cs
	mov	sp,offset stackp	;set up stack pointer
	test	sysif,ifmask8	;see if interrupts were enabled
	jz	d0		;don't turn them on if they were off
	sti
d0:				;exiting critical region
;
	call	setbdosint	;copy vector since ddt uses bdosi+1 internally
;
	test	savevecflag,0ffh	;ddt interrupts saved on each g/t/u?
	jnz	d1			;if so, don't initialize here
	call	bpvect			;if not, initialize them here
d1:
	if	debug
;
	sub	ax,ax
	mov	es,ax
	mov	si,bdosi * 4 + 2
	mov	ax,es:[si]	;get bdos segment
	mov	es,ax
	mov	biosentryseg,ax
	mov	di,biosentryoff
	mov	al,81h
	stos	al
	mov	al,0c3h
	stos	al
	mov	al,0h
	stos	al
	mov	al,25h
	stos	al
	mov	al,0ffh
	stos	al
	mov	al,0d3h
	stos	al
	mov	al,0cbh
	stos	al
;
	endif
;
	mov	si,offset signon	;get sign on message
	call	printm	        ;and print it
;
	CALL	VERSION
	CMP	AL,30H		;SEE IF WE ARE UNDER FILE SYSTEM III (MP/M)
	MOV	BH,0
	JC	D2		;IF EARLIER VERSION, SKIP
	MOV	DL,0FEH
	CALL	SETERRMODE	;SO BDOS RETURNS TO DDT ON FILE ERRORS
	MOV	BH,1
D2:
	MOV	ERRMODE,BH
;
	call	checkcmdtail	;if non-blank, do E command
;
;	*************************************************
;	*						*
;	*	    w o r k i n g  l o o p		*
;	*						*
;	*************************************************
;
start:	cld			;direction flag points up
	mov	sp,offset stackp	;make sure stack is right
	call	crlf		;print crlf
	mov	al,'-'		;and prompt
	call	conout
	call	getline		;get command line
	call	conin		;read first char
	cmp	al,eol
	jz	start
	CMP	AL,';'
	JZ	START		;IGNORE COMMENT LINES
	sub	al,'A'		;check range for valid command
	jb	err
	cmp	al,'Z'-'A'
	ja	err
	shl	al,1		;* 2 (2 bytes per ctable entry)
	mov	ah,0
	xchg	ax,bx
	mov	numreq,1	;most commands require an argument
	mov	wmode,0		;most commands are not word mode
	call  	word ptr ctable [bx]	;immed call command routine
	jmps	start		;start over
;
err:
	call	crlf
	mov	al,'?'		;error handler
	call	conout		;print error char
	jmps	start		;stack maybe messed up, keep this jmp
;
;	**************************************************
;	*						 *
;	*       c o m m a n d  j u m p  t a b l e	 *
;	*						 *
;	**************************************************
;
ctable	dw	assm		;assemble mnemonics
	DW	BLOCKCOMPARE	;COMPARE MEMORY BLOCKS
	dw	err
	dw	display		;display memory
	dw	execute		;load user program for execution
	dw	fill		;fill memory with constant
	dw	gouser		;go to user program
	dw	hexmath		;compute hex sum and difference
	dw	ifcb		;input file control block
	dw	err
	dw	err
	dw	lassm		;disassemble memory
	dw	move		;move block
	dw	err
	dw	err
	dw	err
	dw	err
	dw	read		;read file
	dw	setmem		;set memory
	dw	trace		;trace program execution
	dw	untrace		;untraced program execution
	dw	verify		;display file info
	dw	write		;write memory block to disk
	dw	xcom		;display/alter CPU state
	dw	err
	dw	err
;
;	*************************************************
;	*						*
;	*          b d o s   i n t e r f a c e          *
;	*						*
;	*************************************************
;
bdos:				;this interrupt instruction is overwritten on initialization
				;the actual int # used is the one at bdosint: + 1
ddtbdosintnum	equ	offset bdos + 1
;
	int	bdosi
	ret
;
	if	debug
;
bios:
	callf	dword ptr biosentryoff
	ret
;
	endif
;
	if	debug
;
consin:
	mov	bx,9
	call	bios
	push	ax
	call	conout
	pop	ax
	ret
;
	endif
;
	if	not debug
;
consin:
	mov	cl,1
	call	bdos
	ret
;
	endif
;
	if	debug
;
conout:
	mov	bx,0ch
	mov	cl,al
	jmp	bios
;
	endif
;
	if	not debug
;
conout:
	mov	cl,2
	mov	dl,al
	call	bdos
	ret
;
	endif
;
rdconbuff:
	mov	cl,10
	call	bdos
	ret
;
	if	debug
;
constat:
	mov	bx,6
	jmp	bios
;
	endif
;
	if	not debug
;
constat:
	mov	cl,11
	call	bdos
	ret
;
	endif
;
VERSION:
	MOV	CL,12
	JMP	BDOS
;
open:
	mov	cl,15
	call	bdos
	inc	al		;test for 0ffh returned
	jz	openerr
	ret
openerr:
	mov	si,offset openm
	jmps	errm
;
close:
	mov	cl,16
	call	bdos
	inc	al
	jz	closeerr
	ret
closeerr:
	mov	si,offset closem
	jmps	errm
;
delete:
	mov	cl,19
	jmp	bdos
;
readsec:
	mov	cl,20
	jmp	bdos
;
writesec:
	mov	cl,21
	call	bdos
	or	al,al
	jnz	writeerr
	ret
writeerr:
	mov	si,offset writem
	jmps	errm
;
make:
	mov	cl,22
	call	bdos
	inc	al
	jz	makeerr
	ret
makeerr:
	mov	si,offset makem
	jmps	errm
;
setdma:
	mov	cl,26
	jmp	bdos
;
SETERRMODE:
	MOV	CL,45
	JMP	BDOS
;
setdmab:
	mov	cl,51
	jmp	bdos
;
getmaxmem:
	mov	cl,53
	call	bdos
	inc	al
	jz	memerr
	ret
;
allocabsmem:
	mov	cl,56
	call	bdos
;	inc	al
;	jz	memerr
	NOP
	NOP
	NOP
	NOP		;REPLACE INC AL, JZ MEMERR
	ret
memerr:
	mov	si,offset memm
	jmps	errm
;
freemem:
	mov	cl,57
	jmp	bdos
;
load:
	mov	cl,59
	call	bdos
	inc	ax		;test for 0ffffh returned
	jz	loaderr
	ret
loaderr:
	mov	si,offset loadm
;
errm:
	call	printm
	jmp	start
;
plmconout:
	push	bp
	mov	bp,sp
	mov	ax,4[bp]
	call	conout
	pop	bp
	ret	2
;
plmgetline:
	push	bp
	call	getline
	pop	bp		;restore bp for pl/m
	ret
;
;	****************************************************
;	*                                                  *
;	*      c o n s o l e  i / o  r o u t i n e s       *
;	*                                                  *
;	****************************************************
;
	if	debug
;
ctlx:
	mov	al,'#'
	call	conout
	call	crlf
getline:
	mov	conptr,0
get0:
	call	consin
	cmp	al,3
	jz	ctlc
	cmp	al,8
	jz	backsp
	cmp	al,24		;ctl-x
	jz	ctlx
	cmp	al,cr
	jz	getlinedone
	cmp	conptr,conbuffmax
	jnb	getlinedone
	mov	di,offset conbuff	;normal character store
	add	di,conptr
	mov	[di],al
	inc	conptr
	jmps	get0
getlinedone:
	mov	di,offset conbuff
	add	di,conptr
	mov	byte ptr [di],eol
	mov	conptr,0
	ret
backsp:
	cmp	conptr,0
	jz	get0
	dec	conptr
	call	blank
	mov	al,8
	call	conout
	jmps	get0
ctlc:
	mov	cl,0
	mov	dl,0
	jmp	bdos
;
	endif
;
	if	not debug
;
getline:
	mov	dx,offset conbuffhdr
	call	rdconbuff
	mov	bl,conbuffcnt
	mov	bh,0
	add	bx,offset conbuff
	mov	byte ptr [bx], eol
	mov	conptr,0
	ret
;
	endif
;
conin:
	mov	si,offset conbuff
	add	si,conptr
	lods	al
	inc	conptr
				;fall thru to upper
upper:	cmp	al,'a'		;less than 'a'
	jb	upret		;or
	cmp	al,'z'		;greater than 'z'
	ja	upret		;then no change
	and	al,5fh		;else convert to uc
upret:	ret
;
ctlchek:			;check for ctl-s, ctl-q and ctl-c
	call	constat		;keypress?
	or	al,al		;zero?
	jz	ctlexit		;no keypress so return
	call	consin		;if keypress then get the data
	cmp	al,ctls		;check for ctl-s
	jz	kwait
	jmp	start		;any other key will restart
kwait:	call	consin		;if ctl-s then wait for another keypress
ctlexit:
	ret
;
crlf:
	mov	al,cr		;send cr and lf to console
	call	conout
	mov	al,lf
	call	conout
	ret
;
CRLFCHK:			;DO CRLF AND CHECK FOR ABORT
	CALL	CRLF
	CALL	CTLCHEK
	RET
;
blank:				;print a blank.
	mov	al,' '
	call	conout
	ret
;
tabs:				;print # blanks in cx
	push	cx
	call	blank
	pop	cx
	loop	tabs
	ret
;
printm:				;print the message at [si] on console
				;end of message indicated by parity set.
	lods	al		;get a byte
	test	al,80h		;check for end of message
	jnz	pquit		;quit if parity set
	push	si
	call	conout		;otherwise display byte
	pop	si
	jmps	printm		;print more message 
pquit:
	and	al,7fh		;strip parity
	call	conout		;print last byte
	ret
;
ascout:				;output [al] in ascii
	cmp	al,' '
	jb	perout		;less than blank?
	cmp	al,7eh
	jna	ascend
perout:
	mov	al,'.'		;output '.'
ascend:
	call	conout		;else output ascii
	ret
;
print8or16:			;print byte or word at es:[si] depending on wmode
	mov	ax,es:[si]
	test	wmode,1
	jz	printbyte
	jmps	printword
;
printdword:			;print double word as ssss:oooo
	; called with:
	;  es = segment
	;  di = offset
	push	di
	mov	ax,es
	call	printword	;print segment
	mov	al,':'
	call	conout
	pop	ax
;
printword:			;print value in [ax] as 4 hex digits
	push	ax
	mov	al,ah
	call	printbyte
	pop	ax
;
printbyte:			;print value in [al] as 2 hex digits
	push	ax
	mov	cl,4
	shr	al,cl		;shift al right 4 places
	call	printnibble	;output upper nibble
	pop	ax		;restore al (now we do lower nibble)
;
printnibble:			;print value in low 4 bits of [al] as a hex digit
	and	al,0fh		;mask upper 4 bits
	add	al,90h
	daa
	adc	al,40h
	daa
	call	conout
	ret
;
;	**************************************
;	*                                    *
;	*     file name parsing routines     *
;	*                                    *
;	**************************************
;
parse:				;parse into fcb whose offset is in [di]
	push	cs
	pop	es		;set es=cs
	push	di		;save fcb address
	sub	al,al
	mov	cx,36		;fcblen
rep	stos	al		;initialize fcb to 0
	pop	di		;restore fcb address
;
parse2:				;enter here to parse without clearing
				;assumes es = cs from parse:
	mov	fcbadr,di	;save fcb address
	inc	di		;point to first byte of filename
	call	setupdisk	;check for d: and set drive byte
	mov	cx,8
	call	fillfield	;first item was disk, now get filename
	mov	cx,3		;length of file type
	cmp	lastchar,'.'
	jz	filltype
	call	fillbl		;fill type with blanks if no '.'
	jmps	parseret
filltype:
	call	fillfield	;if '.', fill field from console buff
parseret:
	call	scanq		;count '?'s in fcb
	mov	al,lastchar
	ret			;with last char scanned in [al]
parseerr:
	jmp	err
;
setupdisk:			;set byte 0 of fcb according to char in fcb (1)
	call	conin
	mov	lastchar,al
	cmp	al,' '
	jz	setupdisk	;deblank input
	cmp	al,eol
	jz	s1		;can't be drive, decrement conptr to rescan
	call	conin
	cmp	al,':'
	jnz	s0		;not a drive, subtract 2 from conptr to rescan
	mov	al,lastchar	;get drive char
	sub	al,'A'-1
	dec	di		;point to fcb (0)
	stos	al		;store drive byte
	ret
s0:
	dec	conptr
s1:
	dec	conptr
	ret
;
pdelim:				;check char in [al] for delimiter; return ZF if so.
	mov	di,offset delims
	mov	cx,ndelims
repnz	scas	al		;look in table
	ret
;
fillfield:			;count in [cx], dest ptr in [di]
	call	conin
	mov	lastchar,al	;save last char scanned
	cmp	al,'*'
	jnz	notast
	call	fillq		;fill with '?'
	jmps	fillfield	;continue till delimiter
notast:
	push	di
	push	cx
	call	pdelim
	pop	cx
	pop	di
	jz	fillbl		;if delimiter, fill field with ' '
	jcxz	parseerr	;error if count exceeded
	stos	al		;store char in fcb
	dec	cx		;decrement count
	jmps	fillfield
fillq:
	mov	al,'?'
	jmps	fillx
fillbl:
	mov	al,' '
fillx:
	jcxz	filldone
rep	stos	al		;store '?' or ' '
filldone:
	ret
;
scanq:				;count '?'s in fcb, return ZF set if found
	mov	di,fcbadr
	inc	di		;point to first char of filename
	mov	cx,11		;11 chars to check
	mov	al,'?'
repnz	scas	al
	ret
;
;	***********************************
;	*                                 *
;	*     user CPU state routines     *
;	*                                 *
;	***********************************
;
chkreg:				;if reg name in [ax] is valid, return with 
				;register number in regnum
				;else go to error processor
	mov	cx,totreg+1	;number of names to check + 1
	mov	di,offset regname
	push	cs
	pop	es
repnz	scas	ax
	jcxz	checkerr	;not a valid reg name
	mov	dx,totreg
	sub	dx,cx
	mov	regnum,dx	;save reg number
	ret
;
checkflag:			;check for valid flag name
	mov	cx,nflag+1	;number of names to check + 1
	mov	di,offset flagname
	push	cs
	pop	es
repnz	scas	al
	jcxz	checkerr	;not a valid flag name
	mov	dx,nflag
	sub	dx,cx
	mov	regnum,dx	;save flag number
	ret
;
checkerr:
	jmp	err
;
setreg:				;set reg whose number is in [cx] to value in [ax]
	mov	si,offset userreg
	add	si,cx
	add	si,cx
	mov	[si],ax
	ret
;
printflags:			;print values of flags
	mov	cx,0
pf0:
	push	cx		;save count
	call	printflag
	pop	cx
	inc	cx
	cmp	cx,9
	jb	pf0
	ret
;
setflag:			;set flag whose # is in [cx] to value in [bx]
	mov	si,offset flagbits
	add	si,cx
	lods	al
	mov	cl,al
	mov	ax,0fffeh
	ror	ax,cl
	ror	bx,cl
	and	userfl,ax
	or	userfl,bx
	ret
;
printflagname:			;print flag name whose # is in [cx]
	mov	si,offset flagname
	add	si,cx
	lods	al		;get flag name
	call	conout
	ret
;
getflag:			;check flag whose # is in [cx]
				;return with ZF set if flag is set
	mov	ax,1
	mov	si,offset flagbits
	add	si,cx
	mov	cl,[si]		;get flagbits (flagnum)
	ror	ax,cl		;get mask into position
	and	ax,userfl	;see if bit set in CPU state
	ret
;
printflagval:			;print value of flag (as 0 or 1) whose # is in [cx]
	call	getflag
	mov	al,'0'
	jz	pf2		;if flag not set, print '0'
	mov	al,'1'		;else print '1'
pf2:
	call	conout
	ret
;
printflag:			;print flag (as flagname of '-') whose # is in [cx]
	mov	si,offset flagname
	add	si,cx		;point to flag name
	push	word ptr [si]	;save flag char
	call	getflag
	pop	ax		;get flag char
	jnz	pname		;if flag set, use flag char
	mov	al,'-'		;else print hyphen
pname:
	call	conout
	ret
;
PREG1:				;PRINT FIRST 6 REGISTER NAMES (FOR 40 COLUMNS)
	MOV	CX,0
	MOV	NREG,6
	JMPS	PR0
PREG2:				;PRINT NEXT 7 REGISTER NAMES (FOR 40 COLUMNS)
	MOV	CX,6
	JMPS	PR00
printregs:			;print register values
	mov	cx,0
PR00:
	MOV	NREG,13
pr0:
	call	testregcl	;see if reg should be printed
	jnb	pr2		;don't print if carry not set
	push	cx
	call	printregval
	call	blank
	pop	cx
pr2:
	inc	cx
	CMP	CL,NREG
	jb	pr0
	ret
;
printregval:			;print value of reg whose # is in [cx]
	mov	si,offset userreg
	add	si,cx
	add	si,cx
	lods	ax
	call	printword
	ret
;
printregname:			;print name of reg whose # is in [cx]
	mov	si,offset regname
	add	si,cx
	add	si,cx
	call	printm
	ret
;
testregcl:			;see if reg whose # is in [cl] should be printed
				;return with carry set if so
	test	segflag,0ffh
	jnz	printit		;print all reg's if segflag set
	cmp	cl,11		;otherwise, see if [cl] has seg reg #
	ja	printit
	cmp	cl,8
	ret
printit:
	stc
	ret
;
SETUPHDR:
	call	crlf
	mov	cx,11
	call	tabs		;leave space for flags
	mov	cx,0
	RET
;
PREGHDR1:			;PRINT HEADER FOR FIRST 6 REGS (FOR 40 COL)
	CALL	SETUPHDR
	MOV	NREG,6
	JMPS	PRH0
PREGHDR2:			;PRINT HEADER FOR NEXT 7 REGISTERS
	CALL	BLANK
	MOV	CX,6
	JMPS	PRH00
printregheader:			;print header for registers
	CALL	SETUPHDR
PRH00:
	MOV	NREG,13
prh0:
	call	testregcl	;see if reg should be printed
	jnb	prh1		;don't print if carry not set
	push	cx
	call	printregname
	mov	cx,3
	call	tabs
	pop	cx
prh1:
	inc	cx
	CMP	CL,NREG
	jb	prh0
	ret
;
printinstr:			;disassemble instruction at [cs:ip]
	mov	es,usercs
	mov	si,userip
	test	disempresent,0ffh
	jz	pi1
	push	es
	push	si
	test	segflag,0ffh
	jz	pi0
	call	crlf
pi0:
	call	disem
	ret
pi1:
	mov	al,es:[si]
	call	printbyte
	ret
;
printseginfo:			;print name, start and end address of segment whose
				;number is in [al] if length is non-zero.
	mov	cl,al		;save seg number
	mov	bl,6
	mul	bl		;6 bytes per segment in base page
	add	ax,offset basepagesave
	mov	si,ax		;si now points to entry in base page
	lods	ax		;get low 16 bits of length
	mov	bx,ax		;save in bx
	lods	al		;get high nibble of length
	mov	dl,al		;save it
	mov	ah,0
	or	ax,bx		;test for zero length
	jz	psiret		;if zero, no display
	lods	ax		;get base
	push	bx		;save low (length)
	push	dx		;save high (length)
	push	ax		;save base
	mov	ch,0		;zero high byte of segment #
	shl	cx,1		;* 2 (2 bytes per segment name)
	add	cx,offset segnames	;cx now points to segment name
	push	cx		;save it
	call	crlf
	pop	si
	call	printm		;print segment name
	call	blank
	pop	es		;get base
	push	es		;save base
	mov	di,0
	call	printdword	;print start address
	call	blank
	pop	bx		;get base
	pop	ax		;get high (len)
	mov	cl,12
	shl	ax,cl		;move ls nibble of al to ms nibble of ah
	add	ax,bx		;add ms nibble of length to base
	mov	es,ax
	pop	di		;get low (len)
	call	printdword	;print end address
psiret:
	ret
;
setcpustate:			;set users regs after E command
	MOV	AX,CCPSS
	MOV	USERSS,AX
	MOV	AX,CCPSP
	MOV	USERSP,AX	;RESET USER STACK POINTER TO CCP STACK
	mov	ax,bx		;get ds base in [ax] (returned from bdos load)
	mov	userds,ax	;set user's ds
	mov	usercs,ax
	mov	useres,ax
	mov	type1seg,ax
	mov	type2seg,ax
	mov	es,ax
	test	es:byte ptr .5, 1	;test 8080 flag
	jz	not8080
	mov	ax,100h		;default for userip, lasloc, disloc
	jmps	setdone
not8080:
	mov	ax,es:.3	;get cs base
	mov	usercs,ax
	mov	type1seg,ax
	mov	ax,es:.15	;get es base
	or	ax,ax
	jz	sc1
	mov	useres,ax	;set it if there was one
sc1:
	mov	ax,es:.21	;get ss base
	or	ax,ax
	jz	setdone
	mov	userss,ax	;set it if there was one
	mov	ax,es:.18	;get stack length
	mov	usersp,ax	;set user's sp
	sub	ax,ax		;userip, lasloc, disloc = 0 for non-8080 model
setdone:
	mov	userip,ax
	mov	lasloc,ax
	ret
;
;	*********************************************
;	*                                           *
;	*     breakpoint/single step procedures     *
;	*                                           *
;	*********************************************
;
setbp:				;set breakpoint at address stored in dword at [di]
	les	si,[di]		;point [es]:[si] to breakpoint location
	mov	al,0cch		;int 3 instruction
	xchg	al,es:[si]	;set breakpoint and fetch instruction
	mov	4[di],al	;save user instruction in breakpoint table
	inc	bpcnt		;increment breakpoint count
	ret
;
bpclear:			;clear breakpoint table
	sub	cx,cx
	mov	cl,bpcnt	;get # of bp's to clear
	mov	si,offset brk1loc	;point to bp table
bpcloop:
	jcxz	bpend		;0..quit
	lods	ax		;get bp offset
	push	ax		;save it
	lods	ax		;get bp segment
	mov	es,ax
	lods	al		;get inst byte
	pop	di		;get bp offset
	stos	al		;store user instruction back
	loop	bpcloop
	mov	bpcnt,0		;zero bp counter
bpend:	ret
;
BPV:
	TEST	SAVEVECFLAG,0FFH
	JZ	BPVECTRET
bpvect:				;set up breakpoint/single step vectors
	call	savevect
	mov	dx,0
	mov	es,dx		;make sure dest is absolute 0
	mov	di,4		;set up single step vector
	mov	ax,offset ssentry	;single step entry point
	stos	ax		;save at ss vector
	mov	ax,cs
	stos	ax		;save cs
	mov	di,12		;set up breakpoint vector
	mov	ax,offset breakentry 	;set up bp vector
	stos	ax		;save at bp vector
	mov	ax,cs
	stos	ax		;save cs
BPVECTRET:
	ret
;
savevect:			;save previous contents of 0:4 thru 0:f
	mov	si,4
	mov	di,offset vectorsave
	push	ds
	pop	es		;point to ddt segment
	mov	cx,12
	push	ds
	mov	dx,0
	mov	ds,dx
rep	movs	al,al
	pop	ds
svret:
	ret
;
restorevect:			;restore previous contents of 0:4 thru 0:f
	test	savevecflag,0ffh
	jz	rvret
	mov	si,offset vectorsave
	mov	di,4
	mov	cx,12
	mov	dx,0
	mov	es,dx
rep	movs	al,al
rvret:
	ret
;
SETDEFSEG:			;SET DEFAULT TYPE1SEG, LASLOC
	mov	di,userip
	mov	lasloc,di	;set disassembler offset
	mov	es,usercs
	mov	type1seg,es	;set type1seg segment
	RET
;
breakaddr:			;print address where break occurred
	call	crlf
	mov	al,'*'
	call	conout
	mov	ax,userds
	mov	type2seg,ax	;set type2 segment to userds
	CALL	SETDEFSEG
	call	printdword	;print break address
	ret
;
breakentry:			;breakpoint entry
	mov	breakfl,1
	jmps	savecpu		;common code for break and single step
ssentry:			;single step entry
	mov	breakfl,0
savecpu:
	mov	userax,ax
	mov	userbx,bx
	mov	usercx,cx
	mov	userdx,dx
	mov	usersi,si
	mov	userdi,di
	mov	userbp,bp
	mov	usersp,sp
	mov	useres,es
	mov	userds,ds
	mov	userss,ss
	mov	bp,sp
	mov	ax,[bp]
	mov	userip,ax
	mov	ax,2[bp]
	mov	usercs,ax
	mov	ax,4[bp]
	mov	userfl,ax
;
	mov	ax,cs
	mov	ds,ax
	mov	ss,ax
	mov	sp,offset stackp
;
	test	sysif,ifmask8	;see whether interrupts should be enabled
	jz	sav0
	sti
sav0:
	add	usersp,6	;to make up for stacked cs, ip, and fl
	cld
	call	restorevect
	test	breakfl,0ffh
	jz	sst0
;
break0:				;continuation of break processing
	dec	userip		;adjust user ip for breakpoint instr
	call	bpclear		;clear all breakpoints
	test	skipbdos,0ffh	;were we originally in trace mode?
	jnz	sst00		;if so, continue tracing
;
tracedone:
	call	breakaddr
	jmp	start
;
sst00:				;get here on breakpoint on return from bdos
	mov	skipbdos,0	;no longer tracing thru bdos
sst0:				;continuation of single step processing
	and	userfl,0feffh	;clear user trap flag
	TEST	USERIFOFF,1
	JZ	SST1
	MOV	USERIFOFF,0
	OR	USERFL,200H	;RESTORE USER IF
SST1:
	dec	tracecount
	jz	tracedone
	CALL	CTLCHEK		;CHECK FOR ABORT
	test	traceprint,0ffh
	jz	tracerestore
	call	xnohdr		;display regs without header
;
tracerestore:			;enter here when in trace mode
	mov	es,usercs
	mov	si,userip
	mov	ax,word ptr .bdosintloc	;get bdos interrupt instruction
	cmp	ax,es:[si]	;see if instruction to be traced is bdos int
	jnz	tr00
	mov	brk1seg,es
	add	si,2		;point to instruction after bdos int
	mov	brk1loc,si
	mov	di,offset brk1loc
	call	setbp		;set breakpoint at return from bdos
	mov	skipbdos,1	;so we know we were in trace mode when we hit bp
	jmps	rstore		;without setting single step flag
tr00:
	MOV	AX,USERFL
	OR	AX,100H		;SET TRACE FLAG
	TEST	AX,200H		;IS USER IF SET?
	JZ	TR01
	AND	AX,NOT 200H	;CLEAR IT (SO WE DON'T END UP IN INT HANDLER)
	MOV	ES,USERCS
	MOV	SI,USERIP
	MOV	BL,ES:[SI]	;GET INSTRUCTION TO EXECUTE
	CMP	BL,0FAH		;IS IT CLI?
	JZ	TR01
	CMP	BL,0CFH		;IRET?
	JZ	TR01
	CMP	BL,09DH		;POPF?
	JZ	TR01
	CMP	BL,0CDH		;INT?
	JZ	TR01
	MOV	USERIFOFF,1	;SET FLAG SO DDT86 WILL TURN IF BACK ON
TR01:
	MOV	USERFL,AX
rstore:				;enter here when in G mode
	CALL	BPV
	cli
	mov	sp,offset userreg	;point to reg save area
	pop	ax
	pop	bx
	pop	cx
	pop	dx
	pop	savesp
	pop	bp
	pop	si
	pop	di
	pop	ds		;throw away cs
	pop	ds
	pop	savess
	pop	es
	mov	ss,savess	;restore stack
	mov	sp,savesp
	push	userfl		;flags
	push	usercs		;cs
	push	userip		;ip
	iret			;transfer to user program
;
;	**********************************
;	*                                *
;	*     miscellaneous routines     *
;	*                                *
;	**********************************
;
delim:
	cmp	al,eol
	jz	delret
	cmp	al,','
	jz	delret
	cmp	al,' '
	jz	delret
	cmp	al,':'
delret:
	ret
;
hexcon:
	sub	al,'0'
	cmp	al,10
	jb	hexret
	add	al,('0' - 'A' + 10) and 0ffh
	cmp	al,16
	jnb	hexerr
	cmp	al,10
	jb	hexerr
hexret:
	ret
hexerr:
	jmp	err
;
plmset:				;get here when assembler wants to set memory
	mov	bp,sp		;for parameter fetching
	mov	ax,2[bp]	;get value in [al]
	mov	es,type1seg	;segment used in A command is in type1 seg
	mov	di,4[bp]	;get offset from stack
	call	setbyte		;set and verify
	inc	di		;increment offset
	jnz	psret		;if incremented offset is non-zero, return
	jmp	start		;otherwise exit A command, since wrap occurred
psret:
	ret	4		;remove 2 parameters
;
set8or16:			;set byte or word at es:[di] depending on wmode
	test	wmode,1
	jz	setbyte
				;fall through to setword
;
setword:			;set word at es:[di] to [ax] and verify
;
;	NOTE:  THIS CODE COULD BE REPLACED BY THE FOLLOWING 4 INSTRUCTIONS
;	       FOR SYSTEMS IN WHICH MEMORY CAN ONLY BE ADDRESSED BY WORDS.
;	       HOWEVER, THIS WILL WRAP AROUND AND MODIFY LOCATIONS 0 IF
;	       [DI] CONTAINS 0FFFEH.
;
;	MOV	ES:[DI],AX
;	CMP	ES:[DI],AX
;	JNZ	BADVER
;	RET
;
	push	ax		;save hi byte
	call	setbyte		;set low byte
	pop	ax
	mov	al,ah
	inc	di		;point to next location
	jz	sret		;don't set byte if wraparound occurred
				;fall thru to setbyte
;
setbyte:			;set byte at es:[di] to [al] and verify
	mov	es:[di],al	;store byte
	cmp	es:[di],al	;see if it got stored
	jnz	badver
sret:
	ret
;
badver:
	push	di
	push	es
	mov	si,offset verm
	call	printm		;print verify error message
	pop	es
	pop	di
	call	printdword
	jmp	start
;
inc1or2:			;inc pointer at [si] by 1 or 2, depending on wmode
				;return with carry flag set if wrap occurred
	mov	al,wmode
	and	ax,1		;mask to 0 or 1
	inc	ax		;increment value is now 1 or 2
	add	[si],ax		;increment pointer
	cmp	[si],ax		;test for wraparound
	ret
;
getnumber:			;get number from input buffer
				;returns:
				;bx = value of number from input
				;al = last character scanned (delimiter)
				;ah = blank flag (0 = blank, 1 = non-blank)
	sub	bx,bx		;initialize value to 0
	mov	ah,bh		;initialize blank flag to blank
getn0:
	call	conin
	call	delim		;check for delimiter
	jz	getnret		;delimiter found, exit
	mov	cl,4
	shl	bx,cl		;make room for new nibble
	call	hexcon		;convert ascii to binary
	add	bl,al		;add nibble
	mov	ah,1		;blank flag = non-blank
	jmps	getn0
getnret:
	ret
;
getoffset:			;get offset from input line
				;offset is a non-blank number not followed by ':'
				;returns:
				;al = last char scanned (delimiter)
				;bx = value
	call	getnumber	;get value to bx
	or	ah,ah		;check for blank entry
	jz	geterr		;don't allow blank entry
	cmp	al,':'		;check delimiter for ':'
	jz	geterr		;don't allow ':' delimiter
	ret
;
getlastoffset:			;same as getoffset but delimiter must be a cr
	call	getoffset
	cmp	al,eol
	jnz	geterr
	ret
geterr:
	jmp	err
;
checkword:			;check for 'W' following command letter
	call	conin
	cmp	al,'W'
	jnz	chret
	mov	wmode,1
	ret
chret:	dec	conptr		;to rescan character
	ret
;
checkreg:			;check for valid segment register prefix - <sr>:
				;called with:
				;bl = first char
				;bh = second char
				;returns:
				;si = offset to register, if found
				;zf = found flag (1 = found, 0 = not found)
	or	bh,80h		;since they are defined like that
	mov	bp,offset segreg	;point to seg reg names
	sub	si,si		;initialize index to 0
check0:
	cmp	bx,[bp+si]	;is it a seg reg name
	jz	checkret
	add	si,2		;point to next name
	cmp	si,8		;check for done (4 seg reg names)
	jnz	check0
	or	si,si		;unset zero flag
checkret:
	ret
;
checksegreg:			;check for valid seg reg name
				;if found, return contents of seg reg
				;else reset input pointer for rescan
				;returns:
				;dx = seg reg value
				;zf = valid seg reg (1 = valid, 0 = not valid)
	push	conptr		;save input pointer for possible rescan
	call	conin
	push	ax
	call	conin
	push	ax
	call	conin
	cmp	al,':'		;valid seg reg must have colon
	pop	bx
	pop	cx
	mov	bh,cl
	xchg	bl,bh
	jnz	notsr
	call	checkreg	;see if it's a valid name
	jnz	notsr
	mov	bp,offset usercs	;point to saved user seg reg's
	mov	dx,[bp+si]	;get value of user seg reg
	pop	cx		;throw away saved input pointer
	ret
notsr:
	pop	conptr		;reset for rescan
	ret
;
getsegandoff:			;get user location specification
				;may be one of the following forms:
				;<empty>
				;nnnn
				;sr:nnnn
				;mmmm:nnnn
				;if numreq set, <empty> is invalid
				;called with:
				;di = offset of 4 byte area containing <offset><segment>
				;numreq must have been initialized by calling routine
	call	checksegreg	;see if there is a segment prefix
	jz	gets0
	call	getnumber	;no segment prefix, check for number
	or	ah,ah		;was there one?
	jz	gets3
	mov	dx,bx		;move number to dx
	cmp	al,':'		;was delimiter a ':'
	jnz	gets2
gets0:
	call	getoffset	;segment prefix present, must have number
	mov	[di],bx		;number goes to <offset>
	mov	2[di],dx	;first number (or sr) goes to <segment>
	ret
gets2:
	mov	[di],dx		;only one number, put it in <offset>
getsret:
	ret
gets3:
	test	numreq,0ffh	;blank field, see if ok
	jz	getsret		;ok, return with no change at [di]
	jmp	err		;number was required
;
;	*****************************
;	*                           *
;	*     disk i/o routines     *
;	*                           *
;	*****************************
;
readfile:			;read file in fcb into memory described in mcb
				;when done, mcb will have base and length of block to free
	mov	ax,mcbbase
	mov	startreadseg,ax
	mov	endreadseg,ax
	mov	dmaseg,ax
	sub	ax,ax
	mov	startreadoff,ax
	mov	endreadoff,ax
rf0:
	mov	dx,dmaseg
	call	setdmab		;set dma base
	mov	dmaoff,0
rf1:
	mov	dx,dmaoff
	call	setdma		;set dma offset
	cmp	mcblen,8	;8 paragraphs per sector
	jb	readerr		;if less than 8 pp's left, not enough memory
	mov	dx,offset fcb
	call	readsec
	or	al,al		;test value returned from bdos
	jnz	readdone
	add	mcbbase,8	;point mcb to next available paragraph
	sub	mcblen,8	;decrement # of available paragraphs
	mov	ax,dmaoff
	add	al,7fh		;add sector size - 1
	mov	endreadoff,ax
	MOV	AX,DMASEG
	MOV	ENDREADSEG,AX
	add	dmaoff,80h	;increment dma offset
	jnz	rf1		;if no wrap occurred, simply continue
	add	dmaseg,1000h	;else increment dma segment
	jmps	rf0
readdone:
	MOV	DX,OFFSET FCB
	CALL	CLOSE
	ret
readerr:
	jmp	loaderr
;
writefile:			;write block at startwriteloc - endwriteloc to file in fcb
	mov	ax,startwriteoff
	mov	cl,4
	shr	ax,cl		;divide offset by 16 - truncate ls nibble
	add	ax,startwriteseg	;compute absolute paragraph number
	mov	mcbbase,ax
	mov	dmaseg,ax
	mov	bx,ax		;store start paragraph # in [bx]
	mov	ax,endwriteoff
	shr	ax,cl
	add	ax,endwriteseg	;calculate absolute paragraph number of end
	sub	ax,bx		;compute # of paragraphs to write
	jb	wferr		;start can't be > end
	mov	mcblen,ax	;store # paragraphs to write
	mov	dx,offset fcb
	call	delete
	TEST	ERRMODE,0FFH
	JZ	WF00
	INC	AL		;DID DELETE RETURN 0FFH?
	JNZ	WF00		;IF NOT, OK
	OR	AH,AH		;SEE IF EXTENDED OR PHYSICAL ERROR
	JNZ	WFERR		;IF SO, DON'T CONTINUE
WF00:
	mov	dx,offset fcb
	call	make
wf0:
	mov	dx,dmaseg
	call	setdmab
	mov	dmaoff,0	;clear dma offset
wf1:
	mov	dx,dmaoff
	call	setdma
	mov	dx,offset fcb
	call	writesec
	sub	mcblen,8	;8 paragraphs per sector
	jb	writedone
	add	dmaoff,80h	;increment dma pointer
	jnz	wf1		;loop if no wrap occurred
	add	dmaseg,1000h	;if wrap occurred, increment dma segment
	jmps	wf0
writedone:
	ret
wferr:
	jmp	err
;
eject
;
;	**********************************
;	*                                *
;	*     a - assemble mnemonics     *
;	*                                *
;	**********************************
;
assm:
	test	assempresent,0ffh
	jz	asmerr
	mov	asmspsav,sp	;save in case of error in pl/m
	mov	di,offset type1loc
	call	getsegandoff	;get start address
asm0:
	push	type1seg	;for pl/m call
	push	type1loc	;for pl/m call
	call	assem		;returns offset of next available byte
	cmp	ax,type1loc	;test for no input
	jna	asmret		;done unless greater than original type1loc
	mov	type1loc,ax	;update type1loc
	jmps	asm0
asmret:
	ret
asmerr:
	jmp	err
asment:				;arrive here on input error in pl/m
	mov	sp,asmspsav	;reset stack to where it was
	jmps	asm0		;go back for more input
;
;	*****************************
;	*                           *
;	*     B - BLOCK COMPARE     *
;	*                           *
;	*****************************
;
BLOCKCOMPARE:
	mov	di,offset type2loc
	call	getsegandoff
	call	getoffset	;get end offset
	mov	usermax,bx
	cmp	al,eol
	jz	cmperr		;need 3 arguments
	sub	bx,type2loc
	jb	cmperr		;error if start > end
	mov	ax,type2seg
	mov	userseg2,ax	;default to same seg as source
	mov	di,offset userloc2
	call	getsegandoff	;get destination address
	cmp	al,eol
	jnz	cmperr		;error if more than 3 arguments
CMP0:
	LES	SI,DWORD PTR TYPE2LOC
	MOV	AL,ES:[SI]
	LES	SI,DWORD PTR USERLOC2
	CMP	AL,ES:[SI]
	JZ	CMPCONT
	CALL	CRLFCHK
	MOV	DI,OFFSET TYPE2LOC
	CALL	PRINTERROR
	CALL	BLANK
	CALL	BLANK
	MOV	DI,OFFSET USERLOC2
	CALL	PRINTERROR
CMPCONT:
	INC	TYPE2LOC
	MOV	AX,TYPE2LOC
	CMP	USERMAX,AX
	JC	CMPDONE
	INC	USERLOC2
	JZ	CMPDONE		;PREVENT WRAPAROUND
	JMPS	CMP0
;
CMPDONE:
	RET
CMPERR:
	JMP	ERR
;
PRINTERROR:			;PRINT DWORD AT [DI], BYTE POINTED TO BY DWORD
	LES	DI,[DI]
	MOV	AL,ES:[DI]
	PUSH	AX		;SAVE BYTE AT ES:DI
	CALL	PRINTDWORD
	CALL	BLANK
	POP	AX
	CALL	PRINTBYTE
	RET
;
;	******************************
;	*                            *
;	*     d - display memory     *
;	*                            *
;	******************************
;
display:
	mov	numreq,0	;ok to have no entries
	mov	ax,type2seg
	mov	disseg,ax	;default to type2 seg
	call	checkword
	TEST	COL40,0FFH
	JZ	DIS01
	TEST	WMODE,1
	JNZ	DIS00
	MOV	AL,ND40
	JMPS	DIS02
DIS00:
	MOV	AL,NDW40	;CHARS PER LINE FOR DW IN 40 COL MODE
	JMPS	DIS02
DIS01:
	MOV	AL,ND80		;16 BYTES PER LINE IN NORMAL MODE
DIS02:
	MOV	LINEMAX,AL
	mov	di,offset disloc
	call	getsegandoff
	cmp	al, ','
	mov	ax,disseg
	mov	type2seg,ax	;update default type2 seg
	jnz	dis0		;must be cr, no dismax entered
	call	getlastoffset	;get dismax
	jmps	dis1
dis0:
	mov	bx,disloc	;no dismax entered, calculate default
	MOV	AL,LINEMAX
	MOV	CL,NLINES
	MUL	CL
	DEC	AL
	ADD	BX,AX
	cmp	bx,disloc	;see if we went over ffff
	jnb	dis1
	mov	bx,0ffffh	;set dismax if we wrapped around
dis1:
	mov	dismax,bx
disp3:
	CALL	CRLFCHK
	les	di,dword ptr disloc
	mov	tdisp,di
	call	printdword
disp4:
	call	blank
	les	si,dword ptr disloc
	call	print8or16
	mov	si,offset disloc
	call	inc1or2
	jb	disp6		;stop if wrap occurred
	mov	ax,disloc
	sub	ax,tdisp	;calculate # bytes printed on line
	CMP	AL,LINEMAX	;SEE IF LINE FULL
	jz	disp6
	mov	ax,disloc
	cmp	ax,dismax	;check for done
	jna	disp4
disp6:
	call	blank
disp7:
	mov	es,disseg
	mov	si,tdisp
	mov	al,es:[si]
	call	ascout
	inc	tdisp
	jz	disp8		;stop if wrap occurred
	mov	ax,tdisp
	cmp	ax,disloc
	jnz	disp7
	cmp	ax,dismax
	ja	disp8
	jmps	disp3
disp8:
	ret
;
;	******************************************
;	*                                        *
;	*     e - load program for execution     *
;	*                                        *
;	******************************************
;
cmd		db	'CMD'
;
execute:
	call	conin
	cmp	al,eol		;check for no filename
	jz	eerr		;don't allow no filename
	dec	conptr		;to rescan character
	mov	di,offset fcb
	call	parse
	jz	eerr		;no '?' or '*' allowed
	cmp	al,eol
	jnz	eerr		;eol must follow filename
	push	cs
	pop	es		;set es = cs
	cmp	es:fcb+9, ' '	;see if filetype blank
	jnz	ex0
	mov	si,offset cmd
	mov	di,offset fcb+9
	mov	cx,3
rep	movs	al,al		;set filetype to 'CMD' if empty
ex0:
	mov	dx,offset fcb
	call	open		;see if file exists
	mov	mcbext,0ffh	;free all allocations below DDT86
	mov	dx,offset mcb
	call	freemem		;free all memory previously allocated under DDT
	mov	dx,offset fcb
	call	load		;load user program
	push	bx		;save ds base
	call	setcpustate
	pop	dx		;get ds base back
	call	setdmab		;set dma base
	mov	dx,80h
	call	setdma		;default to 80h in user's DS
	MOV	DX,OFFSET FCB
	CALL	CLOSE
	mov	mode,'E'
	mov	si,0
	mov	di,offset basepagesave
	push	ds
	pop	es		;set es to ddt's segment
	mov	ax,userds
	push	ds		;save it
	mov	ds,ax
	mov	cx,48
rep	movs	al,al		;copy user's base page into ddt save area
	pop	ds		;restore ds
	call	verify		;display load info
	DEC	CONPTR		;TO RESCAN CR
	JMP	IFCB		;TO CLEAR FCB
eerr:
	jmp	err
;
;	***************************
;	*                         *
;	*     f - fill memory     *
;	*                         *
;	***************************
;
fill:
	call	checkword	;check for 'FW'
	mov	di,offset type2loc
	call	getsegandoff
	call	getoffset	;get end address
	mov	usermax,bx	;save end address
	call	getlastoffset	;get fill constant
	test	wmode,1
	jnz	fil0
	or	bh,bh		;if not wmode, high byte must be 0
	jnz	filerr
fil0:
	mov	cx,usermax	;get end address
	sub	cx,type2loc	;compare for valid range
	jb	filerr		;error if start > end
fil1:
	les	di,dword ptr type2loc
	mov	ax,bx		;get fill constant
	call	set8or16
	mov	si,offset type2loc
	call	inc1or2
	jb	filret		;stop if wrap occurred
	mov	ax,type2loc
	cmp	ax,usermax
	jbe	fil1
filret:
	ret
filerr:
	jmp	err
;
;	**********************************
;	*                                *
;	*     g - go to user program     *
;	*                                *
;	**********************************
;
gouser:
	mov	ax,usercs
	mov	goseg,ax	;default goseg = usercs
	mov	ax,userip
	mov	goloc,ax	;default goloc = userip
	mov	numreq,0	;number not required in G command
	mov	di,offset goloc
	call	getsegandoff	;get start address
	cmp	al,eol
	jz	gorestore	;if eol, no breakpoints set
	mov	ax,goseg
	mov	brk1seg,ax
	mov	brk2seg,ax	;defaults for breakpoint segments = goseg
	mov	di,offset brk1loc
	call	getsegandoff	;get first breakpoint
	push	ax		;save terminating char
	mov	di,offset brk1loc
	call	setbp		;save breakpoint in table
	pop	ax		;get char
	cmp	al,eol
	jz	gorestore	;only one breakpoint
	mov	di,offset brk2loc
	call	getsegandoff	;get second breakpoint
	cmp	al,eol
	jnz	goerr		;only 2 breakpoints allowed
	mov	di,offset brk2loc
	call	setbp		;set second breakpoint
gorestore:
	mov	skipbdos,0	;make sure it's 0 since we aren't in T/U mode
	mov	ax,goseg
	mov	usercs,ax	;usercs = goseg
	mov	ax,goloc
	mov	userip,ax	;userip = goloc
	jmp	rstore		;restore user CPU state
goerr:
	call	bpclear		;in case any were set
	jmp	err
;
;
;	************************
;	*                      *
;	*     h - hex math     *
;	*                      *
;	************************
;
hexmath:
	call	getoffset
	push	bx		;save first value
	call	getlastoffset
	pop	ax		;get first value
	push	ax		;save a copy
	add	ax,bx
	push	bx		;save second value
	push	ax		;save sum
	call	crlf
	pop	ax		;get sum
	call	printword	;print sum
	call	blank
	pop	bx		;get second value
	pop	ax		;get first value
	sub	ax,bx
	call	printword	;print difference
	ret
;
;	****************************************
;	*                                      *
;	*     i - input file control block     *
;	*                                      *
;	****************************************
;
ifcb:
	push	conptr		;save input pointer
	mov	di,offset fcb
	call	parse
	cmp	al,eol
	jnz	i0		;only one filename
	dec	conptr		;to rescan eol and blank second filename in fcb
i0:
	mov	di,offset fcb2
	call	parse2		;parse second filename
	push	ds
	pop	es		;point to DDT's ds
	pop	conptr		;restore input pointer
	mov	di,81h		;move command tail to [es]:[di]
	sub	cx,cx		;zero count
i1:
	call	conin		;get char from command tail
	cmp	al,eol		;end of command tail?
	jz	i2
	stos	al		;store in user's base page
	inc	cx		;increment count
	jmps	i1		;loop until eol
i2:
	mov	al,0
	stos	al		;store 0 at end of string
	mov	es:.80h,cl	;store count at start of buffer
	cmp	mode,'E'
	jnz	idone		;if no file loaded with E command, we're done
	mov	si,offset fcb
	mov	di,si
	mov	es,userds
	add	cx,38		;total bytes to move = # in command + 36 (fcb)
				; +2 (0 at end of command and count byte)
rep	movs	al,al		;move fcb from ddt86 basepage to user's basepage
idone:
	ret
ierr:
	jmp	err
;
;	**********************************
;	*                                *
;	*     l - list assembly code     *
;	*                                *
;	**********************************
;
lassm:
	test	disempresent,0ffh
	jz	laserr
	mov	lascntsw,0	;don't use count if end addr specified
	mov	numreq,0	;ok if no entries
	mov	ax,type1seg
	mov	lasseg,ax	;default to type1 seg
	mov	di,offset lasloc
	call	getsegandoff
	cmp	al,eol
	mov	ax,lasseg
	mov	type1seg,ax	;update default type1 seg
	jz	las0
	call	getlastoffset	;if ',', get end address
	jmps	las1
las0:
	mov	lascntsw,1	;disassemble fixed # of instructions
	MOV	AL,NLINES
	MOV	LASCNT,AL
	mov	bx,0ffffh	;set lasmax to big number
las1:
	mov	lasmax,bx
las2:
	mov	di,lasloc
	cmp	di,lasmax
	ja	lasret
	push	di
	CALL	CRLFCHK
	pop	di
	mov	es,lasseg
	push	es
	push	di		;for disem call (PL/M)
	call	printdword
	call	blank
	call	disem
	cmp	ax,lasloc
	jb	lasret		;stop if wrap occurred
	mov	lasloc, ax
	test	lascntsw,0ffh
	jz	las2
	dec	lascnt
	jnz	las2
lasret:
	ret
laserr:
	jmp	err
;
;	**************************
;	*                        *
;	*     m - move block     *
;	*                        *
;	**************************
;
move:
	mov	di,offset type2loc
	call	getsegandoff
	call	getoffset	;get end offset
	mov	usermax,bx
	cmp	al,eol
	jz	moverr		;need 3 arguments
	sub	bx,type2loc
	jb	moverr		;error if start > end
	mov	ax,type2seg
	mov	userseg2,ax	;default to same seg as source
	mov	di,offset userloc2
	call	getsegandoff	;get destination address
	cmp	al,eol
	jnz	moverr		;error if more than 3 arguments
mov0:
	les	si,dword ptr type2loc
	mov	al,es:[si]	;get source byte
	les	di,dword ptr userloc2
	call	setbyte		;put destination byte
	inc	type2loc
	jz	movret		;don't allow wraparound
	inc	userloc2
	jz	movret		;don't allow wraparound in destination segment
	mov	ax,type2loc
	cmp	ax,usermax	;check for done
	jna	mov0
movret:
	ret
moverr:
	jmp	err
;
;	*************************
;	*                       *
;	*     r - read file     *
;	*                       *
;	*************************
;
read:
	call	conin		;get first command char
	cmp	al,eol		;check for no input
	jz	rerr		;filename must be included in command
	dec	conptr		;to rescan first char
	mov	di,offset fcb
	call	parse
	jz	rerr		;no '?' or '*' allowed
	cmp	al,eol
	jnz	rerr		;no parameters after filename
	mov	dx,offset fcb
	call	open
	mov	mcblen,0ffffh	;largest memory request
	mov	dx,offset mcb
	call	getmaxmem	;get size of largest chuck of memory
	mov	dx,offset mcb
	call	allocabsmem	;allocate block returned from getmaxmem
	call	readfile	;read file into memory block
	mov	mcbext,0	;only free memory at mbase
	mov	dx,offset mcb
	call	freemem		;free memory not used in read (read updated mcb)
	mov	ax,startreadseg
	mov	type2seg,ax	;set default type2 segment to file just read
	mov	type1seg,ax	;also type1 segment
	sub	ax,ax
	mov	disloc,ax	;display pointer offset = 0
	mov	lasloc,ax	;list pointer offset = 0
	mov	mode,'R'	;last disk input was read (not execute)
	call	verify
	ret
rerr:
	jmp	err
;
;	**************************
;	*                        *
;	*     s - set memory     *
;	*                        *
;	**************************
;
setmem:
	call	checkword	;check for 'SW'
	mov	di,offset type2loc
	call	getsegandoff
set0:
	call	crlf
	les	di,dword ptr type2loc
	call	printdword
	call	blank
	les	si,dword ptr type2loc
	call	print8or16
	call	blank
	call	getline
	call	conin
	cmp	al,eol
	jz	set2
	cmp	al,'.'
	jz	setret
	dec	conptr		;to rescan first character
	call	getlastoffset
	mov	ax,bx		;get new value to ax
	test	wmode,1
	jnz	set1
	or	bh,bh
	jnz	seterr		;must be < 256 if not SW
set1:
	les	di,dword ptr type2loc
	call	set8or16
set2:
	mov	si,offset type2loc
	call	inc1or2
	jnb	set0
setret:
	ret
seterr:
	jmp	err
;
;	***************************************
;	*                                     *
;	*     t - trace program execution     *
;	*                                     *
;	***************************************
;
trace:
	mov	traceprint,1
trace0:				;untrace enters here with traceprint = 0
	call	conin
	cmp	al,'S'		;check for TS
	mov	ah,1
	jz	tr0		;if TS, set segflag to 1
	dec	ah		;else set segflag to 0, and
	dec	conptr		;decrement pointer to rescan character
tr0:
	mov	segflag,ah	;print segment registers or not
	mov	tracecount,1	;default to 1 instruction trace
	call	getnumber
	cmp	al,eol
	jnz	traceerr	;only 1 parameter allowed
	or	ah,ah		;see if a number was entered
	jz	trace1		;skip if no number typed
	mov	tracecount,bx	;store number of instructions to trace
trace1:
	call	xdisp		;display CPU state
	jmp	tracerestore	;restore user's CPU state and return
traceerr:
	jmp	err
;
;	******************************************
;	*                                        *
;	*     u - untraced program execution     *
;	*                                        *
;	******************************************
;
untrace:
	mov	traceprint,0
	jmps	trace0		;common code with trace command
;
;	*********************************
;	*                               *
;	*     v - display file info     *
;	*                               *
;	*********************************
;
verify:
	mov	al,mode
	cmp	al,'R'
	jz	verifyr
	cmp	al,'E'
	jz	verifye
	jmp	err	;neither R nor E command done
verifyr:
	call	crlf
	mov	si,offset readm
	call	printm
	call	crlf
	les	di,dword ptr startreadoff
	call	printdword
	call	blank
	les	di,dword ptr endreadoff
	call	printdword
	ret
;
verifye:
	call	crlf
	mov	cx,3
	call	tabs
	mov	si,offset readm
	call	printm		;print header
	mov	al,0		;initialize count to 0
v0:
	push	ax		;save it
	pop	ax		;get count
	push	ax		;save it
	call	printseginfo	;print name, start, end of segment if non-zero
	pop	ax		;get count
	inc	al		;increment it
	cmp	byte ptr basepagesave+5,1	;check for 8080 model
	jz	verret		;no more segments if 8080 model
	cmp	al,8		;max of 8 segments described in base page
	jb	v0		;done when count = 8
verret:
	ret
;
;	******************************************
;	*                                        *
;	*     w - write memory block to disk     *
;	*                                        *
;	******************************************
;
write:
	mov	ax,startreadseg
	mov	startwriteseg,ax
	mov	ax,startreadoff
	mov	startwriteoff,ax
	mov	ax,endreadseg
	mov	endwriteseg,ax
	mov	ax,endreadoff
	mov	endwriteoff,ax
	call	conin
	cmp	al,eol		;check for no parameters
	jz	werr		;must have a filename
	dec	conptr		;to rescan first char
	mov	di,offset fcb
	call	parse		;get filename
	jz	werr		;don't allow '?' or '*'
	cmp	al,eol
	jnz	w0		;not end of input - must be 2 parameters
	cmp	mode,'R'	;see if a file was read in
	jnz	werr		;no file read - must have start, end addresses
	jmps	w1		;continue with write
w0:
	mov	ax,type1seg
	mov	startwriteseg,ax	;set default to userds
	mov	di,offset startwriteoff
	call	getsegandoff	;get start address
	cmp	al,eol
	jz	werr		;need 2 parameters
	mov	ax,startwriteseg
	mov	endwriteseg,ax	;end defaults to start
	mov	di,offset endwriteoff
	call	getsegandoff	;get end address
	cmp	al,eol
	jnz	werr		;no more than 2 parameters
w1:
	call	writefile
	mov	dx,offset fcb
	call	close
	ret
werr:
	jmp	err
;
;	***************************************
;	*                                     *
;	*     x - display/alter CPU state     *
;	*                                     *
;	***************************************
;
xdisp:				;display CPU state
	CALL	SETDEFSEG	;SET TYPE1SEG, LASLOC TO CS:IP
	TEST	COL40,0FFH
	JNZ	XD40
	call	printregheader
xnohdr:				;entry point to display CPU state without header
	TEST	COL40,0FFH
	JNZ	XNH40
	call	crlf
	call	printflags
	call	blank
	call	printregs
	call	printinstr	;disassemble instruction at [cs:ip]
	ret
;
XD40:
	CALL	PREGHDR1
	MOV	AL,1
	JMPS	XD0
XNH40:
	MOV	AL,0
XD0:
	PUSH	AX		;SAVE HEADER/NO HEADER FLAG
	CALL 	CRLF
	CALL	PRINTFLAGS
	CALL	BLANK
	CALL	PREG1
	CALL	CRLF
	POP	AX
	DEC	AL
	JNZ	XD1
	CALL	PREGHDR2
	CALL	CRLF
XD1:
	CALL	PREG2
	CALL	PRINTINSTR
	RET
xcom:
	mov	segflag,1	;display seg reg's in x command
	call	conin
	cmp	al,eol		;check for command by itself
	jz	xdisp		;if so, simply display CPU state
	mov	xtemp,al	;else save char
	call	conin
	cmp	al,eol		;check for single character after X
	jz	xflag		;if so, must be a flag name
	mov	ah,xtemp	;else it's a reg name
	or	al,80h		;since names are declared that way
	xchg	al,ah		;since that's how it is in memory
	call	chkreg		;check for valid reg name + store number in regnum
	call	conin
	cmp	al,eol
	jnz	xerr		;eol must follow reg name
x0:
	call	crlf
	mov	cx,regnum
	call	printregname
	call	blank
	mov	cx,regnum
	call	printregval
	call	blank
	call	getline
	call	conin
	cmp	al,'.'
	jz	xret		;done when '.' entered
	dec	conptr		;else rescan character
	call	getnumber
	cmp	al,eol
	jnz	xerr		;eol must follow number
	or	ah,ah		;see if non-blank entry
	jz	xnext		;if blank, go to next reg
	mov	cx,regnum
	mov	ax,bx		;get new value
	cmp	cl,8		;are we updating cs?
	jnz	x1
	mov	type1seg,ax	;if so, update default type1 segment
x1:
	cmp	cl,9		;are we updating ds?
	jnz	x2
	mov	type2seg,ax	;if so, update default type2 segment
x2:
	call	setreg
xnext:
	inc	regnum
	cmp	regnum,totreg
	jb	x0
	ret
xerr:
	jmp	err
;
xflag:
	mov	al,xtemp	;get flag name
	call	checkflag	;check for valid flag name
	call	crlf
	mov	cx,regnum	;restore flag number
	call	printflagname
	call	blank
	mov	cx,regnum
	call	printflagval
	call	blank
	call	getline
	call	getnumber
	cmp	al,eol
	jnz	xerr		;eol must follow number
	or	ah,ah		;see if non-blank entry
	jz	xret		;if blank, done
	cmp	bx,1
	ja	xerr		;flag value must be 0 or 1
	mov	cx,regnum
	call	setflag
xret:
	ret
;
	eject
;	*********************************
;	*				*
;	*	d a t a   a r e a	*
;	*				*
;	*********************************
;
;	user regs must be in cseg, others may be in dseg
;
userax	dw	0
userbx	dw	0
usercx	dw	0
userdx	dw	0
usersp	dw	0
userbp	dw	0
usersi	dw	0
userdi	dw	0
usercs	dw	0
userds	dw	0
userss	dw	0
useres	dw	0
userip	dw	0
userfl	dw	0
userreg	equ	userax
;
savess	dw	0		;temp holder for sp
savesp	dw	0		;temp holder for sp
;
breakfl	rs	1		;break/single step flag (must be in CS)
;
endcs	equ	$
;
	dseg
	org	offset endcs
;
;	CCP STACK LOCATION
;
CCPSS		DW	0
CCPSP		DW	0
;
;	console buffer declarations
;
conbuffmax	equ	64
conbuffhdr	db	conbuffmax
conbuffcnt	db	0
conbuff		rs	conbuffmax+1	;leave room for eol 
conptr		dw	0
;
;	a command declarations
;
assempresent	db	1	;assembler in memory flag
asmspsav	rw	1	;temporary save for stack pointer
;
;	d command declarations
;
disloc		dw	0	;offset for display
disseg		dw	0	;segment for display
dismax		rw	1	;end offset of display
tdisp		rw	1	;temporary storage for disloc
LINEMAX		DB	0	;# OF BYTES PER LINE
ND80		DB	16	;16 BYTES PER LINE IN 80 COL MODE
ND40		DB	6	;6 BYTES PER LINE IN 40 COL MODE
NDW40		DB	8	;8 BYTES (4 WORDS) FOR DW IN 40 COL MODE
NLINES		DB	12	;DEFAULT NUMBER OF LINES FOR L, D COMMANDS
;
;	g command declarations
;
goloc		dw	0
goseg		dw	0
vectorsave	rs	12	;save area for bytes at 0004h to 000fh
bpcnt		db	0	;breakpoint count
brk1loc		dw	0
brk1seg		dw	0
brk1byt		db	0
brk2loc		dw	0
brk2seg		dw	0
brk2byt		db	0
;
;	l command declarations
;
lasloc		dw	0
lasseg		dw	0
lasmax		dw	0
lascntsw	rb	1	;# instructions specified or not
lascnt		rb	1	;number of instructions to disassemble
disempresent	db	1	;disassembler in memory flag
;
;	r command declarations
;
startreadoff	rw	1	;offset where file read starts
startreadseg	rw	1	;segment where file read starts
endreadoff	rw	1	;offset where file read ends
endreadseg	rw	1	;segment where file read ends
dmaoff		rw	1	;offset of 20-bit dma address
dmaseg		rw	1	;segment of 20-bit dma address
;
;	t/u command declarations
;
tracecount	rw	1	;number of instructions to trace
traceprint	rb	1	;display CPU state on each step flag
skipbdos	db	0	;set when trace suspended during BDOS call
USERIFOFF	DB	0	;SET WHEN DDT86 MUST REENABLE USER IF
;
;	w command declarations
;
startwriteoff	rw	1	;offset where file write starts
startwriteseg	rw	1	;segment where file write starts
endwriteoff	rw	1	;offset where file write ends
endwriteseg	rw	1	;segment where file write ends
;
;	x command declarations
;
NREG		DB	0	;CURRENT NUMBER OF REGISTER NAMES TO DISPLAY
				;(MAY DIFFER FOR 40 COLUMN MODE)
TOTREG		EQU	13	;TOTAL NUMBER OF REGISTER NAMES
nflag		equ	9	;number of flag names
segflag		db	1	;print segment register flag
regnum		rw	1	;temp for reg/flag number
xtemp		rb	1	;temp for first char of reg name
;
type1loc	dw	0	;offset for type 1 commands
type1seg	dw	0	;segment for type 1 commands
type2loc	dw	0	;offset for type 2 commands
type2seg	dw	0	;segment for type 2 commands
usermax		rw	1
userloc2	rw	1
userseg2	rw	1
;
;	memory control block declarations
;
mcb		rs	0	;used in reading/writing file
mcbbase		dw	0	;segment of memory block
mcblen		dw	0	;length of memory block
mcbext		db	0	;returned value from bdos memory functions
;
sysif		rb	1	;system interrupt flag
numreq		rb	1	;number required or optional
wmode		rb	1	;set for DW, FW and SW commands
mode		db	'I'	;last disk access with 'R' or 'E' command
savevecflag	db	0	;save/restore bp and ss vectors, or not
COL40		DB	0	;PATCHED TO 1 FOR 40 COLUMN CONSOLE
ERRMODE		DB	0	;SET IF BDOS RETURN ERR MODE SET (V3.0)
;
basepagesave	rb	48	;copy of user's base page
;
;	parsing declarations
;
delims		db	' ', '=', '.', ',', ':', ';', '[', ']', '<', '>', eol
ndelims		equ	offset $ - offset delims
lastchar	db	0
fcbadr		dw	0	;temp storage for fcb address
;
		rs	stsize	;stack size
stackp		rs	0	;top of stack
;
	if	debug
;
biosentryoff	dw	0a00h	;empty part of ccp (hopefully)
biosentryseg	dw	0	;same as bdos segment
;
	endif
;
	end
