Page 55,132
	Title DDM

MaxBufLen	EQU	80	;input buffer
BPLen		EQU	8	;number of breakpoints
cr		EQU	0Dh	;carriage return
lf		EQU	0Ah	;line feed
IOSpace		EQU	0	;equates for target space
MemSpace	EQU	2
RegSpace	EQU	4

ReadMode	EQU	0	;mode of cell access
NoReadMode	EQU	1

MemSize		EQU	2	;offset of memory size in PSP
TermCS		EQU	0Ch	;offset of terminate address in PSP
TermIP		EQU	0Ah
TermIntNo	EQU	22h	;terminate interrupt number
CBrkCS		EQU	10h	;offset of the ctrl-Break address in PSP
CBrkIP		EQU	0Eh
CBrkIntNo	EQU	23h	;ctrl-break interrupt number

DefaultDTA	EQU	80h  ;the EXE file header falls here
LStkSeg		EQU	8Eh
LStkPtr		EQU	90h
LCSReg		EQU	96h
LIPReg		EQU	94h
FileSize	EQU	84h	;load module file size offset in PSP
HeaderSize	EQU	88h	;load module header size offset in PSP
RelocItem	EQU	98h	;offset of first relocation item
ItemCount	EQU	86h	;number of relocation items

myFCB		EQU	5Ch	;EXE file FCB falls here in the PSP
CurrentBlock 	EQU	0Ch	;offset of current block in FCB
CurrentRecord	EQU	20h	;offset of relative record no. in FCB
RelRec		EQU	21h	;offset of relative record no. for random access


Stack	Segment Stack
		DW 256 Dup (?)
Stack	ENDS

Data	Segment 'Data'

TargSpace	DW	(?)
TargSeg		DW	(?)
TargOffset	DW	(?)

BPTable	DW	2*BPLen DUP (?)	;breakpoint entries contain a
;segment in the first word, the opcode being replaced in the
;first byte of the second word, 3 bits of 0's, a bit indicating
;that the table entry is in use, and a four-bit offset from the
;segment given by the first word.
BPTableEnd	LABEL WORD

Mode		DW	(?)	;printing mode
LoadFlag	DW	(?)	;indicates debugee loaded
DStkp		DW	(?)	;saves stkp when debugee is running

RegSave		LABEL	WORD
RegAX		DW	0
RegBX		DW	0
RegCX		DW	0
RegDX		DW	0
RegSP		DW	0
RegBP		DW	0
RegSI		DW	0
RegDI		DW	0
RegCS		DW	0
RegDS		DW	0
RegSS		DW	0
RegES		DW	0
RegIP		DW	0
RegFR		DW	0
RegXS		DW	0
RegYS		DW	0

Buf	DB	MaxBufLen+1 Dup (?)
BufLen	DW	(?)

LoadSeg	DW	(?)	;segment into which to load debugee
PSPSeg	DW	(?)
RelocSeg	DW	(?) ;during loading, relocation is done
;relative to this segment
Broken	DW	(?)	;nonzero means breakpoints are set in the debugee

Data	ENDS

CSeg	Segment 'Code'
	Assume CS: CSeg, DS: Data

;*********************************************************************
DDMain	PROC Far
	PUSH	DS	;save PSP for return to DOS
	SUB	AX, AX
	PUSH	AX
	MOV	AX, Data
	MOV	DS, AX
	MOV	PSPSeg, ES
	MOV	CL, 4	;the segment after the stack holds the debugee
	MOV	AX, SP
	SHR	AX, CL
	INC	AX
	MOV	BX, SS
	ADD	AX, BX
	MOV	LoadSeg, AX
	MOV	RegXS, AX
	MOV	RegYS, ES	;save PSP offset
	MOV	TargSpace, MemSpace
	MOV	TargSeg, 0
	MOV	TargOffset, 0
	MOV	Mode, ReadMode
	MOV	LoadFlag, 0
	CALL	InitBPTable
	MOV	BufLen, 0	;clear input buffer
	MOV	Broken, 0
;Set COM1 to 2400baud, no parity, one stop bit, 8 data bits
	MOV	AX, 0A3h
	MOV	DX, 0	;com card 0
	INT	14h

;commands return here
Main00:	CALL	Prompt	;Prompt
Main01:	CALL	GetLine
Main02:	MOV	AH, 0     ;command character is in AL
	MOV	BX, AX
	SHL	BX, 1	;dispatch on command character
	JMP	CS:ComTab[BX]

ComTab	LABEL	WORD
;dispatch table for command characters
	DW	QPr, QPr, CtrlB, I23, QPr, QPr, QPr, Go
	DW	QPr, QPr, QPr, KillBP, LoadEXE, Main00, NextLoc, CurLocR
	DW	PrevLoc, Quit, RegPrint, SStep, TermMode, QPr, QPr, CurLocN
	DW	QPr, QPr, Prgm, QPr, QPr, QPr, QPr, QPr

