		.286c
.xlist
		include	biosdata.asm
.list
;**********************************************************
;**********************************************************
;**********************************************************
;***							***
;***							***
;***			SLICER DEBUGGER I.3		***
;***			===================		***
;***							***
;***							***
;**********************************************************
;**********************************************************
b		equ	byte ptr
w		equ	word ptr
home		equ	7
read		equ	8
write		equ	9
dskcheck	equ	11h
message		equ	14h
hexword		equ	15h
hexbyte		equ	16h
decdisp		equ	17h
conout		equ	3
conin		equ	2
const		equ	1
function_call	equ	0fbh
cr		equ	0dh
lf		equ	0ah
bs		equ	8
cntl		equ	1-'A'
brkcode		equ	0cch
inline		equ	1


;		*** INITIALIZATION ***
;		======================
		extrn	bootstrap1:near,bootstrap2:near,memtest:near
		extrn	old_load:near
		public	monitor,bomb,moninit
cgroup		group	code
code		segment	byte public 'code'
		assume	cs:cgroup,ds:data,ss:stack,es:nothing
MONINIT:
	mov	ax,data
	mov	ds,ax
	mov	bx,message
	int	function_call
	DB	CR,LF,LF,LF,'SLICER  Monitor 2.1E-1                  SEPT  29, 1987',CR,LF,'        ',0
	MOV	AX,MEMSIZE			
	mov	bx,decdisp
	int	function_call
	mov	bx,message
	int	function_call
	DB	'K  RAM installed',0
	JMP	monitor

;**********************************************************
;***							***
;***			MONITOR SUBROUTINE		***
;***							***
;**********************************************************




;		*** OUTPUT ROUTINES ***
;		=======================


;Output CR, LF combination to console

CRLF:
	PUSH	AX
	push	bx
	MOV	AL,CR
	mov	bx,conout
	int	function_call
	MOV	AL,LF
	mov	bx,conout
	int	function_call
	pop	bx
	POP	AX
	RET


;Output a space to the console

SPACE:
	PUSH	AX
	push	bx
	MOV	AL,' '
	mov	bx,conout
	int	function_call
	pop	bx
	POP	AX
	RET


;Erase a character on the console

BACKSP:
	PUSH	AX
	push	bx
	MOV	AL,BS
	mov	bx,conout
	int	function_call
	CALL	SPACE
	mov	bx,conout
	int	function_call
	pop	bx
	POP	AX
	RET

REGNAMES	DB	'AXBXCXDXBPSIDISPCSDSSSESIPF '

;Display register name on console.
;	AX contains register name, two bytes.
;	A space is added.

;In REGOUT0, BX points to register save area
REGOUT0:
	MOV	AX,w cs:REGNAMES[BX]
REGOUT:
	PUSH	AX
	push	bx
	mov	bx,conout
	int	function_call
	MOV	AL,AH
	mov	bx,conout
	int	function_call
	CALL	SPACE
	pop	bx
	POP	AX
	RET



;Get users register value.

;IN:	AX=Register name

;OUT:	BX=Pointer to register value.


REGVALUE:
	PUSH	CX
	MOV	CX,14
	xor	bx,bx
REG0:	CMP	AX,w cs:regnames[BX]
	JZ	REG2
	ADD	BX,2
	LOOP	REG0
	STC
REG2:	POP	CX
	RET


;Print header for register display

REGHEAD:
	CALL	CRLF
	PUSH	BX
	PUSH	CX
	MOV	CX,14		;Number of registers
	MOV	BX,OFFSET REGNAMES ;Names
REG4:	CALL	SPACE		;Get name
	MOV	AX,cs:[BX]
	CALL	REGOUT		;Print it.
	CALL	SPACE
	ADD	BX,2
	LOOP	REG4		;And loop.
	POP	CX
	POP	BX
	RET


;Print register values.

REGDISP:
	CALL	CRLF
	PUSH	BX
	PUSH	CX
	MOV	CX,14		;Number of registers.
	MOV	BX,OFFSET AXSAVE
REG5:	MOV	AX,[BX]		;Display values.
	push	bx
	mov	bx,hexword
	int	function_call
	pop	bx
	CALL	SPACE
	ADD	BX,2
	LOOP	REG5
	POP	CX
	POP	BX
	RET




;		*** CONSOLE INPUT ***
;		=====================

;Check for user break
;	If no character ready return AL=0,Z,NC
;	If control-S then wait for another character
;	If control-C then return AL=3,Z,C
;	Otherwise return AL=ASCII,NZ,NC

CNTLCHK:push	bx
	mov	bx,const
	int	function_call
	pop	bx
	JZ	CNT2
	push	bx
	mov	bx,conin
	int	function_call
	pop	bx
	CMP	AL,CNTL+'S'	;Control S
	JNZ	CNT0
	push	bx
	mov	bx,conin
	int	function_call
	pop	bx
CNT0:	CMP	AL,CNTL+'C'	;Control-C
	JC	CNT1
	JNZ	CNT2
	AND	BITS,NOT INLINE
CNT1:	CMC
CNT2:	RET



;Input a line of text from console.  BS may be used for
;editing.  CR marks the end of the line.  Other control
;characters are not allowed.  Characters typed pass the
;Maximum line width are ignored.

;IN:	CX=Max length (must be less than LEN LINBUF)
;OUT:	CX=Length (including CR)
;	SI=Pointer to start of line.

;Any routine that takes characters from input can assume
;that SI points to the next character.  These routines
;must update SI after using an input character.

LININ:
	AND	BITS,NOT INLINE
	PUSH	AX
	PUSH	BX
	PUSH	DI
	MOV	DI,OFFSET LINBUF	;Set DI and SI
	MOV	SI,DI		;to the start of the input
					;buffer.
	MOV	BX,CX		;BX holds max length
				;CX holds current length
