	title	MORROW 80188 Slave Debugger
	page	62, 132
	.list



;****************************************************************************
;
;	MBUG
;
;	MORROW 80188 debugger.
;
;	This debugger is written for the MORROW 80188 slave board.  The
;	debugger will use the serial port attached to the I/O connector
;	as the console port.  The commands are single letter commands
;	and behave as they are described below.  Where possible, the
;	syntax is kept as close to the 'debug' utility syntax under MSDOS.
;	The commands currently supported are:
;
;		d - dumps memory in hexadecimal and ascii.
;		e - allows modification of memory one byte at a time.
;		f - fill memory block with value.
;		i - displays value at input port.
;		m - move block of memory.
;		o - output byte value to output port.
;		j - start executing at address.
;		
;	The debugger is intended to be burned into ROM.  For debugging
;	purposes, the code was first written to run under MSDOS 2.0.
;	The hardware drivers are then replaced with the ones for the
;	slave card before burning into ROM.  This version of code
;	contains the hardware drivers for the Morrow slave card.
;
;	The debugger is contained in 2 files.  They are MBUG.ASM and
;	MFUNCT.ASM.  MBUG.ASM contains the main scanner and parser of
;	commands and MFUNCT.ASM contains the code for the specific
;	functions of the debugger.
;
;	The debugger should be assembled and linked as follows for the
;	MSDOS version:
;			masm mbug;	* this generates MBUG.OBJ
;			link mbug;	* this produces MBUG.EXE
;
;	The file MBUG.EXE can then be run under MSDOS for testing.
;
;
;	MODIFICATIONS:
;
;		5/7/84		written			Raymond Yu
;		5/15/84		V1.0 completed		RYU
;				tested under MSDOS 2.0
;		6/4/84		revised for ROM		RYU
;				renamed 'mbugrom.asm'
;				'mfunct.asm' remains
;
;****************************************************************************

		
data		segment para public 'data'

;**********************************************************************
;
;	S100 80188 slave board constant and address definitions
;
;**********************************************************************

	; 80188 internal control registers

cntrl_base	equ	0ff00h		; base addr of 80188 control ports
					; in I/O space, this is the default
					; addr immediately after a reset

umcs		equ	cntrl_base+0a0h	; addr of upper memory select reg
lmcs		equ	cntrl_base+0a2h	; addr of lower memory select reg
mpcs		equ	cntrl_base+0a8h	; addr of middle memory select reg
mmcs		equ	cntrl_base+0a6h	; addr of middle memory select reg
pacs		equ	cntrl_base+0a4h	; addr of peripheral select reg

	; 80188 control register initialization values

UMCSVAL		equ	0ff38h		; 4K byte block, 0 wait states,
					; use external ready
LMCSVAL		equ	03ff8h		; 256K byte block, 0 wait states,
					; use external ready
MPCSVAL		equ	0a0bfh		; 256K byte block in 64K byte incr,
					; 7 PCS lines mapped into I/O space
MMCSVAL		equ	041f8h		; middle ram starts at 256K,
					; 0 wait states, use external ready
PACSVAL		equ	0003fh		; PCS decoding starts at 0 in
					; I/O space, 3 wait states,
					; ignore external ready


;********** 8250 UART constant and address definitions ****************

uart_base	equ	0		; addr of uart in I/O space

	; UART registers

uartdata	equ	uart_base+0	; data register for uart .. DLAB=0
uartdivisorlow	equ	uart_base+0	; clk divisor, low byte .. DLAB=1
uartdivisorhi	equ	uart_base+1	; clk divisor, high byte .. DLAB=1
uartinten	equ	uart_base+1	; interrupt enable register .. DLAB=0
uartintident	equ	uart_base+2	; interrupt identification (read only)
uartlinecntrl	equ	uart_base+3	; line control register
uartmdmcntrl	equ	uart_base+4	; modem control register
uartlinestatus	equ	uart_base+5	; line status register
uartmdmstatus	equ	uart_base+6	; modem status register

	; UART register bit definitions

	; interrupt enable register

rcvinten	equ	01h		; enable data received interrupt bit
xmitinten	equ	02h		; enable transmitter buffer empty int
rcvlineinten	equ	04h		; enable receiver line status int bit
mdmstatinten	equ	010h		; enable modem status interrupt bit

	; interrupt identification register (read only)

intpending	equ	01h		; interrupt pending bit mask
intid		equ	06h		; interrupt ID mask ( 2 bits )

	; line control register