TermMode:	MOV	AH, 1	;kbd char ready?
	INT	16h
	JE	TM01
	MOV	AH, 3	;RS232 transmitter ready?
	MOV	DX, 0
	INT	14h
	TEST	AH, 20h	;bit 5 is xmt holding register empty
	JE	TM01
	MOV	AH, 0	;read keyboard
	INT	16h
	CMP	AL, 14h	;control-T?
	JNE	TM00
	JMP	Main00	;exit terminal mode
TM00:	MOV	AH, 1	;send char to RS232
	INT	14h
TM01:	MOV	AH, 3	;RS232 char available?
	MOV	DX, 0
	INT	14h
	TEST	AH, 1	;receiver ready?
	JE	TermMode
	MOV	AH, 2	;get char from com line
	INT	14h
	AND	AL, 7Fh	;mask character to 7 bits
	MOV	AH, 14	;send character to screen
	MOV	BX, 0
	INT	10h
	JMP	TermMode

Prgm:	CMP	LoadFlag, 0
	JNE	Prg00
	JMP	QPr	;can't do it if debugee not loaded
Prg00:	CALL	SendCS
	JMP	Main00

KillBP:	CMP	BufLen, 0
	JE	ZapBP
	CALL	Parse
	JC	KBp01
	JMP	QPr	;bad parse
KBp01:	MOV	CX, TargSeg
	MOV	DX, TargOffset
	MOV	AX, 10h
	MOV	SI, 0FFFFh
	MOV	DI, 1Fh
	MOV	BP, OFFSET KBp00
	CALL	ScanBP
	JMP	QPr	;zap location not found
KBp00:	POP	AX	;pop 2 return links
	POP	AX
	MOV	BPTable+2 [BX], 0
	JMP	Main00
ZapBP:	CALL	InitBPTable
	JMP	Main00

CtrlB:	CMP BufLen, 0	;set bp if preceded by seg:offset, else print all
	JNE CtB00
	CALL	PrintBreaks
	JMP	Main00
CtB00:	CALL	Parse
	JC	CtB01
	JMP	QPr	;bad parse
CtB01:	CMP	TargSpace, MemSpace
	JE	CtB02
	JMP	QPr
CtB02:	MOV	AX, 0
	CALL	SetBp
	JC	CtB03
	JMP	QPr
CtB03:	JMP	Main00

RegPrint:	CALL PrintRegs
	JMP	Main00

I23:	INT	23h

SStep:	CMP	LoadFlag, 1	;1 means program has run a bit already
	JG	SSt00
	JMP	QPr
SSt00:	MOV	AX, OFFSET StepStep
	JMP	Go04

Go:	CMP	LoadFlag, 0
	JNE	Go00
	JMP	QPr	;can't go unless debuggee loaded
Go00:	INC	LoadFlag
	MOV	DS, LoadSeg
	MOV	DX, 80h
	MOV	AH, 1Ah
	INT	21h	;set DTA to load seg:80h
;Set up the terminate (22h) and CtrlBrk (23h) interrupts
;from the debuggee PSP
Go01:	MOV	AX, WORD PTR DS: TermIP
	MOV	CX, WORD PTR DS: TermCS
	MOV	BX, TermIntNo
	CALL	SetInt
	MOV	AX, WORD PTR DS: CBrkIP
	MOV	CX, WORD PTR DS: CBrkCS
	MOV	BX, CBrkIntNo
	CALL	SetInt

	MOV	AX, Data
	MOV	DS, AX
	MOV	CX, RegCS	;check for break at go location
	MOV	DX, RegIP
	MOV	AX, 10h
	MOV	BP, OFFSET Go02
	MOV	SI, 0FFFFh
	MOV	DI, 1Fh
	CALL	ScanBP
	CALL	BPExchange ;no break at go location. Set breaks
	AND	RegFR, 0FEFFh	;clear TF
	MOV	AX, OFFSET BrkStop
	MOV	CX, CS
	MOV	BX, 3	;breakpoint interrupt is type 3
	CALL	SetInt
;set SS vector so that it clears TF and restarts
	MOV	AX, OFFSET BrkStep
	MOV	CX, CS
	MOV	BX, 1
	CALL	SetInt
	MOV	Broken, 1	;breaks are set
	JMP	Go03

Go02:	POP	AX  ;pop 2 return links
	POP	AX
	MOV	AX, OFFSet BrkStep
Go04:	OR	RegFR, 100h	;a breakpoint is set at go location. Set TF
	MOV	CX, CS
	MOV	BX, 1	;set Single Step interrupt vector
	CALL	SetInt
	MOV	Broken, 0 ;breaks are not set in the debugee
	JMP	Go03

