1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
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
|