TITLE ATRSX.ASM -- Z-System cp/m 2.2 RSX 9/6/89 ; WAITVALUE equ 5000h ; SHELL$ equ 0 ; bit 0, cmdstat flg (zmsg+3) .accept "Enter 1 for CP/M 2.2, 0 for CP/M Plus",CPM22 .xlist include atdefs.lib INCCP$ equ 0 ; bit 0, zmsg+7 ; atrsx: org atrsx + 100h ; Origin for PRL file (skip one page) IF CPM22 ;---------- RSX HEADER Standard P*PS RSX header for CP/M 2.2 ------- ; begin: ds 6 rsx: jp rsx_bdos ; BDOS intercept 6 jp rsx_wboot ; warm-boot intercept 9 jp rsxremove ; remove-rsx entry 0c rsxwba: dw $-$ ; original 0001 value 0f rsxprot:dw rsx ; lowest rsx addr 11 dw rsxname ; -> rsx name 13 rsxnext:jp $-$ ; -> next wb or ccp entry 15 ; next: jp $-$ ; -> next rsx, or BDOS 18 ; ds HDRLEN - ($-begin) ; filler for CP/M 2.2 ; ;------------------------------------------------------- ; ELSE ; not cpm22 ; ;---------- RSX HEADER Standard DRI Header for CP/M Plus --------- ; begin: ds 6 ; rsx: jp rsx_bdos ; BDOS intercept NEXT: jp 0006h ; modified to JMP BDOS PREV: dw 0007h ; modified to point to prev RSX *HI* byte remov: db 0 ; remove flag db 0 ; non-banked flag db 'AT ' ; exactly 8 letters total db (VERS/10)+'0','.',(VERS MOD 10)+'0',VLETTER ; db 00h ; CP/M Plus loader flag dw 0 ; reserved, ptr to next cmd line ; End of CP/M Plus RSX prefix ; ; toccp:jp $-$ ; next warmboot addr ; 1bh ; ;------------------------------------------------------- ; ENDIF ;cpm22 ; origwbvec: IF CPM22 jp rsx+3 ; original warmboot ;+1eh ELSE ; jp rsx_wboot db 0,0,0 ; unused, preserved for alignment ENDIF ; cpm22 ; bconst: jp rsx_constat ; original constat ;+21h bconin: jp rsx_conin ; original conin ;+24h ; ;=================== config_data: ;+27h<<< ; ; scb_base: ds 2 ; ptr to CP/M Plus scb bankedflg: db 0 ; NZ if banked system ; ; original values of CP/M Plus's 2nd bios JP table opcodes ; wboot_op: db 0 const_op: db 0 conin_op: db 0 ; ; dsclk.: dw 0 ; ptr to Datestamper clock nxtchr.: dw 0 cmdlin.: dw 0 zmclend: dw 0 zcst.: dw 0 zstat.: dw 0 mhz: db 0 bgflg.: dw 0 dogdelay: db 01 ; static lowdog: db 0 dog: dw 0 ; watchdog count ; ; update area pendingflg: db 0 ; in lock: db 0FFh ; exaxtly count: dw DELAYVALUE*256+0 ; this speed: db DELAYVALUE ; order ringcnt: db 0 ; ringflg, # of rings dueflg: db 0 autoflg: db 0 ; atime: ds 6 ; the alarm date/time atimej equ atime+1 ; julian word, followed by hr:mi:se in bcd ; atcmd: db ';' db 'M00:AT !' acode: db ' ',0 atcmdend equ $-1 atcmdlen equ $-atcmd ;========================= ; WARM-BOOT INTERCEPT ;========================= ; IF CPM22 ; ; BDOS intercept ; rsx_bdos: .new ld a,c ; if line input cp 10 jr nz,2$ call inccp? ; ..and in ccp jp z,next call next ; ..CALL bdos .testa dueflg ; ..on return, if alarm is due jr z,1$ push hl ; (save bdos parameter) call push2ccp ; ..append to user's command line pop hl ; (restore it) 1$: ld a,l ret ; 2$: cp AT_COMMAND ; if "lock/unlock" call jp nz,next ld hl,lock ; set/unset lock byte ld (hl),e ld hl,begin ; return ptr to rsx base ret ; RSX name for P*PS RSX header ; rsxname:db 'AT v. ' db (VERS/10)+'0','.',(VERS MOD 10)+'0',vletter db 0 ; nul-terminator ; ; This routine may be called by P*PS-compatible REMOVE utility ; rsxremove: call disable call ckbelow ; if there is an RSX below ZEX scf ; clear CY = can't remove ccf ret nz ; ..return with CY clear call movbak ; else move jumps back scf ; and return CY set ret ; Z if this is lowest rsx ; ckbelow: ld hl,(rsxwba) ; if bios warm-boot jp points to inc hl ld a,(hl) inc hl ld h,(hl) ld l,a ld de,rsx+3 ; this rsx's warmboot entry or a sbc hl,de ret ; then Z set = we are the lowest RSX ; ; Warm-boot intercept ; rsx_wboot: ld hl,(rsxwba) ; always restore (0001) ld (0001),hl call ckbelow ; If this is the lowest rsx jr nz,toccp ; ld hl,(rsxprot) ; .. reprotect zex on page 0 ld (0006),hl ; toccp: ld bc,(4) ; C = logged DU jp rsxnext ; continnue to next rsx, or to ccp entry ; ; Move the original BIOS jumps back into place, but only ; if there is no RSX below ZEX. ; movbak: ld hl,(next+1) ; take rsx out of BDOS chain ld (0006),hl ; ; DON'T TRACE this under a debugger!! ; swap local and BIOS jump tables ; swapbk: ld hl,(0001) ; restore the original bios vectors ld de,origwbvec ; and restore rsx's addresses to ld b,3*3 ; the local jp table (for MBASIC... swplp: ld a,(de) ; which copies addresses out of the bios ld c,(hl) ; jp table, and may still be running when) ld (hl),a ; zex terminates) ld a,c ld (de),a inc hl inc de djnz swplp f121: ret ; ELSE ; not cpm22 ; ; BDOS intercept for CP/M Plus ; rsx_bdos: .new ld a,c ; if line input cp 10 jr nz,2$ call inccp? ; ..and in ccp jr z,jnext call next ; ..CALL bdos .testa dueflg ; ..on return, if alarm is due jr z,1$ push hl ; (save bdos parameter) call push2ccp ; ..append to user's command line pop hl ; (restore it) 1$: ld a,l ret ; 2$: cp AT_COMMAND ; if "lock/unlock" call jr nz,3$ ld hl,lock ld (hl),e ld hl,begin ret ; 3$: cp 3Bh ; if "remove rsx" call jr nz,jnext ld a,d or e jr nz,jnext push de call ckbelow ; and AT is lowest RSX pop de jr nz,jnext push bc push de call movbak ; ..unpatch the BIOS pop de pop bc jnext: jp next ; Z if lowest rsx ckbelow: ld hl,(scb_base) ; if maxtpa page address ld l,mxtpaOFF+1 ld a,(hl) ld de,rsx cp d ret movbak: ld hl,(0001) ; restore the original BIOS vectors inc hl ; -> constat inc hl inc hl ld de,bconst ld b,2*3 swplp: ld a,(de) ld c,(hl) ld (hl),a ld a,c ld (de),a inc hl inc de djnz swplp ; ; .testa bankedflg ; if banked system ret z ld hl,(scb_base) ; .. restore the banked BDOS vector bytes ld l,bnkwbOFF ld bc,6 add hl,bc ; skip to const ; ld de,const_op ; de -> wb byte ld a,(de) ld (hl),a ; add hl,bc ; for conin inc de ld a,(de) ld (hl),a ret ; ENDIF ; cpm22 ; ;====================== ; Console Input Intercept Routine ; ====================================== ; rsx_conin: .new call rsx_constat ; until keypress or a jr z,rsx_conin ; ..spin on constat ld hl,(dogdelay-1) ; reset watchdog count, get h = byte ld l,0 ld (dog),hl jp bconin ; ; ; Console Input Status Intercept Routine ; ====================================== ; rsx_constat: .testa dueflg ; if alarm has arrived jr z,notyet call inccp? ; if in ccp jp nz,bconst ; ..go to bconst ; ; This countout is for shells... ; n0: ld hl,lowdog ; if count >0 ld a,(hl) or a jr nz,n1 ; ..go decrement it inc hl ld a,(hl) or a jr nz,n1 inc hl ld a,(hl) or a jr z,n2 ; ; count is > 0, decrement it ; n1: ld hl,lowdog dec (hl) jr nz,notyet inc hl dec (hl) jr nz,notyet inc hl dec (hl) jr nz,notyet ; ; count now 0 ; ; alarm has hit, and there's been no console activity ; for at least watchdog time ; n2: ld hl,(zcst.) ; if in a shell bit SHELL$,(hl) ; (-> zmsg+3) jr z,notyet res SHELL$,(hl) ; clear bit, in case ; scheduled appl. is a shell! ; and would think it had been invoked. ; ; Terminate shell after period of no console input. ; breakout: xor a ld (dueflg),a rst 0 ; ; ; ; notyet: ld hl,pendingflg ; if nothing pending ld a,(hl) or a jp z,bconst ; ..continue inc hl ; -> lock ld a,(hl) ; if locked or a jp nz,bconst ; ..continue inc hl ; -> count dec (hl) ; if count not expired jp nz,bconst ; ..continue inc hl ; -> high byte of count dec (hl) jp nz,bconst ; ..continue ld a,(speed) ; reset delay ld (hl),a ; ld (savesp),sp ; use local stack ld sp,rsxstack IF CPM22 ld hl,clkbuf ; read the clock push hl call dsclock pop hl call cktime ELSE ; call plusclk ; read clk & compare time ENDIF ; cpm22 jr nc,exit ; ; time > alarmtime ; action: .new ld hl,ringcnt inc (hl) ; pre-increment count byte jr rngbot ; rnglp: push hl ld c,BELL call conot ld a,(mhz) ld b,a 1$: ld de,WAITVALUE 2$: dec de ld a,d or e jr nz,2$ djnz 1$ pop hl rngbot: dec (hl) ; decrement ring count jr nz,rnglp ; ; exit w/ count = 0 ; so won't ring again if in background noring: IF CPM22 ld hl,(bgflg.) ; if in BGii background state bit 3,(hl) jr nz,exit ; ..wait until in foreground ENDIF call inccp? jr z,delayat ; ..skip ; inccp: ; if user has not yet entered any character to the ccp... ; ld de,(cmdlin.) ; point at start of mcl ld a,(de) ; test for any chars entered yet or a jr z,inccp1 call disable ; A=0 dec a ld (dueflg),a jr exit ; ; Z set inccp1: call putcmd ; install AT command xor a ; nul terminate it ld (de),a jr breakout ; ; set up cmd line, but return to application or shell ; delayat: call append ; exit: ld sp,(savesp) ; restore user's sp jp bconst ; and continue to constat ; ; ; ; Append AT !x to end of pending mcl. ; ; >> A = NZ if action is to be delayed ; append: .new ld a,TRUE ld (dueflg),a ld hl,(nxtchr.) ; addr of nxtchr ptr .gethl ; addr of nxtchr ; ; find end of cmds in mcl ; append AT command ; findend: .new 1$: ld a,(hl) ; find end of cmds in mcl or a inc hl jr nz,1$ dec hl ; push hl ; save ptr to nul at end of cmdline ld de,atcmdlen add hl,de ex de,hl ; de -> end + len to append ld hl,(zmclend) ; check for overflow sbc hl,de pop de ; -> nul at end of pending cmds jr c,noroom ; ld hl,(cmdlin.) ; if de != start of cmdline or a sbc hl,de ; ; called entry putcmd: ld hl,atcmd+1 jr z,3$ dec hl ; -> semicolon ldi ; ..add it 3$: ld bc,atcmdlen-1 ldir ; append AT cmd ld a,TRUE ld (autoflg),a ; tell AT.COM this is an auto-invocation noroom: disable: xor a ; clear pending flag ld (pendingflg),a ret ; push2ccp: ld hl,(cmdlin.) dec hl ; -> count byte push hl ; ld a,(hl) ; get count byte ld e,(hl) ld d,0 inc hl add hl,de ; -> end of user-entered cmd ex de,hl or a ; Z if no bytes call putcmd xor a ; possibly extra NUL ld (de),a ; for no-semicolon case pop hl ; -> cnt byte ld a,(hl) ; increase count to include add atcmdlen ; appended cmd. ld (hl),a ret ; ========== SUPPORT ROUTINES ========== ; ; inccp?: ld hl,(zstat.) ; if constat called from ccp bit INCCP$,(hl) ret conot: ld hl,(0001) ld de,0ch-3 add hl,de jp (hl) ; ; IF CPM22 ; ; call DateStamper clock ; dsclock: ld de,(dsclk.) push de ret ; ; << CY if time at hl > alarm time ; cktime: ld de,atime ; has alarm time passed? ld b,6 timlp: ld a,(de) cp (hl) ret nz inc hl inc de djnz timlp ret ; ELSE ; ; read CP/M Plus clock ; plusclk: ld hl,(0001) ; call bios TIME ld l,3*26 ; to get scb values updated ld c,0 ; get-time parameter call gohl ld hl,(scb_base) ld l,0F5h ; HI byte of julian date word ; ; << CY if CP/M Plus time at hl (Julian HI byte) > alarm time ; cktime: ld de,atimej+1 ; has alarm time passed? ld a,(de) ; compare HI byte of julian date word cp (hl) ret nz dec hl ; compare LO byte " dec de ld b,2+3 ; (ok to re-check hi byte, it will match) timlp: ld a,(de) cp (hl) inc hl inc de ret nz djnz timlp ret ; gohl: jp (hl) ; ENDIF ; cpm22 ; savesp: dw 0 ; user's sp ; clkbuf: db 0,0,0,0,0,0 ; buffer for current time ; ds 24 ; local stack .list rsxstack equ $ rsxlength equ $ - begin ; .prtval 16,,rsxlength, end