;Come here on a single step stop
StepStep:	CALL	SaveRegs
	CALL	BPSwap
	CALL	PrintRegs
	MOV	AL, "S"
	JMP	Term00

;Come here on a breakpoint stop
BrkStop:	CALL	SaveRegs
	CALL	BPSwap
	DEC	RegIP	;back up IP to point to the break instruction
	CALL	PrintRegs
	MOV	AL, "B"
	JMP	Term00

;Get here on a step over a breakpointed instruction
BrkStep:	CALL	SaveRegs
	CALL	BPSwap
	AND	RegFR, 0FEFFh	;clear TF
	MOV	DS, LoadSeg
	JMP	Go01

;Load up the machine registers and give control to the debugee
Go03:	MOV	DStkp, SP	;save stkp while debugee runs
	MOV	SS, RegSS
	MOV	SP, RegSP
	MOV	AX, RegFR
	PUSH	AX
	MOV	AX, RegCS
	PUSH	AX
	MOV	AX, RegIP
	PUSH	AX
	MOV	AX, RegAX
	MOV	BX, RegBX
	MOV	CX, RegCX
	MOV	DX, RegDX
	MOV	BP, RegBP
	MOV	SI, RegSI
	MOV	DI, RegDI
	MOV	ES, RegES
	MOV	DS, RegDS
	IRET

LoadEXE:	CMP	BufLen, 0	;special relocation?
	JE	LE10
	MOV	BP, 0
	MOV	SI, BufLen
	CALL	NumCheck
	JC	LE11
	JMP	QPr	;funny non-number for relocation segment
LE10:	MOV	AX, LoadSeg	;normal relocation
	ADD	AX, 10h	;debugee PSP is 100h long
LE11:	MOV	RelocSeg, AX
LE12:	MOV	DX, LoadSeg
	MOV	AH, 26h	;create new program segment
	INT	21h	;DOS call
	MOV	BP, DS	;lots of segment switching soon
	MOV	ES, BP
	MOV	DS, PSPSeg
	MOV	DX, DefaultDTA
	MOV	AH, 1Ah	;set DTA
	INT	21h

	MOV	DX, myFCB	;open file (use debugger PSP)
	MOV	AH, 0Fh
	INT	21h
	CMP	AL, 0
	JE	LE00
	MOV	DS, BP
	JMP	QPr	;could not open file
LE00:	MOV	WORD PTR DS: (myFCB+CurrentBlock), 0
	MOV	BYTE PTR DS: (myFCB + CurrentRecord), 0
	MOV	AH, 14h	;sequential read
	INT	21h
;print the 14 header values
	CALL	CRLF
	MOV	BX, 0
	MOV	CX, 14
	PUSH	BP	;save segment
phloop:	MOV	AX, WORD PTR DS: DefaultDTA[BX]
	ADD	BX, 2
	CALL	PutNum
	MOV	AL, " "
	CALL	PutChar
	DEC	CX
	JG	phloop
	CMP	WORD PTR DS: DefaultDTA, 5A4Dh
	JE	LE01
	POP	BP
	JMP	QPr
LE01:	POP	BP
	MOV	DS, ES: LoadSeg
	MOV	DX, 100h	;set load segment for transfer
	MOV	AH, 1Ah
	INT	21h
	MOV	DS, ES: PSPSeg	;get starting record

 	MOV	AX, WORD PTR DS: MemSize	;copy the memory size
;information from PSP to PSP, since DOS doesn't
	MOV	DS, ES: LoadSeg
	MOV	WORD PTR DS: MemSize, AX
;set the Terminate and CtrlBrk addresses into the debugee PSP
	MOV	AX, OFFSET Term
	MOV	WORD PTR DS: TermIP, AX
	MOV	WORD PTR DS: TermCS, CS
	MOV	AX, OFFSET CBrk
	MOV	WORD PTR DS: CBrkIP, AX
	MOV	WORD PTR DS: CBrkCS, CS

	MOV	DS, ES: PSPSeg
	MOV	CL, 3
;header size is in paragraphs.  divide by 8 to get records.
	MOV	AX, WORD PTR DS: HeaderSize
	SHR	AX, CL
	MOV	WORD PTR DS: (myFCB+RelRec), AX
	MOV	WORD PTR DS: (myFCB+RelRec+2), 0
	MOV	BX, WORD PTR DS: FileSize
	MOV	CL, 2
	SHL	BX, CL	;number of records in file
	MOV	CX, BX
	SUB	CX, AX	;number of records to read
	MOV	DX, myFCB
	MOV	AH, 27h	;random block read
	INT	21h	;DOS call
	MOV	ES: RegAX, AX	;AL has completion code
	MOV	ES: RegCX, CX	;CX has number of records read
