mirror of
https://github.com/microsoft/MS-DOS.git
synced 2025-08-27 16:26:00 +00:00
MZ is back!
This commit is contained in:
committed by
Microsoft Open Source
parent
8ee9712c74
commit
2d04cacc53
553
v4.0-ozzie/bin/DISK2/BIOS/BUGCODE.INC
Normal file
553
v4.0-ozzie/bin/DISK2/BIOS/BUGCODE.INC
Normal file
@@ -0,0 +1,553 @@
|
||||
;*** Bugcode.inc - Debug code for including into sysini.asm and ibmbio.asm
|
||||
;
|
||||
; Can't link in via buglib due to memory and relocation games played
|
||||
; by these modules. Each gets a private, local-only copy of these
|
||||
; modules.
|
||||
|
||||
|
||||
IFDEF DEBUGFLG
|
||||
|
||||
|
||||
;** DPRINTF _ Debug Printf
|
||||
;
|
||||
; Dprintf is a kernel debug print formatting package. It is intended
|
||||
; to produce conviently formatted output.
|
||||
;
|
||||
; Dprintf is called, indirectly, by a macro:
|
||||
;
|
||||
; DEBUG n,m,"string",<a1,...,an>
|
||||
;
|
||||
; string = format string
|
||||
; a1 = first argument
|
||||
; an = last argument
|
||||
;
|
||||
; The format string is an ASCIZ string which can contain 2 types of
|
||||
; specifications: data-format specifications and literal characters.
|
||||
; Data format specifications always begin with a '$' character; all
|
||||
; characters not part of a data format specification are treated as
|
||||
; literal characters.
|
||||
;
|
||||
; Literal characters
|
||||
; - any character not part of a format specification. Special
|
||||
; non-printing characters are:
|
||||
; \n - CRLF
|
||||
; \t - tab
|
||||
; \b - bell
|
||||
; \\ - \
|
||||
; \$ - $
|
||||
;
|
||||
; Format Specifications
|
||||
;
|
||||
; A format specification takes the form:
|
||||
; $ [@] <char>
|
||||
;
|
||||
; where <char> =
|
||||
;
|
||||
; x - print argument as a hex word
|
||||
; d - print argument as decimal word
|
||||
; c - print argument as ascii character
|
||||
; b - print argument as hex byte
|
||||
; For each of the above formats, the supplied argument
|
||||
; is a 16-bit word - the value to be printed. The optional @
|
||||
; (described below) allows a segmented address to be supplied,
|
||||
; instead.
|
||||
;
|
||||
; s[nn] - print argument as asciz string; if optional decimal
|
||||
; argument follows the format character this specifys
|
||||
; a maximum string length. Non printing characters are
|
||||
; printed in the form \nnn where "nnn" is the octal byte
|
||||
; value.
|
||||
; Note that this format character cannot be directly
|
||||
; followed by a digit unless that digit is to be taken
|
||||
; as the start of a length argument.
|
||||
;
|
||||
; Bnn - print argument as hex bytes. The required following
|
||||
; decimal argument is the number of bytes to print.
|
||||
;
|
||||
; Both of these formats take a long address as their argument.
|
||||
; The '@' character is thus invalid for these formats.
|
||||
;
|
||||
; WARNINGS
|
||||
; As befitting a debug routine, DPRINTF does not have a whole lot
|
||||
; of "failsafe" code in it. Supplying screwed up formats can
|
||||
; muck things up. Specifically:
|
||||
; The @ argument must NOT be specified with the 's' or 'B'
|
||||
; format
|
||||
; A string/byte-length argument of 0 is taken as 65536
|
||||
; The string "%% BAD FMT %%" appears in the output when
|
||||
; 1) an illegal format specifier is given, or
|
||||
; 2) the B format is given a 0 or missing length
|
||||
;
|
||||
; ENTRY (sp+n ) = address of format string (offset from return cs value)
|
||||
; (sp+n-2) = first argument word
|
||||
; (sp+n-4) = second argument word
|
||||
; .
|
||||
; (sp+4 ) = last argument word
|
||||
; (sp+2 ) = seg of return address
|
||||
; (sp ) = offset of return address
|
||||
; (bp) = offset of format string on the stack
|
||||
; EXIT none
|
||||
; USES flags
|
||||
|
||||
PUBLIC DPRINTF
|
||||
DPRINTF PROC near
|
||||
|
||||
push ds
|
||||
push es
|
||||
push bp
|
||||
push di
|
||||
push si
|
||||
push dx
|
||||
push cx
|
||||
push bx
|
||||
push ax ; save registers
|
||||
cld
|
||||
|
||||
mov si,[bp] ; get address of format string
|
||||
sub bp,2
|
||||
mov bx,sp
|
||||
mov ds,ss:20[bx] ; (ds:si) = address of format string
|
||||
push cs
|
||||
pop ds
|
||||
|
||||
; Scan format string for next character
|
||||
;
|
||||
; (ds:si) = address of format string
|
||||
; (ss:bp) = address of next argument
|
||||
|
||||
dpf1: lodsb ; (al) = format string byte
|
||||
and al,al
|
||||
je dpf3 ; all done
|
||||
cmp al,'$'
|
||||
je dpf4 ; is data escape
|
||||
cmp al,'\'
|
||||
jnz dpf2 ; got the character
|
||||
|
||||
; it's an "\" escape code - crack the argument character
|
||||
|
||||
lodsb
|
||||
and al,al
|
||||
je dpf3 ; all done, ignore hanging \
|
||||
xchg ah,al
|
||||
mov al,0Ch
|
||||
cmp ah,'n'
|
||||
jne dpf1$5 ; not \n
|
||||
mov al,0dH
|
||||
call putchar
|
||||
mov al,0aH
|
||||
jmp SHORT dpf2 ; print LF
|
||||
|
||||
dpf1$5: cmp ah,'t'
|
||||
mov al,9
|
||||
je dpf2 ; is \t
|
||||
cmp ah,'b'
|
||||
mov al,7
|
||||
je dpf2 ; is \b
|
||||
xchg ah,al
|
||||
dpf2: call putchar
|
||||
jmp dpf1
|
||||
|
||||
; have the end of the format string - exit
|
||||
|
||||
dpf3: pop ax
|
||||
pop bx
|
||||
pop cx
|
||||
pop dx
|
||||
pop si
|
||||
pop di
|
||||
pop bp
|
||||
pop es
|
||||
pop ds
|
||||
ret
|
||||
|
||||
|
||||
;* Have a '$' character - is data format escape
|
||||
;
|
||||
; Get address of data into es:di
|
||||
;
|
||||
; (bp) = address of data value
|
||||
|
||||
dpf4: mov di,bp
|
||||
push ss
|
||||
pop es ; (es:di) = address of data value
|
||||
sub bp,2 ; point to next argument
|
||||
lodsb ; (al) = format specifier
|
||||
cmp al,'@'
|
||||
jne dpf5 ; not an indirect flag
|
||||
les di,[bp]
|
||||
sub bp,2 ; have an extra 2 for @
|
||||
lodsb
|
||||
dpf5: cmp al,'x'
|
||||
jne dpfd1 ; not 'x'
|
||||
|
||||
; is 'x' format - print hex word
|
||||
|
||||
mov ax,es:[di]
|
||||
call THW ; type hex word
|
||||
jmp dpf1
|
||||
|
||||
dpfd1: cmp al,'d'
|
||||
jnz dpfc1 ; not 'd'
|
||||
|
||||
; is 'd' format - print decimal word
|
||||
|
||||
mov ax,es:[di]
|
||||
call TDW ; type decimal word
|
||||
jmp dpf1
|
||||
|
||||
dpfc1: cmp al,'c'
|
||||
jne dpfb1
|
||||
|
||||
; is 'c' format - print character
|
||||
|
||||
mov al,es:[di]
|
||||
call putchar
|
||||
jmp dpf1
|
||||
|
||||
dpfb1: cmp al,'b'
|
||||
jne dpfs1
|
||||
|
||||
; is 'b' format - print hex byte
|
||||
|
||||
mov al,es:[di]
|
||||
call THB ; type hex byte
|
||||
jmp dpf1
|
||||
|
||||
dpfs1: cmp al,'s'
|
||||
jne dpfbb1
|
||||
|
||||
; is 's' format - print ASCIZ string. First, check for
|
||||
; optional decimal limit
|
||||
|
||||
public SSB
|
||||
SSB: sub cx,cx ; set 65536 limit
|
||||
les di,[bp] ; (es:DI) = fwa of string
|
||||
sub bp,2 ; argument to 's' was two words
|
||||
mov al,[si]
|
||||
cmp al,'0'
|
||||
jb dpfs2 ; not decimal
|
||||
cmp al,'9'
|
||||
ja dpfs2 ; not decimal
|
||||
call atod ; (ax) = decimal value, (ds:si) updated
|
||||
xchg cx,ax
|
||||
|
||||
; print asciz string at es:di, max of (cx) characters
|
||||
; (cx) = 0 means max of 65536
|
||||
;
|
||||
; Other sections of code in dpf jump here to print strings
|
||||
|
||||
dpfs2: mov al,es:[di]
|
||||
inc di
|
||||
and al,al
|
||||
je dpfs3
|
||||
call putchar
|
||||
loop dpfs2 ; continue if not at limit
|
||||
dpfs3: jmp dpf1
|
||||
|
||||
dpfbb1: cmp al,'B'
|
||||
je dpfbb2 ; is 'B' format
|
||||
|
||||
; error in format code - print message
|
||||
|
||||
dpferr: push cs
|
||||
pop es
|
||||
mov di,OFFSET dpfa ; (es:di) = error message
|
||||
sub cx,cx
|
||||
jmp dpfs2
|
||||
|
||||
dpfa: DB '%% BAD FMT %%',0
|
||||
|
||||
; have B format
|
||||
|
||||
dpfbb2: call atod ; (ax) = length specifier
|
||||
jc dpferr ; number not there - error
|
||||
xchg cx,ax
|
||||
jcxz dpferr ; number is 0 - error
|
||||
les di,[bp] ; (es:DI) = fwa of string
|
||||
sub bp,2 ; argument to 's' was two words
|
||||
dpfbb3: mov al,es:[di]
|
||||
call THB ; type hex byte
|
||||
mov al,' '
|
||||
call putchar ; space em out
|
||||
inc di
|
||||
loop dpfbb3 ; do em all
|
||||
jmp dpf1
|
||||
|
||||
DPRINTF ENDP
|
||||
|
||||
|
||||
;** THB - Type Hex Byte
|
||||
;
|
||||
; THB types a hex byte (via "putchar")
|
||||
;
|
||||
; ENTRY (AL) = byte
|
||||
; EXIT none
|
||||
; USES ax, flags
|
||||
|
||||
THBA DB '0123456789abcdef'
|
||||
|
||||
PUBLIC THB
|
||||
THB PROC near
|
||||
|
||||
push ax
|
||||
shr al,1
|
||||
shr al,1
|
||||
shr al,1
|
||||
shr al,1
|
||||
and ax,0fH
|
||||
xchg bx,ax
|
||||
mov bl,CS:THBA[bx]
|
||||
xchg ax,bx
|
||||
call putchar ; put first character
|
||||
pop ax
|
||||
and ax,0fH
|
||||
xchg bx,ax
|
||||
mov bl,CS:THBA[bx]
|
||||
xchg ax,bx
|
||||
call putchar
|
||||
ret
|
||||
|
||||
THB ENDP
|
||||
|
||||
|
||||
|
||||
|
||||
;** THW - Type Hex Word
|
||||
;
|
||||
; THW types a word in hex (via "putchar")
|
||||
;
|
||||
; ENTRY (AX) = word
|
||||
; EXIT none
|
||||
; USES AX, flags
|
||||
|
||||
PUBLIC THW
|
||||
THW PROC near
|
||||
|
||||
push ax
|
||||
xchg ah,al
|
||||
call THB
|
||||
pop ax
|
||||
call THB
|
||||
ret
|
||||
|
||||
THW ENDP
|
||||
|
||||
|
||||
|
||||
;** TDW - Type Decimal Word
|
||||
;
|
||||
; TDW types (via "putchar") the unsigned decimal representation
|
||||
; of a 16-bit unsigned integer. Only significant digits are
|
||||
; printed; if the number is 0 a "0" is printed.
|
||||
;
|
||||
; ENTRY (AX) = number
|
||||
; EXIT none
|
||||
; USES AX, flags
|
||||
|
||||
PUBLIC TDW
|
||||
TDW PROC near
|
||||
|
||||
push cx ; preserve registers
|
||||
push dx
|
||||
mov cx,10
|
||||
call tdw$ ; recurse cracking digits
|
||||
pop dx
|
||||
pop cx
|
||||
ret
|
||||
|
||||
TDW ENDP
|
||||
|
||||
|
||||
;* tdw$ - crack number recursively
|
||||
;
|
||||
; tdw$ cracks the least significant decimal digit. If there
|
||||
; are no higher-significant digits, print and return.
|
||||
; else, recurse for higher digits
|
||||
;
|
||||
; (AX) = value
|
||||
; (CX) = 10
|
||||
|
||||
tdw$ PROC NEAR
|
||||
|
||||
sub dx,dx
|
||||
div cx ; (ax) = quotient, (dx) = remainder
|
||||
and ax,ax
|
||||
jz tdw$1 ; this is highest-order, do it
|
||||
push dx
|
||||
call tdw$
|
||||
pop dx
|
||||
tdw$1: xchg ax,dx
|
||||
add al,'0'
|
||||
call putchar
|
||||
ret
|
||||
|
||||
TDW$ ENDP
|
||||
|
||||
|
||||
|
||||
;** ATOD - Convert ASCII string to decimal number
|
||||
;
|
||||
; ATOD is called to convert an ascii string of digits to a
|
||||
; decimal number. Digits are converted until we run out of them.
|
||||
;
|
||||
; ENTRY (DS:SI) = address of first digit
|
||||
; EXIT 'C' clear if OK
|
||||
; (AX) = value
|
||||
; (SI) updated to first non-digit
|
||||
; 'C' set if error - no digits, or result >65535
|
||||
; (DS:SI) points to error character
|
||||
; USES AX, SI, FLAGS
|
||||
|
||||
PUBLIC ATOD
|
||||
ATOD PROC near
|
||||
|
||||
push dx
|
||||
push cx ; save registers
|
||||
mov al,[si]
|
||||
sub al,'0'
|
||||
jc atod9 ; error - no digits
|
||||
cmp al,10
|
||||
cmc
|
||||
jc atod9 ; error - no digits
|
||||
sub ax,ax ; clear accumulator
|
||||
mov cx,10 ; base 10
|
||||
|
||||
; crack next digit
|
||||
;
|
||||
; (AX) = number accumulated so near
|
||||
; (CX) = 10
|
||||
; (DS:SI) = next character
|
||||
|
||||
atod1: xchg dx,ax ; keep accum in dx for a while
|
||||
lodsb ; (al) = character
|
||||
sub al,'0'
|
||||
jc atod7 ; not digit - all done
|
||||
cmp al,9
|
||||
ja atod7 ; not digit - all done
|
||||
sub ah,ah ; (ax) = digit value (0 - 9)
|
||||
push ax
|
||||
xchg ax,dx
|
||||
mul cx ; (ax) = 10*accum
|
||||
pop dx ; (dx) = digit to add
|
||||
jo atod8 ; overflow
|
||||
add ax,dx
|
||||
jmp atod1 ; go back for more
|
||||
|
||||
; Done with number, all OK
|
||||
;
|
||||
; (dx) = number
|
||||
; (ds:si) = address+1 of first unused character
|
||||
|
||||
atod7: clc
|
||||
|
||||
; Done with number, error
|
||||
; 'C' set
|
||||
|
||||
atod8: dec si ; backup over non-decimal (or error) char
|
||||
atod9: pop cx
|
||||
xchg ax,dx ; (ax) = number iff no error
|
||||
pop dx ; restore registers
|
||||
ret ; exit
|
||||
|
||||
ATOD ENDP
|
||||
|
||||
;** putchar - put a character on the console
|
||||
;
|
||||
; ENTRY (al) = character
|
||||
; EXIT none
|
||||
; USES ax,flags
|
||||
|
||||
|
||||
UR_DAT = 02f8H ; COM1 = 03f8H, COM2 = 02f8H
|
||||
UR_IEN = UR_DAT+1 ; Interrupt enable
|
||||
UR_IER = UR_DAT+2 ; interrupt ID
|
||||
UR_LCR = UR_DAT+3 ; line control registers
|
||||
UR_MCR = UR_DAT+4 ; modem control register
|
||||
UR_LSR = UR_DAT+5 ; line status register
|
||||
UR_MSR = UR_DAT+6 ; modem status regiser
|
||||
UR_DLL = UR_DAT ; divisor latch least sig
|
||||
UR_DLM = UR_DAT+1 ; divisor latch most sig
|
||||
|
||||
iflag DB 0 ; != 0 when initialized 8250
|
||||
|
||||
;* inchr - input character
|
||||
;
|
||||
; EXIT 'z' set if no character
|
||||
; 'z' clear if char
|
||||
; (al) = char
|
||||
|
||||
inchr: mov dx,UR_LSR
|
||||
in al,dx
|
||||
and al,1
|
||||
jz inchr1
|
||||
mov dx,UR_DAT
|
||||
in al,dx
|
||||
and al,07fh
|
||||
inchr1: ret
|
||||
|
||||
|
||||
PUBLIC putchar
|
||||
putchar PROC NEAR
|
||||
pushf
|
||||
cli
|
||||
push dx
|
||||
push cx
|
||||
push bx
|
||||
push ax ; (al) = character
|
||||
test iflag,255
|
||||
jnz putc1 ; is initialized
|
||||
inc iflag
|
||||
|
||||
; program the usart
|
||||
|
||||
mov dx,UR_LCR
|
||||
mov al,80h
|
||||
out dx,al ; command it
|
||||
sub al,al
|
||||
mov dx,UR_DLM
|
||||
out dx,al
|
||||
mov dx,UR_DLL
|
||||
mov al,12 ; 9600 baud = 12, 19.2 Kbaud = 6
|
||||
out dx,al
|
||||
mov al,3
|
||||
mov dx,UR_LCR
|
||||
out dx,al ; command normal mode
|
||||
|
||||
; see if CTL-Q or CTL-S
|
||||
|
||||
putc1: pushf
|
||||
cli
|
||||
call inchr
|
||||
jz putc3 ; no characters incomming
|
||||
cmp al,19 ; ctl-S?
|
||||
jnz putc3 ; no, ignore
|
||||
|
||||
; have ctl-s. wait till we see ctl-Q
|
||||
|
||||
putc2: call inchr
|
||||
jz putc2
|
||||
cmp al,17
|
||||
jnz putc2
|
||||
|
||||
putc3: popf
|
||||
mov dx,UR_LSR
|
||||
putc4: in al,dx
|
||||
test al,020h
|
||||
jz putc4
|
||||
|
||||
; ready. crank it out!
|
||||
|
||||
mov dx,UR_DAT
|
||||
|
||||
pop ax
|
||||
out dx,al
|
||||
|
||||
pop bx
|
||||
pop cx
|
||||
pop dx
|
||||
popf
|
||||
ret
|
||||
|
||||
putchar ENDP
|
||||
|
||||
ENDIF
|
Reference in New Issue
Block a user