LIN0:	push	bx
	mov	bx,conin
	int	function_call
	pop	bx
	CMP	AL,BS		;Check for BS.
	JNZ	LIN2
	CMP	CX,BX		;Empty line?
	JNZ	LIN4
LIN1:	MOV	AL,7		;If so, ignore it
	push	bx
	mov	bx,conout
	int	function_call
	pop	bx
	jmp short	LIN0
LIN2:	CMP	AL,CR		;Check for end of line.
	JZ	LIN3
	CMP	AL,' '		;Ignore other controls
	JC	LIN1
	push	bx
	mov	bx,conout
	int	function_call		;Echo character.
	pop	bx
LIN3:	STOSB			;Put it in buffer
	LOOPNZ	LIN0
	JZ	LIN5		;Exit because of CR?
	MOV	AL,7		;If not, line too long
	push	bx
	mov	bx,conout
	int	function_call
	pop	bx
LIN4:	DEC	DI		;Erase a character
	INC	CX
	CALL	BACKSP
	jmp short	LIN0
LIN5:	CALL	CRLF		;All done
	SUB	BX,CX		;Compute length
	MOV	CX,BX
	POP	DI
	POP	BX
	POP	AX
	RET



;		*** INPUT PROCESSING ***
;		========================


;These routines aid in the processing of the command line.
;SI always points to the next character to be processed.
;Registers which do not hold return values are saved.
;Syntax errors in the command line are flagged by setting
;C.



;Convert possible lower case in AL to upper case.

UCONVERT:
	CMP	AL,'a'
	JC	UCON0
	CMP	AL,'z'
	JA	UCON0
	SUB	AL,20H
UCON0:	RET


;Convert hex character in AL to binary.

HEXCHR:
	CALL	UCONVERT
	SUB	AL,'0'
	JC	HEX1
	CMP	AL,10
	JC	HEX0
	SUB	AL,7
	CMP	AL,10
	JC	HEX1
	CMP	AL,16
HEX0:	CMC
HEX1:	RET