;set DTA back to PSP and process relocation info.
	MOV	DS, ES:PSPSeg
	MOV	DX, DefaultDTA
	MOV	AH, 1Ah ;set DTA
	INT	21h

	MOV	DI, ES: LoadSeg
	ADD	DI, 10h	;DI contains the start segment
;get SS from the header
	MOV	AX, WORD PTR DS: LStkSeg
	ADD	AX, DI
	MOV	ES: RegSS, AX
;get SP
	MOV	AX, WORD PTR DS: LStkPtr
	MOV	ES: RegSP, AX
;get CS
	MOV	AX, WORD PTR DS: LCSReg
	ADD	AX, DI
	MOV	ES: RegCS, AX
;get IP
	MOV	AX, WORD PTR DS: LIPReg
	MOV	ES: RegIP, AX
;set the FCB block number to 0 and the relative record no. to 1
;in case more disk accesses are required
	MOV	WORD PTR DS: (myFCB+CurrentBlock), 0
	MOV	BYTE PTR DS: (myFCB+CurrentRecord), 1
	MOV	DX, myFCB

	MOV	BX, WORD PTR DS: RelocItem ;offset of the first item
	MOV	CX, WORD PTR DS: ItemCount
	MOV	AX, ES:RelocSeg	;put this on the stack
	PUSH	AX

RelocLoop:	CMP	CX, 0	;more items?
	JE	RelocDone
	MOV	SI, WORD PTR DS: DefaultDTA[BX] ;offset
	CALL	ChkDskBuf
	MOV	AX, WORD PTR DS: DefaultDTA[BX]	;segment
	CALL	ChkDskBuf
	ADD	AX, DI	;segment + start segment
	MOV	ES, AX
	POP	AX	;get RelocSeg
	PUSH	AX
	ADD	AX, WORD PTR ES: [SI]	;item to be relocated
	MOV	WORD PTR ES: [SI], AX	;put it back
	DEC	CX
	JMP RelocLoop

RelocDone:	MOV	DS, BP
	POP	AX	;discard RelocSeg
	MOV	AX, LoadSeg	;segment of debugee PSP
	MOV	RegDS, AX
	MOV	RegES, AX
	MOV	RegFR, 0	;interrupts OFF
	MOV	LoadFlag, 1	;indicate that debugee is loaded
	JMP	Main00

Quit:	RET	  ;return to DOS

PrevLoc:	MOV	DX, -2	;offset delta to access previous location
	JMP	NL01
NextLoc:	MOV	DX, 2
NL01:	CMP	BufLen, 0	;nonzero length is an error here
	JE	CLR02
	JMP	QPr	;error prompt

CurLocN:	MOV	Mode, NoReadMode
	JMP	CLR01
CurLocR:	MOV	Mode, ReadMode
CLR01:	CMP	BufLen, 0
	JE	CLR03
	Call	Parse
	JC	CLR04
	JMP	QPr	;bad parse

CLR02:	ADD	TargOffset, DX
	CMP	TargSpace, RegSpace
	JNE	CLR03
	AND	TargOffset, 1Fh ;mask offset in register mode
CLR03:	MOV	BX, TargSpace	;print the current location
	JMP	CS:PrintTab[BX]

PrintTab	LABEL	WORD
	DW	PrintIO,PrintMem,PrintReg

PrintIO:	MOV	AL, "I"
	CALL	PutChar
	JMP	PM01
PrintMem:	MOV	AX, TargSeg
	CALL	PutNum
	MOV	AL, ":"
	CALL	PutChar
PM01:	MOV	AX, TargOffset
	CALL	PutNum
	JMP	CLR04
PrintReg:	MOV	BX, TargOffset
	CALL	PrintRegName
CLR04:	CMP	Mode, ReadMode
	JE	CLR05
	MOV	AL, "\"
	CALL	PutChar
	JMP	CLR10
CLR05:	MOV	AL, "/"
	CALL	PutChar
	MOV	BX, TargSpace	;now get and print contents
	JMP	CS:ReadTab[BX]

ReadTab	LABEL	WORD
	DW	ReadIO,ReadMem,ReadReg

ReadIO:	MOV	DX, TargOffset
	IN	AX, DX
	JMP	CLR06
ReadMem:	MOV	ES, TargSeg
	MOV	BX, TargOffset
	MOV	AX, ES:[BX]
	JMP	CLR06
ReadReg:	MOV	BX, TargOffset
	MOV	AX, RegSave[BX]
CLR06:	CALL	PutNum
CLR10:	MOV	AL, " "
	CALL	PutChar
	CALL	GetLine
	PUSH	AX	;save termination character
	CMP	BufLen, 0
	JE	CLR07
	MOV	BP, 0
	MOV	SI, BufLen
	CALL	NumCheck
	JC	CLR08
	POP	AX
	JMP	QPr	;bad number?
