
;	--------------------------------------------------------
;	DDT.COM is a part of the collection of programs which
;	one receives when buying CP/M from Digital Research. Of
;	all the programs in the CP/M package, it is one of the
;	weakest, and seems to have been mainly intended to use
;	to insert the custom part of BIOS into CP/M when it is
;	desired to generate a new system. Its strongest point is
;	its single step facility and its suppression during the
;	execution of BDOS. Its most frustrating point may be its
;	lack of transparency to the command line of programs to
;	which it is to be applied.
;
;	The present program was based on a disassembly of the
;	Digital Research version, which has now been very
;	extensively rearranged, even though vestiges of that
;	original program still remain. Several minor errors
;	have been corrected, but the important changes consist
;	in the greatly expanded capabilities of most of the
;	options, besides a complete replacement of both the
;	assembler and the disassembler. Many commands now admit
;	a repeat factor, examination of registers and memory is
;	much more extensive, and a bitmap can generated to mark
;	significant memory locations. Other modifications or
;	extensions may be deduced from the change log below.
;
;	Since DDT will be coresident with the program it will
;	examine, it is convenient to relocate it to high memory
;	and adjust the BDOS call to reflect less free space. If
;	an origin for the relocated DDT can be assigned, a small
;	translation program is included to move it once loaded.
;	It has been disabled by commenting it out. It would have
;	to be assembled by Microsoft's M80 or a similar assembler
;	allowing phasing and dephasing. It is much more general
;	to generate a bitmap for a page relocator, for which the
;	following script will serve as a guide. It assumes that
;	the utilities LOHD.COM, GENBIM.COM, and PAGREL.COM are
;	available; also that two separate copies of DDT were
;	prepared: NDDT at origin 100H, and ZDDT at origin 000H,
;	but otherwise identical.
;
;		A>ASM NDDT.AAZ
;		A>ASM ZDDT.AAZ
;		A>LOHD NDDT
;		A>LOHD ZDDT
;		A>GENBIM ZDDT NDDT
;		A>NDDT PAGREL		[NEXT = 180]
;		-IZDDT.COM
;		-R100			[NEXT = 1600]
;		-IZDDT.BIM
;		-R1500			[NEXT = 1900]
;		-S103
;		. 0103 BB 00
;		. 0104 BB 02
;		. 0105 EE 00
;		. 0106 EE 16
;		h 0107 68 .
;		-^C
;		A>SAVE 24 NDDT.COM
;
;		    NDDT.ASM -- Copyright (C) 1983
;		    Universidad Autonoma de Puebla
;			   20 November 1983
;
;	---------------: B generates a bitmap, L shows X's.
;	---------------: V is a T which ignores CALLs.
;	24 October 1982: R sets 007C to zero before starting.
;	24 October 1982: I will read an entire command line.
;	06 November 1982 - preliminary circulation copies.
;	12 December 1982 - XA shows both HEX, ASCII values.
;	12 December 1982 - X confirms register changes.
;	13 December 1982 - 007C zeroed while opening file.
;	13 December 1982 - I <pop h> when leaving HEX option.
;	13 December 1982 - <no extension> taken as .COM
;	13 December 1982 - P "Peek" added.
;	16 December 1982 - E "Execute" added.
;	18 December 1982 - S accepts quoted character.
;	20 December 1982 - edition for Assembler II.
;	7 August 1983 - correct overwrite of b in G.
;	7 August 1983 - zero 7C after initial program load.
;	20 August 1983 - clear memory before loading.
;	20 August 1983 - decimal prefix to all commands.
;	22 August 1983 - new format for display line.
;	22 August 1983 - En,xxxx superseded by nG,xxxx.
;	23 August 1983 - nV/, nT/, nU/ suppress display lines.
;	23 August 1983 - X=xxxx displays a window around xxxx.
;	23 August 1983 - nU superseded by nT/.
;	23 August 1983 - P incorporated into X.
;	26 August 1983 - M moves overlapping interval backwards.
;	26 August 1983 - A does not leave 3 0D's on exit.
;	28 August 1983 - General rearrangement and revision.
;	30 August 1983 - Edition for Languages II.
;	20 November 1983 - X - jz for jnz refused flag changes.
;	20 November 1983 - ASM - assembly of RST N was wrong.
;	20 November 1983 - stor - xra a to avoid false signals.
;	[Harold V. McIntosh, 20 December 1982]
;	[Harold V. McIntosh, 30 August 1983]
;	--------------------------------------------------------

HT	equ	09H	;tab
LF	equ	0AH	;line feed
CR	equ	0DH	;carriage return
KZ	equ	1AH	;^Z
RO	equ	7FH	;rubout

;ddtorg	equ	09000H	;absolute DDT origin
;
;
;;	Move DDT up to higher memory.
;
;X0100:	lxi	b,enddt-begn
;X013D:	lxi	sp,begn
;	lxi	d,ddtorg
;	lxi	h,X0165
;X0158:	mov	a,b
;	ora	c
;	jz	ddtorg
;	dcx	b
;	mov	a,m
;	stax	d
;	inx	d
;	inx	h
;	jmp	X0158
;X0165:	ds	0
;
;;	-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
;
;	.phase	ddtorg

	org	0100H

begn:	jmp	init	;initialize DDT

;	========================================================
;	Assembler for the INTEL 8080.  As a "small" assembler,
;	it is subject to the following restraints:
;		1) only hexadecimal numbers are accepted
;		2) opcode identification is merely sufficient
;		3) source code is not confined to a single line
;		4) error detection only for an unintelligible
;		   opcode or field; then three zero bytes are
;		   deposited to allow patches, assembler line
;		   is abandoned
;		5) implausible combinations are not rejected
;
;	Register pair HL points to the byte in which the
;	assembled opcode will be stored.  If necessary, hex
;	data or address fields will be read and HL will be
;	incremented by 1, 2, or 3 as required.  Flags are valid
;	on return; zero means no error.
;
;	No RAM memory is used directly by the program, so that
;	it may be inscribed in its entirity in a PROM.  All its
;	requirements for temporary storage are met from the
;	internal registers of the 8080 or the stack.
;	========================================================

assm:	push	h
	lxi	h,stor
	push	h
	call	alfa
	jmp	aopco

;	Read an alpha field by ignoring leading separators,
;	storing letters in registers C,D,E, and terminating
;	reading when a separator is again encountered.  All
;	fields are held to three letters, so that the only
;	letters in a chain that are stored are the first,
;	second, and last.

alfa:	lxi	d,'  '
ala:	call	relc
	call	sepa
	jz	ala
	mov	c,a
	call	relc
	call	sepa
	rz
	call	term
	rz
	mov	d,a
alb:	call	relc
	call	sepa
	rz
	call	term
	rz
	mov	e,a
	jmp	alb

;	Read an alpha field with the intention of keeping only
;	the last letter in the field.  Otherwise the same rules
;	apply as in the subroutine alfa: leading separators are
;	ignored, trailing separators terminate.

beta:	call	relc
	call	sepa
	jz	beta
bet:	mov	b,a
	call	relc
	call	sepa
	jz	bta
	call	term
	jnz	bet
bta:	mov	a,b
	ret

;	Locate the operation codes.  A simple linear search is
;	made of some sixty mnemonics, grouping them mostly in
;	sets of eight because their position within an octet
;	translates directly into a source or destination field
;	in the 2-3-3 decomposition of INTEL 8080 opcodes.

aopco:	mvi	b,0CH
	lxi	H,AT4	;Quadrant 0 with minor modifications
	call	mnem
	jp	AQ0
	mvi	b,01H
	lxi	h,AT0	;Quadrant 1: interregister movements
	call	mnem
	jp	AQ1
	mvi	b,08H
	lxi	h,AT1	;Quadrant 3: arithmetic-logical
	call	mnem
	jp	AQ2
	mvi	b,08H
	lxi	h,AT2	;Quadrant 2, column 6: immediate
	call	mnem
	jp	AB6
	mvi	b,11H
	lxi	h,AT5	;All the sporadic opcodes
	call	mnem
	jp	qq
	mvi	b,08H
	lxi	h,AT3	;Quadrant 0, column 7: accumulator
	call	mnem
	jp	AA7
	mov	a,c
	cpi	'r'
	jz	AB0	;Quadrant 3, column 0: returns
	cpi	'j'
	jz	AB2	;Quadrant 3, column 2: jumps
	cpi	'c'
	jz	AB4	;Quadrant 3, column 4: calls
	mvi	b,05H
	lxi	h,AT7	;Assembler directives
	call	mnem
	jp	QD
	jmp	hexb

;	Quadrant zero - memory to register - and some others.

AQ0:	mov	c,a
	call	juta
	dw	X0	;pop  pair
	dw	AA1	;lxi  pair,addr
	dw	AA0	;stax pair  - beware - only b, d legal
	dw	AA0	;inx  pair
	dw	AA4	;inr  register
	dw	AA4	;dcr  register
	dw	AA6	;mvi  register,data
	dw	AB7	;rst  digit in opcode
	dw	Y0	;push pair
	dw	AA0	;dad  pair
	dw	AA0	;ldax pair  - beware - only b, d legal
	dw	AA0	;dcx  pair

X0:	mvi	c,0C1H
	jmp	AA0
Y0:	mvi	c,0C5H
AA0:	call	beta
	call	apair
	ora	c
	ret

AA1:	call	AA0
	jmp	addq

AA4:	call	rdst
	ora	c
	ret

AA6:	call	AA4
	jmp	datq

AA7:	add	a
	add	a
	add	a
	ori	07H
	ret

AQ1:	call	rdst
	mov	c,a
	call	rsrc
	ora	c
	ori	040H
	ret

AQ2:	add	a
	add	a
	add	a
	mov	c,a
	call	rsrc
	ora	c
	ori	080H
	ret

qq:	cpi	09H
	jc	ss
	lxi	h,adata
	cpi	0BH
	jc	rr
	lxi	h,aaddr
