]> cloudbase.mooo.com Git - z180-stamp-cpm3.git/blame_incremental - cbios/utils.180
Extended drive table for use with DRIVE.COM, a dynamic drive re-assignment utility.
[z180-stamp-cpm3.git] / cbios / utils.180
... / ...
CommitLineData
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
15 public ?pchar,?pmsg ; print char <A>, print message (<HL>)\r
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
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
221 push hl ; put pointer to first message on stack\r
222 ld b,a ; save message number\r
223 or a\r
224 jr z,pdc_done\r
225 xor a\r
226pdc_skip:\r
227 bit 7,(hl)\r
228 inc hl\r
229 jr z,pdc_skip\r
230 cp (hl)\r
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
236 pop bc\r
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
253 ret\r
254\r
255;-------------------------------------------------------------------------------\r
256; print message inline up to a null\r
257; saves <BC>, <DE>, <HL>\r
258\r
259pr.inln:\r
260 ex (sp),hl\r
261 call ?pmsg\r
262 ex (sp),hl\r
263 ret\r
264\r
265;-------------------------------------------------------------------------------\r
266; print <CR><LF>\r
267; saves <BC>, <DE>, <HL>\r
268\r
269pr.crlf:\r
270 call pr.inln\r
271 dc cr,lf\r
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
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
306\r
307?pchar:\r
308 push bc\r
309 push de\r
310 push hl\r
311 ld c,a\r
312 call ?cono\r
313 pop hl\r
314 pop de\r
315 pop bc\r
316 ret\r
317\r
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
323; number is printed right-aligned\r
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
338; number is printed right-aligned\r
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
397 ld a,(@adrv)\r
398 add a,'A'\r
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
405 ld c,0\r
406 ld hl,(@trk)\r
407 call pr.dec ; track number\r
408 call pr.inln ; sector header\r
409 dc ', S-'\r
410 ld hl,(@sect)\r
411 jp pr.dec ; sector number\r
412\r
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
473 dc ' Retry (Y/N) ? '\r
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
481 dc ', Unknown op, '\r
482 dc ', Read, '\r
483 dc ', Write, '\r
484 db 0\r
485\r
486 end\r