CLR08:	MOV	BX, TargSpace
	JMP	CS:WriteTab[BX]

WriteTab	LABEL	WORD
	DW	WriteIO, WriteMem, WriteReg

WriteIO:	MOV	DX, TargOffset
	OUT	DX, AX
	JMP	CLR07

WriteMem:	MOV	ES,TargSeg
	MOV	BX, TargOffset
	MOV	ES:[BX], AX
	JMP	CLR07
WriteReg:	MOV	BX, TargOffset
	MOV	RegSave[BX], AX
CLR07:	POP	DX
	CMP	DL, cr
	JE	CLR09
	CALL	Prompt
CLR09:	MOV	AX, DX
	MOV	BufLen, 0
	JMP	Main02

QPr:	MOV	AL, " "
	CALL	PutChar
	MOV	AL, "?"
	CALL	PutChar
	CALL	Prompt
	JMP	Main01

;Come here on a CtrlBreak interrupt
CBrk:	CALL	SaveRegs
	CALL	BPSwap
	MOV	AL, "C"
	JMP	Term00
;Come here when the debugee terminates
Term:	CALL	SaveRegs
	CALL	BPSwap
	MOV	AL, "T"
Term00:	CALL	CRLF
	CALL	PutChar
	MOV	AL, "*"
	CALL	PutChar
	JMP	Main01

DDMain	ENDP

;*********************************************************************
BPSwap	PROC	Near	;check for breaks set, clear them if so
	CMP	Broken, 0
	JE	BPS00
	CALL	BPExchange
BPS00:	RET
BPSwap	ENDP

;*********************************************************************
PrintRegName	PROC	Near
	MOV	AL, CS:RegTabB+1[BX]
	CALL	PutChar
	MOV	AL, CS:RegTabB[BX]
	CALL	PutChar
	RET
PrintRegName	ENDP

;*********************************************************************
SaveRegs	PROC	Near
;called when debuggee returns via interrupt.  Save debugee's registers.
;We are operating with the debuggee's stack.
	PUSH	DS
	PUSH	AX
	MOV	AX, Data
	MOV	DS, AX
	MOV	RegBX, BX
	MOV	RegCX, CX
	MOV	RegDX, DX
	MOV	RegBP, BP
	MOV	RegSI, SI
	MOV	RegDI, DI
	MOV	RegES, ES
	POP	AX
	MOV	RegAX, AX
	POP	AX
	MOV	RegDS, AX
	POP	BX	;SaveRegs' return link
	POP	AX	;debugee IP, CS, Flags
	MOV	RegIP, AX
	POP	AX
	MOV	RegCS, AX
	POP	AX
	MOV	RegFR, AX
	MOV	RegSS, SS	;debugee's stack seg
	MOV	RegSP, SP	;debugee's sp
	MOV	AX, Stack	;switch to our stack
	MOV	SS, AX
	MOV	SP, DStkp
	PUSH	BX
;restore the ctrl-break interrupt vector
	MOV	ES, PSPSeg
	MOV	AX, ES: CBrkIP
	MOV	CX, ES: CBrkCS
	MOV	BX, CBrkIntNo
	CALL	SetInt
	RET
SaveRegs	ENDP

;*********************************************************************
Prompt	PROC	Near
	CALL	CRLF
	MOV	AL, "*"
	CALL	PutChar
	RET
Prompt	ENDP

;*********************************************************************
GetLine	PROC Near
	MOV	BufLen, 0	;clear input buffer

Gl00:	MOV	AH, 0
	INT	16h	;character to AL

	CMP	AL, 20h
	JG	Gl01	;jump if non-control char
	JE	Gl02	;jump if space
	CMP	AL, 8h	;check for backspace
	JE	Gl03
	RET		;not backspace, return
Gl03:	CMP	BufLen, 0
	JE	Gl00	;jump if buffer empty
	DEC	BufLen
	MOV	AL, 8h	;echo BS,SP,BS
	CALL	PutChar
	MOV	AL, 20h
	CALL	PutChar
	MOV	AL, 8h
	CALL	PutChar
	JMP	Gl00

Gl01:	CMP	AL, 7Ah	;check for upper case
	JG	Gl04
	CMP	AL, 61h
	JL	Gl04
	SUB	AL, 20h	;make lower into upper
Gl04:	MOV	BX, BufLen	;buffer the character
	MOV	Buf[BX], AL
	CMP	BX, MaxBufLen
	JGE	Gl02	;don't overflow buffer
	INC	BufLen
Gl02:	CALL	PutChar	;echo
	JMP	Gl00
GetLine	ENDP

