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