1 ;*** Bugcode.inc - Debug code for including into sysini.asm and ibmbio.asm
3 ; Can't link in via buglib due to memory and relocation games played
4 ; by these modules. Each gets a private, local-only copy of these
11 ;** DPRINTF _ Debug Printf
13 ; Dprintf is a kernel debug print formatting package. It is intended
14 ; to produce conviently formatted output.
16 ; Dprintf is called, indirectly, by a macro:
18 ; DEBUG n,m,"string",<a1,...,an>
20 ; string = format string
24 ; The format string is an ASCIZ string which can contain 2 types of
25 ; specifications: data-format specifications and literal characters.
26 ; Data format specifications always begin with a '$' character; all
27 ; characters not part of a data format specification are treated as
31 ; - any character not part of a format specification. Special
32 ; non-printing characters are:
39 ; Format Specifications
41 ; A format specification takes the form:
46 ; x - print argument as a hex word
47 ; d - print argument as decimal word
48 ; c - print argument as ascii character
49 ; b - print argument as hex byte
50 ; For each of the above formats, the supplied argument
51 ; is a 16-bit word - the value to be printed. The optional @
52 ; (described below) allows a segmented address to be supplied,
55 ; s[nn] - print argument as asciz string; if optional decimal
56 ; argument follows the format character this specifys
57 ; a maximum string length. Non printing characters are
58 ; printed in the form \nnn where "nnn" is the octal byte
60 ; Note that this format character cannot be directly
61 ; followed by a digit unless that digit is to be taken
62 ; as the start of a length argument.
64 ; Bnn - print argument as hex bytes. The required following
65 ; decimal argument is the number of bytes to print.
67 ; Both of these formats take a long address as their argument.
68 ; The '@' character is thus invalid for these formats.
71 ; As befitting a debug routine, DPRINTF does not have a whole lot
72 ; of "failsafe" code in it. Supplying screwed up formats can
73 ; muck things up. Specifically:
74 ; The @ argument must NOT be specified with the 's' or 'B'
76 ; A string/byte-length argument of 0 is taken as 65536
77 ; The string "%% BAD FMT %%" appears in the output when
78 ; 1) an illegal format specifier is given, or
79 ; 2) the B format is given a 0 or missing length
81 ; ENTRY (sp+n ) = address of format string (offset from return cs value)
82 ; (sp+n-2) = first argument word
83 ; (sp+n-4) = second argument word
85 ; (sp+4 ) = last argument word
86 ; (sp+2 ) = seg of return address
87 ; (sp ) = offset of return address
88 ; (bp) = offset of format string on the stack
103 push ax ; save registers
106 mov si,[bp] ; get address of format string
109 mov ds,ss:20[bx] ; (ds:si) = address of format string
113 ; Scan format string for next character
115 ; (ds:si) = address of format string
116 ; (ss:bp) = address of next argument
118 dpf1: lodsb ; (al) = format string byte
122 je dpf4 ; is data escape
124 jnz dpf2 ; got the character
126 ; it's an "\" escape code - crack the argument character
130 je dpf3 ; all done, ignore hanging \
138 jmp SHORT dpf2 ; print LF
150 ; have the end of the format string - exit
164 ;* Have a '$' character - is data format escape
166 ; Get address of data into es:di
168 ; (bp) = address of data value
172 pop es ; (es:di) = address of data value
173 sub bp,2 ; point to next argument
174 lodsb ; (al) = format specifier
176 jne dpf5 ; not an indirect flag
178 sub bp,2 ; have an extra 2 for @
183 ; is 'x' format - print hex word
186 call THW ; type hex word
192 ; is 'd' format - print decimal word
195 call TDW ; type decimal word
201 ; is 'c' format - print character
210 ; is 'b' format - print hex byte
213 call THB ; type hex byte
219 ; is 's' format - print ASCIZ string. First, check for
220 ; optional decimal limit
223 SSB: sub cx,cx ; set 65536 limit
224 les di,[bp] ; (es:DI) = fwa of string
225 sub bp,2 ; argument to 's' was two words
228 jb dpfs2 ; not decimal
230 ja dpfs2 ; not decimal
231 call atod ; (ax) = decimal value, (ds:si) updated
234 ; print asciz string at es:di, max of (cx) characters
235 ; (cx) = 0 means max of 65536
237 ; Other sections of code in dpf jump here to print strings
239 dpfs2: mov al,es:[di]
244 loop dpfs2 ; continue if not at limit
248 je dpfbb2 ; is 'B' format
250 ; error in format code - print message
254 mov di,OFFSET dpfa ; (es:di) = error message
258 dpfa: DB '%% BAD FMT %%',0
262 dpfbb2: call atod ; (ax) = length specifier
263 jc dpferr ; number not there - error
265 jcxz dpferr ; number is 0 - error
266 les di,[bp] ; (es:DI) = fwa of string
267 sub bp,2 ; argument to 's' was two words
268 dpfbb3: mov al,es:[di]
269 call THB ; type hex byte
271 call putchar ; space em out
273 loop dpfbb3 ; do em all
279 ;** THB - Type Hex Byte
281 ; THB types a hex byte (via "putchar")
287 THBA DB '0123456789abcdef'
301 call putchar ; put first character
315 ;** THW - Type Hex Word
317 ; THW types a word in hex (via "putchar")
337 ;** TDW - Type Decimal Word
339 ; TDW types (via "putchar") the unsigned decimal representation
340 ; of a 16-bit unsigned integer. Only significant digits are
341 ; printed; if the number is 0 a "0" is printed.
343 ; ENTRY (AX) = number
350 push cx ; preserve registers
353 call tdw$ ; recurse cracking digits
361 ;* tdw$ - crack number recursively
363 ; tdw$ cracks the least significant decimal digit. If there
364 ; are no higher-significant digits, print and return.
365 ; else, recurse for higher digits
373 div cx ; (ax) = quotient, (dx) = remainder
375 jz tdw$1 ; this is highest-order, do it
388 ;** ATOD - Convert ASCII string to decimal number
390 ; ATOD is called to convert an ascii string of digits to a
391 ; decimal number. Digits are converted until we run out of them.
393 ; ENTRY (DS:SI) = address of first digit
394 ; EXIT 'C' clear if OK
396 ; (SI) updated to first non-digit
397 ; 'C' set if error - no digits, or result >65535
398 ; (DS:SI) points to error character
405 push cx ; save registers
408 jc atod9 ; error - no digits
411 jc atod9 ; error - no digits
412 sub ax,ax ; clear accumulator
417 ; (AX) = number accumulated so near
419 ; (DS:SI) = next character
421 atod1: xchg dx,ax ; keep accum in dx for a while
422 lodsb ; (al) = character
424 jc atod7 ; not digit - all done
426 ja atod7 ; not digit - all done
427 sub ah,ah ; (ax) = digit value (0 - 9)
430 mul cx ; (ax) = 10*accum
431 pop dx ; (dx) = digit to add
434 jmp atod1 ; go back for more
436 ; Done with number, all OK
439 ; (ds:si) = address+1 of first unused character
443 ; Done with number, error
446 atod8: dec si ; backup over non-decimal (or error) char
448 xchg ax,dx ; (ax) = number iff no error
449 pop dx ; restore registers
454 ;** putchar - put a character on the console
456 ; ENTRY (al) = character
461 UR_DAT = 02f8H ; COM1 = 03f8H, COM2 = 02f8H
462 UR_IEN = UR_DAT+1 ; Interrupt enable
463 UR_IER = UR_DAT+2 ; interrupt ID
464 UR_LCR = UR_DAT+3 ; line control registers
465 UR_MCR = UR_DAT+4 ; modem control register
466 UR_LSR = UR_DAT+5 ; line status register
467 UR_MSR = UR_DAT+6 ; modem status regiser
468 UR_DLL = UR_DAT ; divisor latch least sig
469 UR_DLM = UR_DAT+1 ; divisor latch most sig
471 iflag DB 0 ; != 0 when initialized 8250
473 ;* inchr - input character
475 ; EXIT 'z' set if no character
496 push ax ; (al) = character
498 jnz putc1 ; is initialized
505 out dx,al ; command it
510 mov al,12 ; 9600 baud = 12, 19.2 Kbaud = 6
514 out dx,al ; command normal mode
516 ; see if CTL-Q or CTL-S
521 jz putc3 ; no characters incomming
523 jnz putc3 ; no, ignore
525 ; have ctl-s. wait till we see ctl-Q
538 ; ready. crank it out!