SLR180 works with both, CR/LF and LF only, but M80 does not.
- public @dtbl
- extrn sd0,sd1,sd2,sd3
- extrn sd4,sd5,sd6,sd7
- extrn cf0,cf1,cf2,cf3
-
- cseg
-
-@dtbl dw sd0,sd1,sd2,sd3 ; drives A-D
- dw sd4,sd5,sd6,sd7 ; drives E-H
- dw cf0,cf1,cf2,cf3 ; drives I-L
- dw 0,0,0,0 ; drives M-P
-
- end
+ public @dtbl\r
+ extrn sd0,sd1,sd2,sd3\r
+ extrn sd4,sd5,sd6,sd7\r
+ extrn cf0,cf1,cf2,cf3\r
+\r
+ cseg\r
+\r
+@dtbl dw sd0,sd1,sd2,sd3 ; drives A-D\r
+ dw sd4,sd5,sd6,sd7 ; drives E-H\r
+ dw cf0,cf1,cf2,cf3 ; drives I-L\r
+ dw 0,0,0,0 ; drives M-P\r
+\r
+ end\r
-
- public intinit
- public bufinit
- public cpu_frq
- public get_tmr
-
- public fifolst
-
- extrn div32_r,?pmsg
- extrn msg.sm,msg.recv,hwl2phy
-
- include config.inc
- include z180reg.inc
-
-
-;----------------------------------------------------------------------
-
- dseg
-
-intinit:
- ld hl,ivtab ;
- ld a,h ;
- ld i,a ;
- out0 (il),l ;
- im 2
-
-; Let all vectors point to spurious int routines.
-
- ld de,sp.int0
- ld bc,sp.int.len
- ld a,9
-ivt_i1:
- ld (hl),e
- inc l
- ld (hl),d
- inc l
- ex de,hl
- add hl,bc
- ex de,hl
- dec a
- jr nz,ivt_i1
- ret
-
-
-;--------------------------------------------------------------------
-; Spurious interrupt handler
-
- cseg ; common area
-sp.int0:
- ld a,00h
- jr sp.i.1
-sp.int.len equ $-sp.int0
- ld a,01h
- jr sp.i.1
- ld a,02h
- jr sp.i.1
- ld a,03h
- jr sp.i.1
- ld a,04h
- jr sp.i.1
- ld a,05h
- jr sp.i.1
- ld a,06h
- jr sp.i.1
- ld a,07h
- jr sp.i.1
- ld a,08h
-sp.i.1:
-; out (80h),a
-
- add a,'0'
- ld (spi$nr),a
- ld hl,spi$msg
- call ?pmsg
-sp.i.2:
- halt
- jr sp.i.2
-
-spi$msg:
- db 13,10,'Spurious Int: '
-spi$nr: db '0'
- db 0
-
-;--------------------------------------------------------------------
-;
-; Get/compute CPU clock
-;
-; return:
-; hlde: CPU frequency (Hz)
-;
-
- dseg
-
-cpu_frq:
- ld hl,0
- ld d,h
- ld e,l
- call get_tmr
- push de
- push hl
-
-; delay ~8ms @ 18.432MHz --> 147456 clock cycles
-; delay ~10ms @ 18.432MHz --> 184320 clock cycles
-;
-
-; ld hl,8192 ; 147456/18
- ld hl,(10240-100)*5 ; 184320/18
- ld de,1
- or a
-dly_lp:
- sbc hl,de ; 10
- jr nz,dly_lp ; 6/8 -> 18 cycles
-
- pop hl
- pop de
- call get_tmr
-
- ld b,h
- ld c,l
- ld de,036EEh ;18432000/(2**16) * 50
- ld hl,08000h ;18432000%(2**16) * 50
-
- ld a,b
- or a
- jr nz,cpuf_div
- ld a,c
- cp 2
- jr c,cpuf_done
-cpuf_div:
- call div32_r
-cpuf_done:
- ret
-
-;--------------------------------------------------------------------
-
- dseg
-get_tmr:
- push de
- push hl
- ld hl,1*256 + 3 ; h = subcommand, l = command
- push hl
- ld hl,0
- add hl,sp
- ld b,6
- call msg.sm
-
- dec sp
- ld hl,0
- add hl,sp
- ld b,7 ; max receive message len
- call msg.recv
-
- pop bc
- inc sp
- pop hl
- pop de
- ret
-
-;--------------------------------------------------------------------
-
- dseg
-
-fifolst:
- rept 4
- dw 0
- endm
-
-;--------------------------------------------------------------------
-
- dseg
-
-bufinit:
- ld (ix+o.in_idx),0 ;reset pointers (empty fifo)
- ld (ix+o.out_idx),0
- ld a,(ix+o.id)
- ld hl,fifolst
- ld e,a
- ld d,0
- add hl,de
- add hl,de
- push ix
- pop de
- cp 4
- jr nc,bfi_skip
-
- ld (hl),e
- inc hl
- ld (hl),d
-
-bfi_skip:
- ex de,hl
- call hwl2phy ;get phys. address of fifo
- ld c,a
- ld a,(ix+o.id) ;fifo id
- or a ;test if fifo 0
- ret z
-
- ld b,a
- push bc ;c: bank-addr, b: ignored
- push hl ;address
- ld c,0
- push bc ;c: function, b:subf
- ld b,5
- ld h,c
- ld l,c
- add hl,sp
- call msg.sm
- pop hl
- pop hl
- pop hl
- ret
-
-;----------------------------------------------------------------------
-
-
- end
+\r
+ public intinit\r
+ public bufinit\r
+ public cpu_frq\r
+ public get_tmr\r
+\r
+ public fifolst\r
+\r
+ extrn div32_r,?pmsg\r
+ extrn msg.sm,msg.recv,hwl2phy\r
+\r
+ include config.inc\r
+ include z180reg.inc\r
+\r
+\r
+;----------------------------------------------------------------------\r
+\r
+ dseg\r
+\r
+intinit:\r
+ ld hl,ivtab ;\r
+ ld a,h ;\r
+ ld i,a ;\r
+ out0 (il),l ;\r
+ im 2\r
+\r
+; Let all vectors point to spurious int routines.\r
+\r
+ ld de,sp.int0\r
+ ld bc,sp.int.len\r
+ ld a,9\r
+ivt_i1:\r
+ ld (hl),e\r
+ inc l\r
+ ld (hl),d\r
+ inc l\r
+ ex de,hl\r
+ add hl,bc\r
+ ex de,hl\r
+ dec a\r
+ jr nz,ivt_i1\r
+ ret\r
+\r
+\r
+;--------------------------------------------------------------------\r
+; Spurious interrupt handler\r
+\r
+ cseg ; common area\r
+sp.int0:\r
+ ld a,00h\r
+ jr sp.i.1\r
+sp.int.len equ $-sp.int0\r
+ ld a,01h\r
+ jr sp.i.1\r
+ ld a,02h\r
+ jr sp.i.1\r
+ ld a,03h\r
+ jr sp.i.1\r
+ ld a,04h\r
+ jr sp.i.1\r
+ ld a,05h\r
+ jr sp.i.1\r
+ ld a,06h\r
+ jr sp.i.1\r
+ ld a,07h\r
+ jr sp.i.1\r
+ ld a,08h\r
+sp.i.1:\r
+; out (80h),a\r
+\r
+ add a,'0'\r
+ ld (spi$nr),a\r
+ ld hl,spi$msg\r
+ call ?pmsg\r
+sp.i.2:\r
+ halt\r
+ jr sp.i.2\r
+\r
+spi$msg:\r
+ db 13,10,'Spurious Int: '\r
+spi$nr: db '0'\r
+ db 0\r
+\r
+;--------------------------------------------------------------------\r
+;\r
+; Get/compute CPU clock\r
+;\r
+; return:\r
+; hlde: CPU frequency (Hz)\r
+;\r
+\r
+ dseg\r
+\r
+cpu_frq:\r
+ ld hl,0\r
+ ld d,h\r
+ ld e,l\r
+ call get_tmr\r
+ push de\r
+ push hl\r
+\r
+; delay ~8ms @ 18.432MHz --> 147456 clock cycles\r
+; delay ~10ms @ 18.432MHz --> 184320 clock cycles\r
+;\r
+\r
+; ld hl,8192 ; 147456/18\r
+ ld hl,(10240-100)*5 ; 184320/18\r
+ ld de,1\r
+ or a\r
+dly_lp:\r
+ sbc hl,de ; 10\r
+ jr nz,dly_lp ; 6/8 -> 18 cycles\r
+\r
+ pop hl\r
+ pop de\r
+ call get_tmr\r
+\r
+ ld b,h\r
+ ld c,l\r
+ ld de,036EEh ;18432000/(2**16) * 50\r
+ ld hl,08000h ;18432000%(2**16) * 50\r
+\r
+ ld a,b\r
+ or a\r
+ jr nz,cpuf_div\r
+ ld a,c\r
+ cp 2\r
+ jr c,cpuf_done\r
+cpuf_div:\r
+ call div32_r\r
+cpuf_done:\r
+ ret\r
+\r
+;--------------------------------------------------------------------\r
+\r
+ dseg\r
+get_tmr:\r
+ push de\r
+ push hl\r
+ ld hl,1*256 + 3 ; h = subcommand, l = command\r
+ push hl\r
+ ld hl,0\r
+ add hl,sp\r
+ ld b,6\r
+ call msg.sm\r
+\r
+ dec sp\r
+ ld hl,0\r
+ add hl,sp\r
+ ld b,7 ; max receive message len\r
+ call msg.recv\r
+\r
+ pop bc\r
+ inc sp\r
+ pop hl\r
+ pop de\r
+ ret\r
+\r
+;--------------------------------------------------------------------\r
+\r
+ dseg\r
+\r
+fifolst:\r
+ rept 4\r
+ dw 0\r
+ endm\r
+\r
+;--------------------------------------------------------------------\r
+\r
+ dseg\r
+\r
+bufinit:\r
+ ld (ix+o.in_idx),0 ;reset pointers (empty fifo)\r
+ ld (ix+o.out_idx),0\r
+ ld a,(ix+o.id)\r
+ ld hl,fifolst\r
+ ld e,a\r
+ ld d,0\r
+ add hl,de\r
+ add hl,de\r
+ push ix\r
+ pop de\r
+ cp 4\r
+ jr nc,bfi_skip\r
+\r
+ ld (hl),e\r
+ inc hl\r
+ ld (hl),d\r
+\r
+bfi_skip:\r
+ ex de,hl\r
+ call hwl2phy ;get phys. address of fifo\r
+ ld c,a\r
+ ld a,(ix+o.id) ;fifo id\r
+ or a ;test if fifo 0\r
+ ret z\r
+\r
+ ld b,a\r
+ push bc ;c: bank-addr, b: ignored\r
+ push hl ;address\r
+ ld c,0\r
+ push bc ;c: function, b:subf\r
+ ld b,5\r
+ ld h,c\r
+ ld l,c\r
+ add hl,sp\r
+ call msg.sm\r
+ pop hl\r
+ pop hl\r
+ pop hl\r
+ ret\r
+\r
+;----------------------------------------------------------------------\r
+\r
+\r
+ end\r
- page 255
- .z80
-
-
- global mmuinit
- global bnk2log,bnk2phy,hwl2phy,phy2log
-
- include config.inc
- include z180reg.inc
-
-
-;----------------------------------------------------------------------
-; Memory Map 1:
-;
-; Common CAStart .. 0FFFF
-; Bank 0 00000 .. CAStart-1
-; Bank 1 10000 ..
-; Bank 2
-;
-; Memory Map 2:
-;
-; Common 18000 .. 1BFFF BANK1
-;
-; Bank 0 00000 .. 0BFFF 0
-; Bank 1 0C000 .. 17FFF 1*BNK_SIZE
-; Bank 2 1C000 .. 27FFF 2*BNK_SIZE + CMN_SIZE
-; Bank 3 28000 .. 33FFF 3*BNK_SIZE + CMN_SIZE
-; Bank n n*BNK_SIZE + (n < 2) ? 0 : CMN_SIZE
-;
-;----------------------------------------------------------------------
-
- cseg
-
-mmuinit:
- ld a,USR$CBAR
- out0 (cbar),a
- ret
-
-;--------------------------------------------------------------------
-; Return the BBR value for the given bank number
-;
-; in a: Bank number
-; out a: bbr value
-
- if 0 ; Memory Map 1
-
-bnk2log:
- or a ;
- ret z ; Bank 0 is at physical address 0
-
- dec a ;
- push bc ;
- ld c,a ;
- ld b,BNK_SIZE ;
- mlt bc ; bank size * bank number
- ld a,c ;
- add a,10h ; add bank0 + common
- pop bc ;
- ret ;
-
- else ; Memory Map 2
-
-bnk2log:
- or a
- ret z ; Bank 0 is at physical address 0
-
- push bc
- ld c,a ;
- ld b,BNK_SIZE ;
- mlt bc ; bank size * bank number
- cp 2 ;
- ld a,c ;
- pop bc
- ret c
- add a,CMN_SIZE
- ret
-
- endif
-
- if 0 ; table version
-
- push hl
- ld hl,bnk_table ;
- add a,l ;
- ld l,a ;
- jr nc,$+3 ;
- inc h ;
- ld a,(hl) ;
- pop hl
- ret
-
- endif
-
-;--------------------------------------------------------------
-
-;in hl: Log. Address
-; a: Bank number
-;
-;out ahl: Phys. (linear) Address
-
-
-bnk2phy:
- push bc
- ld c,a
- ld a,h
- and a,0f0h
- cp CA*16
- ld a,c
- pop bc
- jr c,b2p_banked
- ; address is in common
- if 0 ; Memory Map 1
- ld a,0 ; base is 0
- else ; Memory Map 2
- ld a,1 ; same as bank1
- endif
-
-b2p_banked:
- call bnk2log ; get address base
-
- ; fall thru
-
-;--------------------------------------------------------------
-;
-; hl: Log. Address
-; a: Bank base (bbr)
-;
-; 2 0 0
-; 0 6 8 0
-; hl hhhhhhhhllllllll
-; a + bbbbbbbb
-;
-; OP: ahl = (a<<12) + (h<<8) + l
-;
-;out ahl: Phys. (linear) Address
-
-log2phy:
- push bc ;
-l2p_i:
- ld c,a ;
- ld b,16 ;
- mlt bc ; bc = a<<4
- ld a,c ;
- add a,h ;
- ld h,a ;
- ld a,b ;
- adc a,0 ;
- pop bc ;
- ret ;
-
-;--------------------------------------------------------------
-;
-; hl: Log. Address
-;
-;
-; OP: ahl = (bankbase<<12) + (h<<8) + l
-;
-;out ahl: Phys. (linear) Address
-
-
-hwl2phy:
- push bc ;
- in0 c,(cbar) ;
- ld a,h ;
- or 00fh ; log. addr in common1?
- cp c
- jr c,hlp_1
-
- in0 a,(cbr) ; yes, cbr is address base
- jr hl2p_x
-hlp_1:
- ld b,16 ; log. address in baked area?
- mlt bc
- ld a,h
- cp c
- jr c,hlp_2
- in0 a,(bbr) ; yes, bbr is address base
- jr hl2p_x
-hlp_2:
- xor a ; common1
-hl2p_x:
- jr nz,l2p_i
-
- pop bc ; bank part is 0, no translation
- ret ;
-
-
-;--------------------------------------------------------------
-; return logical bank 0 address for given physical address.
-;
-; in: ahl: pyhsical addres (20 bit)
-; out hl: logical address.
-; logical address is in bank 0 or common, no bank number returned
-;
-
-phy2log:
- or a
- ret z
-
- push bc
- push hl
- ld l,h
- ld h,0
- ld bc,-16*SYS$CBR
- add hl,bc
- ld h,l
- pop bc
- ld l,c
- pop bc
- ret
-
-;--------------------------------------------------------------
-; Trampoline for routines in banked ram.
-; Switch stack pointer to "system" stack in top ram
-; Save cbar
-;
- extrn bs$stack
-
- cseg ; common!
-
- public _b0call
-_b0call:
- push af
- in0 a,(bbr)
- jr nz,b0c_doit
- pop af
-
- ex (sp),hl ;16
- push de
- ld e,(hl)
- inc hl
- ld d,(hl)
- inc hl
- ld (b0c_fast_go),de
- pop de
- ex (sp),hl ;16
-b0c_fast_go equ $+1
- jp 0
-
-b0c_doit:
- ld (b0_save_hl),hl
- ld (b0_save_de),de
- pop hl
- ld (b0_save_af),hl
-
- pop de ;get ptr to 'function address' in de
- ld hl,2
- add hl,de
- push hl ;put return address on stack
-
- if 0 ; link80
-
- ld hl,0
- add hl,sp ;
- ld a,h
- cp high (bs$stack-bs$stack$size) ;link80 can't process this
- jr nc,$ + 5 ;skip if stack allready in common bios ram
-
- else
-
- ld hl,bs$stack-bs$stack$size
- ld a,h
- dec a
- ld hl,0
- add hl,sp ;
- cp h
- jr c,$ + 5 ;skip if stack allready in common bios ram
- endif
- ld sp,bs$stack ;
-
- push hl ;save user stack pointer
-
- in0 h,(bbr) ;
- push hl ;
- ld hl,b0c_ret
- push hl
- xor a
- out0 (bbr),a ;
- ex de,hl ;ptr
- ld e,(hl) ;get 'function address'
- inc hl ;
- ld d,(hl) ;
- push de ;put on (switched) stack
-
- ld hl,(b0_save_af) ;get back users registers
- push hl
- pop af
- ld de,(b0_save_de)
- ld hl,(b0_save_hl)
- ret ;go to function
-b0c_ret:
- ld (b0_save_hl),hl
-
- pop hl ;
- out0 (bbr),h ;
- pop hl ;
- ld sp,hl ;
- ld hl,(b0_save_hl)
- ret ;
-
-
-b0_save_hl: dw 0
-b0_save_de: dw 0
-b0_save_af: dw 0
-
-
-
-;====================================================================
-
- if 0
-
-;--------------------------------------------------------------------
-; Return the BBR value for the given bank number
-
-bnk2bbr:
- or a ; 4
- ret z ; 5/10 | 11 14
-
- push bc ;11 | 11
- ld b,a ; 4
- ld c,CA ; 6
- mlt bc ;17 >45
- ld a,c ; 4
- add a,10h ; 6
- pop bc ; 9 | 10
- ret ; 9 | 10 76
-
- push ix ;2 / 14 | 15
- ld ix,bnktbl ;4 / 12 | 14
- ld ($+3+2),a ;3 / 15 | 19
- ld a,(ix+0) ;3 / 14 | 19
- pop ix ;2 / 12 | 14
- ret ;1 / 9 | 10 15 / 76|91
-
- push hl ;1 / 11 | 11
- ld hl,bnktbl ;3 / 9 | 10
- add a,l ;1 / 4 | 4
- ld l,a ;1 / 4 | 4
- ld a,0 ;1 / 6 | 7
- adc a,h ;1 / 4 | 4
- ld h,a ;1 / 4 | 4
- ld a,(hl) ;1 / 6 | 7
- pop hl ;1 / 9 | 10
- ret ;1 / 9 | 10 12 / 66|71
-
- push hl ;1 / 11 | 11
- add a,low bnktbl ;2 / 6 | 7
- ld l,a ;1 / 4 | 4
- ld a,0 ;1 / 6 | 7
- adc a,high bnktbl ;2 / 6 | 7
- ld h,a ;1 / 4 | 4
- ld a,(hl) ;1 / 6 | 7
- pop hl ;1 / 9 | 10
- ret ;1 / 9 | 10 11 / 61|67
-
- endif
-
-
- end
+ page 255\r
+ .z80\r
+\r
+\r
+ global mmuinit\r
+ global bnk2log,bnk2phy,hwl2phy,phy2log\r
+\r
+ include config.inc\r
+ include z180reg.inc\r
+\r
+\r
+;----------------------------------------------------------------------\r
+; Memory Map 1:\r
+;\r
+; Common CAStart .. 0FFFF\r
+; Bank 0 00000 .. CAStart-1\r
+; Bank 1 10000 ..\r
+; Bank 2\r
+;\r
+; Memory Map 2:\r
+;\r
+; Common 18000 .. 1BFFF BANK1\r
+;\r
+; Bank 0 00000 .. 0BFFF 0\r
+; Bank 1 0C000 .. 17FFF 1*BNK_SIZE\r
+; Bank 2 1C000 .. 27FFF 2*BNK_SIZE + CMN_SIZE\r
+; Bank 3 28000 .. 33FFF 3*BNK_SIZE + CMN_SIZE\r
+; Bank n n*BNK_SIZE + (n < 2) ? 0 : CMN_SIZE\r
+;\r
+;----------------------------------------------------------------------\r
+\r
+ cseg\r
+\r
+mmuinit:\r
+ ld a,USR$CBAR\r
+ out0 (cbar),a\r
+ ret\r
+\r
+;--------------------------------------------------------------------\r
+; Return the BBR value for the given bank number\r
+;\r
+; in a: Bank number\r
+; out a: bbr value\r
+\r
+ if 0 ; Memory Map 1\r
+\r
+bnk2log:\r
+ or a ;\r
+ ret z ; Bank 0 is at physical address 0\r
+\r
+ dec a ;\r
+ push bc ;\r
+ ld c,a ;\r
+ ld b,BNK_SIZE ;\r
+ mlt bc ; bank size * bank number\r
+ ld a,c ;\r
+ add a,10h ; add bank0 + common\r
+ pop bc ;\r
+ ret ;\r
+\r
+ else ; Memory Map 2\r
+\r
+bnk2log:\r
+ or a\r
+ ret z ; Bank 0 is at physical address 0\r
+\r
+ push bc\r
+ ld c,a ;\r
+ ld b,BNK_SIZE ;\r
+ mlt bc ; bank size * bank number\r
+ cp 2 ;\r
+ ld a,c ;\r
+ pop bc\r
+ ret c\r
+ add a,CMN_SIZE\r
+ ret\r
+\r
+ endif\r
+\r
+ if 0 ; table version\r
+\r
+ push hl\r
+ ld hl,bnk_table ;\r
+ add a,l ;\r
+ ld l,a ;\r
+ jr nc,$+3 ;\r
+ inc h ;\r
+ ld a,(hl) ;\r
+ pop hl\r
+ ret\r
+\r
+ endif\r
+\r
+;--------------------------------------------------------------\r
+\r
+;in hl: Log. Address\r
+; a: Bank number\r
+;\r
+;out ahl: Phys. (linear) Address\r
+\r
+\r
+bnk2phy:\r
+ push bc\r
+ ld c,a\r
+ ld a,h\r
+ and a,0f0h\r
+ cp CA*16\r
+ ld a,c\r
+ pop bc\r
+ jr c,b2p_banked\r
+ ; address is in common\r
+ if 0 ; Memory Map 1\r
+ ld a,0 ; base is 0\r
+ else ; Memory Map 2\r
+ ld a,1 ; same as bank1\r
+ endif\r
+\r
+b2p_banked:\r
+ call bnk2log ; get address base\r
+\r
+ ; fall thru\r
+\r
+;--------------------------------------------------------------\r
+;\r
+; hl: Log. Address\r
+; a: Bank base (bbr)\r
+;\r
+; 2 0 0\r
+; 0 6 8 0\r
+; hl hhhhhhhhllllllll\r
+; a + bbbbbbbb\r
+;\r
+; OP: ahl = (a<<12) + (h<<8) + l\r
+;\r
+;out ahl: Phys. (linear) Address\r
+\r
+log2phy:\r
+ push bc ;\r
+l2p_i:\r
+ ld c,a ;\r
+ ld b,16 ;\r
+ mlt bc ; bc = a<<4\r
+ ld a,c ;\r
+ add a,h ;\r
+ ld h,a ;\r
+ ld a,b ;\r
+ adc a,0 ;\r
+ pop bc ;\r
+ ret ;\r
+\r
+;--------------------------------------------------------------\r
+;\r
+; hl: Log. Address\r
+;\r
+;\r
+; OP: ahl = (bankbase<<12) + (h<<8) + l\r
+;\r
+;out ahl: Phys. (linear) Address\r
+\r
+\r
+hwl2phy:\r
+ push bc ;\r
+ in0 c,(cbar) ;\r
+ ld a,h ;\r
+ or 00fh ; log. addr in common1?\r
+ cp c\r
+ jr c,hlp_1\r
+\r
+ in0 a,(cbr) ; yes, cbr is address base\r
+ jr hl2p_x\r
+hlp_1:\r
+ ld b,16 ; log. address in baked area?\r
+ mlt bc\r
+ ld a,h\r
+ cp c\r
+ jr c,hlp_2\r
+ in0 a,(bbr) ; yes, bbr is address base\r
+ jr hl2p_x\r
+hlp_2:\r
+ xor a ; common1\r
+hl2p_x:\r
+ jr nz,l2p_i\r
+\r
+ pop bc ; bank part is 0, no translation\r
+ ret ;\r
+\r
+\r
+;--------------------------------------------------------------\r
+; return logical bank 0 address for given physical address.\r
+;\r
+; in: ahl: pyhsical addres (20 bit)\r
+; out hl: logical address.\r
+; logical address is in bank 0 or common, no bank number returned\r
+;\r
+\r
+phy2log:\r
+ or a\r
+ ret z\r
+\r
+ push bc\r
+ push hl\r
+ ld l,h\r
+ ld h,0\r
+ ld bc,-16*SYS$CBR\r
+ add hl,bc\r
+ ld h,l\r
+ pop bc\r
+ ld l,c\r
+ pop bc\r
+ ret\r
+\r
+;--------------------------------------------------------------\r
+; Trampoline for routines in banked ram.\r
+; Switch stack pointer to "system" stack in top ram\r
+; Save cbar\r
+;\r
+ extrn bs$stack\r
+\r
+ cseg ; common!\r
+\r
+ public _b0call\r
+_b0call:\r
+ push af\r
+ in0 a,(bbr)\r
+ jr nz,b0c_doit\r
+ pop af\r
+\r
+ ex (sp),hl ;16\r
+ push de\r
+ ld e,(hl)\r
+ inc hl\r
+ ld d,(hl)\r
+ inc hl\r
+ ld (b0c_fast_go),de\r
+ pop de\r
+ ex (sp),hl ;16\r
+b0c_fast_go equ $+1\r
+ jp 0\r
+\r
+b0c_doit:\r
+ ld (b0_save_hl),hl\r
+ ld (b0_save_de),de\r
+ pop hl\r
+ ld (b0_save_af),hl\r
+\r
+ pop de ;get ptr to 'function address' in de\r
+ ld hl,2\r
+ add hl,de\r
+ push hl ;put return address on stack\r
+\r
+ if 0 ; link80\r
+\r
+ ld hl,0\r
+ add hl,sp ;\r
+ ld a,h\r
+ cp high (bs$stack-bs$stack$size) ;link80 can't process this\r
+ jr nc,$ + 5 ;skip if stack allready in common bios ram\r
+\r
+ else\r
+\r
+ ld hl,bs$stack-bs$stack$size\r
+ ld a,h\r
+ dec a\r
+ ld hl,0\r
+ add hl,sp ;\r
+ cp h\r
+ jr c,$ + 5 ;skip if stack allready in common bios ram\r
+ endif\r
+ ld sp,bs$stack ;\r
+\r
+ push hl ;save user stack pointer\r
+\r
+ in0 h,(bbr) ;\r
+ push hl ;\r
+ ld hl,b0c_ret\r
+ push hl\r
+ xor a\r
+ out0 (bbr),a ;\r
+ ex de,hl ;ptr\r
+ ld e,(hl) ;get 'function address'\r
+ inc hl ;\r
+ ld d,(hl) ;\r
+ push de ;put on (switched) stack\r
+\r
+ ld hl,(b0_save_af) ;get back users registers\r
+ push hl\r
+ pop af\r
+ ld de,(b0_save_de)\r
+ ld hl,(b0_save_hl)\r
+ ret ;go to function\r
+b0c_ret:\r
+ ld (b0_save_hl),hl\r
+\r
+ pop hl ;\r
+ out0 (bbr),h ;\r
+ pop hl ;\r
+ ld sp,hl ;\r
+ ld hl,(b0_save_hl)\r
+ ret ;\r
+\r
+\r
+b0_save_hl: dw 0\r
+b0_save_de: dw 0\r
+b0_save_af: dw 0\r
+\r
+\r
+\r
+;====================================================================\r
+\r
+ if 0\r
+\r
+;--------------------------------------------------------------------\r
+; Return the BBR value for the given bank number\r
+\r
+bnk2bbr:\r
+ or a ; 4\r
+ ret z ; 5/10 | 11 14\r
+\r
+ push bc ;11 | 11\r
+ ld b,a ; 4\r
+ ld c,CA ; 6\r
+ mlt bc ;17 >45\r
+ ld a,c ; 4\r
+ add a,10h ; 6\r
+ pop bc ; 9 | 10\r
+ ret ; 9 | 10 76\r
+\r
+ push ix ;2 / 14 | 15\r
+ ld ix,bnktbl ;4 / 12 | 14\r
+ ld ($+3+2),a ;3 / 15 | 19\r
+ ld a,(ix+0) ;3 / 14 | 19\r
+ pop ix ;2 / 12 | 14\r
+ ret ;1 / 9 | 10 15 / 76|91\r
+\r
+ push hl ;1 / 11 | 11\r
+ ld hl,bnktbl ;3 / 9 | 10\r
+ add a,l ;1 / 4 | 4\r
+ ld l,a ;1 / 4 | 4\r
+ ld a,0 ;1 / 6 | 7\r
+ adc a,h ;1 / 4 | 4\r
+ ld h,a ;1 / 4 | 4\r
+ ld a,(hl) ;1 / 6 | 7\r
+ pop hl ;1 / 9 | 10\r
+ ret ;1 / 9 | 10 12 / 66|71\r
+\r
+ push hl ;1 / 11 | 11\r
+ add a,low bnktbl ;2 / 6 | 7\r
+ ld l,a ;1 / 4 | 4\r
+ ld a,0 ;1 / 6 | 7\r
+ adc a,high bnktbl ;2 / 6 | 7\r
+ ld h,a ;1 / 4 | 4\r
+ ld a,(hl) ;1 / 6 | 7\r
+ pop hl ;1 / 9 | 10\r
+ ret ;1 / 9 | 10 11 / 61|67\r
+\r
+ endif\r
+\r
+\r
+ end\r
- title 'Bank & Move Module for the Modular CP/M 3 BIOS'
-
-; CP/M-80 Version 3 -- Modular BIOS
-; Bank and Move Module for Z180-Stamp
-; Initial version 1.0
-; Compile with M80, slr180, or compatible
-
- public ?move,?xmove,?bank
-
- extrn bnk2log,bnk2phy
- extrn @cbnk
-
-
- include config.inc
- include z180reg.inc
-
-
- cseg ; must be in common memory
-
-?xmove:
- if banked
- ld (src$bnk),bc ; c -> src$bnk, b -> dst$bnk
- endif
- ret
-
-?move:
- ex de,hl ; we are passed source in DE and dest in HL
- if banked
- ld a,(src$bnk) ; contains 0FEh if normal block move
- cp 0FEh
- jr nz,inter_bank_move
- endif
- ldir ; use Z80 block move instruction
- ex de,hl ; need next address in same regs
- ret
-
-; select bank in A
-
-?bank:
- if banked
- call bnk2log
- out0 (bbr),a
- endif
- ret
-
- if banked
-
-inter_bank_move: ; source in HL, dest in DE, count in BC
-
- if 1 ; works with new memory map
-
- out0 (bcr0l),c ; setup DMA count
- out0 (bcr0h),b
-
- push hl
- push de
- ld a,(src$bnk)
- call bnk2phy
- out0 (sar0l),l ; setup DMA src address
- out0 (sar0h),h
- out0 (sar0b),a
-
- ex de,hl
- ld a,(dst$bnk)
- call bnk2phy
- out0 (dar0l),l ; setup DMA dst address
- out0 (dar0h),h
- out0 (dar0b),a
-
- ld a,M_MMOD ; DMA burst mode
- out0 (dmode),a
- ld a,M_DE0+M_NDWE1 ; enable DMA0
- out0 (dstat),a ; move the block
-
- pop de
- pop hl
- add hl,bc ; src must point past end block
- ex de,hl
- add hl,bc ; and so must dst
- ld bc,0
-
- ld a,0FEh
- ld (src$bnk),a
-
- ret ; return with src in DE, dst in HL, count = 0
-
- else ; inefficient fall back
-
- ld (tmp$sp),sp
- ld sp,tmp$stk
- ex af,af' ;
- push af
-mv$blk:
- ld a,(src$bnk) ;
- call ?bank
- ld a,(hl)
- ex af,af' ;
- ld a,(dst$bnk)
- call ?bank
- ex af,af' ;
- ld (de),a
- inc de
- cpi
- jp pe,mv$blk
- ld a,(@cbnk)
- call ?bank
- ld a,0FEh
- ld (src$bnk),a
- ex de,hl
- pop af
- ex af,af' ;
- ld sp,(tmp$sp)
- ret
-
- ds 16
-tmp$stk:
-tmp$sp: ds 2
-
- endif
-
-src$bnk: db 0FEh
-dst$bnk: db 0FEh
-
-
- endif ;banked
-
- end
+ title 'Bank & Move Module for the Modular CP/M 3 BIOS'\r
+\r
+; CP/M-80 Version 3 -- Modular BIOS\r
+; Bank and Move Module for Z180-Stamp\r
+; Initial version 1.0\r
+; Compile with M80, slr180, or compatible\r
+\r
+ public ?move,?xmove,?bank\r
+\r
+ extrn bnk2log,bnk2phy\r
+ extrn @cbnk\r
+\r
+\r
+ include config.inc\r
+ include z180reg.inc\r
+\r
+\r
+ cseg ; must be in common memory\r
+\r
+?xmove:\r
+ if banked\r
+ ld (src$bnk),bc ; c -> src$bnk, b -> dst$bnk\r
+ endif\r
+ ret\r
+\r
+?move:\r
+ ex de,hl ; we are passed source in DE and dest in HL\r
+ if banked\r
+ ld a,(src$bnk) ; contains 0FEh if normal block move\r
+ cp 0FEh\r
+ jr nz,inter_bank_move\r
+ endif\r
+ ldir ; use Z80 block move instruction\r
+ ex de,hl ; need next address in same regs\r
+ ret\r
+\r
+; select bank in A\r
+\r
+?bank:\r
+ if banked\r
+ call bnk2log\r
+ out0 (bbr),a\r
+ endif\r
+ ret\r
+\r
+ if banked\r
+\r
+inter_bank_move: ; source in HL, dest in DE, count in BC\r
+\r
+ if 1 ; works with new memory map\r
+\r
+ out0 (bcr0l),c ; setup DMA count\r
+ out0 (bcr0h),b\r
+\r
+ push hl\r
+ push de\r
+ ld a,(src$bnk)\r
+ call bnk2phy\r
+ out0 (sar0l),l ; setup DMA src address\r
+ out0 (sar0h),h\r
+ out0 (sar0b),a\r
+\r
+ ex de,hl\r
+ ld a,(dst$bnk)\r
+ call bnk2phy\r
+ out0 (dar0l),l ; setup DMA dst address\r
+ out0 (dar0h),h\r
+ out0 (dar0b),a\r
+\r
+ ld a,M_MMOD ; DMA burst mode\r
+ out0 (dmode),a\r
+ ld a,M_DE0+M_NDWE1 ; enable DMA0\r
+ out0 (dstat),a ; move the block\r
+\r
+ pop de\r
+ pop hl\r
+ add hl,bc ; src must point past end block\r
+ ex de,hl\r
+ add hl,bc ; and so must dst\r
+ ld bc,0\r
+\r
+ ld a,0FEh\r
+ ld (src$bnk),a\r
+\r
+ ret ; return with src in DE, dst in HL, count = 0\r
+\r
+ else ; inefficient fall back\r
+\r
+ ld (tmp$sp),sp\r
+ ld sp,tmp$stk\r
+ ex af,af' ;\r
+ push af\r
+mv$blk:\r
+ ld a,(src$bnk) ;\r
+ call ?bank\r
+ ld a,(hl)\r
+ ex af,af' ;\r
+ ld a,(dst$bnk)\r
+ call ?bank\r
+ ex af,af' ;\r
+ ld (de),a\r
+ inc de\r
+ cpi\r
+ jp pe,mv$blk\r
+ ld a,(@cbnk)\r
+ call ?bank\r
+ ld a,0FEh\r
+ ld (src$bnk),a\r
+ ex de,hl\r
+ pop af\r
+ ex af,af' ;\r
+ ld sp,(tmp$sp)\r
+ ret\r
+\r
+ ds 16\r
+tmp$stk:\r
+tmp$sp: ds 2\r
+\r
+ endif\r
+\r
+src$bnk: db 0FEh\r
+dst$bnk: db 0FEh\r
+\r
+\r
+ endif ;banked\r
+\r
+ end\r
- title 'Time module for the Modular CP/M 3 BIOS'
-
- public ?time, gs_rtc
- public prt0ini
- public gtimer,gstimer
-
- extrn @date,@hour,@min,@sec
- extrn f_cpu
- extrn ioiniml,div32_16
- extrn msg.sm,msg.recv
- extrn _b0call
-
- include config.inc
- include z180reg.inc
-
-
-;----------------------------------------------------------------------
-; c == 00h: get time
-; c == ffh: set time
-
- cseg ; time must be done from resident memory
-?time:
- inc c ;zero if ff
- ld c,3
- jr z,time_set
-
- ld a,(time_to)
- or a
- ret nz
-
- dec c
-time_set:
- b0call gs_rtc
- ld a,0ffh
- ld (time_to),a
- ret
-
-;----------------------------------------------------------------------
-; c = 2: get time
-; c = 3: set time
-
- dseg
-gs_rtc:
-
- push hl
- push de
-
- ld hl,(@date)
- ld a,(@hour)
- ld d,a
- ld a,(@min)
- ld e,a
- ld a,(@sec)
- ld b,a ;b = sec, c = subcommand
- push hl ;2
- push de ;4
- push bc ;6
- ld hl,3 * 256 + 0 ;h = command, l = 0
- push hl ;8
-
- ld h,l ;hl = 0
- add hl,sp
- push hl
- inc hl ;7
-
- ld b,7
- call msg.sm
-
- pop hl ;8
- ld b,8 ; max receive message len
- call msg.recv
-
- pop hl ;len/command (discard)
- pop bc ;subc/sec
- pop de
- pop hl
- ld a,b
- ld (@sec),a
- ld a,e
- ld (@min),a
- ld a,d
- ld (@hour),a
- ld (@date),hl
-
- pop de
- pop hl
- ret
-
-;----------------------------------------------------------------------
-
-;uint32_t get_timer(uint32_t base)
-;{
-; uint32_t ret;
-; ATOMIC_BLOCK(ATOMIC_FORCEON)
-; {
-; ret = timestamp;
-; }
-; return ret - base;
-;}
-
- dseg ; called from banked only
-gstimer:
- push de
- ex de,hl
- ld hl,(uptime)
- or a
- sbc hl,de
- pop de
- ret
-
-;----------------------------------------------------------------------
-
-gtimer:
- push bc
- ld b,h
- ld c,l
- or a
- di
- ld hl,(uptime)
- sbc hl,bc
- push hl
- ei
- ld hl,(uptime+2)
- sbc hl,de
- ex de,hl
- pop hl
- pop bc
- ret
-
-;----------------------------------------------------------------------
-; intit timer interrupt
-
- dseg
-
-prt0ini:
- in0 a,(tcr)
- push af
- and ~(M_TIE0+M_TDE0) ;stop timer 0
- out0 (tcr),a
-
- ld a,i
- ld h,a
- in0 a,(il)
- and 0E0h
- or IV$PRT0
- ld l,a
- ld de,isvprt0
- ld (hl),e
- inc hl
- ld (hl),d
-
- ld hl,(f_cpu)
- ld de,(f_cpu+2)
- ld bc,PRT_PRE * 800 ;1/800 s == 1,25 ms interrupt rate
- call div32_16
-
- out0 (tmdr0l),l
- out0 (tmdr0h),h
- out0 (rldr0l),l
- out0 (rldr0h),h
- pop af
- or (M_TIE0+M_TDE0)
- out0 (tcr),a
- ret
-
-
-;----------------------------------------------------------------------
-; timer interrupt
-;
-; 1,25 ms clock tick
-
-
- cseg ;common!
-isvprt0:
- push af
- in0 a,(tcr) ;reset TIF0 flag
- in0 a,(tmdr0l)
- in0 a,(tmdr0h)
-
- push hl ;11
- ld hl,uptime ; 9
- inc (hl) ;10
- jr nz,iprt_1 ;6/8 38
- inc hl ; 4
- inc (hl) ;10
- jr nz,iprt_1 ;6/8 58
- inc hl ; 4
- inc (hl) ;10
- jr nz,iprt_1 ;6/8
- inc hl ; 4
- inc (hl) ;10
-iprt_1:
- pop hl ; 9
- ld a,(time_to)
- sub a,1
- jr c,iprt_0
- ld (time_to),a
-iprt_0:
- pop af
- ei
- ret
-
-uptime:
- dw 0,0
-time_to:
- db 0
-
- end
+ title 'Time module for the Modular CP/M 3 BIOS'\r
+\r
+ public ?time, gs_rtc\r
+ public prt0ini\r
+ public gtimer,gstimer\r
+\r
+ extrn @date,@hour,@min,@sec\r
+ extrn f_cpu\r
+ extrn ioiniml,div32_16\r
+ extrn msg.sm,msg.recv\r
+ extrn _b0call\r
+\r
+ include config.inc\r
+ include z180reg.inc\r
+\r
+\r
+;----------------------------------------------------------------------\r
+; c == 00h: get time\r
+; c == ffh: set time\r
+\r
+ cseg ; time must be done from resident memory\r
+?time:\r
+ inc c ;zero if ff\r
+ ld c,3\r
+ jr z,time_set\r
+\r
+ ld a,(time_to)\r
+ or a\r
+ ret nz\r
+\r
+ dec c\r
+time_set:\r
+ b0call gs_rtc\r
+ ld a,0ffh\r
+ ld (time_to),a\r
+ ret\r
+\r
+;----------------------------------------------------------------------\r
+; c = 2: get time\r
+; c = 3: set time\r
+\r
+ dseg\r
+gs_rtc:\r
+\r
+ push hl\r
+ push de\r
+\r
+ ld hl,(@date)\r
+ ld a,(@hour)\r
+ ld d,a\r
+ ld a,(@min)\r
+ ld e,a\r
+ ld a,(@sec)\r
+ ld b,a ;b = sec, c = subcommand\r
+ push hl ;2\r
+ push de ;4\r
+ push bc ;6\r
+ ld hl,3 * 256 + 0 ;h = command, l = 0\r
+ push hl ;8\r
+\r
+ ld h,l ;hl = 0\r
+ add hl,sp\r
+ push hl\r
+ inc hl ;7\r
+\r
+ ld b,7\r
+ call msg.sm\r
+\r
+ pop hl ;8\r
+ ld b,8 ; max receive message len\r
+ call msg.recv\r
+\r
+ pop hl ;len/command (discard)\r
+ pop bc ;subc/sec\r
+ pop de\r
+ pop hl\r
+ ld a,b\r
+ ld (@sec),a\r
+ ld a,e\r
+ ld (@min),a\r
+ ld a,d\r
+ ld (@hour),a\r
+ ld (@date),hl\r
+\r
+ pop de\r
+ pop hl\r
+ ret\r
+\r
+;----------------------------------------------------------------------\r
+\r
+;uint32_t get_timer(uint32_t base)\r
+;{\r
+; uint32_t ret;\r
+; ATOMIC_BLOCK(ATOMIC_FORCEON)\r
+; {\r
+; ret = timestamp;\r
+; }\r
+; return ret - base;\r
+;}\r
+\r
+ dseg ; called from banked only\r
+gstimer:\r
+ push de\r
+ ex de,hl\r
+ ld hl,(uptime)\r
+ or a\r
+ sbc hl,de\r
+ pop de\r
+ ret\r
+\r
+;----------------------------------------------------------------------\r
+\r
+gtimer:\r
+ push bc\r
+ ld b,h\r
+ ld c,l\r
+ or a\r
+ di\r
+ ld hl,(uptime)\r
+ sbc hl,bc\r
+ push hl\r
+ ei\r
+ ld hl,(uptime+2)\r
+ sbc hl,de\r
+ ex de,hl\r
+ pop hl\r
+ pop bc\r
+ ret\r
+\r
+;----------------------------------------------------------------------\r
+; intit timer interrupt\r
+\r
+ dseg\r
+\r
+prt0ini:\r
+ in0 a,(tcr)\r
+ push af\r
+ and ~(M_TIE0+M_TDE0) ;stop timer 0\r
+ out0 (tcr),a\r
+\r
+ ld a,i\r
+ ld h,a\r
+ in0 a,(il)\r
+ and 0E0h\r
+ or IV$PRT0\r
+ ld l,a\r
+ ld de,isvprt0\r
+ ld (hl),e\r
+ inc hl\r
+ ld (hl),d\r
+\r
+ ld hl,(f_cpu)\r
+ ld de,(f_cpu+2)\r
+ ld bc,PRT_PRE * 800 ;1/800 s == 1,25 ms interrupt rate\r
+ call div32_16\r
+\r
+ out0 (tmdr0l),l\r
+ out0 (tmdr0h),h\r
+ out0 (rldr0l),l\r
+ out0 (rldr0h),h\r
+ pop af\r
+ or (M_TIE0+M_TDE0)\r
+ out0 (tcr),a\r
+ ret\r
+\r
+\r
+;----------------------------------------------------------------------\r
+; timer interrupt\r
+;\r
+; 1,25 ms clock tick\r
+\r
+\r
+ cseg ;common!\r
+isvprt0:\r
+ push af\r
+ in0 a,(tcr) ;reset TIF0 flag\r
+ in0 a,(tmdr0l)\r
+ in0 a,(tmdr0h)\r
+\r
+ push hl ;11\r
+ ld hl,uptime ; 9\r
+ inc (hl) ;10\r
+ jr nz,iprt_1 ;6/8 38\r
+ inc hl ; 4\r
+ inc (hl) ;10\r
+ jr nz,iprt_1 ;6/8 58\r
+ inc hl ; 4\r
+ inc (hl) ;10\r
+ jr nz,iprt_1 ;6/8\r
+ inc hl ; 4\r
+ inc (hl) ;10\r
+iprt_1:\r
+ pop hl ; 9\r
+ ld a,(time_to)\r
+ sub a,1\r
+ jr c,iprt_0\r
+ ld (time_to),a\r
+iprt_0:\r
+ pop af\r
+ ei\r
+ ret\r
+\r
+uptime:\r
+ dw 0,0\r
+time_to:\r
+ db 0\r
+\r
+ end\r
- title 'general utility routines'
-
- ; i/o port init routines
-
- public ioiniml,ioini1l ;
-
- ; math
-
- public add_hla ; add a to hl
- public div32_16,div32_r ; divide 32 bit by 16 bit number (rounded)
-
- ; print utils
-
- public ?pmsg ; print message
- public pr.inln,pr.crlf ; print message inline, print newline
- public phex2,phex4 ; print 2 digit hex (A) or 4 digit hex (HL)
- public pr.dec,pr.decl ; print 16 or 32 bit decimal number
- public ?pderr ; print BIOS disk error message header
-
-
-
- extrn ?cono
- extrn @adrv,@trk,@sect ; used by disk error message
-
-;-------------------------------------------------------------------------------
-
-cr equ 13
-lf equ 10
-bell equ 7
-
-
- dseg
-
-;----------------------------------------------------------------------
-; output bytes to consecutive portaddresses
-;
-; hl: table with following structure:
-; db n, port1, val1, val2,... valn
-; db m, port1, val1, val2,... valm
-; ...
-; db 0 ; Terminate table
-
-ioiniml:
- push bc
- xor a
-ioml_lp:
- ld b,(hl)
- inc hl
- cp b
- jr z,ioml_e
-
- ld c,(hl)
- inc hl
- otimr
- jr ioml_lp
-ioml_e:
- pop bc
- ret
-
-;----------------------------------------------------------------------
-; output bytes to ports
-;
-; hl: tables of port,value pairs:
-; db n, port1,val1, port2,val2,... portn,valn
-; ...
-; db 0 ; Terminate table
-
-ioini1l:
- push bc
- jr io1_nxt
-io1_lp:
- ld c,(hl) ;port address
- inc hl
- otim
- jr nz,io1_lp
-io1_nxt:
- ld b,(hl) ;count
- inc hl
- inc b
- djnz io1_lp
-
- pop bc
- ret
-
-;--------------------------------------------------------------------
-; add a to hl
-;
-; return:
-; hl = hl + a
-; Flags undefined
-
-add_hla:
- add a,l
- ld l,a
- ret nc
- inc h
- ret
-
-;--------------------------------------------------------------------
-; rounded div 32 by 16 bit
-;
-; DEHL: Dividend (x)
-; BC: Divisor (y)
-; return:
-; HLDE: Rounded Quotient (q)
-; BC: Remainder (r)
-
-div32_r:
- push bc
- srl b ;y/2
- rr c
- add hl,bc ;low x + y/2
- pop bc
- jr nc,div_r1
- inc de
-div_r1:
- ;fall thru
-
-;--------------------------------------------------------------------
-; Divide 32 bit by 16
-;
-; DEHL: Dividend (x)
-; BC: Divisor (y)
-;
-; return:
-; DEHL: Quotient
-; BC: Reminder
-
-div32_16:
- exx ;low
- push de ;save alternate registers (de,bc)
- push bc
- exx ;high
- push hl ;lx
- push bc ;ly
- ld bc,0 ;bc = hy = 0
- ld h,b ;hl = hr = 0
- ld l,c
- ;de = x, hl = r
- exx ;low
- pop bc ;bc' = ly
- ex (sp),hl ;hl' = lx, save alternate hl
- ld de,0 ;de' = lr = 0
- ex de,hl ;de = x, hl = r
- exx ;high
- ld a,32 ;count
-;
-; start:
-; de: x (de: hx, de': lx)
-; bc: y (bc: hy, bc': ly)
-; hl: 0
-;
-div_lp: ;do
- exx ; low
- ex de,hl ; x
- add hl,hl ; x <<= 1
- exx ; high
- ex de,hl ; x
- adc hl,hl ; x <<= 1
- exx ; low
- ex de,hl ; r
- adc hl,hl ; r <<= 1
- exx ; high
- ex de,hl ; r
- adc hl,hl ; r <<= 1
- exx ; low
- inc de ; x/q += 1
- or a ;
- sbc hl,bc ;
- exx ; high
- sbc hl,bc ;
- jr nc,div_no_restore
- exx ; low
- dec de ;
- add hl,bc ; r += y
- exx ; high
- adc hl,bc ;
-
-div_no_restore: ;
- dec a ;
- jr nz,div_lp ;while (--count)
-
-; result:
-; de: q (de: hq, de': lq)
-; hl: r (hl: hr, hl': lr)
-
- exx ;low
- ex de,hl ;hl = lq, de = lr
-
- ex (sp),hl ;lq
- push de ;lr
- exx ;high
- pop bc ;bc = lr
- pop hl ;de = lq
-
- exx ;low
- pop bc ;restore alternate registers
- pop de
- exx ;high
- ret
-
-;-------------------------------------------------------------------------------
-; print message @<HL> up to a null
-; saves <BC> & <DE>
-
-?pmsg:
- push bc
- push de
-pmsg$loop:
- ld a,(hl)
- inc hl
- or a
- jr z,pmsg$exit
- ld c,a
- push hl
- call ?cono
- pop hl
- jr pmsg$loop
-pmsg$exit:
- pop de
- pop bc
- ret
-
-;-------------------------------------------------------------------------------
-; print message inline up to a null
-; saves all registers
-
-pr.inln:
- ex (sp),hl
- push af
- call ?pmsg
- pop af
- ex (sp),hl
- ret
-
-;-------------------------------------------------------------------------------
-; print <CR><LF>
-; saves all registers
-
-pr.crlf:
- call pr.inln
- db cr,lf,0
- ret
-
-;-------------------------------------------------------------------------------
-; print hl as a 4 digit hexadecimal number
-; saves all registers
-
-phex4:
- ld a,h
- call phex2
- ld a,l
- ; fall thru
-
-;-------------------------------------------------------------------------------
-; print a as a 2 digit hexadecimal number
-; saves all registers
-
-phex2:
- push af
- rra
- rra
- rra
- rra
- call print.digit
- pop af
-
-print.digit:
- push hl
- push de
- push bc
- push af
- and 00fh
- cp 10
- jr c,prd_1
- add a,007h
-prd_1:
- add a,'0'
-
- ld c,a
- call ?cono
- pop af
- pop bc
- pop de
- pop hl
- ret
-
-
-;-------------------------------------------------------------------------------
-; print decimal 16 bit number from HL
-;
-; HL: unsigned binary number to print
-; C: minimum print field width
-; number is prined right-aligned
-; B: pad character, typically ' ' or '0'
-
-pr.dec:
- push de
- ld de,0
- call pr.decl
- pop de
- ret
-
-;-------------------------------------------------------------------------------
-; print decimal 32 bit number from DEHL
-;
-; DEHL: unsigned binary number to print
-; C: minimum print field width
-; number is prined right-aligned
-; B: pad character, typically ' ' or '0'
-
-pr.decl:
- push bc ;save width and fillchar
- push bc
- exx ;(alt)
- ex (sp),hl ;save hl', get width and fill
- push de ;save de'
-
- xor a
- ld d,a ;clear counter
- ld e,a
- push af ; string terminator
- inc sp
-
-prd_divloop: ;do
- exx ; (main)
- ld bc,10 ;
- call div32_16 ; get a digit
- ld a,c ;
- add a,'0' ; make it printable
- push af ;
-
- ld a,h ;
- or l ;
- or d ;
- or e ;
- exx ; (alt)
- inc sp ;
- inc de ;
- jr nz,prd_divloop ;
-
-prd_filloop: ;h=filler, l=field width
- ld a,e
- cp l
- jr nc,prd_out
- push hl
- inc sp
- inc de
- jr prd_filloop
-prd_out:
- ld hl,0
- add hl,sp ;ptr to beginning of number string (hl==0 here)
- call ?pmsg
- ex de,hl
- add hl,sp
- ld sp,hl
- inc sp ;remove string terminator
- pop de
- pop hl
- exx ;(main)
- pop bc
- ret
-
-
-;-------------------------------------------------------------------------------
-
-?pderr:
- ld hl,drive$msg
- call ?pmsg ; error header
- ld a,(@adrv)
- add a,'A'
- ld c,a
- call ?cono ; drive code
- ld hl,track$msg
- call ?pmsg ; track header
- ld c,0
- ld hl,(@trk)
- call pr.dec ; track number
- ld hl,sector$msg
- call ?pmsg ; sector header
- ld hl,(@sect)
- call pr.dec ; sector number
- ret
-
- ; error message components
-drive$msg: db cr,lf,bell,'BIOS Error on ',0
-track$msg: db ': T-',0
-sector$msg: db ', S-',0
+ title 'general utility routines'\r
+\r
+ ; i/o port init routines\r
+\r
+ public ioiniml,ioini1l ;\r
+\r
+ ; math\r
+\r
+ public add_hla ; add a to hl\r
+ public div32_16,div32_r ; divide 32 bit by 16 bit number (rounded)\r
+\r
+ ; print utils\r
+\r
+ public ?pmsg ; print message\r
+ public pr.inln,pr.crlf ; print message inline, print newline\r
+ public phex2,phex4 ; print 2 digit hex (A) or 4 digit hex (HL)\r
+ public pr.dec,pr.decl ; print 16 or 32 bit decimal number\r
+ public ?pderr ; print BIOS disk error message header\r
+\r
+\r
+\r
+ extrn ?cono\r
+ extrn @adrv,@trk,@sect ; used by disk error message\r
+\r
+;-------------------------------------------------------------------------------\r
+\r
+cr equ 13\r
+lf equ 10\r
+bell equ 7\r
+\r
+\r
+ dseg\r
+\r
+;----------------------------------------------------------------------\r
+; output bytes to consecutive portaddresses\r
+;\r
+; hl: table with following structure:\r
+; db n, port1, val1, val2,... valn\r
+; db m, port1, val1, val2,... valm\r
+; ...\r
+; db 0 ; Terminate table\r
+\r
+ioiniml:\r
+ push bc\r
+ xor a\r
+ioml_lp:\r
+ ld b,(hl)\r
+ inc hl\r
+ cp b\r
+ jr z,ioml_e\r
+\r
+ ld c,(hl)\r
+ inc hl\r
+ otimr\r
+ jr ioml_lp\r
+ioml_e:\r
+ pop bc\r
+ ret\r
+\r
+;----------------------------------------------------------------------\r
+; output bytes to ports\r
+;\r
+; hl: tables of port,value pairs:\r
+; db n, port1,val1, port2,val2,... portn,valn\r
+; ...\r
+; db 0 ; Terminate table\r
+\r
+ioini1l:\r
+ push bc\r
+ jr io1_nxt\r
+io1_lp:\r
+ ld c,(hl) ;port address\r
+ inc hl\r
+ otim\r
+ jr nz,io1_lp\r
+io1_nxt:\r
+ ld b,(hl) ;count\r
+ inc hl\r
+ inc b\r
+ djnz io1_lp\r
+\r
+ pop bc\r
+ ret\r
+\r
+;--------------------------------------------------------------------\r
+; add a to hl\r
+;\r
+; return:\r
+; hl = hl + a\r
+; Flags undefined\r
+\r
+add_hla:\r
+ add a,l\r
+ ld l,a\r
+ ret nc\r
+ inc h\r
+ ret\r
+\r
+;--------------------------------------------------------------------\r
+; rounded div 32 by 16 bit\r
+;\r
+; DEHL: Dividend (x)\r
+; BC: Divisor (y)\r
+; return:\r
+; HLDE: Rounded Quotient (q)\r
+; BC: Remainder (r)\r
+\r
+div32_r:\r
+ push bc\r
+ srl b ;y/2\r
+ rr c\r
+ add hl,bc ;low x + y/2\r
+ pop bc\r
+ jr nc,div_r1\r
+ inc de\r
+div_r1:\r
+ ;fall thru\r
+\r
+;--------------------------------------------------------------------\r
+; Divide 32 bit by 16\r
+;\r
+; DEHL: Dividend (x)\r
+; BC: Divisor (y)\r
+;\r
+; return:\r
+; DEHL: Quotient\r
+; BC: Reminder\r
+\r
+div32_16:\r
+ exx ;low\r
+ push de ;save alternate registers (de,bc)\r
+ push bc\r
+ exx ;high\r
+ push hl ;lx\r
+ push bc ;ly\r
+ ld bc,0 ;bc = hy = 0\r
+ ld h,b ;hl = hr = 0\r
+ ld l,c\r
+ ;de = x, hl = r\r
+ exx ;low\r
+ pop bc ;bc' = ly\r
+ ex (sp),hl ;hl' = lx, save alternate hl\r
+ ld de,0 ;de' = lr = 0\r
+ ex de,hl ;de = x, hl = r\r
+ exx ;high\r
+ ld a,32 ;count\r
+;\r
+; start:\r
+; de: x (de: hx, de': lx)\r
+; bc: y (bc: hy, bc': ly)\r
+; hl: 0\r
+;\r
+div_lp: ;do\r
+ exx ; low\r
+ ex de,hl ; x\r
+ add hl,hl ; x <<= 1\r
+ exx ; high\r
+ ex de,hl ; x\r
+ adc hl,hl ; x <<= 1\r
+ exx ; low\r
+ ex de,hl ; r\r
+ adc hl,hl ; r <<= 1\r
+ exx ; high\r
+ ex de,hl ; r\r
+ adc hl,hl ; r <<= 1\r
+ exx ; low\r
+ inc de ; x/q += 1\r
+ or a ;\r
+ sbc hl,bc ;\r
+ exx ; high\r
+ sbc hl,bc ;\r
+ jr nc,div_no_restore\r
+ exx ; low\r
+ dec de ;\r
+ add hl,bc ; r += y\r
+ exx ; high\r
+ adc hl,bc ;\r
+\r
+div_no_restore: ;\r
+ dec a ;\r
+ jr nz,div_lp ;while (--count)\r
+\r
+; result:\r
+; de: q (de: hq, de': lq)\r
+; hl: r (hl: hr, hl': lr)\r
+\r
+ exx ;low\r
+ ex de,hl ;hl = lq, de = lr\r
+\r
+ ex (sp),hl ;lq\r
+ push de ;lr\r
+ exx ;high\r
+ pop bc ;bc = lr\r
+ pop hl ;de = lq\r
+\r
+ exx ;low\r
+ pop bc ;restore alternate registers\r
+ pop de\r
+ exx ;high\r
+ ret\r
+\r
+;-------------------------------------------------------------------------------\r
+; print message @<HL> up to a null\r
+; saves <BC> & <DE>\r
+\r
+?pmsg:\r
+ push bc\r
+ push de\r
+pmsg$loop:\r
+ ld a,(hl)\r
+ inc hl\r
+ or a\r
+ jr z,pmsg$exit\r
+ ld c,a\r
+ push hl\r
+ call ?cono\r
+ pop hl\r
+ jr pmsg$loop\r
+pmsg$exit:\r
+ pop de\r
+ pop bc\r
+ ret\r
+\r
+;-------------------------------------------------------------------------------\r
+; print message inline up to a null\r
+; saves all registers\r
+\r
+pr.inln:\r
+ ex (sp),hl\r
+ push af\r
+ call ?pmsg\r
+ pop af\r
+ ex (sp),hl\r
+ ret\r
+\r
+;-------------------------------------------------------------------------------\r
+; print <CR><LF>\r
+; saves all registers\r
+\r
+pr.crlf:\r
+ call pr.inln\r
+ db cr,lf,0\r
+ ret\r
+\r
+;-------------------------------------------------------------------------------\r
+; print hl as a 4 digit hexadecimal number\r
+; saves all registers\r
+\r
+phex4:\r
+ ld a,h\r
+ call phex2\r
+ ld a,l\r
+ ; fall thru\r
+\r
+;-------------------------------------------------------------------------------\r
+; print a as a 2 digit hexadecimal number\r
+; saves all registers\r
+\r
+phex2:\r
+ push af\r
+ rra\r
+ rra\r
+ rra\r
+ rra\r
+ call print.digit\r
+ pop af\r
+\r
+print.digit:\r
+ push hl\r
+ push de\r
+ push bc\r
+ push af\r
+ and 00fh\r
+ cp 10\r
+ jr c,prd_1\r
+ add a,007h\r
+prd_1:\r
+ add a,'0'\r
+\r
+ ld c,a\r
+ call ?cono\r
+ pop af\r
+ pop bc\r
+ pop de\r
+ pop hl\r
+ ret\r
+\r
+\r
+;-------------------------------------------------------------------------------\r
+; print decimal 16 bit number from HL\r
+;\r
+; HL: unsigned binary number to print\r
+; C: minimum print field width\r
+; number is prined right-aligned\r
+; B: pad character, typically ' ' or '0'\r
+\r
+pr.dec:\r
+ push de\r
+ ld de,0\r
+ call pr.decl\r
+ pop de\r
+ ret\r
+\r
+;-------------------------------------------------------------------------------\r
+; print decimal 32 bit number from DEHL\r
+;\r
+; DEHL: unsigned binary number to print\r
+; C: minimum print field width\r
+; number is prined right-aligned\r
+; B: pad character, typically ' ' or '0'\r
+\r
+pr.decl:\r
+ push bc ;save width and fillchar\r
+ push bc\r
+ exx ;(alt)\r
+ ex (sp),hl ;save hl', get width and fill\r
+ push de ;save de'\r
+\r
+ xor a\r
+ ld d,a ;clear counter\r
+ ld e,a\r
+ push af ; string terminator\r
+ inc sp\r
+\r
+prd_divloop: ;do\r
+ exx ; (main)\r
+ ld bc,10 ;\r
+ call div32_16 ; get a digit\r
+ ld a,c ;\r
+ add a,'0' ; make it printable\r
+ push af ;\r
+\r
+ ld a,h ;\r
+ or l ;\r
+ or d ;\r
+ or e ;\r
+ exx ; (alt)\r
+ inc sp ;\r
+ inc de ;\r
+ jr nz,prd_divloop ;\r
+\r
+prd_filloop: ;h=filler, l=field width\r
+ ld a,e\r
+ cp l\r
+ jr nc,prd_out\r
+ push hl\r
+ inc sp\r
+ inc de\r
+ jr prd_filloop\r
+prd_out:\r
+ ld hl,0\r
+ add hl,sp ;ptr to beginning of number string (hl==0 here)\r
+ call ?pmsg\r
+ ex de,hl\r
+ add hl,sp\r
+ ld sp,hl\r
+ inc sp ;remove string terminator\r
+ pop de\r
+ pop hl\r
+ exx ;(main)\r
+ pop bc\r
+ ret\r
+\r
+\r
+;-------------------------------------------------------------------------------\r
+\r
+?pderr:\r
+ ld hl,drive$msg\r
+ call ?pmsg ; error header\r
+ ld a,(@adrv)\r
+ add a,'A'\r
+ ld c,a\r
+ call ?cono ; drive code\r
+ ld hl,track$msg\r
+ call ?pmsg ; track header\r
+ ld c,0\r
+ ld hl,(@trk)\r
+ call pr.dec ; track number\r
+ ld hl,sector$msg\r
+ call ?pmsg ; sector header\r
+ ld hl,(@sect)\r
+ call pr.dec ; sector number\r
+ ret\r
+\r
+ ; error message components\r
+drive$msg: db cr,lf,bell,'BIOS Error on ',0\r
+track$msg: db ': T-',0\r
+sector$msg: db ', S-',0\r