;Convert ascii hex string to binary.  If string contains more
;than four digits then only the lowest four are used.  String
;ends with comma or CR.  Non-hex characters cause errors.
;(/// MAY WANT TO ALLOW SPACES)

;IN:	AX=Default value
;OUT:	AX=Conversion result


HEXSTRING:
	PUSH	BX
	PUSH	DX
	MOV	DX,AX		;Move default
	MOV	BX,0		;Start with 0
HEX4:	shl	BX,4
	LODSB			;Get next char in string
	CMP	AL,','		;End of string?
	JZ	HEX6
	CMP	AL,CR
	JZ	HEX5
	CMP	AL,' '
	JZ	HEX5
	CALL	HEXCHR		;Convert char
	JC	HEX6
	ADD	BL,AL		;Move char into result
	MOV	DX,BX
	jmp short	HEX4
HEX5:	DEC	SI		;Do not swallow CR or space
HEX6:	MOV	AX,DX
	POP	DX
	POP	BX
	RET


;Address strings are in the form SEGMENT:OFFSET where
;SEGMENT and OFFSET are 16 bit hex strings
;SEGMENT can be a segment register.

;IN:	AX=Default offset
;	BX=Default segment
;OUT:	AX=Offset
;	BX=Segment


ADRSTRING:
	PUSH	DX
	MOV	DX,AX		;Save default offset
	CMP	WORD PTR 1[SI],':S' ;Segment override.
	JNZ	ADR2
	LODSW
	CALL	REGVALUE
	JC	ADR4
	MOV	BX,[BX]
	INC	SI
	jmp short	ADR3
ADR2:	CALL	HEXSTRING	;Maybe, get value
	JNC	ADR4
	CMP	BYTE PTR (-1)[SI],':'	;Then check for colon
	STC
	JNZ	ADR4		;If not then error exit
	MOV	BX,AX
ADR3:	MOV	AX,DX
	CALL	HEXSTRING	;Get offset
ADR4:	POP	DX
	RET


;Get code address.

;OUT:	AX=Offset
;	BX=Offset (same as AX)
;	DX=Segment

CODESTRING:
	MOV	AX,IPSAVE
	MOV	BX,CSSAVE
	jmp short	DAT0


;Get address in data segment, defaults in MEM1,DSSAVE

;OUT:	AX=Offset
;	BX=Offset (same as AX)
;	DX=Segment

DATASTRING:
	MOV	AX,MEM1
	MOV	BX,DSSAVE
DAT0:	CALL	ADRSTRING
	MOV	DX,BX
	MOV	BX,AX
	RET



;Pull a break point out of the input.

;IN:	DS:[DI]=Break point area
;OUT:	AX=Messed up
;	BX=Offset
;	DX=Segment

;Break point area is updated to show that the break point
;is active.  The break point area consists of 6 bytes.
;0:	ACTIVE	If bit 7 is set the break point is set.
;1:	OP CODE	Op code that the break is replacing.
;2,3:	OFFSET
;4,5:	SEGMENT


BRKSTRING:
	MOV	AL,[SI]
	CMP	AL,CR
	JZ	BRK0		;If CR then no break.
	CMP	AL,' '
	JZ	BRK0
	INC	SI
	CMP	AL,','
	JZ	BRK0		;If , don't set break
	CMP	AL,'.'
	JZ	BRK2		;If . use defaults
	DEC	SI		;Otherwise break in input
BRK2:	MOV	AX,2[DI]
	MOV	BX,CSSAVE
	CALL	DAT0		;Get break points from input.
	JC	BRK0
	MOV	2[DI],BX	;Store them.
	MOV	4[DI],DX
	MOV	BYTE PTR [DI],80H ;Activate break.
	CALL	GETDXBX
	MOV	1[DI],AL
	MOV	AL,BRKCODE
	CALL	PUTDXBX
BRK0:	RET


;Get parameters for disk operation.

;Get number of sectors, SECCNT, and sectors per
;track, TRKSIZE.  Default for seccnt is 1.

;IN:	NONE

;OUT:	AX=TRKSIZE=Sectors/track
;	SECCNT=Number of sectors.



DSKSTRING:
	MOV	AL,1		;Number of sectors
	CALL	HEXSTRING
	JC	DSK6
	MOV	SECCNT,AL
	MOV	AL,TRKSIZE	;Sectors/track.
	CALL	HEXSTRING
	JC	DSK6
	MOV	TRKSIZE,AL
DSK6:	RET



;Get parameters for a from/to pair in the data segement
;(Ex. D(ump) from,to)

;IN:	CX=Default length

;OUT:	AX=To offset
;	BX=From offset
;	CX=Length (AX-BX)
;	DX=Segment
;	MEM3=To offset
;	SEG1=Segment

FROMTO:
	CALL	DATASTRING
	JC	FRM1
	ADD	AX,CX
	JNC	FRM0
	MOV	AX,-1
FRM0:	CALL	HEXSTRING
	JC	FRM1
	MOV	CX,AX
	SUB	CX,BX
	JC	FRM1
	MOV	MEM3,AX
	MOV	SEG1,DX
FRM1:	RET


;Get from/to/with parameters.  (Ex. C(ompare) from,to,with).
;From and with may be in different segments

;IN:	CX=Default length
;OUT:	AX=With offset
;	BX=From offset
;	CX=Length
;	DX=With segment
;	MEM1=From offset
;	MEM3=To offset
;	SEG1=From segment
;	SEG3=With segment


FRMTOTO:
	CALL	FROMTO
	JC	FRM2
	MOV	MEM1,BX
	MOV	AX,MEM2
	MOV	BX,ESSAVE
	CALL	ADRSTRING
	JC	FRM2
	MOV	SEG2,BX
	MOV	BX,MEM1
FRM2:	RET


;	OTHER USEFUL SUBROUTINES
;	------------------------



;Pretend that DX is a segment register

GETDXBX:
	PUSH	DS
	MOV	DS,DX
	MOV	AL,[BX]
	POP	DS
	RET

PUTDXBX:
	PUSH	DS
	MOV	DS,DX
	MOV	[BX],AL
	POP	DS
	RET


;Dump the next CX bytes at BX to the console in ascii.
;Convert controls and negatives to periods.

ASCDMP:
	PUSH	AX
	PUSH	BX
	PUSH	CX
ASC0:	MOV	AL,[BX]
	CMP	AL,' '
	JC	ASC1
	OR	AL,AL
	JNS	ASC2
ASC1:	MOV	AL,'.'
ASC2:	push	bx
	mov	bx,conout
	int	function_call
	pop	bx
	INC	BX
	LOOP	ASC0
	POP	CX
	POP	BX
	POP	AX
	RET

;Dump the next CX bytes at BX to the console in hex.

HEXDMP:
	PUSH	AX
	PUSH	BX
	PUSH	CX
HEX3:	MOV	AL,[BX]
	INC	BX
	push	bx
	mov	bx,hexbyte
	int	function_call
	pop	bx
	CALL	SPACE
	LOOP	HEX3
	POP	CX
	POP	BX
	POP	AX
	RET






;Execute user program.

;STEP does one step, GO goes until break.
	assume	es:vectors
STEP:	push	es
	push	ax
	xor	ax,ax
	mov	es,ax
	MOV	w es:vector_1+2,CS	;Set single step vector
	MOV	w es:vector_1,OFFSET RETURN
	OR	FSAVE,100H	;and trace flag.
	jmp	short go1
GO:	push	es
	push	ax
	xor	ax,ax
	mov	es,ax
	MOV	w es:vector_3+2,CS	;Set up break vector.
	MOV	w es:vector_3,OFFSET RETURN
go1:	pop	ax
	pop	es
	assume	es:nothing
	PUSHF			;Save my registers.
	PUSHA
	MOV	MONSP,SP
	MOV	SS,SSSAVE
	MOV	SP,SPSAVE
	PUSH	FSAVE
	PUSH	CSSAVE
	PUSH	IPSAVE
	PUSH	DSSAVE
	MOV	AX,AXSAVE	;Set user registers.
	MOV	BX,BXSAVE
	MOV	CX,CXSAVE
	MOV	DX,DXSAVE
	MOV	BP,BPSAVE
	MOV	SI,SISAVE
	MOV	DI,DISAVE
	MOV	ES,ESSAVE
	POP	DS
	IRET

;Return from user program.  BOMB is for unexpected returns.

BOMB:
	STC
	jmp short	RET1
RETURN:
	CLC
RET1:	push	ds
	push	ax
	MOV	AX,data		;Set my DS.
	MOV	DS,AX
	pop	ax
	MOV	AXSAVE,AX
	pop	ax
	MOV	DSSAVE,ax
	MOV	BXSAVE,BX	;Save users registers
	MOV	CXSAVE,CX
	MOV	DXSAVE,DX
	MOV	BPSAVE,BP
	MOV	SISAVE,SI
	MOV	DISAVE,DI
	MOV	SSSAVE,SS
	MOV	ESSAVE,ES
	POP	IPSAVE
	POP	CSSAVE
	POP	FSAVE
	MOV	SPSAVE,SP
	MOV	AX,DS		;Set my segments
	MOV	ES,AX
	mov	ax,stack
	MOV	SS,AX
	JC	RET2
	MOV	SP,MONSP	;And stack
	POPA			;And registers
	POPF
	sti
	RET
RET2:	MOV	SP,OFFSET stack_top	;Program bombed.
	sti
	mov	bx,message
	int	function_call
	DB	CR,LF,'Welcome to the Error Recovery Routine (Or Rats!)',0
	JMP	MONINIT




;		*** COMMAND FLOW CONTROL ***
;		============================

;Get command from command line and branch to proper routine.


;Pointer to branch table is at TOS. Grab a character from the
;command line, locate it in the table, and jump to the
;corresponding routine (note that its a jump, not a call).
;A 0 at the end of the table will catch everything that
;falls through.

BRANCH:
	POP	AX		;Get table pointer
	PUSH	BX
	MOV	BX,AX
	LODSB			;Get command letter.
	CALL	UCONVERT
BR0:	MOV	AH,cs:[BX]	;Search.
	INC	BX
	CMP	AL,AH		;Found it?
	JZ	BR1
	CMP	AH,0
	JZ	BR1		;End of table?
	INC	BX
	INC	BX
	jmp short	BR0
BR1:	MOV	AX,cs:[BX]	;Get routine.
	POP	BX
	JMP	AX

;A macro to help build branch tables.

BNCH	macro	BITE,ROUTINE
	DB	BITE
	DW	ROUTINE
ENDM

;	BRANCH TABLES
;	-------------

;Branch on first letter of command.

MAINBRANCH:
	CALL	BRANCH
	BNCH	'D',DBRANCH
	BNCH	'S',SBRANCH
	BNCH	'X',EXAMINE
	BNCH	'G',GOTO
	BNCH	'F',FILL
	BNCH	'M',MBRANCH
	BNCH	'R',RBRANCH
	BNCH	'C',COMPARE
	BNCH	'H',HEXMATH
	BNCH	'I',IBRANCH
	BNCH	'O',OUTPUT
	BNCH	'P',PUTTEXT
	BNCH	'B',bbranch
	BNCH	'T',TRACE
	BNCH	'U',UNTRACE
	BNCH	'W',WAIT
	BNCH	'Z',SLEEP
	BNCH	' ',MAINBRANCH
	BNCH	',',MAINBRANCH
	BNCH	'&',REPEAT
	BNCH	CR,ROMRET
	BNCH	0,WHAT


;These branch on second letter of command.

DBRANCH:
	CALL	BRANCH
	BNCH	'Q',DMPASC
	BNCH	'I',DMPIO
	BNCH	'M',DSKMEMORY
	BNCH	'N',SETDSKNUM
	BNCH	'T',SETDSKTRK
	BNCH	'S',SETDSKSEC
	BNCH	'R',DSKREAD
	BNCH	'W',DSKWRITE
	BNCH	'P',DSKPARAMS
	BNCH	'Z',DSKZERO
	BNCH	'?',DISKSET
	BNCH	0,DMPHEX

bbranch:
	CALL	BRANCH
	BNCH	'I',ibmboot
	BNCH	'O',OLD_LOADER
	BNCH	0,boot	      


SBRANCH:
	CALL	BRANCH
	BNCH	'M',SRCHBYTE
	BNCH	'W',SRCHWORD
	BNCH	'S',SHOWSEGS
	BNCH	0,SUBSTITUTE


RBRANCH:
	CALL	BRANCH
	BNCH	'M',REVMOVE
	BNCH	0,WHAT


MBRANCH:
	CALL	BRANCH
	BNCH	'T',MEMTEST
	BNCH	0,MOVE


IBRANCH:
	CALL	BRANCH
	BNCH	'S',SILENTIP
	BNCH	0,INPUT





;**********************************************************
;***							***
;***		MONITOR COMMAND ROUTINES		***
;***							***
;**********************************************************


;These routines save all registers except AX (which was destroyed
;by BRANCH anyway), and SI which is left pointing to the end of
;the command line, or after the character which caused an error.

;Since these routines are close to the top level, it is probably
;not necessary to save registers (although it is nice).



;Hex dump command

;	Df,t

;Display memory from f to t.

DMPHEX:
	DEC	SI		;Back up one character
	PUSH	BX
	PUSH	CX
	PUSH	DX
	MOV	CX,0ffh		;Defalut is 256 bytes
	CALL	FROMTO
	JC	DMP3
	PUSH	DS
	MOV	DS,DX		;Segment to DS.
	MOV	DX,CX		;Length in DX.
DMP0:	MOV	AX,BX		;Compute length of line
	AND	AL,0F0H		;Line ends at the next
	ADD	AX,10H		;multiple of 10H,
	SUB	AX,BX
	MOV	CX,AX
	MOV	AX,DX		;or at DX.
	INC	AX
	JZ	DMP1
	CMP	AX,CX		;Whichever is less
	JNC	DMP1
	XCHG	AX,CX
DMP1:	CALL	CRLF
	MOV	AX,BX
	push	bx
	mov	bx,hexword
	int	function_call
	pop	bx
	CALL	SPACE
	CALL	HEXDMP		;Have start in BX,
	CALL	ASCDMP		;and length in CX.
	ADD	BX,CX		;New starting point.
	SUB	DX,CX
	JC	DMP2
	CALL	CNTLCHK
	JNC	DMP0
DMP2:	POP	DS
	JMP	EXIT2
DMP3:	JMP	SAYWHAT


;ASCII dump routine

;DQf,t

DMPASC:
	PUSH	BX
	PUSH	CX
	PUSH	DX
	MOV	CX,1279		;Default is 1280 chars.
	CALL	FROMTO
	JC	DMP3
	PUSH	DS
	MOV	DS,DX		;Data segment to DS.
	MOV	DX,CX		;Length to DX
DMP4:	MOV	CX,64		;Length is either 64,
	MOV	AX,DX		;or all the rest.
	INC	AX
	JZ	DMP5
	CMP	AX,CX		;Whichever is less
	JNC	DMP5
	XCHG	AX,CX
DMP5:	CALL	CRLF
	MOV	AX,BX
	push	bx
	mov	bx,hexword
	int	function_call
	pop	bx
	CALL	SPACE
	CALL	ASCDMP
	ADD	BX,CX		;New start
	SUB	DX,CX
	JC	DMP2
	CALL	CNTLCHK
	JC	DMP2
	JNC	DMP4



;Substitute memory values

;Sf,v1,v2,...,vn

;This command may extend over several lines.  Replace
;one of the v's with a period to exit

SUBSTITUTE:
	DEC	SI		;Back up one character
	PUSH	BX
	PUSH	CX
	PUSH	DX
	CALL	DATASTRING	;Get memory location
	JC	SUB3
	CMP	BYTE PTR [SI],' '
	JA	SUB1
	MOV	MEM1,BX
	MOV	SEG1,DX
SUB0:	MOV	AX,BX		;Start another line
	push	bx
	mov	bx,hexword
	int	function_call		;Display current location.
	pop	bx
	CALL	SPACE
	CALL	GETDXBX
	push	bx
	mov	bx,hexbyte
	int	function_call		;Display old value
	pop	bx
	CALL	SPACE
	MOV	CX,64
	CALL	LININ		;Get new line
SUB1:	CMP	BYTE PTR [SI],'.' ;Time to quit?
	JZ	SUB2
	CALL	GETDXBX		;Get old value, and
	CALL	HEXSTRING	;use as default
	JC	SUB3
	CALL	PUTDXBX
	INC	BX
	MOV	MEM1,BX
	CMP	BYTE PTR [SI],' ' ;End of line?
	JNA	SUB0
	JNZ	SUB1
SUB2:	JMP	EXIT3
SUB3:	JMP	SAYWHAT


;Put ascii into memory

;	Pf,text

PUTTEXT:
	PUSH	BX
	PUSH	CX
	PUSH	DX
	CALL	DATASTRING
	JC	PUT2
	PUSH	DI
	PUSH	ES
	MOV	DI,BX		;Set up destination
	MOV	ES,DX		;Source already set
PUT0:	CMP	BYTE PTR [SI],CR ;(command line)
	JZ	PUT1
	MOVSB			;Move string
	jmp short	PUT0
PUT1:	JMP	EXIT1
PUT2:	JMP	SAYWHAT


;Fill memory with byte

;	Ff,t,b

;Default for t is 0FFFFH (rest of segment)

FILL:
	PUSH	BX
	PUSH	CX
	PUSH	DX
	MOV	CX,-1
	CALL	FROMTO
	JC	FILL0
	MOV	AL,0		;Get byte to fill in
	CALL	HEXSTRING
	JC	FILL0
	PUSH	DI
	PUSH	ES
	MOV	DI,BX
	MOV	ES,DX
	STOSB
	REP	STOSB
	JMP	EXIT1
FILL0:	JMP	SAYWHAT



;Move memory

;	Mf,t1,t2

;Move memory from f to t1 to t2.  f and t1 are in the same
;segment, t2 may be in a different segment

;	RMf,t1,t2

;does the move from the top down.  This may be needed to avoid
;destroying data during the move.  It may also be used to
;repeat a pattern in memory.

REVMOVE:
	PUSH	BX
	PUSH	CX
	PUSH	DX
	MOV	CX,-1
	CALL	FRMTOTO
	JC	MOV1
	STD			;Reverse direction
	ADD	BX,CX		;Adjust pointers
	ADD	AX,CX
	jmp short	MOV0

MOVE:
	DEC	SI
	PUSH	BX
	PUSH	CX
	PUSH	DX
	MOV	CX,-1
	CALL	FRMTOTO
	JC	MOV1
MOV0:	PUSH	DI		;Set registers to
	PUSH	ES		;use string instructions
	PUSH	SI
	PUSH	DS
	MOV	DI,AX
	MOV	ES,SEG2
	MOV	SI,BX
	MOV	DS,SEG1
	MOVSB
	REP	MOVSB		;Move them
	JMP	EXIT0
MOV1:	JMP	SAYWHAT

;Compare two memory areas.

;	Cf,t1,t2


COMPARE:
	PUSH	BX
	PUSH	CX
	PUSH	DX
	MOV	CX,-1
	CALL	FRMTOTO
	JC	CMP2
	PUSH	DI		;Set up registers for
	PUSH	ES		;String compare
	PUSH	SI
	PUSH	DS
	MOV	DI,AX
	MOV	ES,SEG2
	MOV	SI,BX
	MOV	DS,SEG1
	CMPSB
	JNZ	CMP3
CMP0:	REPZ	CMPSB		;Do string compare
	JZ	CMP1		;CX=0 means all done
CMP3:	CALL	CRLF
	MOV	AX,SI		;Otherwise show error
	DEC	AX
	push	bx
	mov	bx,hexword
	int	function_call
	pop	bx
	CALL	SPACE
	MOV	AL,(-1)[SI]
	push	bx
	mov	bx,hexbyte
	int	function_call
	pop	bx
	CALL	SPACE
	MOV	AL,ES:(-1)[DI]
	push	bx
	mov	bx,hexbyte
	int	function_call
	pop	bx
	CALL	SPACE
	MOV	AX,DI
	DEC	AX
	push	bx
	mov	bx,hexword
	int	function_call
	pop	bx
	POP	DS
	CALL	CNTLCHK
	PUSH	DS
	MOV	DS,SEG1
	JNC	CMP0
CMP1:	JMP	EXIT0
CMP2:	JMP	SAYWHAT


;Input command, displays input data

;	Ip

INPUT:
	DEC	SI
	CALL	CRLF
	PUSH	BX
	PUSH	CX
	PUSH	DX
	MOV	AX,PORT1
	CALL	HEXSTRING
	JC	INP0
	push	bx
	mov	bx,hexword
	int	function_call
	pop	bx
	CALL	SPACE
	MOV	DX,AX
	IN	AX,DX
	push	bx
	mov	bx,hexword
	int	function_call
	pop	bx
	JMP	EXIT4
INP0:	JMP	SAYWHAT



;Silent input, does not display data

;	ISp

SILENTIP:
	PUSH	BX
	PUSH	CX
	PUSH	DX
	MOV	AX,PORT1	;Get default value
	CALL	HEXSTRING
	JC	SIP0
	MOV	DX,AX
	IN	AX,DX
	JMP	EXIT4
SIP0:	JMP	SAYWHAT


;Output

;	Op,w

OUTPUT:
	PUSH	BX
	PUSH	CX
	PUSH	DX
	MOV	AX,PORT1	;Get port
	CALL	HEXSTRING
	JC	OUT0
	MOV	DX,AX
	MOV	AX,WORD1	;Get word
	CALL	HEXSTRING
	JC	OUT0
	MOV	WORD1,AX
	OUT	DX,AX
	JMP	EXIT4
OUT0:	JMP	SAYWHAT


;Wait, gives a delay of n milliseconds

;	Wn

WAIT:
	PUSH	BX
	PUSH	CX
	PUSH	DX
	MOV	AX,1
	CALL	HEXSTRING
	JC	WT0
	DEC	AX
	JZ	WT1
WTLP1:	PUSH	AX
	MOV	AX,494
WTLP2:	DEC	AX
	JNZ	WTLP2
	POP	AX
	DEC	AX
	JNZ	WTLP1
WT1:	PUSH	AX
	MOV	AX,120	;Fill up routine overhead
WTLP3:	DEC	AX	;  to make up the last millisec
	JNZ	WTLP3
	POP	AX
	JMP	EXIT3
WT0:	JMP	SAYWHAT



;Hexmath

;	Hw1,w2

HEXMATH:
	CALL	CRLF
	PUSH	BX
	PUSH	CX
	PUSH	DX
	XOR	AX,AX
	CALL	HEXSTRING	;Get first operand
	JC	HEX7
	MOV	BX,AX
	XOR	AX,AX
	CALL	HEXSTRING	;Get second operand
	JC	HEX7
	XCHG	AX,BX
	MOV	WORD1,AX
	MOV	WORD2,BX
	ADD	AX,BX
	push	bx
	mov	bx,hexword
	int	function_call		;Display sum
	pop	bx
	MOV	AL,'+'
	push	bx
	mov	bx,conout
	int	function_call
	pop	bx
	CALL	SPACE
	MOV	AX,WORD1
	SUB	AX,BX
	push	bx
	mov	bx,hexword
	int	function_call		;Display difference
	pop	bx
	MOV	AL,'-'
	push	bx
	mov	bx,conout
	int	function_call
	pop	bx
	JMP	EXIT3
HEX7:	JMP	SAYWHAT

;Examine and modify registers

;Xr
;X

;First form is examine & modify register
;Second is examine all.


EXAMINE:
	PUSH	BX
	PUSH	CX
	PUSH	DX
	LODSW
	CMP	AL,'F'		;Have name in AX
	JNZ	EXM0
	MOV	AH,' '		;Only one letter for flags
EXM0:	CALL	REGVALUE
	JC	EXM2		;Did not find it.
EXM1:	CALL	CRLF
EXM6:	CALL	REGOUT0		;Display register name.
	MOV	AX,axsave[BX]
	push	bx
	mov	bx,hexword
	int	function_call		;And value.
	pop	bx
	CALL	SPACE
	MOV	CX,60
	CALL	LININ		;Get new value
	CMP	BYTE PTR [SI],'.'
	JZ	EXM4
	CALL	HEXSTRING
	JC	EXM5
	MOV	axsave[BX],AX	;And put it.
	ADD	BX,2
	CMP	BX,offset fsave - offset axsave
	JBE	EXM6
	jmp short	EXM4
EXM2:	SUB	SI,2
	CALL	REGHEAD
	CALL	REGDISP
EXM4:	JMP	EXIT3
EXM5:	JMP	SAYWHAT


;Goto with breaks

;Gg,b1,b2

GOTO:
	PUSH	BX
	PUSH	CX
	PUSH	DX
	CALL	CODESTRING	;Get goto address
	JC	GT4
	MOV	IPSAVE,AX	;Put into user registers
	MOV	CSSAVE,DX
	PUSH	DI
	MOV	DI, OFFSET BREAK1
	MOV	CX,2
GT0:	CALL	BRKSTRING	;Get break points
	JC	GT1
	ADD	DI,6
	LOOP	GT0
GT1:	POP	DI
	JC	GT4
	AND	FSAVE,NOT 100H	;Shut off single step
	CALL	GO		;And go.
	DEC	IPSAVE
	PUSH	DI
	MOV	CX,2
	MOV	DI,OFFSET BREAK2
GT2:	TEST	BYTE PTR [DI],80H ;Remove breaks
	JZ	GT3
	MOV	AL,1[DI]
	MOV	BX,2[DI]
	MOV	DX,4[DI]
	CALL	PUTDXBX
	MOV	BYTE PTR [DI],0
GT3:	SUB	DI,6
	LOOP	GT2
	POP	DI
	JMP	EXIT3
GT4:	JMP	SAYWHAT



;Untrace

;Uw

;Execute w steps, instructions which modify segment
;registers are not counted.

UNTRACE:
	PUSH	BX
	PUSH	CX
	PUSH	DX
	MOV	AX,1
	CALL	HEXSTRING	;Get number.
	JC	UN0
	MOV	CX,AX
UN1:	CALL	STEP		;Do step.
	LOOP	UN1
	JMP	EXIT3
UN0:	JMP	SAYWHAT


;Trace

;Tw

;Execute W steps, display registers after each step.
;A check is made for control-C or control-S after
;each step.
;Instructions which modify the segment registers are not
;counted as steps.


TRACE:
	PUSH	BX
	PUSH	CX
	PUSH	DX
	MOV	AX,1
	CALL	HEXSTRING	;Get step count.
	JC	TR0
	MOV	CX,AX
	CALL	REGHEAD		;Print header.
TR1:	CALL	STEP		;Do step.
	CALL	REGDISP		;Display registers
	CALL	CNTLCHK		;Check for exit or stop.
	JC	TR2
	LOOP	TR1
TR2:	JMP	EXIT3
TR0:	JMP	SAYWHAT


;Set memory area for disk transfers.

;DMs:m

DSKMEMORY:
	PUSH	BX
	PUSH	CX
	PUSH	DX
	MOV	AX,DSKMEM
	MOV	BX,DSKSEG
	CALL	DAT0
	JC	DSK5
	MOV	DSKSEG,DX
	MOV	DSKMEM,AX
	JMP	EXIT3
DSK5:	JMP	SAYWHAT


;Set sector for disk transfers.

;DSs

SETDSKSEC:
	CMP	WORD PTR [SI],':S'
	JNZ	DS0
	JMP	DMPHEX
DS0:	PUSH	BX
	PUSH	CX
	PUSH	DX
	MOV	AL,DSKSECTOR
	CALL	HEXSTRING
	JC	DSK5
	MOV	DSKSECTOR,AL
	JMP	EXIT3
;Set drive number for disk transfer.

;DNn

SETDSKNUM:
	PUSH	BX
	PUSH	CX
	PUSH	DX
	MOV	AL,DSKNUM
	CALL	HEXSTRING
	JC	DSK5
	MOV	DSKNUM,AL
	JMP	EXIT3

;Set track for disk transfer.

;DTn

SETDSKTRK:
	PUSH	BX
	PUSH	CX
	PUSH	DX
	MOV	AX,DSKTRACK
	CALL	HEXSTRING
	JC	DSK5
	MOV	DSKTRACK,AX
	JMP	EXIT3

;Display current disk parameters.

;DP

DSKPARAMS:
	PUSH	BX
	PUSH	CX
	PUSH	DX
	mov	bx,message
	int	function_call
	DB	CR,LF,LF,'          DISK PARAMETERS'
	DB	CR,LF,LF,'MEMORY (DM)     ',0
	MOV	AX,DSKSEG
	mov	bx,hexword
	int	function_call
	MOV	AL,':'
	mov	bx,conout
	int	function_call
	MOV	AX,DSKMEM
	mov	bx,hexword
	int	function_call
	mov	bx,message
	int	function_call
	DB	CR,LF,'LOGICAL DISK (DN)      ',0
	MOV	AL,DSKNUM
	mov	bx,hexbyte
	int	function_call
	mov	bx,message
	int	function_call
	DB	CR,LF,'TRACK (DT)           ',0
	MOV	AX,DSKTRACK
	mov	bx,hexword
	int	function_call
	mov	bx,message
	int	function_call
	DB	CR,LF,'LOGICAL SECTOR (DS)    ',0
	MOV	AL,DSKSECTOR
	mov	bx,hexbyte
	int	function_call
	mov	bx,message
	int	function_call
	DB	CR,LF,'DISK DISCRIPTOR (D?)   ',0
	mov	bl,dsknum
	xor	bh,bh
	mov	al,d_type_0[bx]
	mov	bx,hexbyte
	int	function_call
DSK10:	JMP	EXIT3

;Determine disk type.

DISKSET:
	PUSH	BX
	PUSH	CX
	PUSH	DX
	PUSH	DI
	mov	bx,dskcheck
	int	function_call
	JZ	DSK16
	CALL	SELERR
DSK16:	POP	DI
	JMP	EXIT3

;Zero disk.
;Set lsttrk so that drive looks uncalibrated.

;DZ

DSKZERO:
	PUSH	BX
	PUSH	CX
	PUSH	DX
	PUSH	DI
	mov	bx,home
	int	function_call
	POP	DI
	JC	DSK12		;Disk exists?
	JMP	EXIT3
DSK12:	JMP	DSK7

;Read disk sector.

;DRb1,b2

;Read b1 sectors from disk, assume b2 sectors per track.


DSKREAD:
	PUSH	BX
	PUSH	CX
	PUSH	DX
	CALL	DSKSTRING
	JC	DSK11
	CALL	REPREAD
	JZ	DSK8
DSK9:	CALL	DSKERR
DSK8:	JMP	EXIT3
DSK7:	mov	bx,message
	int	function_call
	DB	CR,LF,'BAD DISK SELECT',0
	jmp short	DSK8
DSK11:	JMP	SAYWHAT

;Write to disk.

;DWb1,b2

;Write b1 setors to the disk, assume b2 sectors per track.

DSKWRITE:
	PUSH	BX
	PUSH	CX
	PUSH	DX
	CALL	DSKSTRING
	JC	DSK11
	CALL	REPWRITE
	JZ	DSK8
	JNZ	DSK9






;	READ/WRITE A RANGE OF SECTORS
;	-----------------------------


REPREAD:
	PUSH	DI
	PUSH	SI		;Put read routine in SI
	MOV	SI,READ
	JMP	short REP3

REPWRITE:
	PUSH	DI
	PUSH	SI		;Put write routine in SI
	MOV	SI,WRITE

REP3:
REP2:	push	bx
	mov	bx,si
	int	function_call	;Read or write
	pop	bx
	JNZ	REP0		;Quit if error
	MOV	AL,SECCNT
	DEC	AL		;Or if done.	
	JZ	REP0
	MOV	SECCNT,AL
	mov	ax,200h
	cmp	dsknum,4
	jae	rep10
	mov	ax,sector_size
rep10:	ADD	DSKMEM,AX
	MOV	AL,DSKSECTOR
	CMP	AL,TRKSIZE
	JNZ	REP1
	INC	DSKTRACK	;and track
	MOV	AL,0
REP1:	INC	AL
	MOV	DSKSECTOR,AL	;and sector.
	JMP	short REP2		;Then repeat
REP0:	POP	SI
	POP	DI
	RET
ibmboot:	int	19h		;boot ibm disk in drive 0
BOOT:
	dec	si
	xor	ax,ax
	CALL	HEXSTRING
	cmp	al,4 		;this should be made call to dskchk to varify floppy
	jae	boot1
	call	bootstrap1		;boot floppy
	jmp	booterr
boot1:	jmp	bootstrap2		;boot harddisk


OLD_LOADER:
	call	old_load

;		DISK ERRORS
;		===========

;select error

SELERR:
	AND	AL,80H
	JNZ	DSKERR
	MOV	AL,0F9H

;disk error, code in al

DSKERR:
	PUSH	AX
	mov	bx,message
	int	function_call
	DB	CR,LF,'DISK ERROR CODE ',0
DSK15:	POP	AX
	mov	bx,hexbyte
	int	function_call
	ret

;boot error, code in ah

BOOTERR:
	MOV	AL,AH
	mov	bx,message
	int	function_call
	DB	CR,LF,'BOOT ERROR CODE ',0
	mov	bx,hexbyte
	int	function_call
	ret






;Show current default segments.

;SS

SHOWSEGS:
	CMP	WORD PTR [SI],':S'
	JNZ	SS0
	JMP	SUBSTITUTE
SS0:	PUSH	BX
	PUSH	CX
	PUSH	DX
	mov	bx,message
	int	function_call
	DB	CR,LF,LF,'       SEGMENTS'
	DB	CR,LF,LF,'DATA         ',0
	MOV	AX,DSSAVE
	mov	bx,hexword
	int	function_call
	mov	bx,message
	int	function_call
	DB	CR,LF,'EXTRA        ',0
	MOV	AX,ESSAVE
	mov	bx,hexword
	int	function_call
	mov	bx,message
	int	function_call
	DB	CR,LF,'CODE         ',0
	MOV	AX,CSSAVE
	mov	bx,hexword
	int	function_call
	mov	bx,message
	int	function_call
	DB	CR,LF,'STACK        ',0
	MOV	AX,SSSAVE
	mov	bx,hexword
	int	function_call
	mov	bx,message
	int	function_call
	DB	CR,LF,'GOTO         ',0
	MOV	AX,IPSAVE
	mov	bx,hexword
	int	function_call
	mov	bx,message
	int	function_call
	DB	CR,LF,'IO PORT      ',0
	MOV	AX,PORT1
	mov	bx,hexword
	int	function_call
	JMP	EXIT3



REPEAT:
	CALL	CNTLCHK
	JC	REP4
	MOV	SI,OFFSET LINBUF
REP4:	RET


SLEEP:
	mov	bx,conin
	int	function_call
	CMP	AL,'C'-40H
	JNZ	SLP0
	AND	BITS,NOT INLINE
SLP0:	RET




;	THINGS TO DO YET
;	----------------


DMPIO:
SRCHBYTE:
SRCHWORD:
	JMP	WHAT





;Exits for the monitor routines all look pretty
;much the same, so they are grouped together here.

;The beginnings of these routines also have some
;similarities, maybe these could also be combined
;to save space (some other day).

EXIT0:
	CLD			;Set string direction
	MOV	MEM2,SI
	POP	DS
	POP	SI
EXIT1:
	MOV	BX,DI
	POP	ES
	POP	DI
EXIT2:
	MOV	MEM1,BX
EXIT3:
	POP	DX
	POP	CX
	POP	BX
	RET
EXIT4:
	MOV	PORT1,DX
	JMP	EXIT3

;These are for errors

SAYWHAT:
	POP	DX
	POP	CX
	POP	BX
WHAT:
	AND	BITS,NOT INLINE
	mov	bx,message
	int	function_call
	DB	'  what?',0
romret:	RET




;		**** MAIN MONITOR LOOP ***
;		==========================


MONITOR:
	mov	ax,data
	mov	ds,ax
	mov	es,ax
	mov	ax,stack
	mov	ss,ax
	mov	sp,offset stack_top

monitor1:
	sti
	CALL	CRLF
	MOV	AL,'+'		;Monitor prompt
	mov	bx,conout
	int	function_call
	MOV	CX,78		;Maximum line length
	CALL	LININ
	OR	BITS,INLINE
MON0:	CALL	MAINBRANCH
	CMP	BYTE PTR[SI],CR
	JZ	monitor1
	TEST	BITS,INLINE
	JNZ	MON0
	jmp	monitor1

code	ends
	end

