]> cloudbase.mooo.com Git - z180-stamp-cpm3.git/blob - cbios/bioskrnl.180
show cpu clock frequency at startup
[z180-stamp-cpm3.git] / cbios / bioskrnl.180
1 title 'Root module of relocatable BIOS for CP/M 3.0'
2
3 ; version 1.0 15 Sept 82
4
5 include config.inc
6 include z180reg.inc
7
8
9 ; Copyright (C), 1982
10 ; Digital Research, Inc
11 ; P.O. Box 579
12 ; Pacific Grove, CA 93950
13
14
15 ; This is the invariant portion of the modular BIOS and is
16 ; distributed as source for informational purposes only.
17 ; All desired modifications should be performed by
18 ; adding or changing externally defined modules.
19 ; This allows producing "standard" I/O modules that
20 ; can be combined to support a particular system
21 ; configuration.
22
23 cr equ 13
24 lf equ 10
25 bell equ 7
26 ctlQ equ 'Q'-'@'
27 ctlS equ 'S'-'@'
28
29 ccp equ 0100h ; Console Command Processor gets loaded
30 ; into the TPA
31
32 cseg ; GENCPM puts CSEG stuff in common memory
33
34
35 ; variables in system data page
36
37 extrn @covec,@civec,@aovec,@aivec,@lovec ; I/O redirection vectors
38 extrn @mxtpa ; addr of system entry point
39 extrn @bnkbf ; 128 byte scratch buffer
40
41 ; initialization
42
43 extrn hwinit,?init ; general initialization and signon
44 extrn ?ldccp,?rlccp ; load & reload CCP for BOOT & WBOOT
45
46 ; user defined character I/O routines
47
48 extrn ?ci,?co,?cist,?cost ; each take device in <B>
49 extrn ?cinit ; (re)initialize device in <C>
50 extrn @ctbl ; physical character device table
51
52 ; disk communication data items
53
54 extrn @dtbl ; table of pointers to XDPHs
55 public @adrv,@rdrv,@trk,@sect ; parameters for disk I/O
56 public @dma,@dbnk,@cnt ; '' '' '' ''
57
58 ; memory control
59
60 public @cbnk ; current bank
61 extrn ?xmove,?move ; select move bank, and block move
62 extrn ?bank ; select CPU bank
63
64 ; clock support
65
66 extrn ?time ; signal time operation
67
68 ; general utility routines
69
70 public ?pmsg ; print message
71 public pr.dec,pr.decl ; print 16 or 32 bit decimal number
72 public ?pderr ; print BIOS disk error message header
73 public pr.inln,pr.crlf ; print message inline
74 public phex4,phex2 ; print 4 digit hex (HL), or 2 digit hex (A)
75
76 extrn div32_16 ; divide 32 bit by 16 bit number
77
78 include modebaud.inc ; define mode bits
79
80
81 ; External names for BIOS entry points
82
83 public ?boot,?wboot,?const,?conin,?cono,?list,?auxo,?auxi
84 public ?home,?sldsk,?sttrk,?stsec,?stdma,?read,?write
85 public ?lists,?sctrn
86 public ?conos,?auxis,?auxos,?dvtbl,?devin,?drtbl
87 public ?mltio,?flush,?mov,?tim,?bnksl,?stbnk,?xmov
88
89 public bs$stack
90
91
92 ; BIOS Jump vector.
93
94 ; All BIOS routines are invoked by calling these
95 ; entry points.
96
97 ?boot: jp boot ; initial entry on cold start
98 ?wboot: jp wboot ; reentry on program exit, warm start
99
100 ?const: jp const ; return console input status
101 ?conin: jp conin ; return console input character
102 ?cono: jp conout ; send console output character
103 ?list: jp list ; send list output character
104 ?auxo: jp auxout ; send auxiliary output character
105 ?auxi: jp auxin ; return auxiliary input character
106
107 ?home: jp home ; set disks to logical home
108 ?sldsk: jp seldsk ; select disk drive, return disk parameter info
109 ?sttrk: jp settrk ; set disk track
110 ?stsec: jp setsec ; set disk sector
111 ?stdma: jp setdma ; set disk I/O memory address
112 ?read: jp read ; read physical block(s)
113 ?write: jp write ; write physical block(s)
114
115 ?lists: jp listst ; return list device status
116 ?sctrn: jp sectrn ; translate logical to physical sector
117
118 ?conos: jp conost ; return console output status
119 ?auxis: jp auxist ; return aux input status
120 ?auxos: jp auxost ; return aux output status
121 ?dvtbl: jp devtbl ; return address of device def table
122 ?devin: jp ?cinit ; change baud rate of device
123
124 ?drtbl: jp getdrv ; return address of disk drive table
125 ?mltio: jp multio ; set multiple record count for disk I/O
126 ?flush: jp flush ; flush BIOS maintained disk caching
127
128 ?mov: jp ?move ; block move memory to memory
129 ?tim: jp ?time ; Signal Time and Date operation
130 ?bnksl: jp bnksel ; select bank for code execution and default DMA
131 ?stbnk: jp setbnk ; select different bank for disk I/O DMA operations
132 ?xmov: jp ?xmove ; set source and destination banks for one operation
133
134 jp 0 ; reserved for future expansion
135 jp 0 ; reserved for future expansion
136 jp 0 ; reserved for future expansion
137
138
139 ; BOOT
140 ; Initial entry point for system startup.
141
142 dseg ; this part can be banked
143
144 boot:
145 ld sp,bs$stack
146
147 call hwinit ; first time hardware initialisation
148
149 ld bc,16*256 + 0 ; initialize all 16 character devices
150 c$init$loop:
151 push bc
152 call ?cinit
153 pop bc
154 inc c
155 djnz c$init$loop
156
157 call ?init ; perform any additional system initialization
158 ; and print signon message
159
160 ld bc,16*256+0
161 ld hl,@dtbl ; init all 16 logical disk drives
162 d$init$loop:
163 push bc ; save remaining count and abs drive
164 ld e,(hl)
165 inc hl
166 ld d,(hl)
167 inc hl ; grab @drv entry
168 ld a,e
169 or d
170 jr z,d$init$next ; if null, no drive
171 push hl ; save @drv pointer
172 if 0
173 ex de,hl ; XDPH address in <HL>
174 dec hl
175 dec hl
176 ld b,(hl) ; get relative drive code
177 ld (@ADRV),bc ; save absolute and relative drive code
178 dec hl ; point to init pointer
179 ld d,(hl)
180 dec hl
181 ld e,(hl) ; get init pointer
182 ex de,hl
183 call ipchl ; call init routine
184 else
185 push de
186 pop ix
187 ld b,(ix-2)
188 ld (@ADRV),bc ; save absolute and relative drive code
189 ld l,(ix-4)
190 ld h,(ix-3) ; get init pointer
191 call ipchl ; call init routine
192 endif
193 pop hl ; recover @drv pointer
194 d$init$next:
195 pop bc ; recover counter and drive #
196 inc c
197 djnz d$init$loop ; and loop for each drive
198 jp boot$1
199
200 cseg ; following in resident memory
201
202 boot$1:
203 call set$jumps
204 call ?ldccp ; fetch CCP for first time
205 jp ccp
206
207
208 ; WBOOT
209 ; Entry for system restarts.
210
211 wboot:
212 ld sp,bs$stack
213 call set$jumps ; initialize page zero
214 call ?rlccp ; reload CCP
215 jp ccp ; then reset jmp vectors and exit to ccp
216
217
218 set$jumps:
219
220 if banked
221 ld a,1
222 call ?bnksl
223 endif
224
225 ld a,0C3h ; jp opcode
226 ld (0),a
227 ld (5),a ; set up jumps in page zero
228 ld hl,?wboot
229 ld (1),hl ; BIOS warm start entry
230 ld hl,(@MXTPA)
231 ld (6),hl ; BDOS system call entry
232 ret
233
234
235 ds 64
236 bs$stack equ $
237
238
239 ; DEVTBL
240 ; Return address of character device table
241
242 devtbl:
243 ld hl,@ctbl
244 ret
245
246
247 ; GETDRV
248 ; Return address of drive table
249
250 getdrv:
251 ld hl,@dtbl
252 ret
253
254
255
256 ; CONOUT
257 ; Console Output. Send character in <C>
258 ; to all selected devices
259
260 conout:
261
262 ld hl,(@covec) ; fetch console output bit vector
263 jr out$scan
264
265
266 ; AUXOUT
267 ; Auxiliary Output. Send character in <C>
268 ; to all selected devices
269
270 auxout:
271 ld hl,(@aovec) ; fetch aux output bit vector
272 jr out$scan
273
274
275 ; LIST
276 ; List Output. Send character in <C>
277 ; to all selected devices.
278
279 list:
280 ld hl,(@lovec) ; fetch list output bit vector
281
282 out$scan:
283 ld b,0 ; start with device 0
284 co$next:
285 add hl,hl ; shift out next bit
286 jr nc,not$out$device
287 push hl ; save the vector
288 push bc ; save the count and character
289 not$out$ready:
290 call coster
291 or a
292 jp z,not$out$ready
293 pop bc
294 push bc ; restore and resave the character and device
295 call ?co ; if device selected, print it
296 pop bc ; recover count and character
297 pop hl ; recover the rest of the vector
298 not$out$device:
299 inc b ; next device number
300 ld a,h
301 or l ; see if any devices left
302 jr nz,co$next ; and go find them...
303 ret
304
305
306 ; CONOST
307 ; Console Output Status. Return true if
308 ; all selected console output devices
309 ; are ready.
310
311 conost:
312 ld hl,(@covec) ; get console output bit vector
313 jr ost$scan
314
315
316 ; AUXOST
317 ; Auxiliary Output Status. Return true if
318 ; all selected auxiliary output devices
319 ; are ready.
320
321 auxost:
322 ld hl,(@aovec) ; get aux output bit vector
323 jr ost$scan
324
325
326 ; LISTST
327 ; List Output Status. Return true if
328 ; all selected list output devices
329 ; are ready.
330
331 listst:
332 ld hl,(@lovec) ; get list output bit vector
333
334 ost$scan:
335 ld b,0 ; start with device 0
336 cos$next:
337 add hl,hl ; check next bit
338 push hl ; save the vector
339 push bc ; save the count
340 ld a,0FFh ; assume device ready
341 call c,coster ; check status for this device
342 pop bc ; recover count
343 pop hl ; recover bit vector
344 or a ; see if device ready
345 ret z ; if any not ready, return false
346 inc b ; drop device number
347 ld a,h
348 or l ; see if any more selected devices
349 jr nz,cos$next
350 or 0FFh ; all selected were ready, return true
351 ret
352
353 ; check for output device ready, including optional
354 ; xon/xoff support
355 coster:
356 ld l,b
357 ld h,0 ; make device code 16 bits
358 push hl ; save it in stack
359 add hl,hl
360 add hl,hl
361 add hl,hl ; create offset into device characteristics tbl
362 ld de,@ctbl+6
363 add hl,de ; make address of mode byte
364 ld a,(hl)
365 and mb$xon$xoff
366 pop hl ; recover console number in <HL>
367 jp z,?cost ; not a xon device, go get output status direct
368 ld de,xofflist
369 add hl,de ; make pointer to proper xon/xoff flag
370 call cist1 ; see if this keyboard has character
371 ld a,(hl)
372 call nz,ci1 ; get flag or read key if any
373 cp ctlq
374 jr nz,not$q ; if its a ctl-Q,
375 ld a,0FFh ; set the flag ready
376 not$q:
377 cp ctls
378 jr nz,not$s ; if its a ctl-S,
379 ld a,00h ; clear the flag
380 not$s:
381 ld (hl),a ; save the flag
382 call cost1 ; get the actual output status,
383 and (hl) ; and mask with ctl-Q/ctl-S flag
384 ret ; return this as the status
385
386 cist1: ; get input status with <BC> and <HL> saved
387 push bc
388 push hl
389 call ?cist
390 pop hl
391 pop bc
392 or a
393 ret
394
395 cost1: ; get output status, saving <BC> & <HL>
396 push bc
397 push hl
398 call ?cost
399 pop hl
400 pop bc
401 or a
402 ret
403
404 ci1: ; get input, saving <BC> & <HL>
405 push bc
406 push hl
407 call ?ci
408 pop hl
409 pop bc
410 ret
411
412
413 ; CONST
414 ; Console Input Status. Return true if
415 ; any selected console input device
416 ; has an available character.
417
418 const:
419 ld hl,(@civec) ; get console input bit vector
420 jr ist$scan
421
422
423 ; AUXIST
424 ; Auxiliary Input Status. Return true if
425 ; any selected auxiliary input device
426 ; has an available character.
427
428 auxist:
429 ld hl,(@aivec) ; get aux input bit vector
430
431 ist$scan:
432 ld b,0 ; start with device 0
433 cis$next:
434 add hl,hl ; check next bit
435 ld a,0 ; assume device not ready
436 call c,cist1 ; check status for this device
437 or a
438 ret nz ; if any ready, return true
439 inc b ; next device number
440 ld a,h
441 or l ; see if any more selected devices
442 jr nz,cis$next
443 xor a ; all selected were not ready, return false
444 ret
445
446
447 ; CONIN
448 ; Console Input. Return character from first
449 ; ready console input device.
450
451 conin:
452 ld hl,(@civec)
453 jr in$scan
454
455
456 ; AUXIN
457 ; Auxiliary Input. Return character from first
458 ; ready auxiliary input device.
459
460 auxin:
461 ld hl,(@aivec)
462
463 in$scan:
464 push hl ; save bit vector
465 ld b,0
466 ci$next:
467 add hl,hl ; shift out next bit
468 ld a,0 ; insure zero a (nonexistant device not ready).
469 call c,cist1 ; see if the device has a character
470 or a
471 jr nz,ci$rdy ; this device has a character
472 inc b ; else, next device
473 ld a,h
474 or l ; see if any more devices
475 jr nz,ci$next ; go look at them
476 pop hl ; recover bit vector
477 jr in$scan ; loop til we find a character
478
479 ci$rdy:
480 pop hl ; discard extra stack
481 jp ?ci
482
483
484 ;-------------------------------------------------------------------------------
485 ; Utility Subroutines
486
487
488 ipchl: ; vectored CALL point
489 jp (hl)
490
491
492 ;-------------------------------------------------------------------------------
493 ; print message @<HL> up to a null
494 ; saves <BC> & <DE>
495
496 ?pmsg:
497 push bc
498 push de
499 pmsg$loop:
500 ld a,(hl)
501 or a
502 jr z,pmsg$exit
503 ld c,a
504 push hl
505 call ?cono
506 pop hl
507 inc hl
508 jr pmsg$loop
509 pmsg$exit:
510 pop de
511 pop bc
512 ret
513
514 ;-------------------------------------------------------------------------------
515 ; print message inline up to a null
516 ; saves all registers
517
518 pr.inln:
519 ex (sp),hl
520 push af
521 call ?pmsg
522 pop af
523 ex (sp),hl
524 ret
525
526 ;-------------------------------------------------------------------------------
527 ; print <CR><LF>
528 ; saves all registers
529
530 pr.crlf:
531 call pr.inln
532 db 13,10,0
533 ret
534
535 ;-------------------------------------------------------------------------------
536 ; print hl as a 4 digit hexadecimal number
537 ; saves all registers
538
539 phex4:
540 ld a,h
541 call phex2
542 ld a,l
543 ; fall thru
544
545 ;-------------------------------------------------------------------------------
546 ; print a as a 2 digit hexadecimal number
547 ; saves all registers
548
549 phex2:
550 push af
551 rra
552 rra
553 rra
554 rra
555 call print.digit
556 pop af
557
558 print.digit:
559 push hl
560 push de
561 push bc
562 push af
563 and 00fh
564 cp 10
565 jr c,prd_1
566 add a,007h
567 prd_1:
568 add a,'0'
569
570 ld c,a
571 call ?cono
572 pop af
573 pop bc
574 pop de
575 pop hl
576 ret
577
578
579 if 0
580
581 ;-------------------------------------------------------------------------------
582 ; print 16 bit number from HL
583 ;
584
585 pr.dec:
586 ex de,hl
587 ld hl,0
588 ;fall thru
589
590 pr.decl:
591 push ix
592 ld ix,1 ; count chars on stack
593 push bc
594 exx
595 ex (sp),hl
596 ; push de
597 ; push bc
598 exx
599
600 xor a
601 push af ; string terminator
602 inc sp
603 prd_divloop:
604 ld bc,10
605 call div32_16 ; get a digit
606 ld a,c
607 add a,'0' ; make it printable
608 push af
609 inc sp
610 inc ix
611
612 ld a,h
613 or l
614 or d
615 or e
616 jr nz,prd_divloop
617 exx
618 push hl
619 exx
620 pop bc ;b=filler, c=field width
621 inc c
622 push ix
623 pop de
624 prd_filloop:
625 ld a,e
626 cp c
627 jr nc,prd_out
628 push bc
629 inc sp
630 inc de
631 jr prd_filloop
632 prd_out:
633 ld hl,0
634 add hl,sp ;ptr to beginning of number string (hl==0 here)
635 call ?pmsg
636 ex de,hl
637 add hl,sp
638 ld sp,hl
639 exx
640 pop hl
641 exx
642 pop ix
643 ret
644
645 endif
646
647 ;-------------------------------------------------------------------------------
648 ; print 16 bit number from HL
649 ;
650
651 pr.dec:
652 ex de,hl
653 ld hl,0
654 ;fall thru
655
656 pr.decl:
657 push bc ;save width and fillchar
658 push bc
659 exx
660 ex (sp),hl ;save hl', get width and fill
661 push de ;save de'
662
663 xor a
664 ld d,a ;clear counter
665 ld e,a
666 push af ; string terminator
667 inc sp
668
669 prd_divloop: ;do
670 exx ; (main)
671 ld bc,10 ;
672 call div32_16 ; get a digit
673 ld a,c ;
674 add a,'0' ; make it printable
675 push af ;
676
677 ld a,h ;
678 or l ;
679 or d ;
680 or e ;
681 exx ; (alt)
682 inc sp ;
683 inc de ;
684 jr nz,prd_divloop ;
685
686 prd_filloop: ;h=filler, l=field width
687 ld a,e
688 cp l
689 jr nc,prd_out
690 push hl
691 inc sp
692 inc de
693 jr prd_filloop
694 prd_out:
695 ld hl,0
696 add hl,sp ;ptr to beginning of number string (hl==0 here)
697 call ?pmsg
698 ex de,hl
699 add hl,sp
700 ld sp,hl
701 inc sp ;remove string terminator
702 pop de
703 pop hl
704 exx ;(main)
705 pop bc
706 ret
707
708
709 ;-------------------------------------------------------------------------------
710 ;
711 ?pderr:
712 ld hl,drive$msg
713 call ?pmsg ; error header
714 ld a,(@adrv)
715 add a,'A'
716 ld c,a
717 call ?cono ; drive code
718 ld hl,track$msg
719 call ?pmsg ; track header
720 ld c,0
721 ld hl,(@trk)
722 call pr.dec ; track number
723 ld hl,sector$msg
724 call ?pmsg ; sector header
725 ld hl,(@sect)
726 call pr.dec ; sector number
727 ret
728
729
730 ; BNKSEL
731 ; Bank Select. Select CPU bank for further execution.
732
733 bnksel:
734 ld (@cbnk),a ; remember current bank
735 jp ?bank ; and go exit through users
736 ; physical bank select routine
737
738
739 xofflist:
740 db -1,-1,-1,-1,-1,-1,-1,-1 ; ctl-s clears to zero
741 db -1,-1,-1,-1,-1,-1,-1,-1
742
743
744
745 dseg ; following resides in banked memory
746
747
748
749 ; Disk I/O interface routines
750
751
752 ; SELDSK
753 ; Select Disk Drive. Drive code in <C>.
754 ; Invoke login procedure for drive
755 ; if this is first select. Return
756 ; address of disk parameter header
757 ; in <HL>
758
759 seldsk:
760 ld a,c ; save drive select code
761 ld (@adrv),a
762 ld b,0 ; create index from drive code
763 ld hl,@dtbl
764 add hl,bc ; get pointer to dispatch table
765 add hl,bc
766 ld a,(hl)
767 inc hl
768 ld h,(hl)
769 ld l,a ; point at disk descriptor
770 ld (@xdph),hl ; save descriptor pointer
771 or h
772 ret z ; if no entry in table, no disk
773
774 ld a,e ; examine login bit
775 and 1
776 ret nz
777
778 push ix
779 ld ix,(@xdph)
780 ld a,(ix-2)
781 ld (@RDRV),a ; get relative drive
782 ld l,(ix-6) ; get address of LOGIN routine
783 ld h,(ix-5)
784 ex (sp),ix
785 pop de
786 call ipchl ; call LOGIN
787 ld hl,(@xdph) ; recover DPH pointer
788 ret
789
790
791 ; HOME
792 ; Home selected drive. Treated as SETTRK(0).
793
794 home:
795 ld bc,0 ; same as set track zero
796
797
798 ; SETTRK
799 ; Set Track. Saves track address from <BC>
800 ; in @TRK for further operations.
801
802 settrk:
803 ld (@trk),bc
804 ret
805
806
807 ; SETSEC
808 ; Set Sector. Saves sector number from <BC>
809 ; in @sect for further operations.
810
811 setsec:
812 ld (@sect),bc
813 ret
814
815
816 ; SETDMA
817 ; Set Disk Memory Address. Saves DMA address
818 ; from <BC> in @DMA and sets @DBNK to @CBNK
819 ; so that further disk operations take place
820 ; in current bank.
821
822 setdma:
823 ld (@dma),bc
824
825 ld a,(@cbnk) ; default DMA bank is current bank
826 ; fall through to set DMA bank
827
828 ; SETBNK
829 ; Set Disk Memory Bank. Saves bank number
830 ; in @DBNK for future disk data
831 ; transfers.
832
833 setbnk:
834 ld (@dbnk),a
835 ret
836
837
838 ; SECTRN
839 ; Sector Translate. Indexes skew table in <DE>
840 ; with sector in <BC>. Returns physical sector
841 ; in <HL>. If no skew table (<DE>=0) then
842 ; returns physical=logical.
843
844 sectrn:
845 ld l,c
846 ld h,b
847 ld a,d
848 or e
849 ret z
850 ex de,hl
851 add hl,bc
852 ld l,(hl)
853 ld h,0
854 ret
855
856
857 ; READ
858 ; Read physical record from currently selected drive.
859 ; Finds address of proper read routine from
860 ; extended disk parameter header (XDPH).
861
862 read:
863 ld ix,(@xdph) ; get drive descriptor pointer
864 ld l,(ix-8) ; get read routine entry
865 ld h,(ix-7)
866 jp (hl)
867
868
869 ; WRITE
870 ; Write physical sector from currently selected drive.
871 ; Finds address of proper write routine from
872 ; extended disk parameter header (XDPH).
873
874 write:
875 ld ix,(@xdph) ; get drive descriptor pointer
876 ld l,(ix-10) ; get write routine entry
877 ld h,(ix- 9)
878 jp (hl)
879
880
881
882 ; MULTIO
883 ; Set multiple sector count. Saves passed count in
884 ; @CNT
885
886 multio:
887 ld (@cnt),a
888 ret
889
890
891 ; FLUSH
892 ; BIOS deblocking buffer flush. Not implemented.
893
894 flush:
895 xor a
896 ret ; return with no error
897
898
899
900 ; error message components
901 drive$msg: db cr,lf,bell,'BIOS Error on ',0
902 track$msg: db ': T-',0
903 sector$msg: db ', S-',0
904
905
906 ; disk communication data items
907 ; do not change order. sd driver depends on this
908
909 @xdph: ds 2 ; pointer to currently selected drives dph
910 @adrv: ds 1 ; currently selected disk drive
911 @rdrv: ds 1 ; controller relative disk drive
912 @trk: ds 2 ; current track number
913 @sect: ds 2 ; current sector number
914 @dma: ds 2 ; current DMA address
915 @dbnk: db 0 ; bank for DMA operations
916 @cnt: db 0 ; record count for multisector transfer
917
918
919 cseg ; common memory
920
921 @cbnk: db 0 ; bank for processor operations
922
923
924 end