summaryrefslogtreecommitdiff
path: root/v4.0-ozzie/bin/DISK2/BIOS/BUGCODE.INC
blob: 4a87725bb84bc074a686ac18498f5e59067679e8 (plain) (blame)
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