;*********************************************************************
NumCheck	PROC	Near
;If Buf[BP..SI-1] represents a hex number, return
;the number in AX and set carry.  If not, clear carry.
	CMP	BP, SI
	JE	Nc03	;zero length?
	MOV	CL, 4
	MOV	AX, 0
Nc00:	MOV	BL, Buf[BP]
	CMP	BL, "0"
	JL	Nc03
	CMP	BL, "9"
	JG	Nc01
	SUB	BL, "0"
	JMP	Nc02
Nc01:	CMP	BL, "A"
	JL	Nc03
	CMP	BL, "F"
	JG	Nc03
	SUB	BL, "A" - 10
Nc02:	SHL	AX, CL
	OR	AL, BL
	INC	BP
	CMP	BP, SI
	JL	Nc00
	STC
	RET
Nc03:	CLC
	RET
NumCheck	ENDP

;*********************************************************************
RegCheck	PROC Near
;If Buf[BP..BP+1] represents a register, return the index
;of the register in BX and set carry.  If not, clear carry
	MOV	AH, Buf[BP]
	MOV	AL, Buf+1[BP]
	MOV	BX, 0
Rc01:	CMP	AX, CS:RegTab[BX]
	JE	Rc02
	ADD	BX, 2
	CMP	BX, Offset RegTabEnd - Offset RegTab
	JL	Rc01
	CLC
	RET
Rc02:	STC
	RET
RegCheck	ENDP

;*********************************************************************
ChkDskBuf	PROC	NEAR
	PUSH	AX
	ADD	BX, 2
	CMP	BX, 80h
	JL	CDB01
	MOV	AH, 14h	;sequential disk read
	INT	21h
	MOV	BX, 0
CDB01:	POP	AX
	RET
ChkDskBuf	ENDP

RegTab	LABEL	WORD
RegTabB	LABEL	BYTE
	DW	"AX", "BX", "CX", "DX", "SP", "BP", "SI", "DI"
	DW	"CS", "DS", "SS", "ES", "IP", "FR", "XS", "YS"
RegTabEnd	LABEL	WORD

;*********************************************************************
PutNum	PROC	Near
;Print AX as a four digit hex number
	PUSH	BX
	PUSH	CX
	MOV	BX, AX
	MOV	CL, 4
	CALL	Pn01
	CALL	Pn01
	CALL	Pn01
	CALL	Pn01
	POP	CX
	POP	BX
	RET
Pn01:	ROL	BX, CL
	MOV	AX, 0Fh
	AND	AX, BX
	CMP	AX, 0Ah
	JGE	Pn02
	ADD	AX, "0"
	JMP	Pn03
Pn02:	ADD	AX, "A" - 0Ah
PN03:	CALL	PutChar
	RET
PutNum	ENDP

;*********************************************************************
CRLF	PROC	Near
	PUSH	AX
	MOV	AL, cr
	CALL	PutChar
	MOV	AL, lf
	CALL	PutChar
	POP	AX
	RET
CRLF	ENDP

;*********************************************************************
PutChar	PROC	Near
	PUSH	AX
	MOV	AH, 14
	PUSH	BX
	MOV	BX, 0
	PUSH	CX
	PUSH	BP
	PUSH	SI
	PUSH	DI
	MOV	CX, SP
	INT	10h
	MOV	SP, CX
	POP	DI
	POP	SI
	POP	BP
	POP	CX
	POP	BX
	POP	AX
	RET
PutChar	ENDP

;*********************************************************************
PrintRegs	PROC	Near
	CALL	CRLF
	MOV	BX, 0
PRE00:	CALL	PrintRegName
	MOV	AL, " "
	CALL	PutChar
	CALL	PutChar
	CALL	PutChar
	ADD	BX, 2
	CMP	BX, 28	;14 registers to print
	JL	PRE00
	CALL	CRLF
	MOV	BX, 0
PRE01:	MOV	AX, RegSave[BX]
	CALL	PutNum
	MOV	AL, " "
	CALL	PutChar
	ADD	BX, 2
	CMP	BX, 28
	JL	PRE01
	RET
PrintRegs	ENDP

;*********************************************************************
Parse	PROC Near
;Try to parse the input buffer contents.  If successful, set
;carry and change TargSpace, TargSeg, and TargOffset.
;If not successful, clear carry.
	CMP	BufLen, 0
	JNE	Pr01
	STC
	RET
Pr01:	CMP	BufLen, 2
	JNE	Pr02
	MOV	BP, 0
	CALL	RegCheck
	JNC	Pr02	;jump if not a register name
	MOV	TargSpace, RegSpace
	MOV	TargOffset, BX
	STC
	RET