rr:	xthl
ss:	lxi	h,AT8
	jmp	reta

;	Quadrant 3 - mostly program counter modification

AB0:	mvi	a,0C0H
	jmp	abb
AB2:	mvi	a,0C2H
	call	abb
	jmp	addq
AB4:	mvi	a,0C4H
	call	abb
	jmp	addq
abb:	push	psw
	mvi	c,' '
	mvi	b,08H
	lxi	h,AT6
	call	mnem
	pop	b
	jm	error
	add	a
	add	a
	add	a
	ora	b
	ret

;	Immediates.

AB6:	add	a
	add	a
	add	a
	ori	0C6H
	jmp	datq

;	Restarts.

AB7:	call	beta
	rlc
	rlc
	rlc
	ani	038H
	ori	0C7H
	ret

;	Assembler directives.

QD:	call	juta
	dw	D0	;data byte
	dw	D1	;data word
	dw	D2	;data space
	dw	D3	;origin
	dw	D4	;end

D0:	inx	sp	;data byte
	inx	sp
	pop	d
	call	hxar
	mov	l,a
	mvi	a,0FDH	;error
	rnz
	inr	a	;(org)
	xchg
	mov	m,e
	inx	h
	ret

D1:	inx	sp	;data word
	inx	sp
	pop	d
	call	hexf
	mvi	a,0FDH	;error
	rnc
	inr	a	;(org)
	xchg
	mov	m,e
	inx	h
	mov	m,d
	inx	h
	ret

D2:	inx	sp	;data space
	inx	sp
	pop	d
	call	hexf
	mvi	a,0FDH	;error
	rnc
	inr	a	;org
	dad	d
	ret

D3:	inx	sp	;origin
	inx	sp
	inx	sp
	inx	sp
	call	hexf
	mvi	a,0FEH	;org
	rc
	dcr	a
	ret

D4:	inx	sp	;end
	inx	sp
	inx	sp
	inx	sp
	mvi	a,0FFH	;done
	ret

;	If the operation field did not hold a valid opcode or
;	assembler directive, try it out for a one-byte, two
;	nibble hexadecimal byte.

hexb:	lxi	h,error
	push	h
	mov	a,e
	cpi	' '
	rz
	mov	a,c
	call	cnh
	rc
	add	a
	add	a
	add	a
	add	a
	mov	b,a
	mov	a,d
	call	cnh
	rc
	add	b
	inx	sp
	inx	sp
	ret

;	Read and deposit a hexadecimal address field.

addq:	inx	sp
	inx	sp
aaddr:	mov	b,a
	call	onar
	xchg
	pop	h
	mov	m,b
	inx	h
	mov	m,e
	inx	h
	mov	m,d
	inx	h
	ret

;	Read and deposit a one-byte hexadecimal data field.

datq:	inx	sp
	inx	sp
adata:	mov	b,a
	call	hxar
	jnz	error	;<missing field>
	xchg
	pop	h
	mov	m,b
	inx	h
	mov	m,e
	inx	h
	ret

;	Deposit the assembled operation code

stor:	pop	h
	mov	m,a
	inx	h
	xra	a	;don't return the wrong signal
	ret

;	Load accumulator with nth item in the list whose
;	origin is contained in register pair HL, when n
;	lies in the accumulator.

reta:	add	l
	mov	l,a
	mov	a,h
	aci	00H
	mov	h,a
	mov	a,m
	ret

;	Find numerical equivalents for register designations.
;	Source registers are reported at their true value, but
;	destination registers are multiplied by eight to have
;	their value positioned correctly for its field.

rsrc:	call	beta
srce:	mvi	b,08H
	lxi	h,atr
	call	regi
	jm	error
	ret

rdst:	call	beta
dest:	call	srce
	add	a
	add	a
	add	a
	ret

;	Find numerical equivalents for register pair symbols.
;	They always left-pack their destination field.

apair:	mvi	b,05H
	lxi	h,atp
	call	regi
	jm	error
	cpi	04H
	cmc
	sbi	00H
	mov	b,a
	add	a
	add	a
	add	a
	add	a
	ret

;	Search a list of bytes whose origin is contained in
;	in HL to find the one, if any, which matches the
;	accumulator.  The length of the list in is B on entry;
;	on exit A contains either the position or FF if no
;	match was found.

regi:	dcx	h
	cmp	m
	jz	reg
	dcr	b
	jnz	regi
reg:	xra	a
	dcr	b
	ora	b
	ret

;	Search a table of three-letter mnemonics to find the
;	code contained in registers C,D,E.  Enter with the
;	table origin in pair HL, the table size N in the
;	accumulator.  On exit the accumulator will contain
;	either the position, ranging between 0 and N-1, of
;	the item in the table, or else FF(hex) if it was not
;	found.

mnem:	dcx	h
	mov	a,m
	cmp	e
	jnz	mnb
	dcx	h
	mov	a,m
	cmp	d
	jnz	mnc
	dcx	h
	mov	a,m
	sub	c
	jnz	mnd
mna:	dcr	b
	ora	b
	ret
mnb:	dcx	h
mnc:	dcx	h
mnd:	dcr	b
	jnz	mnem
	jmp	mna

;	Table of mnemonics grouped by octets and dodecuplets.

dtr:	db	'bcdehlma'
atr:	db	'bdhpw'
atp:	db	'mov'
AT0:	db	'add','adc','sub','sbb'
	db	'ana','xra','ora','cmp'
AT1:	db	'adi','aci','sui','sbi'
	db	'ani','xri','ori','cpi'
AT2:	db	'rlc','rrc','ral','rar'
	db	'daa','cma','stc','cmc'
AT3:	db	'pop','lxi','stx','inx'
	db	'inr','dcr','mvi','rst'
	db	'puh','dad','ldx','dcx'
AT4:	db	'nop','ret','pcl','spl'
	db	'xtl','xcg','di ','ei '
	db	'hlt','out','in ','jmp'
	db	'cal','shd','lhd','sta','lda'
AT5:	db	' nz',' z ',' nc',' c '
	db	' po',' pe',' p ',' m '
AT6:	db	'db ','dw ','ds ','org','end'
AT7:	db	nop
	db	ret
	db	pchl
	db	sphl
	db	xthl
	db	xchg
	db	di
	db	ei
	db	hlt
	db	0D3H	;(out)
	db	0DBH	;(in)
	db	0C3H	;(jmp)
	db	0CDH	;(call)
	db	022H	;(shld)
	db	02AH	;(lhld)
	db	032H	;(sta)
	db	03AH	;(lda)

;	T7 is the end of one table, T8 is the beginning of another.

AT8	equ	AT7


;	=====================================================
;	Disassembler for the INTEL 8080.  Register pair HL
;	points to the byte to be disassembled.  HL will be
;	incremented by 1, 2, or 3 according to the type of
;	instruction encountered.  No RAM storage is used
;	within the program, which may therefore be entirely
;	resident in ROM.
;	=====================================================

dism:	mov	a,m
	push	h
	lxi	h,done
	push	h
	cpi	76H
	jnz	split
halt:	lxi	h,td
	jmp	three

;	separate the instruction field into groups of 2,3,3
;	bits and then continue according to quadrants.

split:	push	psw
	push	psw
	ani	07H
	mov	c,a
	pop	psw
	rrc
	rrc
	rrc
	ani	07H
	mov	b,a
	pop	psw
	rlc
	rlc
	ani	03H
	lxi	h,jq
jump:	call	bndx
	mov	e,m
	inx	h
	mov	d,m
	xchg
	pchl

;	Indexing subroutines which add corresponding multiples
;	[3,4,2,1] of A to the register pair HL.

tndx:	mov	e,a
	add	a
	add	e
	jmp	indx
qndx:	add	a
bndx:	add	a
indx:	add	l
	mov	l,a
	mov	a,h
	aci	00H
	mov	h,a
	ret

;	-------------------------------------------------------
;	Quadrant 0 contains accumulator operations, increments,
;	decrements, loads, stores and immediate moves, all of
;	which must be detailled further.
;	-------------------------------------------------------

DQ0:	mov	a,c
	lxi	h,ja
	jmp	jump

;	Column 0 contains NOP together with seven unused codes

DA0:	mov	a,b
	ora	a
	jnz	node
noop:	lxi	h,tc
	jmp	trey

;	Column 1 alternates lxi to a register pair with dad
;	from a register pair.  The lxi's require data words,
;	but not the dad's.

DA1:	mov	a,b
	ani	01H
	call	aa
	mov	a,b
	ani	01H
	rnz
	call	sngl
	jmp	daddr

;	Column 2 alternates storing and loading instructions.
;	The first six refer to register pairs, the last two to
;	the accumulator; the last four require addresses.

DA2:	mov	a,b
	lxi	h,DT5
	call	vier
	mov	a,b
	ani	04H
	jz	putp
	jmp	daddr

;	Column 3 alternates inx of a register pair with dcx of
;	the same pair.

DA3:	mov	a,b
	ani	01H
	adi	02H
aa:	lxi	h,DT4
	call	drei
	jmp	putp

;	Column 4 contains inr, 5 containd dcr, both modified
;	by the register list.

DA4:	mov	a,c
	lxi	h,DT4
	call	drei
	mov	a,b
	lxi	h,dtr
	jmp	ein

;	Column 6 contains the mvi's, which require a data byte.

DA6:	call	DA4
	call	sngl
	jmp	ddata

;	Column 7 contains the accumulator operations.

DA7:	mov	a,b
	lxi	h,AT2
	call	tndx
	jmp	trey

;	----------------------------------------------------------
;	Quadrant 1 consists of interregister movements.
;	----------------------------------------------------------

DQ1:	lxi	h,tb
	call	three
	mov	a,b
	lxi	h,dtr
	call	ein
	call	sngl
	mov	a,c
	lxi	h,dtr
	jmp	ein

