]> cloudbase.mooo.com Git - z180-stamp-cpm3.git/blob - cbios/utils.180
Update IXON flag from character device table (@ctbl)
[z180-stamp-cpm3.git] / cbios / utils.180
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
87
88 cseg
89
90 ;--------------------------------------------------------------------
91 ; vectored CALL point
92
93 ijphl:
94 jp (hl)
95
96 dseg
97
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