setbreak	equ	040h		; set break bit
dlab		equ	080h		; divisor latch access enable bit

	; modem control register

dtr		equ	01h		; data terminal ready bit
rts		equ	02h		; request to send bit
out1		equ	04h		; output bit 1

out2		equ	08h		; output bit 2
loopcntrl	equ	010h		; loop control bit

	; line status register

dataready	equ	01h		; data ready status bit
overrunerr	equ	02h		; overrun error status bit
parityerr	equ	04h		; parity error status bit
framingerr	equ	08h		; framing error status bit
breakint	equ	010h		; break interrupt status bit
thre		equ	020h		; transmitter holding register empty
tsre		equ	040h		; transmitter shift register empty

	; modem status register

dcts		equ	01h		; delta clear to send status bit
ddsr		equ	02h		; delta data set ready status bit
teri		equ	04h		; trailing edge ring indicator status
drlsd		equ	08h		; delta rcv line signal detect status
cts		equ	010h		; clear to send status read bit
dsr		equ	020h		; data set ready status read bit
ri		equ	040h		; ring indicator status read bit
rlsd		equ	080h		; rcv line signal detect status bit

	; initialization values for divisor latch
	; divisor values for baud rates using 1.8432Mhz 16X clock

baud9600	equ	12
baud4800	equ	24
baud2400	equ	48
baud1200	equ	96
baud300		equ	384

	; initialization values for line control register and
	; modem control register

LCRVAL		equ	07h		; 8 data bits, 2 stop bits, no parity
MCRVAL		equ	0fh		; DTR, RTS, OUT1, OUT2 set


;******************************************************************
;
;	Debugger constant and string definitions
;
;******************************************************************

PRSTRING	equ	09h			; DOS print string function

ENDSTRING	equ	'$'			; string termination char
CR		equ	0dh			; carriage return char
LF		equ	0ah			; line feed char
BS		equ	08h			; backspace char
DELETE		equ	07fh			; delete char
KILL		equ	018h			; control-x is kill char
SPACE		equ	020h			; space char

BUFLENGTH	equ	128			; size of command buffer

SRC_SEG		equ	0			; init source segment value

DEST_SEG	equ	0			; init dest segment value

DEF_COUNT	equ	128			; default count of bytes


SIGNON		db	CR,LF
		db	"MORROW DESIGNS 80188 DEBUGGER V1.0  5/7/84"
		db	CR,LF,CR,LF,ENDSTRING

NEWLINE		db	CR,LF,ENDSTRING

PROMPT		db	"MBUG>",ENDSTRING		

BAD_COMMAND	db	"COMMAND NOT FOUND",ENDSTRING
SYNTAX_MES	db	"usage: ",ENDSTRING

SPACE_2		db	"  ",ENDSTRING
SPACE_3		db	"   ",ENDSTRING
SPACE_4		db	"    ",ENDSTRING

DENTRY		db	" = ",ENDSTRING


syntax		label	byte
S_DUMP		db	"d <address> <address or count>"
		db	CR,LF,ENDSTRING
S_ENTER		db	"e <address>",CR,LF,ENDSTRING
S_FILL		db	"f <address> <address or count> <value>"
		db	CR,LF,ENDSTRING

S_INPUT		db	"i <port>",CR,LF,ENDSTRING
S_MOVE		db	"m <address> <address> <count>"
		db	CR,LF,ENDSTRING
S_OUTPUT	db	"o <port> <value>",CR,LF,ENDSTRING
S_JUMP		db	"j <address>",CR,LF,ENDSTRING
		db	0			; mark end of syntax strings


commands	label	byte			; command table for debugger
		db	'D'
		dw	offset dump
		db	'E'
		dw	offset enter
		db	'F'
		dw	offset fill
		db	'I'
		dw	offset input
		db	'M'
		dw	offset move
		db	'O'
		dw	offset output
		db	'J'
		dw	offset jump
		db	'Q'
		dw	offset quit
		dw	0


segstore	label	word			; segment value temp storage
						; these are used as default
		dw	SRC_SEG			; source segment value
		dw	DEST_SEG		; destination segment value

current_src	dw	0			; source address
current_dest	dw	0			; destination address
current_count	dw	40h			; current count
current_port	dw	0			; current i/o port

buffer		db	BUFLENGTH dup(?)	; command buffer