;	----------------------------------------------------------
;	Quadrant 2 consists of arithmetic operations
;	----------------------------------------------------------

DQ2:	mov	a,b
	lxi	h,AT0
	call	drei
	mov	a,c
	lxi	h,dtr
	jmp	ein

;	---------------------------------------------------------
;	Quadrant 3 has returns, calls, jumps, pushes, pops,
;	and a variety of miscellania needing a detailed study.
;	---------------------------------------------------------

DQ3:	mov	a,c
	lxi	h,jb
	jmp	jump

;	Column 0 contains all the conditional returns

DB0:	mvi	a,'r'
bb:	call	aout	;A to console
	mov	a,b
	lxi	h,AT5
	call	tndx
	inx	h
	jmp	two

;	Column 1 contains the pops, together with the unconditional
;	return, pchl, sphl, and an undefined code.

DB1:	mov	a,b
	lxi	h,DT7
	call	vier
	mov	a,b
	cpi	03H
	jz	dopco
	ani	01H
	rnz
	jmp	putq

;	Column 2 contains all the conditional jumps.

DB2:	mvi	a,'j'
	call	bb
	jmp	daddr

;	Columnn 3 is an assortment, requiring many distinctions.

DB3:	mov	a,b
	lxi	h,DT8
	call	vier
	mov	a,b
	cpi	04H
	rnc
	cpi	01H
	jz	dopco
	jc	daddr
	jmp	ddata

;	Column 4 contains all the conditional calls.

DB4:	mvi	a,'c'
	call	bb
	jmp	daddr

;	Column 5 contains the pushes, simple call, 3 undefined.

DB5:	mov	a,b
	ani	01H
	jnz	xx
	lxi	h,tf
	call	four
	jmp	putq
xx:	mov	a,b
	cpi	01H
	jnz	node
	lxi	h,te
	call	four
	jmp	daddr

;	Column 6 holds all the arithmetic immediates.

DB6:	mov	a,b
	lxi	h,AT1
	call	drei
	jmp	ddata

;	Column 7 contains all the restarts.

DB7:	lxi	h,DT4+21
	call	three
	mov	a,b
	adi	'0'
	jmp	aout	;A to console

;	------------------------------------------------------
;	a collection of copying and spacing routines.
;	------------------------------------------------------

vier:	call	qndx
	jmp	four
drei:	call	tndx
	jmp	three
ein:	call	indx
	jmp	one

four:	call	quad
	jmp	sngl
three:	call	trey
	jmp	dubl
two:	call	dpair
	jmp	dubl

quad:	mov	a,m
	call	aout	;A to console
	inx	h
trey:	mov	a,m
	call	aout	;A to console
	inx	h
dpair:	mov	a,m
	call	aout	;A to console
	inx	h
one:	mov	a,m
	jmp	aout	;A to console

;	-------------------------------------------------------
;	Commonly used transferrence and conversion routines.
;	-------------------------------------------------------

putp:	mov	a,b
	ani	06H
	lxi	h,dtp
	call	indx
	jmp	dpair

putq:	mov	a,b
	ani	06H
	rrc
	lxi	h,tq
	call	tndx
	jmp	trey

done:	pop	h
	inx	h
	ret

daddr:	inx	sp
	inx	sp
	pop	h
	inx	h
	mov	e,m
	inx	h
	mov	d,m
	push	h
	call	word
	jmp	done

node:	lxi	h,ta
	call	three
dopco:	inx	sp
	inx	sp
	pop	h
	jmp	goby

ddata:	inx	sp
	inx	sp
	pop	h
	inx	h
goby:	mov	a,m
	push	h
	call	byte
	jmp	done

;	--------------------------------------------------------
;	Jump tables
;	--------------------------------------------------------

jq:	dw	DQ0,DQ1,DQ2,DQ3

ja:	dw	DA0,DA1,DA2,DA3,DA4,DA4,DA6,DA7

jb:	dw	DB0,DB1,DB2,DB3,DB4,DB5,DB6,DB7

;	--------------------------------------------------------
;	Tables of mnemonics for the 8080 instructions
;	--------------------------------------------------------

ta:	db	'db '
tb:	db	'mov'
tc:	db	'nop'
td:	db	'hlt'
te:	db	'call'
tf:	db	'push'

dtp:	db	'b d h sp'

tq:	db	'b  '
	db	'd  '
	db	'h  '
	db	'psw'

DT4:	db	'lxi','dad','inx','dcx'
	db	'inr','dcr','mvi','rst'

DT5:	db	'stax','ldax','stax','ldax'
	db	'shld','lhld','sta ','lda '

DT7:	db	'pop ','ret ','pop ','db  '
	db	'pop ','pchl','pop ','sphl'

DT8:	db	'jmp ','db  ','out ','in  '
	db	'xthl','xchg','di  ','ei  '

;	-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

DP	equ	16	;paragraph length for D
NL	equ	12	;default lines in L
NR	equ	12	;number of registers to examine in X
WW	equ	5	;window halfwidth in register display

BDOS	equ	0005H	;jump to BDOS
RST7	equ	0038H	;DDT breakpoint handler
TFCB	equ	005CH	;DDT's file control block
TBUF	equ	0080H	;DDT's sector buffer
TORG	equ	0100H	;program origin

bsiz	equ	2000H	;8K = size of bitmap

XDOS:	xthl		;<<DDT analogue of 0005>>
	shld	sica	;site of call to BDOS
	xthl
GDOS:	jmp	0000	;BDOS address

;	Initialize DDT

init:	lhld	BDOS+1
	shld	GDOS+1		;BDOS address
	lxi	h,XDOS		;DDT analogue of 0005
	shld	begn+1
	lxi	h,begn
	shld	BDOS+1
	xra	a
	sta	bkpt		;breakpoint data
	lxi	h,TORG		;CP/M transient origin
	shld	lorg		;origin for L
	shld	dorg		;origin for D
	shld	pmax		;program high limit
	shld	savpc		;PC at breakpoint
	shld	savmr		;memory reference
	lxi	sp,savhl	;breakpoint
	push	h
	lxi	h,0002
	push	h
	dcx	h
	dcx	h
	shld	savhl		;HL at breakpoint
	push	h
	push	h
	mvi	a,0C3H		;(jmp)
	sta	RST7		;RST 7 destination
	lxi	h,rtbk		;return from breakpoint
	shld	RST7+1
	lxi	b,begn		;top of memory
	lxi	h,TORG		;bottom of memory
	mov	a,c
	sub	l
	mov	c,a
	mov	a,b
	sbb	h
	mov	b,a
zero:	mov	a,c
	ora	b
	jz	zerd
	mvi	m,00
	inx	h
	dcx	b
	jmp	zero
zerd:	lxi	h,logo		;"DDT/UAP"
	call	mssg
	mvi	c,25		;(19) read logged in disk
	call	XDOS
	sta	ldsk		;logged disk
	mvi	b,80H
	lxi	d,TBUF
	lxi	h,ctex
	shld	cptr		;pointer to command buffer
	lxi	h,clen
muve:	ldax	d
	mov	m,a
	inx	h
	inx	d
	dcr	b
	jnz	muve
	mov	m,b
	lxi	h,loop		;DDT loop
	push	h
	lda	TFCB+1		;file name
	cpi	' '
	rz
	lxi	h,TFCB+9	;extension
	mov	a,m
	cpi	' '
	jnz	scom
	mvi	m,'C'
	inx	h
	mvi	m,'O'
	inx	h
	mvi	m,'M'
scom:	lxi	h,0000		;zero offset
	call	opra		;R with implicit argument
	jmp	opia		;I after discarding program name

;	----------------------------------------------
;	DDT loop: waits for commands and executes them
;	----------------------------------------------

loop:	lxi	sp,savde	;DDT's private stack
	lxi	h,loop		;DDT loop
	push	h
	call	past		;check limit transgression
	jc	looq
	lxi	h,XDOS		;link to BDOS
	shld	0006H
looq:	call	crlf		;type CR,LF
	mvi	a,'-'
	call	aout		;A to console
	call	incl		;fetch a command line
	call	decf		;read decimal field
	cpi	CR
	rz
	shld	rept
	call	alta		;alternate table
	db	14
	db	'A'
	dw	opta		;A = assemble
	db	'B'
	dw	bmap		;B = bitmap
	db	'D'
	dw	optd		;D = display
	db	'F'
	dw	optf		;F = fill
	db	'G'
	dw	optg		;G = go
	db	'H'
	dw	opth		;H = hex sum, difference
	db	'I'
	dw	opti		;I = initialize CCP command line
	db	'L'
	dw	optl		;L = list program
	db	'M'
	dw	optm		;M = move
	db	'R'
	dw	optr		;R = read file
	db	'S'
	dw	opts		;S = store
	db	'T'
	dw	optt		;T = type registers
	db	'V'
	dw	optv		;V = single step w/ call as 1 step
	db	'X'
	dw	optx		;X = examine registers

;	(A) Assemble 8080 code. <nAx> will assemble n lines
;	of code beginning at address x. Defaults are x=lorg,
;	while no limit is set if n is missing or zero.

opta:	call	past	;check limit transgression
	jnc	error	;<A has been overwritten>
	lhld	lorg	;origin for L
	call	hef
opaa:	shld	lorg	;origin for L
	call	dubl
	call	tyhl	;type HL as four nibbles
	call	dubl
	call	incl	;fetch a command line
	jz	opac
	call	assm
	inr	a	;FF means done
	rz
	inr	a	;FE means new origin
	jnz	opab
	call	crlf
	jmp	opaa
opab:	call	ctlx
	lhld	lorg	;origin for L
	inr	a	;FD means error - retry
	jz	opaa
opac:	call	dubl	;otherwise confirm & advance
	call	tyhl	;type HL as four nibbles
	call	dubl
	call	dism
	call	crlf
	call	drnz	;decrement retn if nonzero
	jnz	opaa
	shld	lorg	;origin for L
	ret

