]> cloudbase.mooo.com Git - z180-stamp-cpm3.git/blame - cbios/utils.180
refactor print utils
[z180-stamp-cpm3.git] / cbios / utils.180
CommitLineData
947c5868
L
1 title 'general utility routines'\r
2\r
3 ; i/o port init routines\r
4\r
5 public ioiniml,ioini1l ;\r
6\r
7 ; math\r
8\r
9 public ijphl ; vectored CALL point\r
10 public add_hla ; add a to hl\r
11 public div32_16,div32_r ; divide 32 bit by 16 bit number (rounded)\r
12\r
13 ; print utils\r
14\r
e8a98308 15 public ?pchar,?pmsg ; print char <A>, print message (<HL>)\r
947c5868
L
16 public pr.idx ; print message from table indexed by <A>\r
17 public pr.inln,pr.crlf ; print message inline, print newline\r
18 public phex2,phex4 ; print 2 digit hex <A> or 4 digit hex <HL>\r
19 public pr.dec,pr.decl ; print 16 or 32 bit decimal number\r
20 public pr.errors ; print BIOS disk error message header\r
21\r
22\r
23\r
24 extrn ?const,?conin,?cono\r
25 extrn @adrv,@trk,@sect ; used by disk error message\r
26 extrn @op,@ermde\r
27\r
28;-------------------------------------------------------------------------------\r
29\r
30cr equ 13\r
31lf equ 10\r
32bell equ 7\r
33\r
34\r
35 dseg\r
36\r
37;----------------------------------------------------------------------\r
38; output bytes to consecutive portaddresses\r
39;\r
40; hl: table with following structure:\r
41; db n, port1, val1, val2,... valn\r
42; db m, port1, val1, val2,... valm\r
43; ...\r
44; db 0 ; Terminate table\r
45\r
46ioiniml:\r
47 push bc\r
48 xor a\r
49ioml_lp:\r
50 ld b,(hl)\r
51 inc hl\r
52 cp b\r
53 jr z,ioml_e\r
54\r
55 ld c,(hl)\r
56 inc hl\r
57 otimr\r
58 jr ioml_lp\r
59ioml_e:\r
60 pop bc\r
61 ret\r
62\r
63;----------------------------------------------------------------------\r
64; output bytes to ports\r
65;\r
66; hl: tables of port,value pairs:\r
67; db n, port1,val1, port2,val2,... portn,valn\r
68; ...\r
69; db 0 ; Terminate table\r
70\r
71ioini1l:\r
72 push bc\r
73 jr io1_nxt\r
74io1_lp:\r
75 ld c,(hl) ;port address\r
76 inc hl\r
77 otim\r
78 jr nz,io1_lp\r
79io1_nxt:\r
80 ld b,(hl) ;count\r
81 inc hl\r
82 inc b\r
83 djnz io1_lp\r
84\r
85 pop bc\r
86 ret\r
87\r
88 cseg\r
89\r
90;--------------------------------------------------------------------\r
91; vectored CALL point\r
92\r
93ijphl:\r
94 jp (hl)\r
95\r
96 dseg\r
97\r
98;--------------------------------------------------------------------\r
99; add a to hl\r
100;\r
101; return:\r
102; hl = hl + a\r
103; Flags undefined\r
104\r
105add_hla:\r
106 add a,l\r
107 ld l,a\r
108 ret nc\r
109 inc h\r
110 ret\r
111\r
112;--------------------------------------------------------------------\r
113; rounded div 32 by 16 bit\r
114;\r
115; DEHL: Dividend (x)\r
116; BC: Divisor (y)\r
117; return:\r
118; HLDE: Rounded Quotient (q)\r
119; BC: Remainder (r)\r
120\r
121div32_r:\r
122 push bc\r
123 srl b ;y/2\r
124 rr c\r
125 add hl,bc ;low x + y/2\r
126 pop bc\r
127 jr nc,div_r1\r
128 inc de\r
129div_r1:\r
130 ;fall thru\r
131\r
132;--------------------------------------------------------------------\r
133; Divide 32 bit by 16\r
134;\r
135; DEHL: Dividend (x)\r
136; BC: Divisor (y)\r
137;\r
138; return:\r
139; DEHL: Quotient\r
140; BC: Reminder\r
141\r
142div32_16:\r
143 exx ;low\r
144 push de ;save alternate registers (de,bc)\r
145 push bc\r
146 exx ;high\r
147 push hl ;lx\r
148 push bc ;ly\r
149 ld bc,0 ;bc = hy = 0\r
150 ld h,b ;hl = hr = 0\r
151 ld l,c\r
152 ;de = x, hl = r\r
153 exx ;low\r
154 pop bc ;bc' = ly\r
155 ex (sp),hl ;hl' = lx, save alternate hl\r
156 ld de,0 ;de' = lr = 0\r
157 ex de,hl ;de = x, hl = r\r
158 exx ;high\r
159 ld a,32 ;count\r
160;\r
161; start:\r
162; de: x (de: hx, de': lx)\r
163; bc: y (bc: hy, bc': ly)\r
164; hl: 0\r
165;\r
166div_lp: ;do\r
167 exx ; low\r
168 ex de,hl ; x\r
169 add hl,hl ; x <<= 1\r
170 exx ; high\r
171 ex de,hl ; x\r
172 adc hl,hl ; x <<= 1\r
173 exx ; low\r
174 ex de,hl ; r\r
175 adc hl,hl ; r <<= 1\r
176 exx ; high\r
177 ex de,hl ; r\r
178 adc hl,hl ; r <<= 1\r
179 exx ; low\r
180 inc de ; x/q += 1\r
181 or a ;\r
182 sbc hl,bc ;\r
183 exx ; high\r
184 sbc hl,bc ;\r
185 jr nc,div_no_restore\r
186 exx ; low\r
187 dec de ;\r
188 add hl,bc ; r += y\r
189 exx ; high\r
190 adc hl,bc ;\r
191\r
192div_no_restore: ;\r
193 dec a ;\r
194 jr nz,div_lp ;while (--count)\r
195\r
196; result:\r
197; de: q (de: hq, de': lq)\r
198; hl: r (hl: hr, hl': lr)\r
199\r
200 exx ;low\r
201 ex de,hl ;hl = lq, de = lr\r
202\r
203 ex (sp),hl ;lq\r
204 push de ;lr\r
205 exx ;high\r
206 pop bc ;bc = lr\r
207 pop hl ;de = lq\r
208\r
209 exx ;low\r
210 pop bc ;restore alternate registers\r
211 pop de\r
212 exx ;high\r
213 ret\r
214\r
947c5868
L
215;-------------------------------------------------------------------------------\r
216; print message from table @<HL>, indexed by <A>\r
217; saves <BC> & <DE>\r
218\r
219pr.idx:\r
220 push bc\r
947c5868 221 push hl ; put pointer to first message on stack\r
e8a98308
L
222 ld b,a ; save message number\r
223 or a\r
224 jr z,pdc_done\r
947c5868 225 xor a\r
e8a98308
L
226pdc_skip:\r
227 bit 7,(hl)\r
228 inc hl\r
229 jr z,pdc_skip\r
947c5868 230 cp (hl)\r
e8a98308
L
231 jr z,pdc_done ; End of List, msg not found. Print first msg.\r
232 djnz pdc_skip\r
233 ex (sp),hl ; Remove first msg from stack\r
234pdc_done:\r
235 pop hl ; Get msg. to print\r
947c5868 236 pop bc\r
e8a98308
L
237 ;fall thru\r
238\r
239;-------------------------------------------------------------------------------\r
240; print message @<HL> up to a null\r
241; saves <BC> & <DE>\r
242\r
243?pmsg:\r
244 ld a,(hl)\r
245 inc hl\r
246 and 07fh\r
247 ret z\r
248 call ?pchar\r
249 dec hl\r
250 bit 7,(hl)\r
251 inc hl\r
252 jr z,?pmsg\r
947c5868
L
253 ret\r
254\r
255;-------------------------------------------------------------------------------\r
256; print message inline up to a null\r
e8a98308 257; saves <BC>, <DE>, <HL>\r
947c5868
L
258\r
259pr.inln:\r
260 ex (sp),hl\r
947c5868 261 call ?pmsg\r
947c5868
L
262 ex (sp),hl\r
263 ret\r
264\r
265;-------------------------------------------------------------------------------\r
266; print <CR><LF>\r
e8a98308 267; saves <BC>, <DE>, <HL>\r
947c5868
L
268\r
269pr.crlf:\r
270 call pr.inln\r
e8a98308 271 dc cr,lf\r
947c5868
L
272 ret\r
273\r
274;-------------------------------------------------------------------------------\r
275; print hl as a 4 digit hexadecimal number\r
276; saves all registers\r
277\r
278phex4:\r
279 ld a,h\r
280 call phex2\r
281 ld a,l\r
282 ; fall thru\r
283\r
284;-------------------------------------------------------------------------------\r
285; print a as a 2 digit hexadecimal number\r
286; saves all registers\r
287\r
288phex2:\r
289 push af\r
290 rra\r
291 rra\r
292 rra\r
293 rra\r
294 call print.digit\r
295 pop af\r
296\r
297print.digit:\r
e8a98308
L
298 daa\r
299 add a,0a0h\r
300 adc a,040h\r
301 ;fall thru\r
302\r
303;-------------------------------------------------------------------------------\r
304; print character in a\r
305; saves <BC>, <DE>, <HL>\r
947c5868 306\r
e8a98308
L
307?pchar:\r
308 push bc\r
309 push de\r
310 push hl\r
947c5868
L
311 ld c,a\r
312 call ?cono\r
947c5868 313 pop hl\r
e8a98308
L
314 pop de\r
315 pop bc\r
947c5868
L
316 ret\r
317\r
947c5868
L
318;-------------------------------------------------------------------------------\r
319; print decimal 16 bit number from HL\r
320;\r
321; HL: unsigned binary number to print\r
322; C: minimum print field width\r
e8a98308 323; number is printed right-aligned\r
947c5868
L
324; B: pad character, typically ' ' or '0'\r
325\r
326pr.dec:\r
327 push de\r
328 ld de,0\r
329 call pr.decl\r
330 pop de\r
331 ret\r
332\r
333;-------------------------------------------------------------------------------\r
334; print decimal 32 bit number from DEHL\r
335;\r
336; DEHL: unsigned binary number to print\r
337; C: minimum print field width\r
e8a98308 338; number is printed right-aligned\r
947c5868
L
339; B: pad character, typically ' ' or '0'\r
340\r
341pr.decl:\r
342 push bc ;save width and fillchar\r
343 push bc\r
344 exx ;(alt)\r
345 ex (sp),hl ;save hl', get width and fill\r
346 push de ;save de'\r
347\r
348 xor a\r
349 ld d,a ;clear counter\r
350 ld e,a\r
351 push af ; string terminator\r
352 inc sp\r
353\r
354prd_divloop: ;do\r
355 exx ; (main)\r
356 ld bc,10 ;\r
357 call div32_16 ; get a digit\r
358 ld a,c ;\r
359 add a,'0' ; make it printable\r
360 push af ;\r
361\r
362 ld a,h ;\r
363 or l ;\r
364 or d ;\r
365 or e ;\r
366 exx ; (alt)\r
367 inc sp ;\r
368 inc de ;\r
369 jr nz,prd_divloop ;\r
370\r
371prd_filloop: ;h=filler, l=field width\r
372 ld a,e\r
373 cp l\r
374 jr nc,prd_out\r
375 push hl\r
376 inc sp\r
377 inc de\r
378 jr prd_filloop\r
379prd_out:\r
380 ld hl,0\r
381 add hl,sp ;ptr to beginning of number string (hl==0 here)\r
382 call ?pmsg\r
383 ex de,hl\r
384 add hl,sp\r
385 ld sp,hl\r
386 inc sp ;remove string terminator\r
387 pop de\r
388 pop hl\r
389 exx ;(main)\r
390 pop bc\r
391 ret\r
392\r
393\r
394;-------------------------------------------------------------------------------\r
395\r
396?pderr:\r
947c5868
L
397 ld a,(@adrv)\r
398 add a,'A'\r
e8a98308
L
399 ld (msg_drv),a\r
400 call pr.inln ; error header\r
401 db cr,lf,bell,'BIOS Error on '\r
402msg_drv:\r
403 db 'A'\r
404 dc ': T-'\r
947c5868
L
405 ld c,0\r
406 ld hl,(@trk)\r
407 call pr.dec ; track number\r
e8a98308
L
408 call pr.inln ; sector header\r
409 dc ', S-'\r
947c5868
L
410 ld hl,(@sect)\r
411 jp pr.dec ; sector number\r
412\r
947c5868
L
413;-------------------------------------------------------------------------------\r
414; get console input, echo it, and shift to upper case\r
415; save hl,de,bc\r
416\r
417uciecho:\r
418 push hl\r
419 push de\r
420 push bc\r
421u$c0:\r
422 call ?const\r
423 or a\r
424 jr z,u$c1 ; see if any char already struck\r
425 call ?conin\r
426 jr u$c0 ; yes, eat it and try again\r
427u$c1:\r
428 call ?conin\r
429 push af\r
430 ld c,a\r
431 cp ' '-1\r
432 call nc,?cono\r
433 pop af\r
434 pop bc\r
435 pop de\r
436 pop hl\r
437 cp 'a'\r
438 ret c\r
439 sub 'a'-'A' ; make upper case\r
440 ret\r
441\r
442;-------------------------------------------------------------------------------\r
443;\r
444\r
445pr.errors:\r
446\r
447 ; suppress error message if BDOS\r
448 ; is returning errors to application...\r
449\r
450 ld a,(@ermde)\r
451 inc a\r
452 jr nz,pre1\r
453 dec a ;return NZ, if @ermde == 0FFH\r
454 ret\r
455pre1:\r
456 push hl\r
457 ld hl,pre2\r
458 ex (sp),hl\r
459 push hl\r
460\r
461 ; Had permanent error, print message like:\r
462 ; BIOS Err on d: T-nn, S-mm, <operation> <type>, Retry ?\r
463\r
464 call ?pderr ; print message header\r
465\r
466 ld hl,op$msg\r
467 ld a,(@op)\r
468 jp pr.idx ; last function (read or write)\r
469\r
470pre2:\r
471 ; prompt for retry\r
472 call pr.inln\r
e8a98308 473 dc ' Retry (Y/N) ? '\r
947c5868
L
474\r
475 call uciecho ; get operator response\r
476 cp 'Y'\r
477 ret ; return Z-flag for yes\r
478\r
479\r
480op$msg:\r
e8a98308
L
481 dc ', Unknown op, '\r
482 dc ', Read, '\r
483 dc ', Write, '\r
947c5868
L
484 db 0\r
485\r
486 end\r