; 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