;	(B)  Generate a bitmap of all bytes in the range
;	100H - (pmax) which could possibly be the address
;	of an instruction.

bmap:	lhld	pmax
	xchg
	lxi	h,begn
	lxi	b,-bsiz
	dad	b
	mov	a,l
	sub	e
	mov	a,h
	sbb	d
	jc	error	;<bitmap would overlap program>
	lxi	b,bsiz
bzer:	mvi	m,00H
	inx	h
	dcx	b
	mov	a,c
	ora	b
	jnz	bzer
	lhld	pmax	;program high limit
	xchg
	lxi	h,TORG	;CP/M transient origin
	mov	a,e
	sub	l
	mov	c,a
	mov	a,d
	sbb	h
	mov	b,a
bbit:	push	b
	mov	a,m
	call	twob
	jnc	bbjt
	push	h
	inx	h
	mov	e,m
	inx	h
	mov	d,m
	xchg
	call	wrib
	pop	h
bbjt:	inx	h
	pop	b
	dcx	b
	mov	a,c
	ora	b
	jnz	bbit
	ret

;	Decide if opcode has one-byte sequel.

oneb:	cpi	0D3H
	jz	oney
	cpi	0DBH
	jz	oney
	ani	0C7H
	cpi	006H
	jz	oney
	cpi	0C6H
	jz	oney
	stc
	cmc
	ret
oney:	stc
	ret

;	decide if opcode has two-byte address

twob:	push	b
	cpi	0C3H
	jz	twoy
	cpi	0CDH
	jz	twoy
	mov	b,a
	ani	0C7H
	cpi	0C2H
	jz	twoy
	cpi	0C4H
	jz	twoy
	mov	a,b
	ani	0CFH
	cpi	001H
	jz	twoy
	mov	a,b
	ani	0E7H
	cpi	022H
	jz	twoy
	stc
	cmc
	pop	b
	ret
twoy:	stc
	pop	b
	ret

;	read bit corresponding to address HL

reab:	push	h
	call	biby	;addr = byte + bit
	mov	a,m
rea:	rrc
	dcr	c
	jnz	rea
	pop	h
	ret

;	define bit corresponding to address HL

wrib:	push	psw
	call	biby	;addr = byte + bit
	push	b
	mov	a,m
wra:	rrc
	dcr	c
	jnz	wra
	mov	m,a
	pop	b
	pop	psw
	mov	a,m
	ral
	rrc
wrb:	rlc
	dcr	c
	jnz	wrb
	mov	m,a
	ret

;	reduce an address to byte (HL), bit (C).

biby:	mov	a,l
	ani	07H
	inr	a
	mov	c,a
	mvi	b,3
bib:	mov	a,h
	rar
	mov	h,a
	mov	a,l
	rar
	mov	l,a
	dcr	b
	jnz	bib
	mov	a,h
	ani	1FH
	mov	h,a
	lxi	d,begn
	dad	d
	lxi	d,-bsiz
	dad	d
	ret

;	(D) Display the memory in groups of 16 bytes, both as
;	pairs of hexadecimal nibbles and as ASCII characters,
;	when the latter is appropriate. The command <nDa,b>
;	will display n lines, or else the interval between
;	hexadecimal addresses a and b; the interval takes
;	precedence but if a or b or both are null, the line
;	count helps determine the interval. When a is null the
;	display will usually continue from where it last ended,
;	but nD,b will display b-n up to b. In general:
;		nDa,b	a through b-1, n lines of 16 bytes
;		 Da,b   a through b-1, DP lines of 16 bytes
;		nDa,	a through a+n
;		nD,b	b-n through b
;		nD,	PC through PC+n
;		 Da,    a to the end
;		 Da	just line containing a
;		 D,b	PC through b
;		 D,	PC to the end
;		 D	just line beginning at PC

optd:	lxi	h,pinc	;paragraph length
	mvi	m,DP
	lhld	rept
	mov	a,l
	ora	h
	sui	1
	sbb	a
	ani	01H
	mov	b,a	;1 means n=0
	dad	h
	dad	h
	dad	h
	dad	h
	shld	rept	;1 line is worth 16 bytes
	lhld	dorg	;default <a> is dorg
	call	hef	;read <a>
	mov	c,a
	mov	a,b
	ral
	mov	b,a	;0 means null <a>
	xchg
	lhld	rept
	dad	d	;<a+n> is default <b>
	mov	a,c
	sui	CR
	jz	opda
	lxi	h,0FFF0H
opda:	sui	1
	mov	c,a	;FF means CR
	mov	a,b
	ral
	mov	b,a	;1 means CR
	call	hef	;read <b>
	mov	a,b
	ral
	mov	b,a
	inr	c
	jnz	opdb	;z means CR
	lhld	rept
	dad	d
opdb:	shld	dorg

;	At this point, DE=<a>, HL=<b>, B defines case,
;	but a few anomalies still have to be resolved.

	mov	a,b
	cpi	01H
	jnz	opdc
	lhld	dorg
	xchg
	lhld	rept
	mov	a,e
	sub	l
	mov	l,a
	mov	a,d
	sbb	h
	mov	h,a
	xchg		;else a=b-n
opdc:	cpi	05H
	jz	opdd
	cpi	04H
	jz	opdd
	cpi	00H
	jnz	opde
opdd:	lhld	rept
	dad	h
	dad	h
	dad	h
	dad	h
	mov	a,h
	sta	pinc	;paragraph length

;	The parameters are now ready to start typing.

opde:	lhld	dorg
	xchg
	mov	a,e
	sub	l
	mov	a,d
	sbb	h
	jc	error	;<inverted interval>
	lda	pinc	;paragraph length
	mov	b,a
opdf:	call	crlf	;type CR,LF
	call	inst	;read console status
	jz	opdg
	shld	dorg	;mark stopping point
	ret
opdg:	call	tyhl	;type HL as four nibbles
	push	h
	call	dubl
	call	hebl
	call	sngl	;type space
	pop	h
	mvi	c,10H
	call	ascl
	dcr	b
	jnz	opdh
	lda	pinc	;paragraph length
	mov	b,a
	call	crlf
opdh:	mov	a,l
	sub	e
	mov	a,h
	sbb	d
	jc	opdf
	ret

hebl:	call	oobl
oobl:	call	fobl
fobl:	call	tetr
	jmp	sngl

tetr:	call	duce
duce:	call	once
once:	mov	a,m
	call	byte
	inx	h
	jmp	sngl

;	(F) Fill an interval. <Fx,y,a> will fill the interval
;	from x to y with the hexadecimal value a.

optf:	call	onar
	push	h
	call	onar
	xchg
	call	hxar
	jnz	error	;<nonstandard argument>
	mov	b,a
	pop	h
opfa:	mov	a,l	;cmp(HL,DE)
	sub	e
	mov	a,h
	sbb	d
	rnc
	mov	m,b
	inx	h
	jmp	opfa