Pr02:	CMP	Buf, "I"	;check for IO Space
	JNE	Pr03
	MOV	BP, 1
	MOV	SI, BufLen
	CALL	NumCheck	;get offset (maybe)
	JNC	Pr03
	MOV	TargSpace, IOSpace
	JMP	Pr11
Pr03:	CLD	;find index of ":" if present
	MOV	DI, OFFSET Buf
	MOV	AX, DS
	MOV	ES, AX
	MOV	AL, ":"
	MOV	CX, BufLen
	REPNE	SCASB
	JE	Pr04 ;ZF means ":" was found.  DI has offset+1
	MOV	BP, 0	;check for isolated number
	MOV	SI, BufLen
	CALL	NumCheck
	JNC	Pr10
	JMP	Pr12
Pr04:	SUB	DI, OFFSET Buf
	CMP	DI, 3
	JNE	Pr05
	MOV	BP, 0 ;string is of form xx:. . . Check for register name
	CALL	RegCheck
	JNC	Pr05
	MOV	AX, RegSave[BX]
	JMP	Pr06
Pr05:	MOV	BP, 0	;check for segment a number
	MOV	SI, DI
	DEC	SI
	CALL	NumCheck
	JNC	Pr10
Pr06:	PUSH	AX	;save segment for later
	MOV	AX, BufLen
	SUB	AX, DI
	CMP	AX, 2	;check for offset a register name
	JNE	Pr07
	MOV	BP, DI
	CALL	RegCheck
	JNC	Pr07
	MOV	AX, RegSave[BX]
	JMP	Pr08
Pr07:	MOV	BP, DI	;check for offset a number
	MOV	SI, BufLen
	CALL	NumCheck
	JNC	Pr09
Pr08:	POP	BX
	MOV	TargSeg, BX
Pr12:	MOV	TargSpace, MemSpace
Pr11:	MOV	TargOffset, AX
Pr13:	STC
	RET

Pr09:	POP	AX
Pr10:	CLC
	RET
Parse	ENDP

;*********************************************************************
ScanBP	PROC	Near
;ScanBP is used to enumerate the entries in the breakpoint table
;and call a procedure when a match is found.

;On entry, CX,DX contains a segment,offset breakpoint address, and
;SI,DI contains a comparison mask to be applied to each table entry.
;AX contains 0 if the match is to occur on unused entries, 10h if
;in-use entries are to be matched.
;BP contains the offset of the (near) proc to be called on a match.

;First, CX,DX are adjusted so that the offset is between 0 and 15, then
;for each entry in the breakpoint table,
;  (SI and BreakSegment = CX) and (DI and BreakOffset = DX)
;is calculated.  If this quantity is true, the proc is called.
	PUSH	DX
	AND	DX, 0Fh	;isolate offset
	OR	DX, AX	;merge in-use bit
	POP	AX
	SHR	AX, 1
	SHR	AX, 1
	SHR	AX, 1
	SHR	AX, 1
	ADD	CX, AX	;CX now has break segment
	MOV	BX, 0
ScBP00:	MOV	AX, BPTable [BX]
	AND	AX, SI
	CMP	AX, CX
	JNE	ScBP01
	MOV	AX, BPTable+2 [BX]
	AND	AX, DI
	CMP	AX, DX
	JNE	ScBP01
	CALL	BP
ScBP01:	ADD	BX, 4
	CMP	BX, 4*BPLen
	JL	ScBP00
	RET
ScanBP	ENDP

;*********************************************************************
BPExchange	PROC	Near
;This procedure is called to plant or remove all in-use breakpoints
	MOV	AX, 10h	;match on in-use =1
	MOV	CX, 0
	MOV	DX, CX
	MOV	SI, CX	;mask out all of BP entry except in-use bit
	MOV	DI, AX
	MOV	BP, OFFSET BPEx00	;call-back proc
	CALL	ScanBP
	RET

BPEx00:	MOV	AX, BPTable+2 [BX]
	MOV	ES, BPTable [BX]
	PUSH	BX
	MOV	BX, AX
	AND	BX, 0Fh	;isolate offset of break byte
	XCHG	AH, BYTE PTR ES: [BX]
	POP	BX
	MOV	BPTable+2 [BX], AX
	RET

BPExchange	ENDP

;*********************************************************************
SetBP	PROC	Near
;Set a breakpoint at TargSeg:TargOffset.
;If successful, set carry, else clear carry
	MOV	AX, 10h	;check for breakpoint already set
	MOV	CX, TargSeg
	MOV	DX, TargOffset
	MOV	SI, 0FFFFh
	MOV	DI, 1Fh
	MOV	BP, OFFSET SBP00
	CALL	ScanBP
	MOV	AX, 0	;set breakpoint.  Look for unused table entry
	MOV	CX, AX
	MOV	DX, AX
	MOV	SI, AX
	MOV	DI, 10h
	MOV	BP, OFFSET SBP03
	CALL	ScanBP
	CLC          ;no unused entries
	RET