data_buf	db	0			; count of bytes in data buf
		db	8 dup(0)		; can fill memory with up to
						; 8 byte sequence

end_data_seg	label	byte			; mark end of data segment

data		ends


;**************************************************************
;	CODE STARTS HERE
;**************************************************************

code		segment para public 'code'
		assume	cs:code, ds:data, es:data

begin		proc	far

		; initialize 80188 internal registers

		mov	dx,umcs		; init upper memory chip select
		mov	ax,UMCSVAL	; init value
		out	dx,ax		; output to 80188 control port

		mov	dx,lmcs		; init lower memory chip select
		mov	ax,LMCSVAL	; init value
		out	dx,ax		; output to 80188 control port

		mov	dx,mmcs		; init middle memory chip select
		mov	ax,MMCSVAL	; init value
		out	dx,ax		; output to 80188 control port

		mov	dx,mpcs		; init middle memory chip select
		mov	ax,MPCSVAL	; init value
		out	dx,ax		; output to 80188 control port

		mov	dx,pacs		; init peripheral chip select
		mov	ax,PACSVAL	; init value
		out	dx,ax		; output to 80188 control port

		; copy initialized data out of ROM and into RAM

		mov	ax,40h		; data starts after interrupt vectors
		mov	es,ax		; put segment addr into ds reg
		mov	ax,data		; get address of init data in ROM
		mov	ds,ax		; use as source address

		mov	cx,offset end_data_seg
		xor	si,si		; clear pointers
		mov	di,si

	rep	movsb			; copy cx count bytes to RAM

		mov	ax,es		; put new data segment reg addr
		mov	ds,ax		; into ds reg
		
		mov	ax,offset end_data_seg
		mov	cl,4		; divide addr by 16 to get segment
		shr	ax,cl
		inc	ax		; point at next paragraph after data
		add	ax,40h		; data seg starts at 400h
		mov	ss,ax		; use as stack pointer
		mov	ax,100h		; give 256 bytes to the stack
		mov	sp,ax

		mov	ax,0ffffh	; push reset address in case of
		push	ax		; return from main loop
		xor	ax,ax		; offset of reset location
		push	ax

		; init the console uart

		mov	dx,uartlinecntrl
		mov	al,LCRVAL+dlab	; set DLAB=1 to load divisor
		out	dx,al

		mov	dx,uartdivisorlow
		mov	ax,baud9600	; init port to 9600 baud
		out	dx,al		; output low byte of divisor
		mov	dx,uartdivisorhi
		mov	al,ah		; get high byte of divisor
		out	dx,al		; output high byte of divisor

		mov	dx,uartlinecntrl
		mov	al,LCRVAL	; init line control register
		out	dx,al

		mov	dx,uartmdmcntrl
		mov	al,MCRVAL	; init modem control register
		out	dx,al

		; end of initialization code

		mov	dx,offset SIGNON
		call	prstr			; print sign on message

main:						; this is the main loop of
						; the debugger
		mov	dx,offset PROMPT	; print the debugger prompt
		call	prstr

		mov	ah,0			; convert data to upper case
		call	get_command		; get command line into buffer

		mov	al,buffer		; get first char in buffer
		test	al,al			; if zero then no chars entered
		je	main			; get the next command

		call	execute			; execute the command

		jc	main			; routine sets carry to cont

		; terminate execution

		ret

begin		endp	far


;**************************************************************
;	COMMAND ENTRY AND PARSE ROUTINES
;**************************************************************

;
;	get_command
;
;	Get a command line into command buffer.
;
;	on entry:
;		ah contains 0 if the data should be converted to upper case.
;		   if ah is not zero then the data is entered as is.
;	on return:
;		command line is stored at buffer.
;	usage:
;		call	get_command
;

get_command	proc	near			; get command in buffer
		push	ax			; save ax

		; clear the buffer

		mov	di,offset buffer	; point to beginning of buffer
		mov	cx,BUFLENGTH		; length of command buffer
		push	es			; need to use es register
		mov	ax,ds			; get segment register
		mov	es,ax			; put in default seg reg
		xor	ax,ax			; fill buffer with zeroes
		cld				; set dir flag to auto incr
	rep	stosb

		pop	es			; restore segment register
		xor	bx,bx			; clear buffer pointer
		pop	cx			; get param value into cx