;	(G)  Go to the program for execution. The form <nG,a,b,c>
;	allows the insertion of up to two breakpoints, b and c,
;	before jumping to the address a. If a count n is also
;	included, the breakpoints will be traversed n times
;	before control is t returned to DDT. If the field a is
;	null, the program will continue from the point where
;	control was surrendered to DDT (or 100H if it is an
;	initial call.

optg:	call	crlf	;type CR,LF
	xra	a
	sta	swtv	;T/V = z/nz
	sta	swgt	;G/T = z/nz
	lhld	rept
	dad	h
	shld	rept
	lhld	savpc	;PC at breakpoint
	call	hef	;fetch a
	shld	savpc
	push	h
	cpi	CR
	mvi	a,1
	jz	opga
	call	hexf	;fetch b
	jnc	gnex
	shld	gbrk	;nG's breakpoint
	xchg
	call	hexf	;fetch c
	mvi	a,2
	jnc	opga
	shld	gbrl
	inr	a
	mov	b,h
	mov	c,l
opga:	pop	h
	sta	gbrn
	ora	a
	jmp	gprg	;G without arguments

;	G without arguments
;		z    unconditional go (savsp)
;		c    ignore HL, but set breakpoints
;		A    number of arguments - 0,1,2,3
;		HL   explicit destination
;		DE   first breakpoint
;		BC   second breakpoint

gnex:	call	step
gprg:	di
	jz	gnez	;no arg, unconditional go
	jc	gney	;comma, set breakpoint & go
	shld	savpc	;PC at breakpoint
gney:	dcr	a
	sta	bkpt
	jz	gnez	;one arg already noted
	xchg
	mov	e,a
	mov	a,m
	sta	brkx
	mvi	m,0FFH	;RST 7
	shld	brkp
	dcr	e
	jz	gnez	;unless 2nd breakpoint
	mov	l,c
	mov	h,b
	mov	a,m
	sta	brky
	mvi	m,0FFH	;RST 7
	shld	brkq

;	Restore registers and return to program.

gnez:	lxi	sp,savde	;DDT's private stack
	pop	d
	pop	b
	pop	psw
	pop	h
	sphl
	lhld	savpc	;PC at breakpoint
	push	h
	lhld	savhl	;HL at breakpoint
	NOP	
	ret	

;	(H) Display a hexadecimal sum and difference. <Hx,y>
;	will result in typing '+'x+y '-'x-y. Mainly used to
;	help patch CP/M during system generation.

opth:	call	onar
	xchg
	call	onar
	xra	a
	sub	l
	mov	c,a
	sbb	h
	sub	c
	mov	b,a
	call	crlf	;type CR,LF
	dad	d
	mvi	a,'s'	;"sum"
	call	aout
	call	tyhl	;type HL as four nibbles
	call	sngl	;type space
	xchg
	dad	b
	mvi	a,'d'	;"difference"
	call	aout
	jmp	tyhl	;type HL as four nibbles

;	(I) Input a command line, according to the same
;	criteria used by CCP; in other words a parameter
;	list can follow the file name.

opia:	call	fico
opti:	lxi	d,TBUF
	lhld	cptr	;pointer to command buffer
	lda	clen
	mov	b,a
	inr	b
moov:	stax	d
	mov	a,m
	call	lcfo
	inx	d
	inx	h
	dcr	b
	jnz	moov
	mvi	a,00
	stax	d
	lxi	h,TBUF+1
	shld	cptr	;pointer to command buffer
	call	fico
	lxi	h,adsk	;active disk
	push	h
	mov	a,m
	sta	TFCB	;CP/M default FCB
	mvi	a,10H
	call	fica
	pop	h
	mov	a,m
	sta	TFCB+16
	xra	a
	sta	TFCB+32
	jmp	crlf

zsep:	ora	a
	rz
	cpi	CR
	rz
	cpi	' '
	jc	error	;<control chars in command line>
	rz
	cpi	'='
	rz
	cpi	'_'
	rz
	cpi	'.'
	rz
	cpi	':'
	rz
	cpi	';'
	rz
	cpi	'<'
	rz
	cpi	'>'
	ret

fsep:	call	zsep
	rz
	call	rech	;read one character
	jmp	fsep
	ret

;	Advance to a non blank character in the console
;	buffer unless there is none, indicated by a 00.

zonb:	call	rech	;read one character
	ora	a
	rz
	cpi	' '
	jz	zonb	;zero or non-blank
	ret

;	Generate a file control block in the manner of CCP.

fico:	mvi	a,00
fica:	lxi	h,TFCB
	add	l
	mov	l,a
	mov	a,h
	aci	00
	mov	h,a
	xra	a
	sta	adsk	;active disk
	call	zonb	;zero or non-blank
	push	psw
	jz	ficb
	sbi	'@'
	mov	b,a
	push	h
	lhld	cptr	;pointer to command buffer
	mov	a,m
	pop	h
	cpi	':'
	jz	ficc
ficb:	lda	ldsk	;logged disk
	jmp	ficd
ficc:	call	rech	;read one character
	pop	psw
	call	rech	;read one character
	push	psw
	mov	a,b
	sta	adsk	;active disk
ficd:	mov	m,a
	inx	h
	mvi	b,08
	pop	psw
	call	ffil
	call	fsep
	mvi	b,03
	cpi	'.'
	jnz	ficp
	call	rech	;read one character
	call	ffil
	call	fsep
	jmp	ficq
ficp:	call	bfil
ficq:	mvi	b,03
	mvi	c,00
	jmp	kfil

;	Fill a field

ffil:	call	zsep
	jz	bfil
	cpi	'*'
	jz	qfil
	mov	m,a
	inx	h
	dcr	b
	rz
	call	rech	;read one character
	jmp	ffil

;	Block fill

qfil:	mvi	c,'?'
	jmp	kfil
bfil:	mvi	c,' '
kfil:	mov	m,c
	inx	h
	dcr	b
	jnz	kfil
	ret

;	(L) List the memory as 8080 operation codes. The
;	command <nLa,b> will list n lines of code between
;	the hexadecimal addresses a and b, with the interval
;	taking precedence over the number of lines, unless
;	either a or b is missing.

optl:	call	past	;check limit transgression
	jnc	error	;<L may have been overwritten>
	lhld	rept
	mov	a,l
	sta	pinc	;paragraph length
	ora	h
	jnz	opla
	lxi	h,NL	;default length
opla:	inx	h
	shld	rept	;line counter for L
	xra	a
	sta	pctr	;paragraph counter
	lhld	lorg	;origin for L
	call	hef	;read <a>
	shld	lorg	;origin for L
	mov	b,a
	xchg
	lxi	h,begn	;bottom DDT = top memory
	call	hef	;read <b>
	shld	llim	;limit for L
	jc	oplc	;c means <b> not null
	mov	a,b
	cpi	CR
	jz	opld
oplc:	lxi	h,0000H
	shld	rept	;line counter for L
	lda	pinc	;paragraph length
	sta	pctr	;paragraph counter

;	The parameters have been established, start typing.

opld:	call	inst	;read console status
	rnz
	lhld	rept	;line counter for L
	mov	a,l
	ora	h
	jnz	oplf	;nz means counter working
	lda	pctr	;paragraph counter
	ora	a
	jz	oplg	;z means no paragraphing
	dcr	a
	jnz	ople
	call	crlf
	lda	pinc	;paragraph length
ople:	sta	pctr	;paragraph counter
	jmp	oplg
oplf:	dcx	h
	mov	a,l
	ora	h
	rz
	shld	rept	;line counter for L
oplg:	call	dubl
	lhld	lorg	;origin for L
	call	reab
	jnc	nox
	mvi	a,'X'
	call	aout	;A to console
nox:	call	tyhl	;type HL as four nibbles
	call	dubl
	lhld	llim	;upper limit for "L"
	xchg
	lhld	lorg	;origin for L
	mov	a,e	;cmp(DE,HL)
	sub	l
	mov	a,d
	sbb	h
	rc
	call	dism
	shld	lorg	;origin for L
	call	crlf
	jmp	opld

;	(M) Move part of the memory from one place to another.
;	<Mx,y,z> will move the interval x,y to begin at z. The
;	direction of movement compensates for possible overlap.

optm:	call	onar
	mov	c,l
	mov	b,h
	call	onar
	xchg
	call	onar
	mov	a,e	;cmp(DE,BC)
	sub	c
	mov	a,d
	sbb	b
	jc	error	;<interval inverted>
	mov	a,e	;cmp(DE,HL)
	sub	l
	mov	a,d
	sbb	h
	jc	opmb
	mov	a,c	;cmp(BC,HL)
	sub	l
	mov	a,b
	sbb	h
	jnc	opmb
	mov	a,e	;BC=DE-BC
	sub	c
	mov	c,a
	mov	a,d
	sbb	b
	mov	b,a
	dad	b	;HL=HL+(DE-BC)
opma:	mov	a,c
	ora	b
	rz
	ldax	d
	mov	m,a
	dcx	h
	dcx	d
	dcx	b
	jmp	opma
opmb:	mov	a,e	;cmp(DE,BC)
	sub	c
	mov	a,d
	sbb	b
	rc
	ldax	b
	mov	m,a
	inx	b
	inx	h
	jmp	opmb

;	(R) Read into memory the file specified by TFCB.
;	It was probably defined by a preceding I command,
;	but might still be the program defined in the DDT
;	command line. <Rx> will start loading at TORG+x.

optr:	call	hexf	;with zero default
opra:	push	h
	call	openf	;open file
	cpi	0FFH
	jz	error	;<failure to open file>
	call	chex	;check for .HEX
	jz	ihex	;load INTEL HEX file
	pop	h
	lxi	d,TORG	;CP/M transient origin
	dad	d
	shld	savpc	;PC at breakpoint
oprb:	push	h
	lxi	d,TFCB	;CP/M default FCB
	mvi	c,20	;(14) read one record
	call	XDOS	;DDT analogue of 0005
	pop	h
	ora	a
	jnz	efil	;EOF
	lxi	d,TBUF	;CP/M default FCB
	mvi	c,80H	;size of one record
oprc:	ldax	d
	inx	d
	mov	m,a
	inx	h
	dcr	c
	jnz	oprc	;move to memory
	call	rmax	;record upper limit
	jmp	oprb	;read another record

;	Test whether HL beyond previous maximum.

tmax:	xchg
	lhld	pmax	;program high limit
	mov	a,l	;cmp(HL,DE)
	sub	e
	mov	a,h
	sbb	d
	xchg
	ret	

;	Record maximum program length.

rmax:	call	tmax
	rnc	
	shld	pmax	;program high limit
	ret	

;	Test for limit transgression.

past:	push	h
	lxi	h,begn	;lower DDT limit
	call	tmax
	pop	h
	ret	

;	Check for the extension 'HEX'

chex:	lxi	h,TFCB+9	;extension
	mov	a,m
	ani	07FH
	cpi	'H'
	rnz	
	inx	h
	mov	a,m
	ani	07FH
	cpi	'E'
	rnz	
	inx	h
	mov	a,m
	ani	07FH
	cpi	'X'
	ret	

;	Load INTEL HEX file, whose records have the form:
;	:NNAAAA00DDDDDDDDDD....DDXX
;	    :	   start of line
;	    NN     number of bytes in line
;	    AAAA   first address of line
;	    00	   class of line (zero in CP/M)
;	    DD	   byte of data - NNH altogether
;	    XX	   checksum - full bytesum w/XX = 00
;	:00AAAA -  end of file, start address AAAA.

ihex:	call	renb	;next byte from CP/M buffer
	cpi	01AH	;^Z
	jz	error	;<no EOF in legal text>
	sbi	':'	;line begins with colon
	jnz	ihex	;load INTEL HEX file
	mov	d,a	;start checksum w/zero
	pop	h
	push	h
	call	nbyt	;next byte w/checksum
	mov	e,a
	call	nbyt	;next byte w/checksum
	push	psw	
	call	nbyt	;next byte w/checksum
	pop	b
	mov	c,a
	dad	b
	mov	a,e
	ora	a
	jnz	ihxx	;read non-null line
	mov	h,b
	mov	l,c
	shld	savpc	;PC at breakpoint
	pop	h	;displacement not added to AAAA <<---
	jmp	efil	;EOF

ihxx:	call	nbyt	;next byte w/checksum
hlin:	call	nbyt	;next byte w/checksum
	mov	m,a
	inx	h
	dcr	e
	jnz	hlin	;read the full line
	call	nbyt	;next byte w/checksum
	push	psw	
	call	rmax	;record upper limit
	pop	psw	
	jnz	error	;<checksum failed>
	jmp	ihex	;load INTEL HEX file

;	Form next byte, add to checksum

nbyt:	push	b
	push	h
	push	d
	call	renb	;next byte from CP/M buffer
	call	cnh
	jc	error	;<not hex digit>
	add	a	
	add	a	
	add	a	
	add	a	
	push	psw	
	call	renb	;next byte from CP/M buffer
	call	cnh
	jc	error	;<not hex digit>
	pop	b
	ora	b
	mov	b,a
	pop	d
	add	d
	mov	d,a
	mov	a,b
	pop	h
	pop	b
	ret	

;	EOF after reading file

efil:	mvi	c,12	;(0C) lift disk head
	call	XDOS	;DDT analogue of 0005
	lxi	h,rmsg	;header: 'NEXT  PC'
	call	mssg
	call	crlf	;type CR,LF
	lhld	pmax	;program high limit
	call	tyhl	;type HL as four nibbles
	call	sngl	;type space
	lhld	savpc	;PC at breakpoint
	shld	dorg	;origin for D
	shld	lorg	;origin for L
	jmp	tyhl	;type HL as four nibbles

rmsg:	db	CR,LF,'NEXT  PC',00

;	(S) Store hexadecimal bytes. <nSx> will store
;	n bytes starting at address x, read one by one
;	from the console. Missing n means indefinite
;	repetition, missing x means TORG. Confirmation
;	and progression is automatic while hexadecimal
;	bytes are being received; however, for
;		 -  go back one byte,
;		'x  deposit ASCII x,
;		^x  deposit ctl x,
;		CR  go on to next byte.
;	Any other input terminates the cycle.

opts:	lxi	h,TORG
	call	hef	;read hex field
	xchg
opsa:	call	crlf	;type CR,LF
	call	typs	;verify the line
	call	incl	;fetch a command line
	jz	opsc	;null buffer, go next line
	call	hxar	;read one-byte arg
	jz	opsb	;<standard field>
	cpi	'-'	;go back
	rnz		;leave the cycle
	dcx	d
	jmp	opsa
opsb:	stax	d
	call	ctlx
	call	typs	;verify the line
opsc:	inx	d
	call	drnz
	jnz	opsa
	ret

;	Type the format line for S.

typs:	ldax	d
	call	prip	;type printable or .
	call	sngl
	call	word	;type DE as four nibbles
	call	sngl	;type space
	ldax	d
	call	byte	;type A as two nibbles
	jmp	sngl	;type space

;	(T)  Type the register status line while single-stepping
;	through the program. <nT> runs through n steps typing
;	each one, while <nT/> executes without typing. The option
;	V, with the same alternatives <nV> and <nV/> treats a
;	call or a conditional call as a single step, avoiding a
;	detailled examination of the interior contents of each
;	subroutine.


optt:	xra	a
oooa:	sta	swtv	;T/V = z/nz
	mvi	a,0FFH
	sta	swgt	;G/T = z/nz
	call	reuc
	cpi	'/'
	jnz	ooob
	xra	a
ooob:	sta	swtu	;T/U = nz/z
	lhld	rept
	mov	a,l
	ora	h
	jz	oooc
	dcx	h
oooc:	shld	rept	;repetition counter
	call	line	;type display line
	jmp	gnex

;	(V) A variant of T.

optv:	mvi	a,0FFH
	jmp	oooa

;	(X) Examine registers. Any one of the registers or
;	register pairs A, BC, HL, DE, SP, PC may be examined,
;	or one of the five flag bits C, Z, M, E, I, by typing
;	Xr, with r = czmeiabhdsp*, or =xxxx with a hexadecimal
;	address xxxx. The latter defines the register * at
;	first. A display line is typed, of the form
;	r=xxxx  xx ...  xx  ... xx  +++++  + +++++  ooo ooooo
;	where xxxx is the contents of register r, xx etc is
;	a window of hexadecimal bytes centered on xxxx, ++ etc
;	is a similar window of ASCII characters, and finally
;	ooo ooooo is the instruction, if meaningful, at xxxx.
;
;	Once an examination is underway, the window may be
;	moved by various operators:
;		*      indirect from window
;		^      indirect from instruction address
;		excl   save value
;		?      recover value
;		/      next instruction
;		+      1 byte forward
;		-      1 byte backward
;		#      forward, stop at nonzero
;		@      backward, stop at nonzero
;		=xx    search for byte xx ('x or ^x also)
;		|xxxx  search for pair xxxx
;		>      forward half-window
;		<      backward half-window
;		.      type crlf - make new line

optx:	call	relc	;char to A from buffer
	cpi	CR
	jz	ljne	;type display line
	cpi	'='
	jnz	opxa
	call	hexf
	shld	savmr	;save memory reference
	mvi	a,'*'
opxa:	lxi	b,NR	;B=0, C=# registers
	lxi	h,regs	;register list
opxb:	cmp	m
	jz	opxc	;modify given register
	inx	h
	inr	b
	dcr	c
	jnz	opxb	;repeat for all
	jmp	error	;<no such register>

opxc:	push	h
	mov	a,b
	call	gesr	;fetch saved register
	shld	savxx	;?/! cell
	call	reuc	;char to A from buffer
	cpi	CR
	jnz	error	;<null field>
	push	b
opxd:	pop	b
	pop	h
	push	h
	push	b
	call	ctlx	;type ^X
	call	tyfr	;type flag or register
	call	sngl	;type space
	call	incl	;fetch a command line
	call	hexf
	pop	b
	jnc	opxg	;nc means null hex field
	push	b
opxe:	mov	a,b
	cpi	05
	jnc	uacc	;update register
	mov	a,h
	ora	a
	jnz	error	;<only one byte admitted>
	mov	a,l
	cpi	02
	jnc	error	;<only 1 bit (0,1) allowed>
	call	fmaf	;fetch mask & flags
	mov	h,a
	mov	b,c
	mvi	a,0FEH	;-2
	call	shla	;shl(A,B)
	ana	h
	mov	b,c
	mov	h,a
	mov	a,l
	call	shla	;shl(A,B)
	ora	h
	stax	d
	jmp	opxd

;	Window modifiers are possible with a null hex field.

opxg:	push	psw
	mov	a,b
	call	gesr	;fetch saved register
	pop	psw
	cpi	CR
	jnz	opxh
	shld	dorg
	shld	lorg
	pop	h
	ret
opxh:	push	b
	lxi	d,opxe
	push	d
	call	alta
	db	14
	db	'*'	;indirect address from window
	dw	opxv
	db	'^'	;indirect address from instruction
	dw	opxu
	db	'!'	;save address
	dw	opxw
	db	'?'	;restore address
	dw	opxx
	db	'/'	;next instruction
	dw	opxy
	db	'+'	;advance 1 byte
	dw	opxz
	db	'-'	;return 1 byte
	dw	opxt
	db	'#'	;advance to nonzero byte
	dw	opxs
	db	'.'	;type crlf
	dw	crlf
	db	'='	;=x: search for xx, 'x, ^x
	dw	opxr
	db	'|'	;|xxxx: search for pair xxxx
	dw	opxm
	db	'>'	;advance halfwindow
	dw	opxp
	db	'<'	;return halfwindow
	dw	opxo
	db	'@'	;return to nonzero
	dw	opxn

opxu:	inx	h	;^
opxv:	mov	e,m	;*
	inx	h
	mov	d,m
	xchg
	ret

opxw:	shld	savxx	;excl
	ret

opxx:	lhld	savxx	;?
	ret

opxy:	mov	a,m	;/
	inx	h
	inx	h
	inx	h
	call	twob
	rc
	dcx	h
	call	oneb
	rc
opxt:	dcx	h	;- (beware - it's part of opxy)
	ret

opxz:	inx	h	;+
	ret

opxs:	xra	a	;#
oxs:	inx	h
	cmp	m
	jz	oxs
	ret

opxr:	xchg		;=
	lhld	rept
	call	hxr	;hex argument w/default
	shld	rept	;be sure to find it again
	mov	a,l
	xchg
oxr:	inx	h
	cmp	m
	jnz	oxr
	ret

opxp:	lxi	d,WW+1	;>
	dad	d
	ret

opxo:	lxi	d,-WW-1	;<
	dad	d
	ret

opxn:	xra	a	;@
oxn:	dcx	h
	cmp	m
	jz	oxn
	ret

opxm:	xchg		;|
	lhld	rept
	call	hef
	shld	rept	;be sure we'll find the pair
	xchg
	inx	h
oxm:	mov	a,e
	call	oxr
	inx	h
	mov	a,d
	cmp	m
	dcx	h
	jnz	oxm
	dcx	h
	ret

;	shl(A,B)

shla:	dcr	b
	rz	
	rlc	
	jmp	shla	;shl(A,B)

;	Decrement REPT if it is non-zero.

drnz:	push	h
	lhld	rept
	mov	a,h
	ora	l
	sui	1
	sbb	a
	jnz	dnz
	dcx	h
	shld	rept
	mov	a,h
	ora	l
dnz:	pop	h
	ret

;	Update register

uacc:	jnz	ureg
	mov	a,h
	ora	a
	jnz	error	;<only one byte allowed>
	mov	a,l
	sta	sava	;save A
	jmp	opxd

ureg:	push	h
	call	gasr	;get address of saved register
	pop	d
	mov	m,e
	inx	h
	mov	m,d
	jmp	opxd

;	Open file

openf:	push	h
	push	d
	push	b
	xra	a
	sta	TFCB-1
	sta	TFCB+32
	mvi	c,15	;(0F) open file
	lxi	d,TFCB	;CP/M default FCB
	call	XDOS	;DDT analogue of 0005
	pop	b
	pop	d
	pop	h
	ret	

;	Read next byte from CP/M buffer,
;	replenish when exhausted.

renb:	push	h
	push	d
	push	b
	lda	TFCB-1
	ani	07FH
	jz	ror	;read one record
rnb:	mvi	d,00
	mov	e,a
	lxi	h,TBUF	;CP/M default FCB
	dad	d
	mov	a,m
	cpi	01AH	;^Z
	jz	reen	;end of record
	lxi	h,TFCB-1
	inr	m
	ora	a
	jmp	reex	;return

ror:	mvi	c,20	;(14) read one record
	lxi	d,TFCB	;CP/M default FCB
	call	XDOS	;DDT analogue of 0005
	ora	a
	jnz	reen	;end of record
	sta	TFCB-1
	jmp	rnb

reen:	stc		;end of record
reex:	pop	b	;return
	pop	d
	pop	h
	ret	

;	Error

error:	mvi	a,'?'
	call	aout	;A to console
	jmp	loop	;clear out the stack

;	Read console status.

inst:	push	b
	push	d
	push	h
	mvi	c,11	;(0B) console status
	call	XDOS	;DDT analogue of 0005
	ani	01
	pop	h
	pop	d
	pop	b
	ret	

;	Fill command line buffer from console. The z flag
;	on return indicates whether a null line was read.

incl:	push	h
	push	d
	push	b
	mvi	c,10	;(0A) read buffer
	lxi	d,cbuf	;command buffer
	call	XDOS	;DDT analogue of 0005
	lxi	h,ctex	;command text
	shld	cptr	;pointer to command buffer
	lda	clen
	pop	b
	pop	d
	pop	h
	ora	a
	ret	

;	Read a one-byte argument, which may be hexadecimal,
;	'x or ^x. Blatant errors are rejected, but nz at
;	return means null field not terminated by CR, ', or^.

hxar:	lxi	h,0000
hxr:	call	hef
	jnc	har
	mov	a,h
	ora	a
	jnz	error	;<not one byte>
	mov	a,l
	ret
har:	cpi	''''
	jnz	has
	call	rech
	cpi	' '
	jc	error	;<quoted ctrl char>
	jmp	hat
has:	cpi	'^'
	rnz
	call	rech
	sui	'@'
	jc	error	;<number, symbol, &c>
	cpi	' '
	jc	hat
	sui	' '
	cpi	' '
	jnc	error	;<beyond ASCII range>
hat:	mov	l,a
	call	rech
	cpi	CR
	jnz	error	;<not single character>
	mov	a,l
	ret

;	Read a hexadecimal field; error if null.

onar:	call	hexf
	jnc	error	;<insufficient arguments>
	ret

;	Type CR,LF.

crlf:	mvi	a,CR
	call	aout	;A to console
	mvi	a,LF
	jmp	aout	;A to console

;	Type ^X [erase line]

ctlx:	mvi	a,18H	;^X
	jmp	aout	;A to console

;	Type one or two spaces.

dubl:	call	sngl
sngl:	mvi	a,' '

;	A to console

aout:	push	h
	push	d
	push	b
	mov	e,a
	mvi	c,02
	call	XDOS	;DDT analogue of 0005
	pop	b
	pop	d
	pop	h
	ret	

;	Lower case fold excepting rubout

reuc:	call	rech	;read one character
lcfo:	cpi	'a'
	rc
	cpi	'{'
	rnc
	ani	5FH
	ret	

;	Upper case fold

relc:	call	rech	;read one character
ucfo:	cpi	'['
	rnc
	cpi	'A'
	rc
	ori	20H
	ret

;	Fetch a character into A from command line

rech:	push	h
	lxi	h,clen	;command string length
	mov	a,m
	ora	a
	mvi	a,CR	;fake CR from empty buffer
	jz	recx
	dcr	m
	lhld	cptr	;pointer to command buffer
	mov	a,m
	inx	h
	shld	cptr	;pointer to command buffer
recx:	pop	h
	ret	

;	Type A as two nibbles

word:	mov	a,d
	call	byte
	mov	a,e
byte:	push	psw	
	rar	
	rar	
	rar	
	rar	
	call	nybl
	pop	psw
nybl:	ani	0FH
	adi	90H
	daa
	aci	40H
	daa
	jmp	aout	;A to console

;	Type HL as four nibbles

tyhl:	xchg
	call	word
	xchg
	ret

;	Message terminated by zero to console

mssg:	mov	a,m
	ora	a
	rz
	call	aout	;A to console
	inx	h
	jmp	mssg

;	Print printables, put dot for the rest

prip:	cpi	RO
	jnc	priq
	cpi	' '
	jnc	aout	;A to console
priq:	mvi	a,'.'
	jmp	aout	;A to console

;	Type minus or B, according to sign.

morb:	rlc
	push	psw
	mvi	a,'-'
	jnc	morc
	mov	a,b
morc:	call	aout
	pop	psw
	ret

;	Type 5 flags as letter (1) or minus (0).

feql:	lda	savf
	mvi	b,'s'
	call	morb
	mvi	b,'z'
	call	morb
	rlc
	mvi	b,'i'
	call	morb
	rlc
	mvi	b,'p'
	call	morb
	rlc
	mvi	b,'c'
	call	morb
	jmp	sngl

;	Type <R=XX x > to display a register.

reql:	push	psw
	mov	a,b
	call	aout
	mvi	a,'='
	call	aout
	pop	psw
	push	psw
	call	byte
	call	sngl
	pop	psw
	call	prip
	jmp	sngl

;	Type <P=XXXX > to display a register pair.

peql:	mov	a,b
	call	aout
	mvi	a,'='
	call	aout
	call	tyhl
	jmp	sngl

;	Test for separators, which are characters which can
;	be passed over at the beginning of a field, but which
;	terminate it when found at the end. The character to
;	be tested is in the accumulator, where it remains.

sepa:	cpi	' '
	rz	
	cpi	HT
	ret	

;	Test for terminators, which mean that a field must
;	end, even if it is null.

term:	cpi	','
	rz
	cpi	CR
	ret

;	Test whether the character in the accumulator is a
;	decimal digit. If so, it is replaced by its  binary
;	value, otherwise remaining unchanged. The carry
;	flag distinguishes the cases - carry if not decimal.

cnd:	cpi	'0'
	rc
	cpi	':'
	cmc
	rc
	sui	'0'
	ret

;	Read a decimal field, leaving the last four
;	digits read in HL, with leading zeros for fewer
;	digits.  BC, DE remain unchanged. A null field
;	is zero.  Leading separators are passed by, but
;	trailing separators terminate.	A null field is
;	marked by the carry flag, which is 0 for a null
;	field delimited by a terminator, 1 otherwise.
;	A non-zero default value can be given to a null
;	field using <call def> rather than <call decf>.

decf:	lxi	h,0000
def:	call	reuc
	call	sepa
	jz	def
	call	cnd
	cmc
	rnc
	lxi	h,0000
	push	d
dec:	mov	e,l
	mov	d,h
	dad	h
	dad	h
	dad	d
	dad	h
	mov	e,a
	mvi	d,0
	dad	d
	call	reuc
	call	cnd
	jnc	dec
	pop	d
	ret

;	Test whether the character in the accumulator is a
;	hexadecimal digit. If so, it is replaced by its 
;	binary value, otherwise remaining unchanged. The
;	carry flag distinguishes the cases - carry if not
;	hexadecimal.

cnh:	cpi	'0'
	rc
	cpi	':'
	jc	cni
	cpi	'A'
	rc
	cpi	'G'
	jnc	cnj
	sui	07
cni:	sui	'0'
	stc
cnj:	cmc
	ret

;	Read a hexadecimal field, leaving the last four
;	digits read in HL, with leading zeros for fewer
;	digits.  BC, DE remain unchanged. A null field
;	is zero.  Leading separators are passed by, but
;	trailing separators terminate.	A null field is
;	marked by the carry flag, which is 0 for a null
;	field delimited by a terminator, 1 otherwise.
;	A non-zero default value can be given to a null
;	field using <call hef> rather than <call hexf>.

hexf:	lxi	h,0000
hef:	call	reuc
	call	sepa
	jz	hef
	call	cnh
	cmc
	rnc
	lxi	h,0000
hex:	dad	h
	dad	h
	dad	h
	dad	h
	ora	l
	mov	l,a
	call	reuc
	call	cnh
	jnc	hex
	ret

;	Fetch mask and saved flags

fmaf:	push	h
	lxi	h,fmsk	;flag masks
	mov	e,b
	mvi	d,00
	dad	d
	mov	c,m
	lxi	h,savf	;save AF
	mov	a,m
	xchg
	pop	h
	ret	

;	Get value of saved flag

fval:	call	fmaf	;fetch mask & flags
val:	dcr	c
	jz	vam	;ani a,01
	rar	
	jmp	val
vam:	ani	01
	ret	

;	Get address of saved register

gasr:	sui	06
	lxi	h,rdsp	;list of displacements
	mov	e,a
	mvi	d,00
	dad	d
	dad	d
	mov	e,m
	inx	h
	mov	d,m
	lxi	h,savmr	;save memory reference
	dad	d
	ret	

;	Fetch saved register

gesr:	call	gasr	;get address of saved register
	mov	e,m
	inx	h
	mov	d,m
	xchg
	ret	

;	Type flag or register

tyfr:	mov	a,b
	cpi	05
	jnc	tyra
	mov	a,m
	call	aout	;A to console
	call	fval	;get saved flag
	jmp	nybl	;type A as DEC or HEX

tyra:	mov	b,m
	jnz	tyre	;type saved register
	lda	sava	;save A
	jmp	reql

;	Type register and the memory pointed to in the format:
;		r=value, window, ASCII window, dism

tyre:	call	gesr	;get saved register
	call	peql
	call	sngl
	push	h
	lxi	d,-WW	;go back window halfwidth
	dad	d
	push	h
	call	tyrg
	call	sngl
	pop	h
	call	tyrj
	call	dubl
	pop	h
	jmp	dism

;	Type 2*WW+1 bytes centered on pointer, as nibble pairs.

tyrg:	call	tyrh
	call	sngl
	mov	a,m
	call	byte
	call	dubl
	inx	h
tyrh:	mvi	c,WW
tyri:	mov	a,m
	call	byte
	call	sngl
	inx	h
	dcr	c
	jnz	tyri
	ret

;	Then type the same window using ASCII characters or points.

tyrj:	call	tyrk
	call	sngl
	mov	a,m
	call	prip	;type printable or .
	inx	h
	call	sngl
tyrk:	mvi	c,WW
ascl:	mov	a,m
	call	prip	;type printable or .
	inx	h
	dcr	c
	jnz	ascl
	ret

;	Type display line.

line:	call	ljne
	jmp	crlf
ljne:	mvi	b,'b'
	lhld	savbc
	call	peql
	mvi	b,'d'
	lhld	savde
	call	peql
	mvi	b,'h'
	lhld	savhl
	push	h
	call	peql
	pop	h
	mvi	b,'m'
	mov	a,m
	call	reql
	mvi	b,'a'
	lda	sava
	call	reql
	call	feql
	mvi	b,'s'
	lhld	savsp
	call	peql
	mvi	b,'p'
	lhld	savpc
	call	peql
	call	sngl
	jmp	dism

regs:	db	'czmeiabdhsp*'

rdsp:	dw	-10,-12,-4,-6,-2,0

fmsk:	db	1,7,8,3,5

;	Jump guided by a table of alternatves. The table
;	should have the form:
;		call	alta
;		db	n
;		db	'x'
;		dw	xxxx
;	The last two lines are to be repeated n times, for
;	each of which xxxx is the jump address corresponding
;	to the alternative x. The table is used by jumping
;	to its heading with the alternative in A. Registers
;	C, D, and E are lost in the process.

alta:	xthl
	mov	c,m
alt:	inx	h
	cmp	m
	inx	h
	jnz	alu
	mov	e,m
	inx	h
	mov	d,m
	xchg
	xthl
	ret
alu:	dcr	c
	inx	h
	jnz	alt
	jmp	error	;<alternative not present>

;	Indexed jump through a table.

juta:	pop	h
	mov	e,a
	mvi	d,00
	dad	d
	dad	d
	mov	e,m
	inx	h
	mov	d,m
	xchg
	pchl

;	Return from breakpoint

rtbk:	di
	shld	savhl;	HL at breakpoint
	pop	h
	dcx	h
	shld	savpc	;PC at breakpoint
	push	psw	
	lxi	h,0002
	dad	sp
	pop	psw	
	lxi	sp,savhl	;HL at breakpoint
	push	h
	push	psw	
	push	b
	push	d
	lhld	savpc	;PC at breakpoint
	mov	a,m
	cpi	0FFH	;RST 7
	push	psw	
	push	h
	lxi	h,bkpt	;breakpoint data
	mov	a,m
	mvi	m,00
	ora	a
	jz	rtbb
	dcr	a
	jz	rtba
	lda	brky
	lhld	brkq
	mov	m,a
rtba:	lda	brkx
	lhld	brkp
	mov	m,a
rtbb:	pop	h
	pop	psw	
	jz	rtbc	;if RST 7
	inx	h
	shld	savpc	;PC at breakpoint
	xchg
	lxi	h,GDOS+1	;BDOS address
	mov	c,m
	inx	h
	mov	b,m
	mov	a,e	;cmp(DE,BC)
	sub	c
	mov	a,d
	sbb	b
	jc	rtbc	;if RST 7
	lxi	h,0000
	shld	rept
	lhld	sica	;site of call to BDOS
	xchg
	mvi	a,02H
	ora	a
	stc	
	jmp	gprg	;G without arguments


;	If RST 7 brought us to the breakpoint.

rtbc:	NOP
	lhld	rept	;repetition counter
	mov	a,h
	ora	l
	jz	rtbd	;we won't continue
	dcx	h
	shld	rept	;repetition counter
	lda	swgt	;G/T = z/nz
	ora	a
	jz	rtbf
	call	inst	;read console status
	jnz	rtbd	;we won't continue
	lda	swtu	;T/U = nz/z
	ora	a
	cnz	line	;type display line
	jmp	gnex

;	Return to DDT rather than program.

rtbd:	mvi	a,'*'
	call	aout	;A to console
	lhld	savpc	;PC at breakpoint
	shld	dorg	;origin for D
	call	past	;check limit transgression
	jnc	rtbe	;can't count on using L
	shld	lorg	;origin for L
rtbe:	call	tyhl	;type HL as four nibbles
	jmp	loop	;DDT loop - cannot be <ret>

rtbf:	mov	a,l
	ani	01H
	jnz	gnex
	lhld	gbrl
	mov	c,l
	mov	b,h
	lhld	gbrk
	xchg
	lda	gbrn
	ora	a
	stc
	jmp	gprg	;G without arguments

;	Surround instruction by breakpoints for single-step.

type:	lxi	d,000DH
	lxi	h,mtbl	;table of type codes
tyqe:	mov	a,m
	ana	b
	inx	h
	cmp	m
	inx	h
	jz	tyse
	inr	d
	dcr	e
	jnz	tyqe
tyse:	mov	a,d
	ret	

step:	lhld	savpc	;PC at breakpoint
	mov	b,m
	inx	h
	push	h
	call	type
	call	juta
	dw	xjmp	;jump
	dw	xcju	;conditional jump
	dw	ding	;call
	dw	dong	;conditional call
	dw	xret	;return
	dw	xrst	;restart
	dw	xpch	;pchl
	dw	xmvi	;immediate move
	dw	xmvi	;immediate arithmetic
	dw	xlxi	;lxi
	dw	xlxi	;lhld
	dw	xcrt	;conditional return
	dw	xmvi	;in, out
	dw	xoth	;others

ding:	lda	swtv	;T/V = z/nz
	inr	a
	jz	xlxi	;lxi, lhld
	jmp	xjmp	;jump, call

dong:	lda	swtv	;T/V = z/nz
	inr	a
	jz	xlxi	;lxi, lhld
	jmp	xcju	;cndl jmp, cndl call

;	Jump or call

xjmp:	call	idos
	jnz	xtwo

;	Return

xret:	call	xrtn
	jmp	xtwo

;	qdos - check whether DE = BDOS
;	idos - check whether (DE) = BDOS

idos:	pop	b
	pop	h
	mov	e,m
	inx	h
	mov	d,m
	inx	h
	push	h
	push	b
qdos:	lda	GDOS+1	;BDOS address
	cmp	e
	rnz	
	lda	GDOS+2	;BDOS address
	cmp	d
	ret	

xrtn:	lhld	savsp	;SP at breakpoint
	mov	e,m
	inx	h
	mov	d,m
	ret	

;	Conditional jump or call

xcju:	call	idos
	jz	zdos
	pop	b
	push	b
	mvi	a,02
	jmp	xone

zdos:	pop	d
	push	d
	jmp	xtwo

;	Restart

xrst:	mov	a,b
	cpi	0FFH
	jnz	xsvn
	xra	a
	jmp	xzer

xsvn:	ani	38H
	mov	e,a
	mvi	d,00
	jmp	xtwo

;	PCHL

xpch:	lhld	savhl	;HL at breakpoint
	xchg
	call	qdos	;does DE = BDOS?
	jnz	xtwo
	jmp	xret

jtwo:	jmp	xtwo

;	Other.

xoth:	pop	d
	push	d
	jmp	xtwo

;	Conditional return.

xcrt:	call	xrtn
	pop	b
	push	b
	mvi	a,02
	jmp	xone

;	LXI, LHLD

xlxi:	pop	d
	inx	d
	push	d

;	Immediate move or arithmetic, in, out.

xmvi:	pop	d
	inx	d
	push	d
xtwo:	mvi	a,01
xone:	inr	a
	stc	
xzer:	pop	h
	ret	

mtbl:	db	0FFH,0C3H,0C7H,0C2H	;jump, conditional jump
	db	0FFH,0CDH,0C7H,0C4H	;call, conditional call
	db	0FFH,0C9H,0C7H,0C7H	;return, restart
	db	0FFH,0E9H,0C7H,006H	;pchl, immediate moves
	db	0C7H,0C6H,0CFH,001H	;immediate arithmetc, lxi
	db	0E7H,022H,0C7H,0C0H	;lhlf, conditional return
	db	0F7H,0D3H		;in, out

;	---------------------------------------------------------

logo:	db	'       DDT(8080)/ICUAP',CR,LF
	db	'Universidad Autonoma de Puebla',CR,LF
	db	'      November 20, 1983',00
	dw	00,00,00,00,00,00,00;can't overwrite logo yet
savde:	dw	0000	;save DE, tail of DDT stack	1
savbc:	dw	0000	;save BC			2
savf:	db	00	;save F				3
sava:	db	00	;save A				4
savsp:	dw	0000	;SP at breakpoint		5
savhl:	dw	0000	;HL at breakpoint		6
savpc:	dw	0000	;PC at breakpoint		7
savmr:	dw	0000	;save memory reference		8
savxx:	dw	0000	;storage for optx		9
sica:	dw	0000	;site of call to BDOS
swtv:	db	00	;T/V = z/nz
swtu:	db	00	;T/U = nz/z
swgt:	db	00	;G/T = z/nz
rept:	dw	0000	;counter for commands
gbrk:	dw	0000	;nG's breakpoint
gbrl:	dw	0000	;nG's second breakpoint
gbrn:	db	00	;nG's # of breakpoints
bkpt:	db	00	;number of breakpoints
brkp:	dw	0000	;first breakpoint
brkx:	db	00	;first opcode
brkq:	dw	0000	;second breakpoint
brky:	db	00	;second opcode
pinc:	db	00	;paragraph length
pctr:	db	00	;paragraph counter
dorg:	dw	0000	;origin for D
lorg:	dw	0000	;origin for L
llim:	dw	0000	;upper limit for "L"
pmax:	dw	0000	;program high limit
ldsk:	db	00	;logged disk
adsk:	db	00	;active disk
cptr:	dw	0000	;pointer to command buffer
cbuf:	db	80H	;command buffer
clen:	db	00	;command string length
ctex:	ds	80H	;command text
enddt:	ds	0

;	.dephase

	end