SBP03:	POP	AX	;have an unused entry.  Fix stack
	POP	AX
	MOV	AX, TargOffset
	AND	AX, 0Fh
	OR	AX, 0CC10h	;break inst plus in-use
	MOV	BPTable+2 [BX], AX
	MOV	AX, TargOffset
	MOV	CL, 4
	SHR	AX, CL
	ADD	AX, TargSeg
	MOV	BPTable [BX], AX
	STC
	RET

SBP00:	POP	AX	;match on the break address.  Pop two return
;links
	POP	AX
	STC
	RET
SetBP	ENDP

;*********************************************************************
PrintBreaks	PROC	Near
;print all breakpoint locations
	MOV	AX, 10h
	MOV	CX, 0
	MOV	DX, CX	;look for in-use BPTable entries
	MOV	SI, CX
	MOV	DI, 10h
	MOV	BP, OFFSET PBrk00
	CALL	ScanBP
	RET

PBrk00:	MOV	AL, " "
	CALL	PutChar
	MOV	AX, BPTable [BX]
	CALL	PutNum
	MOV	AX, ":"
	CALL	PutChar
	MOV	AX, BPTable+2 [BX]
	AND	AX, 0Fh
	CMP	AX, 0Ah
	JL	PBrk01
	ADD	AX, "A" - 0Ah
	JMP	PBrk02
PBrk01:	ADD	AX, "0"
PBrk02:	CALL	PutChar
	RET
PrintBreaks	ENDP

;*********************************************************************
SetInt	PROC	Near
;AX,CX has IP,CS for interrupt routine, BX has interrupt number
;This is a DOS call, but it appears not to work
	PUSH	AX
	MOV	AX,0
	MOV	ES, AX
	POP	AX
	SHL	BX, 1
	SHL	BX, 1
	MOV	WORD PTR ES: [BX], AX	;IP
	MOV	WORD PTR ES: [BX+2], CX	;CS
	RET
SetInt	ENDP

;*********************************************************************
InitBPTable	PROC	Near
	MOV	BX, 0
IBpT00:	MOV	WORD PTR BPTable+2 [BX], 0
	ADD	BX, 4
	CMP	BX, 4*BPLen
	JL	IBpT00
	RET
InitBPTable	ENDP

;*********************************************************************
SendCS	PROC	Near
;Send the contents of the Debugee code segment to the Prolog
;programmer in "P" format.  On entry, RegAX contains 0 if
;even bytes are to be sent, 1 if odd bytes are to be sent.
;RegBX contains the length of CS (from the linker .MAP file)
;Prolog "P" format takes two ASCII characters (0-F) per byte.
;The initial header is start address (always 0, four characters),
;end address (four characters), 3 spaces followed by "P", followed
;by endAddress - startAddress + 1 bytes (2 characters each).

	MOV	AL, 0	;start address zero
	CALL	SendByte
	CALL	SendByte
	MOV	AX, RegBX	;length of CS
	MOV	BX, AX
	AND	BX, 1	;get lsb
	ADD	AX, BX
	SHR	AX, 1	;number of bytes to send
	MOV	DX, AX
	SUB	AX, 1	;endAddress
	MOV	CL, 8
	ROL	AX, CL	;msb(endAddress)
	CALL	SendByte
	ROL	AX, CL	;lsb(endAddress)
	CALL	SendByte
	MOV	AL, "P"
	CALL	SendChar
	MOV	BX, RegAX	;even/odd indicator
	MOV	AX, RegCS	;debugee CS
	MOV	ES, AX
SCS00:	MOV	AL, BYTE PTR ES: [BX]
	CALL	SendByte
	ADD	BX, 2
	DEC	DX
	JNE	SCS00
	RET
SendCS	ENDP

;*********************************************************************
SendByte	PROC	Near ;send byte in AL as two ASCII characters
	PUSH	AX
	SHR	AX, 1	;send msb first
	SHR	AX, 1
	SHR	AX, 1
	SHR	AX, 1
	CALL	SBy00
	POP	AX
	CALL	SBy00
	RET
SBy00:	PUSH	AX
	PUSH	BX
	MOV	BX, AX
	AND	BX, 0Fh
	MOV	AL, CS:SByTab[BX]
	CALL	SendChar
	POP	BX
	POP	AX
	RET
SByTab	LABEL	BYTE
	DB	"0123456789ABCDEF"
SendByte	ENDP

;*********************************************************************
SendChar	PROC	Near
	CALL	PutChar
	PUSH	DX
	MOV	DX, 0	;com card 0
	MOV	AH, 1
	INT	14h
	POP	DX
	RET
SendChar	ENDP

CSeg	ENDS
	END DDMain