; CALCRCP.Z80 Version 1.0 ; October 31, 1986 by Carson Wilson. ; ; Please leave any problems, comments, or suggestions at ; Lillipute Z-Node, Chicago, 312-649-1730 or 312-664-1730. ; ; This is a combination of elements from Paul Pomerleau's ; SLTRAP.LBR and Eric Meyer's HP.COM. When assembled into a ; Resident Command Package (RCP) for ZCPR3, it becomes a "pop-up" ; calculator modelled on the principles of Eric Meyer's HP+.COM ; for CP/M Plus. ; ; To use, first put this file and Z3BASE.LIB for your system on ; the current drive and assemble and load to CALC.RCP. Then load ; CALC.RCP with LDR.COM. Use the "H" command to display help on ; usage. The calculator won't become active until activated by ; the command "CALC" from your system's operating system prompt. ; Thereafter, whenever a CONTROL-] is detected, the calculator ; will become active. The calculator can thus be activated from ; the middle of any program which tests for console input, which ; means any interactive program. ; WARNING: BECAUSE THIS RCP LINKS UP WITH YOUR SYSTEM'S BIOS, IT ; IS NECESSARY TO TURN IT OFF BY USING THE "CALC" COMMAND AGAIN ; BEFORE LOADING ANOTHER RCP. ; To make the CALC.RCP even more versatile, create an alias named ; RCP.COM which will respond to commands to automatically go to ; the proper directories, get the proper RCP and load it. ; For example, my CALC.COM contains the following: ; IF EX LOAD:$1.RCP ; ROOT:LDR LOAD:$1.RCP ; FI ; H ; This enables me to type "RCP CALC," thereby commanding my ; system to get CALC.RCP from the proper directory, load it, and ; display its built-in help. When I'm through with CALC, I first type ; CALC to turn it off, then "RCP SYS" to reload my normal RCP. ; Like HP+.COM, this calculator may not work with a very few ; programs such as WordStar, which interact directly with the ; BIOS. See HP+.DOC for more on this. For information on how the ; calculator works, see HP.DOC by Eric Meyer. Both of these files ; are found in HP.LBR. vers equ 10 BDOS equ 5 maclib Z3Base.lib ; use base addresses ; ; System entry point ; org RCP ; Passed from Z3Base db 'Z3RCP' ; Flag for package loader db 04 ; How long each name is ctab: db 'H ' ; Help for RCP dw CList db 'CALC' ; Enable/Disable trigger key dw TrigOn ctab1: db 0 ; ; Banner name of RCP: ; Command list routine ; CList: ld de,RCP$name jp string ; ; Routines for trapping I/O. ; Trigger equ ']'-'@' ; control-] is current trigger key ; TrigOn: ld a,(IsOn) cp 1 ; key detection on? jp z,TrigOff ; yes, turn off ld a,1 ; no, flip flag to ON ld (IsOn),a ; & fall through ; ; ENABLE Trigger Key Detection ; ; First, replace BIOS jump to its "console in" routine with jump ; to RCP routine, and save the addresses of the BIOS jump and the ; routine. ; ld hl,(1) ; Get boot location ld de,07h ; Offset for location of "JP CONIN" in BIOS add hl,de ; hl now holds BIOS "jump" location ld (JConIn),hl ; Save location for BIOS jp to console in ld e,(hl) inc hl ld d,(hl) ; Move to de ld (ConIn),de ; Save BIOS ConIn routine address ld de,NewIn ld (hl),d ; Replace BIOS "jump" with ours dec hl ld (hl),e ; Fill our NewIn location in ; ; Now save the address of the BIOS conout routine. ; ld hl,(1) ; Get boot location ld de,0ah ; Offset for location of "JP CONOUT" in BIOS add hl,de ; hl now holds BIOS "jump" location ld e,(hl) inc hl ld d,(hl) ; Move to de ld (con),de ; Save BIOS ConOut routine address ; ld a,(on) ; Is the calculator running? or a ret nz ; Yes, don't print "Trigger Key Enabled" msg. ld de,OnMsg ; Else tell user trigger key activated jp string ret ; NewIn: call OrigIn ; Bring key in cp Trigger ; Is it the trigger key? ret nz ; No - business as usual ; ld (SavStk),sp ; Yes, run calculator ld sp,newstk ; push ix push iy push af push bc push de push hl ; ld a,(on) cpl ld (on),a ; Flip calculator running flag ; call TrigOff ; Turn off trigger key detection ; and fall through to calculator ; ; ********** Begin Calculator ********* ; ; This is a modified disassembly of HP.COM by Eric Meyer. In place ; of the HP prompt, I have substituted a more informative one. ; Relative jumps are substituted for absolute ones where possible. ; The exit and entry routines have been replaced by my own routines ; which appear immediately before and after the calculator routine. ; The exit key has been changed from ^C to ^] to maintain ; consistency with the trigger key. Finally, direct BIOS calls ; replace BDOS calls to conin and conout, and a routine which ; replaces echoed characters from BDOS conin is no longer ; necessary (commented out). ; jr start signon: db 0dh,'CALC-RCP (^] = Off) ' db ' ',0 ld a,(de) start: xor a ld (r17),a s9: ld hl,signon call StrOut call s2 ld hl,(r4) call s3 ld hl,r5 ld b,8 ; Print 8 spaces prompt: ld (hl),' ' inc hl dec b jr nz,prompt ld hl,r5 ; Print prompt "H>" call StrOut xor a ld (r3),a getin: call s4 ; Get input from BIOS cp Trigger ; RCP trigger key jp z,quit ; End program cp 1bh jp z,esc cp '+' jp z,plus cp '-' jp z,minus cp '*' jp z,times cp '^' jp z,exp cp '/' jp z,div cp '%' jp z,remain cp '&' jp z,bitand cp '|' jp z,bitor cp '~' jp z,negate cp 0dh jp z,run cp 8 jr z,backsp cp '=' jp z,equals cp 18h ; ^X jr z,clear cp 'S' jp z,save cp 's' jp z,save cp 'R' jp z,recall cp 'r' jp z,recall cp '!' ; Space or control char? jp c,illegal ; Yes - error s23: ld hl,r7 ld de,r5 ld bc,7 ldir ld (r8),a ld a,0ffh ld (r3),a s8: ld hl,signon ; Reprint prompt call StrOut call s2 ld hl,r5 call StrOut jp getin ; Get input backsp: ld a,(r3) or a jr z,s7 ld hl,r9 ld de,r8 ld bc,7 lddr ld a,' ' ld (r5),a jr s8 s7: ld hl,0 ld (r4),hl ld a,0ffh ld (r17),a jp s9 clear: ld hl,r4 ; Clear registers ld b,10h ; (16 bytes) s10: ld (hl),0 inc hl dec b jr nz,s10 jp s9 run: call s11 call s12 ld a,0ffh ld (r17),a jp s9 equals: call s11 ld hl,(r4) ex de,hl ld hl,(r10) ex de,hl ld (r10),hl ex de,hl ld (r4),hl jp start negate: call s11 ld hl,(r4) ld a,h cpl ld h,a ld a,l cpl ld l,a inc hl ld (r4),hl jp start bitor: call s11 call s14 ld a,h or d ld h,a ld a,l or e ld l,a s16: ld (r10),hl call s15 jp start bitand: call s11 ; bitwise and call s14 ld a,h and d ld h,a ld a,l and e ld l,a jr s16 remain: call s11 ; remainder call s14 call s17 jp c,s18 ex de,hl jr s16 div: call s11 call s14 call s17 jp c,s18 jr s16 times: call s11 call s14 call s19 jp c,s18 jr s16 exp: call s11 call s14 ld a,d or e jr nz,s20 ld hl,1 jr s16 s20: ld b,d ld c,e ld d,h ld e,l s21: dec bc ld a,b or c jr z,s16 push bc push de call s19 pop de pop bc jp c,s18 jr s21 minus: call s11 call s14 sbc hl,de jr s16 plus: call s11 call s14 add hl,de jp s16 save: call s11 call s4 cp '4' ; Legal register? jp nc,s18 sub '1' ; Legal register? jp c,s18 add a,a ld e,a ld d,0 ld hl,r11 add hl,de ld a,(r4) ld (hl),a inc hl ld a,(r12) ld (hl),a jp start recall: call s11 call s4 cp '4' jp nc,s18 sub '1' jp c,s18 add a,a ld e,a ld d,0 ld hl,r11 add hl,de ld a,(r17) or a jr nz,s22 push hl call s12 pop hl s22: ld a,(hl) ld (r4),a inc hl ld a,(hl) ld (r12),a jp start chars: db '+-*^/%&~=|SsRr' ; Legal commands esc: call s4 ld hl,chars ld b,0eh s24: cp (hl) jp z,s23 inc hl dec b jr nz,s24 and 5fh push af call s11 pop af cp 'H' ; Switch to hex jr z,hex cp 'D' ; Switch to decimal jr z,dec cp 'B' ; Switch to binary jr z,bin cp 'C' ; Switch to character jr z,char jr s18 hex: ld hl,s25 ld de,s26 jr s27 dec: ld hl,s28 ld de,s29 jr s27 bin: ld hl,s30 ld de,s31 jr s27 char: ld hl,s32 ld de,s33 s27: ld (r13),a ld (scale),hl ; Store current scale = hex, dec, etc. ex de,hl ld (r14),hl jp start s14: ld hl,(r4) ex de,hl ld hl,(r10) ret s11: ld a,(r3) or a ret z ld hl,r5 call s35 jr c,s36 ; Illegal - ring bell ld a,(r17) or a jr nz,s37 push hl call s12 pop hl s37: ld (r4),hl xor a ld (r17),a ret s36: pop hl illegal:ld a,7 ; Ring bell call CharOut jp s8 s18: ld a,7 call CharOut jp start s15: ld hl,r10 ld de,r4 ld bc,0eh ldir ret s12: ld hl,r15 ld de,r16 ld bc,0eh lddr ret s2: ld a,(r13) call CharOut ld a,'>' ; Prompt call CharOut ld a,' ' ; Prompt: "H> " call CharOut ret s19: ld c,l ld b,h ld hl,0 ld a,0fh s40: push af or d jp p,s38 add hl,bc jp c,s39 s38: add hl,hl jp c,s39 ex de,hl add hl,hl ex de,hl pop af dec a jr nz,s40 or d ret p add hl,bc ret s17: ld a,e or d jp z,s41 ld c,l ld b,h ld hl,0 ld a,10h or a s43: ld (r20),a rl c rl b rl l rl h ld (r21),hl sbc hl,de ccf jr c,s42 ld hl,(r21) s42: ld a,(r20) dec a jr nz,s43 ex de,hl rl c ld l,c rl b ld h,b or a ret s35: push hl s45: ld a,(hl) or a jr z,s44 cp ' ' jr nz,s44 ld (hl),'0' inc hl jr s45 s44: pop hl db 0c3h ; jp scale: dw s25 ; Current scale (hex default) s25: ld b,04h call s46 call s47 ret c ld d,a inc hl call s47 ret c ld e,a ex de,hl or a ret s47: call s48 ret c rlca rlca rlca rlca inc hl ld e,a call s48 ret c add a,e or a ret s48: ld a,(hl) and 7fh cp 'A' jr c,s49 and 5fh sub 7 s49: sub '0' jp m,s41 cp 10h jr nc,s41 or a ret s39: pop bc s41: scf ret s46: ld a,(hl) cp '0' jr nz,s39 inc hl dec b jr nz,s46 or a ret s28: ld b,3 call s46 ld de,0 ld bc,2710h ; constant call s50 ld bc,03e8h call s50 ld bc,64h call s50 ld bc,0ah call s50 ld bc,1 call s50 ex de,hl or a ret s50: ld a,(hl) cp ':' jr nc,s39 sub '0' jp m,s39 ex de,hl or a s52: jr z,s51 add hl,bc jr c,s39 dec a jr s52 s51: ex de,hl inc hl ret s30: ld b,0 ld c,80h s56: ld a,(hl) inc hl cp '0' jr z,s53 cp '1' jr z,s54 jr s41 s54: ld a,b or c ld b,a s53: ld a,c cp 1 jr z,s55 rrca ld c,a jr s56 s55: ld l,b ld h,0 or a ret s32: ld b,7 call s46 ld a,(hl) and 7fh ld l,a ld h,0 or a ret s3: db 0c3h ; jp r14: dw s26 s26: ld b,4 call s57 ld a,h call s58 ld a,l call s58 ret s58: push af and 0f0h rra rra rra rra call hexout pop af and 0fh call hexout ret hexout: add a,'0' cp ':' ; Arabic number output? jp c,CharOut ; Yes add a,7 ; No - get char. A-F for hex output jp CharOut s57: ld a,' ' call CharOut dec b jr nz,s57 ret s29: ld b,3 call s57 ld c,0 s74: ld a,h cp '''' jr c,s60 jr nz,s61 ld a,l cp 10h jr c,s60 s61: inc c ld de,0d8f0h ; Constant add hl,de jr s74 s60: ld a,'0' add a,c call CharOut ld c,0 s63: ld a,h cp 3 jr c,s62 jr nz,s75 ld a,l cp 0e8h jr c,s62 s75: inc c ld de,0fc18h ; Constant add hl,de jr s63 s62: ld a,'0' add a,c call CharOut ld c,0 s66: ld a,h or a jr nz,s64 ld a,l cp 64h jr c,s65 s64: inc c ld de,0ff9ch ;Constant add hl,de jr s66 s65: push af ld a,'0' ;30h add a,c call CharOut pop af ld c,0 s68: cp 0ah jr c,s67 inc c sub 0ah jr s68 s67: push af ld a,'0' add a,c call CharOut pop af add a,'0' call CharOut ret s31: ld c,80h ld b,l s70: call s69 ld a,c cp 1 ret z rrca ld c,a jr s70 s69: ld a,b and c ld a,'0' jr z,s71 ld a,'1' s71: call CharOut ret s33: ld b,7 call s57 ld a,l and 7fh cp 7fh jr z,s72 cp ' ' jr nc,CharOut or '@' jr s73 s72: ld a,'?' s73: push af ld a,8 ; Backspace call CharOut ld a,5eh call CharOut pop af jr CharOut CharOut: push bc push de push hl ld c,a ; Put char. in C, and call OrigOut ; BIOS console out pop hl pop de pop bc ret StrOut: xor a ; Print string add a,(hl) ret z push hl call CharOut pop hl inc hl jr StrOut s4: call OrigIn and 7fh ; Strip high bit ; ; Since we are calling BIOS directly, characters are ; no longer echoed to the screen, so they needn't be erased ; ; cp '!' ; printable character? ; ret c ; yes ; push af ; no- delete present character ; ld a,8 ; backspace ; call CharOut ; ld a,' ' ; space ; call CharOut ; pop af ; ret r4: db 0 ; Registers cleared by "^X" r12: db 0 r10: ds 11 r15: dw 0 r16: db 0 ; r11: ds 6 r13: db 'H' ; Hex scale is default r5: db 0 r7: db 0,0,0,0,0 r9: db 0 r8: dw 0 r3: db 0 r17: db 0 r20: db 0 r18: db 0 r21: dw 0 ; ; ********* End Calculator ********* ; quit: ; Turn off calculator ld a,0dh call CharOut ; Print carriage return to indicate ; Return to normal call TrigOn ; Enable trigger key checking, ; now that calculator no longer active. ; ; "On" flag tells TrigOn to enable checking ld a,(on) cpl ld (on),a ; Flip calc. running flag to off ; pop hl ; Restore registers pop de pop bc pop af pop iy pop ix ; ld sp,(SavStk) ; Restore stack pointer ; jp OrigIn ; = Call BIOS ConIn, ret to transient program ; ; TrigOff: ; DISABLE trigger key detection ld a,(IsOn) ; Is key detection off? cp 0 jp z,TrigOn ; Yes, turn on ld a,0 ; No, flip flag and turn it off ld (IsOn),a ld hl,(JConIn) ; Get place in BIOS to restore jump ld de,(ConIn) ; Get location of BIOS routine ld (hl),e inc hl ld (hl),d ; Put in a jp and the location ; ld a,(on) ; Is calculator running? or a ret nz ; Yes, just resume key detection, ; don't tell user ld de,OffMsg ; Tell user trigger key de-activated call string ret string: ld c,9 jp BDOS OnMsg: db 'Trigger Key Enabled - Disable Before Re-loading RCP.$' OffMsg: db 'Trigger Key Disabled.$' RCP$name: db 'CALC-RCP ',(vers/10)+'0' db '.0',13,10 ; db 'H',13,10 db 'CALC - Enable/Disable Trigger Key',13,10 db 'Control-] - Calculator On/Off.$' OrigOut: db 0c3h ; Jp con: dw 0 ; Store BIOS console out routine address ; IsOn: db 0 ; Trigger-key detection on flag ; OrigIn: db 0c3h ; jp ConIn: dw 0 ; Store BIOS console in routine address JConIn: dw 0 ; Store BIOS jump to console in address ; on: db 0 ; Calculator running flag ; SavStk: ds 2 ; Save incoming stack pointer ; ds 32 NewStk equ $ ; Our own stack ; ; Size error test ; if ($ gt (RCP+RCPs*128-1)) SizErr equ novalue ; RCP is too large for buffer endif ; end  ; ; Size error test ; if ($ gt (RCP+RCPs*128-1)) SizErr equ noval