gc_nextchar:
		call	getc			; get the next input char
		cmp	al,BS			; if backspace char
		je	gc_delete		; then process
		cmp	al,DELETE		; if delete char
		je	gc_delete		; then process
		cmp	al,KILL			; if kill char
		je	gc_kill			; delete entire buffer
		cmp	al,CR			; if CR then done
		je	gc_done

		cmp	al,SPACE		; reject other control chars
		jl	gc_nextchar

		call	putc			; echo char to display
		test	ch,ch			; if param is 0 then convert
		jne	gc_1			; do not convert to UC
		cmp	al,60h			; if lower case char then
		jl	gc_1			; else do nothing
		and	al,0dfh			; convert to upper case
gc_1:
		mov	buffer[bx],al		; store char away
		inc	bx			; point to next char in buffer
		cmp	bx,BUFLENGTH		; if too many chars
		jg	gc_err			; error exit
		jmp	gc_nextchar

gc_kill:

		mov	al,SPACE		; erase to beginning of line
		call	putc
		mov	al,BS			; back up to orig position
		call	putc
		test	bx,bx			; only to beginning of line
		jz	get_command
		dec	bx
		mov	al,BS			; back up one char
		call	putc
		jmp	gc_kill

gc_delete:					; delete the previous char
		test	bx,bx			; if at beg of buffer
		jz	gc_nextchar		; do nothing ... otherwise
		mov	al,BS			; back space to prev char
		call	putc
		mov	al,SPACE		; erase char
		call	putc
		mov	al,BS			; fix cursor
		call	putc
		dec	bx			; point at prev char position
		xor	al,al			; clear char in buffer
		mov	buffer[bx],al
		jmp	gc_nextchar		; get next char
		
gc_done:
		mov	dx,offset NEWLINE	; print CR, LF
		call	prstr
gc_err:
		ret

get_command	endp	near


;
;	execute
;
;	Executes the command line contained in 'buffer'.
;
;	on entry:
;		the command line is assumed to be in buffer.
;		the command table is at 'commands'.
;	on exit:
;		the carry flag is cleared if the debugger is to terminate.
;	usage:
;		call	execute
;

execute		proc	near			; determine command
		mov	al,buffer		; get 1st char of command line
		mov	bx,offset commands	; point to command table
exe_search:
		mov	ah,[bx]			; get command in table
		test	ah,ah			; if zero then reached end of
		je	exe_bad			; table .. bad command
		cmp	al,ah			; if command is found ..
		je	exe_command		; then execute it
		add	bx,3			; else skip to next command
		jmp	exe_search

exe_command:
		inc	bx			; point to addr of routine
		call	word ptr [bx]		; near call to routine
		ret

exe_bad:					; bad command .. print error
		mov	dx,offset BAD_COMMAND	;  message
		call	prstr
		stc
		ret

execute		endp	near


;**************************************************************
;	DEBUGGER FUNCTIONS
;**************************************************************

include		mfunct.asm


;**************************************************************
;	HARDWARE RELATED ROUTINES
;**************************************************************

getc		proc	near		; get a char from console port
					; return in al
		push	dx		; save dx register
		mov	dx,uartlinestatus
getc_wrdy:
		in	al,dx		; get uart status
		and	al,dataready	; if no char received in uart
		je	getc_wrdy	; wait ..

		mov	dx,uartdata	; get data from uart
		in	al,dx
		and	al,07fh		; get rid of ms bit
		pop	dx		; restore dx
		ret

getc		endp	near


putc		proc	near		; write a char to console port
					; char is in al reg
		push	dx		; save dx register
		push	ax		; save ax register also
		mov	dx,uartlinestatus
putc_wrdy:
		in	al,dx
		and	al,thre		; test if xmit holding reg empty
		je	putc_wrdy	; if not empty then again

		pop	ax		; restore ax register and char
		mov	dx,uartdata	; otherwise send data to port
		out	dx,al		; write char to uart

		pop	dx
		ret

putc		endp	near


prstr		proc	near		; dx pts to string terminated
					; by a '$'
		push	bx		; save bx register
		push	ax		; save ax register
		mov	bx,dx		; get string addr
prstr1:
		mov	al,[bx]		; get next char in string
		cmp	al,'$'		; see if end of string
		je	prstr_done	; done if so
		call	putc		; else send char to console
		inc	bx		; point at next char
		jmp	prstr1		; print next char

prstr_done:
		pop	ax		; restore ax register
		pop	bx		; restore bx register
		ret

prstr		endp	near


code		ends
		end


