home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Freesoft 1999 February
/
Freesoft_1999-02_cd.bin
/
Recenz
/
Emulator
/
GameBoy
/
GBBasic
/
B.ASM
next >
Wrap
Assembly Source File
|
1997-02-15
|
118KB
|
5,950 lines
;********************************
;* Floating-Point Basic *
;* for *
;* Z80 or GameBoy *
;********************************
;last edit: 15-Feb-97
; by Jeff Frohwein
percision .equ 6 ;This is the floating percision in digits.
;It should be an even number because the
;floating point routines can't handle odd.
;Increasing it's size increases percision
;but is slower & requires more ram usage.
fpsiz .equ (percision/2)+2 ;Size in bytes of a fp number
digit .equ percision/2 ;fpsiz-2
fpnib .equ percision
stesiz .equ 2+fpsiz ;symbol table element size
cr .equ 13 ;carriage return
null .equ 0 ;null character value
lf .equ 10 ;line feed
esc .equ 3 ;escape char
eof .equ 1 ;end of file
bell .equ 7 ;bell character
linlen .equ 80 ;# of chrs in legal input line
opbase .equ '('
ftype .equ 1 ;control stack for entry type
forsz .equ fpsiz*2+2+2+1;'for' control stack entry size
gtype .equ 2 ;control stack gosub entry type
etype .equ 0 ;control stack underflow type
uminu .equ 31h ;unary minus
term .equ 22h ; 'prnt' terminator character
subit .equ 2 ;speed up button bit for list
sdbit .equ 3 ;slow down button bit for list
linent .equ 0eh ;line number token
GBB_RDY .equ 1 ;Input ready command for ext terminal
#include "gb.inc"
; floating point ram
LOBLCK(hold1,digit+1)
LOBLCK(hold2,digit+1)
LOBLCK(hold3,digit+1)
LOBLCK(hold4,digit+1)
LOBLCK(hold5,digit+1)
LOBLCK(hold6,digit+1)
LOBLCK(hold7,digit+1)
LOBLCK(hold8,digit+1)
LOBYTE(nu1)
LOBYTE(erri) ;error flag
LOBYTE(nu2)
LOBLCK(buf,digit) ;working buffer
LOBYTE(sign) ;sign bit
LOBYTE(exp) ;exponent
LOBYTE(rctrl) ;rounding control flag 1=msd
LOBYTE(rdigi) ;rounding digit
signd .equ hold1+digit
expd .equ hold1+digit+1
;
; system ram
;
LOBYTE(phead)
LOBYTE(reltyp)
LOBYTE(nullct)
LOBYTE(argf)
LOBYTE(dirf)
LOWORD(txa)
cstksz .equ 100
astksz .equ fpsiz*linlen/2
LOBLCK(cstkl,cstksz)
LOBLCK(astkl,astksz)
LOWORD(rtxa)
LOWORD(cstka)
LOBLCK(sink,fpsiz-1)
LOBLCK(fpsink,fpsiz)
LOBLCK(ftemp,fpsiz)
LOBLCK(ftem1,fpsiz)
LOBLCK(ftem2,fpsiz)
LOBYTE(frand)
LOBYTE(ibcnt)
LOWORD(ibln)
LOBLCK(ibuf,linlen)
LOBLCK(cnsbuf,6) ;storage for 'cns' output
LOWORD(astka)
LOWORD(adds)
LOWORD(addt)
LOWORD(bcadd)
LOBYTE(opst)
LOBYTE(opstr)
LOBYTE(ecnt)
LOBYTE(fsign)
LOBLCK(bcs,digit+2)
abufsiz .equ digit*2+2
LOBLCK(abuf,abufsiz)
LOBYTE(xsign)
LOBYTE(expo)
LOBYTE(fes)
LOBYTE(infes)
LOWORD(maxl)
LOWORD(insa)
LOBYTE(callRegC) ;Storage for C reg for USR
LOBYTE(callRegB) ;Storage for B reg for USR
LOBYTE(callRegE) ;Storage for E reg for USR
LOBYTE(callRegD) ;Storage for D reg for USR
LOWORD(miscW1) ;temp storage for SAVE,LOAD,LIST, & PFIX
;* Important memory pointers *
MemoryPointers .equ lorambase
LOWORD(bofa) ;start of file addr
LOWORD(eofa) ;end of file addr
LOWORD(mata) ;free memory for upward growing matrixs
LOWORD(stb) ;first byte of downward growing variables
LOWORD(memtop) ;last assigned memory location
memfree .equ lorambase
;Basic Statements Storage Format
; byte - Length of line (includes this length)
; word - Line number
; tokens & data
; byte - CR
;Save to backup ram format
; byte 'B' - Basic
; byte 'F' - File
; byte '0' - Format 0
; word crc
; word length
; byte data
; .org 100h
;
; startup basic system
;
;#include "gb.inc"
ld sp,stack
ld hl,memfree
ld a,l
ld (bofa),a ;start of user assigned memory
ld a,h
ld (bofa+1),a
ld hl,0dfffh
ld a,l
ld (memtop),a ;end of assigned memory pointer
ld a,h
ld (memtop+1),a
ld a,l
ld (stb),a
ld a,h
ld (stb+1),a
call new ;new program
ld a,77h ;turn sound volume up
ld (0ff24h),a
xor a ;set sound outputs to off
ld (0ff25h),a
ld a,82h ;turn sound 2 generator on
ld (0ff26h),a
ld a,84h ;set sound duty
ld (0ff16h),a
ld a,0f0h ;set envelope
ld (0ff17h),a
ld a,2*fpnib
ld (infes),a
; initialize random number
ld de,frand
ld hl,rands
call vcopy ;frand=random number seed
ld a,0ah
ld (0),a ;enable sram
ld a,(0a000h)
cp 'B' ;is this file okay?
jr nz,sineon ;no
ld a,(0a001h)
cp 'F' ;is this file okay?
jr nz,sineon ;no
ld a,(0a002h)
cp '0' ;is this file format 0?
jr nz,sineon ;no
ld a,(0a006h)
and 80h ;is high bit set?
jr z,sineon ;no, don't autoload
call loadp ;load file
call crun ;run program
jr cmnd0
sineon:
xor a
ld (0),a ;disable sram
; print sign on message
ld hl,signon
call prnt
;
; command processor
;
cmnd0: call crlf
cmnd1: ld hl,rdys ;print 'Ok'
call prnt
call crlf
cmndr: ld a,1 ;set direct input flag
ld (dirf),a
ld sp,stack
cmnd2:
; ld b,GBB_RDY ;Send input ready char.
; call chout ;Only needed by external terminal.
call inline ;get input line from operator
ld hl,ibuf
ld a,cr
cp (hl) ;is line blank?
jr z,cmnd2 ;yes
call pp ;pre-process it
jr c,cmnd3
call line ;line number..go edit
call cclear
jr cmnd2
cmnd3:
call cmnd4
jr cmnd1
cmnd4: ld hl,ibuf ;point to command or statement
ld a,l
ld (txa),a
ld a,h
ld (txa+1),a
cmnd5:
call istat ;process statement (if allowed)
call gci
cp ':'
jr z,cmnd5
cp cr
ret z
jp e1
;* Error Statements *
ermbs: .byte "Syntax",term ;'bs'
ermba: .byte "Argument",term ;'ba'
ermcs: .byte "Control Stack",term ;'cs'
ermdi: .byte "Direct input",term ;'di'
ermob: .byte "Out of range",term ;'ob'
ermof: .byte "Overflow",term
ermdm: .byte "Duplicate",term ;'dm'
ermdz: .byte "Divide by 0",term
ermfp: .byte "Floating point",term ;'fp'
ermrd: .byte "Out of DATA",term ;'rd'
ermif: .byte "Illegal function call",term
ermin: .byte "Input",term ;'in'
ermso: .byte "Out of memory",term ;'so'
ermll: .byte "Line too long",term ;'ll'
ermln: .byte "Undefined line number",term
e1: ld hl,ermbs ; 6273h 'bs'
jr error
e3: ld hl,ermba ; 6261h 'ba'
jr error
e4: ld hl,ermcs ; 6373h 'cs'
jr error
e5: ld hl,ermob ; 6f62h 'ob'
jr error
e6: ld hl,ermdm ; 646dh 'dm'
jr error
e7: ld hl,ermof
error:
push hl
call text_mode ;set to text mode if not already
pop hl
call prnt
ld hl,ers
erm1: call prnt
ld a,(dirf)
or a
jp nz,cmnd0
ld hl,ins
call prnt
; find line number
ld a,(bofa)
ld l,a
ld a,(bofa+1)
ld h,a
erm2: ld b,h
ld c,l
ld e,(hl)
ld d,0
add hl,de
push hl
ld l,e
ld h,d
pop de
ld hl,txa
call dcmp
push hl
ld l,e
ld h,d
pop de
jp c,erm2
inc bc
ld a,(bc)
ld l,a
inc bc
ld a,(bc)
ld h,a
ld de,ibuf ;use ibuf to accumulate the line line number string
call cns
ld a,cr
ld (de),a
ld hl,ibuf
call prntcr
jp cmnd0
;
; line editor
;
line: ld a,(bofa) ;check for empty file
ld l,a
ld a,(bofa+1)
ld h,a
fin: ld a,(hl) ;check if appending line at end
dec a
jr z,app
push hl
ld l,e
ld h,d
pop de
inc de
ld a,(ibln) ;get input line number
ld l,a
ld a,(ibln+1)
ld h,a
push hl
ld l,e
ld h,d
pop de
call dcmp ;compare with file line number
dec hl
jr c,insr ;less than
jr z,insr ;equal
ld a,(hl) ;length of line
call aa2hl ;jump forward
jr fin
; append line at end case
app: ld a,(ibcnt) ;don't append null line
cp 4
ret z
call full ;check for room in file
ld a,(eofa) ;place line in file
ld l,a
ld a,(eofa+1)
ld h,a
call imov
ld (hl),eof
ld a,l
ld (eofa),a
ld a,h
ld (eofa+1),a
ret
; insert line in file case
insr: ld b,(hl) ;old line count
ld a,l
ld (insa),a ;insert line pointer
ld a,h
ld (insa+1),a
ld a,(ibcnt) ;new line count
jr c,lt2 ;jmp if new line # not = old line number
sub 4
jr z,lt1 ;test if should delete null line
add a,4
lt1: sub b
jr z,lin1 ;line lengths equal
jr c,gt2
; expand file for new or larger line
lt2: ld b,a
ld a,(ibcnt)
cp 4 ;don't insert null line
ret z
ld a,b
call full
ld a,(insa)
ld l,a
ld a,(insa+1)
ld h,a
call nmov
ld a,(eofa)
ld l,a
ld a,(eofa+1)
ld h,a
push hl
ld l,e
ld h,d
pop de
ld a,l
ld (eofa),a
ld a,h
ld (eofa+1),a
inc bc
call rmov
jr lin1
; contract file for smaller line
gt2: cpl
inc a
call aa2hl
call nmov
push hl
ld l,e
ld h,d
pop de
ld a,(insa)
ld l,a
ld a,(insa+1)
ld h,a
call nz,lmov
ld (hl),eof
ld a,l
ld (eofa),a
ld a,h
ld (eofa+1),a
; insert current line into file
lin1: ld a,(insa)
ld l,a
ld a,(insa+1)
ld h,a
ld a,(ibcnt)
cp 4
ret z
; insert current line at addr hl
imov: ld de,ibcnt
ld a,(de)
ld c,a
ld b,0
; copy block from beginning
; hl is destin addr, de is source addr, bc is count
lmov: ld a,(de)
ld (hl),a
inc de
inc hl
dec bc
ld a,b
or c
jr nz,lmov
ret
; copy block starting at end
; hl is destin addr, de is source addr, bc is count
rmov: ld a,(de)
ld (hl),a
dec hl
dec de
dec bc
ld a,b
or c
jr nz,rmov
ret
; compute file move count
; bc gets (eofa) - (hl), ret z set means zero count
nmov: ld a,(eofa)
sub l
ld c,a
ld a,(eofa+1)
sbc a,h
ld b,a
or c
ret
; add a to hl
aa2hl:
add a,l
ld l,a
ret nc
inc h
ret
; check for file overflow, leaves new eofa in de
; a has increase in size
full: push af
ld a,(eofa)
ld l,a
ld a,(eofa+1)
ld h,a
pop af
call aa2hl
ld e,l
ld d,h
ld hl,memtop
call dcmp
jp nc,e8
ret
;
; commands
;
;cls: ld b,26
; jp chout ;clear screen
; "new"
new: ld a,(bofa)
ld (eofa),a
ld l,a
ld a,(bofa+1)
ld (eofa+1),a
ld h,a
ld (hl),eof
; "clear"
cclear: ld a,(eofa) ;clear from eofa to memtop
ld e,a
ld a,(eofa+1)
ld d,a
inc de
ld a,e
ld (mata),a
ld a,d
ld (mata+1),a
ld hl,memtop
cclr1: xor a
ld (de),a
call dcmp
inc de
jr nz,cclr1
ld a,(memtop)
ld l,a
ld a,(memtop+1)
ld h,a
ld a,l
ld (stb),a
ld a,h
ld (stb+1),a
ld hl,cstkl+cstksz-1
ld (hl),etype
ld a,l
ld (cstka),a
ld a,h
ld (cstka+1),a
ld hl,astkl+astksz+fpsiz-1
ld a,l
ld (astka),a
ld a,h
ld (astka+1),a
ret
; "list"
clist:
ld a,1 ;setup list speed
ld (miscW1),a
xor a
ld (miscW1+1),a
ld de,0
ld bc,-1
call gc ;check for parameters
cp cr
jr z,clst3 ;no parameters
cp minrw ;list -X ?
jr z,clst1 ;yes
call intger ;line number valid?
jp c,e1 ;no
ld e,l ;first line = hl
ld d,h
ld c,l ;last line = hl
ld b,h
call gci
cp cr ;Is it just list X?
jr z,clst3 ;yes
cp minrw ;is it list X-?
jp nz,e1
call gc ;yes
ld bc,-1
cp cr ;is it list X-X?
jr z,clst3 ;no
jr clst2
clst1: call gci ;get rid of char
clst2: push de
call intger
pop de
jp c,e1
ld c,l
ld b,h
clst3: ld a,(bofa)
ld l,a
ld a,(bofa+1)
ld h,a
clst4: ld a,(hl)
dec a ;is a program present?
ret z ;no, exit
inc hl
call dcmp
dec hl ;point to count char again
jp c,clst5
jp z,clst5
; inc to next line
ld a,(hl)
call aa2hl
jr clst4
clst5:
ld e,c ;mark last line to list
ld d,b
clst6: inc hl
call dcmp
dec hl ;point to char count
jr c,clstx ;exit
push de
ld de,ibuf ;area for unprocessing
call uppl
inc hl
push hl
ld hl,ibuf
call prntcr
call crlf
pop hl
pop de
push hl
ld a,(miscW1)
ld l,a
ld a,(miscW1+1)
ld h,a
call getbuts
push af
bit subit,a ;speed up button pressed?
jr z,clst7 ;no
dec hl
ld a,h
or l ;does hl = 1 ?
inc hl
jr z,clst7 ;yes, already at max speed
srl h ;hl=hl/2
rr l
clst7:
pop af
bit sdbit,a ;slow down button pressed?
jr z,clst8 ;no
add hl,hl ;hl=hl*4
add hl,hl
clst8:
and BRKBTN
cp BRKBTN ;break pressed?
jr z,clst9 ;yes
ld a,l
ld (miscW1),a
ld a,h
ld (miscW1+1),a
push de
ld e,l
ld d,h
call dely1
pop de
pop hl
ld a,(hl)
dec a ;end of program?
jr nz,clst6 ;not yet
clstx:
jp bend
clst9:
pop hl
jr clstx
;
;
; "Locate"
locat:
call exprb ;get y coordinate
call pfix
ld c,e
push bc
ld b,','
call eatc
call exprb ;get x coordinate
call pfix
pop bc
ld b,e
jp locate
;
; "Poke"
poke:
call exprb ;get address
call pfix
push de
ld b,','
call eatc
call exprb ;get data
call pfix
ld a,d
or a ;is data > 255 ?
jp nz,e5 ;yes, Out of Range error
ld a,e
pop de
ld (de),a ;write byte
ret
; "load"
loadp:
ld a,0ah
ld (0),a ;enable sram
ld hl,0a007h
ld a,(0a005h)
ld c,a
ld a,(0a006h)
and 7fh ;remove auto-run bit
ld b,a
call calccrc ;file okay?
jr c,loaderr ;no
ld a,(bofa)
ld e,a
ld a,(bofa+1)
ld d,a
call move
call findeof ;set eofa
xor a
ld (0),a ;disable ram
jp cclear
loaderr:
xor a
ld (0),a ;disable ram
call ilprc
.byte "Corrupt program",0
ret
; "save"
save:
ld a,0ah
ld (0),a ;enable sram
ld hl,bofa
ld de,eofa
ld a,(de)
sub (hl)
ld c,a
inc de
inc hl
ld a,(de)
sbc a,(hl)
ld b,a
inc bc
ld a,c
ld (0a005h),a
ld a,b
ld (0a006h),a
ld a,(bofa)
ld l,a
ld a,(bofa+1)
ld h,a
ld de,0a007h
call move
ld a,'B' ;Basic File indicator
ld (0a000h),a
ld a,'F'
ld (0a001h),a
ld a,'0'
ld (0a002h),a
ld a,(miscW1)
ld (0a003h),a
ld a,(miscW1+1)
ld (0a004h),a
xor a
ld (0),a
ret
;Compare file with it's crc
;Set carry if no match
calccrc:
push bc
push hl
ld a,(0a000h)
cp 'B'
jr nz,calcc3 ;error
ld a,(0a001h)
cp 'F'
jr nz,calcc3 ;error
ld a,(0a002h)
cp '0'
jr nz,calcc3 ;error
ld de,0
calcc1: ld a,(hl)
push hl
ld l,a
ld h,0
add hl,de
ld e,l
ld d,h
pop hl
inc hl
dec bc
ld a,b
or c
jr nz,calcc1
ld a,(0a003h)
cp e ;does crc check okay?
jr nz,calcc3 ;no
ld a,(0a004h)
cp d ;does crc check okay?
jr nz,calcc3 ;no
or a
jr calcc4
calcc3: scf
calcc4: pop hl
pop bc
ret
;Move BC bytes from HL to DE
move: xor a
ld (miscW1),a
ld (miscW1+1),a
mov1: ld a,(hl)
ld (de),a
ld a,(miscW1)
add a,(hl)
ld (miscW1),a
ld a,(miscW1+1)
adc a,0
ld (miscW1+1),a
inc hl
inc de
dec bc
ld a,b
or c
jr nz,mov1
ret
; "free"
free:
ld a,(mata) ;Upward growing matrix storage
ld l,a
ld a,(mata+1)
ld h,a
ld a,(stb) ;Downward growing variable storage
sub l
ld l,a
ld a,(stb+1)
sbc a,h
ld h,a
ld de,cnsbuf
call cns
ld a,term
ld (de),a ;terminate number string
ld hl,cnsbuf
call prnt
call ilprc
.byte " bytes left.",0
ret
;
; "on"
;on:
; call exprb ;get expression
; call pfix ;convert to integer
; ld c,e
;
; ld a,d
; or a ;is expr > 255?
; jp z,rem ;yes, ignore rest of line
;
; call gci
; ld b,a
; cp gotorw ;is it a goto?
; jr z,on1 ;yes
; cp gosubrw ;is it a gosub?
; jp nz,e1 ;no
;
;on1: gln ;line number present?
; jp c,e1 ;no, error
;
; dec c ;have we got the right line# ?
; jr z,ondo ;yes
;
; call gc
; cp ',' ;comma?
; ret nz ;no
;
; call gci
; jr on1
;
;ondo: ld a,b
; cp gotorw ;goto request?
; jp z,goto1 ;yes
;
;
; ld de,-3 ;create control stack entry
; call pshcs
; push hl ;save stack addr
;
; call gln
; jp c,e1 ;no line # present
;
; ld e,l ;line number in de
; ld d,h
;
; call joe
; ld b,h
; ld c,l
; pop hl ;stack addr
; ld (hl),b ;stack return addr returned by joe
; dec hl
; ld (hl),c
; dec hl
; ld (hl),gtype ;make control stack entry type 'gosub'
; call findln
; inc hl
; inc hl
; inc hl
; jp next6
;
; "renum"
renum:
ld a,(eofa)
ld e,a
ld a,(eofa+1)
ld d,a
inc de
ld a,(bofa)
ld l,a
ld a,(bofa+1)
ld h,a
ld a,(hl)
dec a ;is there a program to renumber?
jp z,bend ;no
; Build lookup table
ren0: ld a,(hl)
dec a ;have we reached end of program?
jr z,ren2 ;yes
push hl
inc hl
call lhli
push de
inc de
inc de
inc de
inc de
push hl
ld hl,memtop
call dcmp ;is table too large?
jp nc,e8 ;yes, out of memory
pop hl
pop de
ld a,l
ld (de),a
inc de
ld a,h
ld (de),a
inc de
pop hl
ld a,(hl)
call aa2hl
jr ren0
ren2: xor a ;end of table marker
ld (de),a
inc de
ld (de),a
ld bc,10
ld a,(bofa)
ld l,a
ld a,(bofa+1)
ld h,a
ren3: ld a,(hl)
dec a ;have we renumbered whole program?
jp z,bend ;yes
push hl
inc hl
ld (hl),c
inc hl
ld (hl),b
ren4: inc hl
ld a,(hl)
cp cr ;end of line?
jr z,ren9 ;yes
cp linent ;line number token?
jr nz,ren4 ;no
inc hl
ld e,(hl)
inc hl
ld d,(hl)
ld a,c ;save line number for errors in conversion
ld (ibuf),a
ld a,b
ld (ibuf+1),a
call cnvtln ;convert de
ld (hl),d
dec hl
ld (hl),e
inc hl
jr ren4
ren9:
pop hl
ld a,(hl)
call aa2hl
;increment line number by 10
ld a,10
ren10: inc bc
dec a
jr nz,ren10
jr ren3
; Convert de from old to new line number
cnvtln:
push bc
push hl
ld bc,10
ld a,(eofa)
ld l,a
ld a,(eofa+1)
ld h,a
cnvtl1:
inc hl
xor a
cp (hl) ;end of table?
jr nz,cnvtl2 ;no
inc hl
cp (hl)
dec hl ;end of table?
jr z,cnvtl9 ;yes
cnvtl2:
ld a,e
cp (hl) ;lsb match?
inc hl
jr nz,cnvtl6 ;no
ld a,d
cp (hl) ;msb match?
jr nz,cnvtl6 ;no
ld e,c
ld d,b
jr cnvtl8
cnvtl6:
ld a,10
cnvt17:
inc bc
dec a
jr nz,cnvt17
jr cnvtl1
cnvtl8:
pop hl
pop bc
ret
; Undefined Line Number x in x.
cnvtl9:
push de
push bc
ld hl,ermln
call prnt
call space
ld l,e
ld h,d
ld de,cnsbuf
call cns
ld a,cr
ld (de),a
ld hl,cnsbuf
call prntcr
ld hl,ins
call prnt
ld a,(ibuf)
ld l,a
ld a,(ibuf+1)
ld h,a
ld de,cnsbuf
call cns
ld a,cr
ld (de),a
ld hl,cnsbuf
call prntcr
call crlf
pop bc
pop de
jr cnvtl8
;
; "run"
crun: call cclear
call def_color ;setup default drawing color
ld a,(bofa)
ld l,a
ld a,(bofa+1)
ld h,a
ld a,(hl)
dec a ;check for null program
jp z,bend
call resto4 ;update rtxa
ld a,l
ld (txa),a
ld a,h
ld (txa+1),a
xor a
ld (dirf),a ;clear direct flag and fall through to driver
jp iloop
; interpret statement located by txa
istat: call gc ;get first non blank
cp 39 ;is it a "'" ?
jp z,rem ;yes
cp 128
jp c,let ;must be let if not rw
cp irwlin
jp nc,e1 ;this token not allowed initially
ld de,cmndd ;statement dispatch table base
ista1: call gci ;advance text pointer
and 7fh
rlca ;multiply by two preparing for table lookup
ld l,a
ld h,0
add hl,de
call lhli
jp (hl) ;branch to statement or command
;
; statements
;
; "let"
let:
call var ;check for variable
jp c,e1 ;not found
push hl ;save value address
ld b,eqrw
call eatc
call exprb
pop de ;destination address
jp popa1 ;copy expr value to variable
; "for"
sfor: call dirt
call var ;control variable
jp c,e4 ;not found
push hl ;control variable value address
ld b,eqrw
call eatc
call exprb ;initial value
pop de ;variable value address
push de ;save
call popa1 ;set initial value
ld b,torw ;rw for 'to'
call eatc
call exprb ;limit value computation
call gc ;check next character for possible step
cp steprw
jr z,for1
; use step of 1
ld de,fpone
call psha1
jr for2
; compute step value
for1: call gci ;eat the step rw
call exprb ;the step value
; here the step and limit are on arg stack
for2: ld de,-2 ;prepare to allocate 2 bytes on control stack
call pshcs ;returns address of those 2 bytes in hl
push hl
ld l,e
ld h,d
pop de
call joe ;test for junk on end
jp c,e4 ;no "for" statement at end of program
push hl ;de has loop text addr, hl has control stack adr
ld l,e
ld h,d
pop de
ld (hl),d ;high order text address byte
dec hl
ld (hl),e ;low "
ld de,-fpsiz ;allocate space for limit on control stack
call pshcs
push hl ;addr on control stack for limit
ld de,-fpsiz ;allocate space for step on control stack
call pshcs
call popas ;copy step value to control stack
pop de ;control stack addr for limit value
call popa1 ;limit value to control stack
ld de,-3 ;allocate space for text addr & cs entry
call pshcs
pop de ;control variable addr
ld (hl),d ;high order byte of control variable addr
dec hl
ld (hl),e ;low "
dec hl
ld (hl),ftype ;set control stack entry type for 'for'
jp next5 ;go finish off carefully
; "next"
next: call dirt
ld a,(cstka) ;control stack addr
ld l,a
ld a,(cstka+1)
ld h,a
ld a,(hl) ;stack entry type byte
dec a ;must be for type else error
jp nz,e4 ;improper nesting error
inc hl ;control stack pointer to control var addr
push hl
call var ;check variable, in case user wants
jr c,next1 ;skip check if var not there
push hl
ld l,e
ld h,d
pop de
pop hl ;control variable addr
push hl ;save it again
call dcmp
jp nz,e4 ;improper nesting if not the same
next1: pop hl ;control variable addr
push hl
push hl
ld de,fpsiz+2-1 ;compute addr to step value
add hl,de
EX_SP_HL ;now addr to var in hl
call lhli ;var addr
ld b,h ;copy var addr to bc
ld c,l
pop de ;step value addr
push de
call fadd ;do increment
pop hl ;step value
dec hl ;point to sign of step value
ld a,(hl) ;sign 0=pos, 1=neg
ld de,fpsiz+1
add hl,de ;puts limit addr in hl
push hl
ld l,e
ld h,d
pop de
pop hl ;var addr
call lhli ;get addr
push de ;save control stack pointer to get text address
or a ;set conditions based on sign of step value
jr z,next2 ;reverse test on negative step value
push hl
ld l,e
ld h,d
pop de
next2: ld b,h ;set up args for compare
ld c,l
call relop ;test <=
pop de ;test addr
jr nc,next3 ;still smaller?
jr z,next3 ;jump if want to continue loop
; terminate loop
ld hl,3 ;remove cstack entry
add hl,de
ld a,l
ld (cstka),a
ld a,h
ld (cstka+1),a
ret
next3: inc de ;test addr
push hl
ld l,e
ld h,d
pop de
call lhli ;get text address in hl
; iterate, skipping normal junk on end test at iloop
next4: push hl ;save new text addr in de
ld l,e
ld h,d
pop de
call joe
push hl
ld l,e
ld h,d
pop de
next6: ld a,l
ld (txa),a
ld a,h
ld (txa+1),a
next5:
pop hl
jp iloop ;to dispatcher skipping joe call there
; "if"
sif: ld b,1 ;specify principal operator is relational
call expb1
ld a,(astka) ;addr of boolean value on arg stack
ld l,a
ld a,(astka+1)
ld h,a
inc (hl) ;sets zero condition if relational was true
push af ;save conditions to test later
call popas ;remove value from arg stack copy to self
pop af
jp nz,rem ;if test false treat rest of line as rem
; test succeeded
ld b,thenrw
call eatc
call gln ;check if line number is desired action
jp c,istat ;no, must be a command
jr goto1
; "goto"
sgoto: xor a
ld (dirf),a ;clears direct statement flag
call getbuts ;break buttons pressed?
and BRKBTN
cp BRKBTN
jp z,iloopb ;yes
call gln ;returns integer in hl if line # present
jp c,e1 ;syntax error - no line error
goto1: ld e,l ;line # in de
ld d,h
call findln ;returns text address points to count value
goto2: inc hl
inc hl
inc hl ;advance text pointer past line # and count
jp next4
; "gosub"
gosub: call dirt
ld de,-3 ;create control stack entry
call pshcs
push hl ;save stack addr
call gln
jp c,e1 ;no line # present
ld e,l ;line number in de
ld d,h
call joe
ld b,h
ld c,l
pop hl ;stack addr
ld (hl),b ;stack return addr returned by joe
dec hl
ld (hl),c
dec hl
ld (hl),gtype ;make control stack entry type 'gosub'
call findln
inc hl
inc hl
inc hl
jp next6
; "return"
retrn: call dirt
ld (dirf),a ;clears dirf if acc is clear
ld a,(cstka)
ld l,a
ld a,(cstka+1)
ld h,a
ret1: ld a,(hl)
or a ;check for stack empty
jp z,e4
cp gtype ;check for gosub type
jr z,ret2
; remove for type from stack
ld de,forsz
add hl,de
jr ret1
; found a gtype stack entry
ret2: inc hl
ld e,(hl) ;low order text address
inc hl
ld d,(hl) ;high "
inc hl ;addr of previous control stack entry
ld a,l
ld (cstka),a
ld a,h
ld (cstka+1),a
push hl ;put text addr in hl
ld l,e
ld h,d
pop de
ld a,(hl) ;addr points to eof if gosub was last line
dec a ;end of file?
jp nz,next4 ;no
jp bend
; "data" and "rem"
data: call dirt ;data statement illegal as direct
rem: call gci
cp cr
jr nz,rem
rem1: dec hl ;backup pointer so normal joe will work
ld a,l
ld (txa),a
ld a,h
ld (txa+1),a
ret
; "dimension"
dim: call name1 ;look for variable name
jp c,e4 ;no variable name error
ld a,c ;prepare turn on high bit to signify matrix
or 80h
ld c,a
call stlk
jp nc,e6 ;error if name already exists
push hl ;symbol table addr
ld b,lparrw
call eatc
call exprb
ld b,')'
call eatc
call pfix ;return integer in de
ld hl,matub ;max size for matrix
call dcmp
jp nc,e6 ;matrix too large error
pop hl ;symbol table address
call dims
call gc ;see if more to do
cp ','
ret nz
call gci ;eat the comma
jr dim
; "stop"
stop: call dirt
; call crlf2
stop1: ld hl,stops
jp erm1
; "end"
bend: .equ cmnd1
; "read"
read: call dirt
ld a,(txa)
ld l,a
ld a,(txa+1)
ld h,a
push hl ;save txa temporarily
ld a,(rtxa) ;the 'read' txa
ld l,a
ld a,(rtxa+1)
ld h,a
read0: ld a,l
ld (txa),a
ld a,h
ld (txa+1),a
call gci
cp ',' ;comma?
jr z,read2 ;yes, process input value
cp datarw
jr z,read2
dec a ;end of file?
jr z,read4 ;yes
; skip to next line
call rem ;leaves addr to last cr in hl
inc hl
ld a,(hl)
dec a
jr z,read4
inc hl
inc hl
inc hl ;hl now points to first byte of next line
jr read0
; process value
read2: call exprb
call gc
cp ',' ;skip joe test if comma
jr z,read3
; junk on end test
call joe
read3: ld a,(txa)
ld l,a
ld a,(txa+1)
ld h,a
ld a,l
ld (rtxa),a ;save new "read" text addr
ld a,h
ld (rtxa+1),a
pop hl ;real txa
ld a,l
ld (txa),a
ld a,h
ld (txa+1),a
call var
jp c,e1
call popas ;put read value into variable
call gc
cp ',' ;check for another variable
ret nz
call gci ;eat the comma
jr read
read4: pop hl ;program txa
ld a,l
ld (txa),a
ld a,h
ld (txa+1),a
ld hl,ermrd ;7264h 'rd'
jp error
; "restore"
restor:
call gln ;returns integer in hl if line # present
jp c,resto3 ;no line number present
resto1 ld e,l ;line # in de
ld d,h
call findln ;returns text address points to count value
jr resto4
resto3: ld a,(bofa) ;beginning of file pointer
ld l,a
ld a,(bofa+1)
ld h,a
; update rtxa
resto4: inc hl ;advance text pointer past line # & count
inc hl
inc hl
ld a,l
ld (rtxa),a
ld a,h
ld (rtxa+1),a
ret
; "print"
print: call gc
cp cr ;check for stand alone print
jp z,crlf
prin9: cp '"'
jr z,pstr ;print the string
cp tabrw
jr z,ptab ;tabulation
cp '%'
jp z,pform ;set format
cp cr
ret z
cp ':'
ret z
call exprb ;must be expression to print
ld de,fpsink
call popa1 ;pop value to fpsink
; ld a,(phead)
; cp 56
; call nc,crlf ;do crlf if print head is past 56
ld hl,fpsink
call fpout
ld b,' '
call chout
pr1: call gc ;get delimiter
cp 3bh ; ';'
jp nz,crlf
pr0: call gci
call gc
jr prin9
pstr: call gci ;gobble the quote
call prnt ;print up to double quote
inc hl ;move pointer past double quote
ld a,l
ld (txa),a
ld a,h
ld (txa+1),a
jr pr1
pform: ld a,2*fpnib
ld (infes),a
call gci ;gobble previous char
pfrm1: call gci
ld hl,infes
cp '%' ;delimiter
jr z,pr1
ld b,80h
cp 'z' ;trailing zeros?
jr z,pf1
ld b,1
cp 'e' ;scientific notation?
jr z,pf1
call nmchk
jp nc,e1
sub '0' ;number of decimal places
rlca
ld b,a
ld a,(hl)
and 0c1h
ld (hl),a
pf1: ld a,(hl)
or b
ld (hl),a
jr pfrm1
ptab: call gci ;gobble tab rw
ld b,lparrw
call eatc
call exprb
ld b,')'
call eatc
call pfix
ptab1: ld a,(phead)
cp e
jr nc,pr1
ld b,' '
call chout
jr ptab1
; "input"
input: call gc
cp ','
jp z,ncrlf
call crlf
inp0: ld b,'?'
call chout
linp: call inline
ld de,ibuf
in1: push de ;save for fpin
call var
jp c,e1
pop de
ld b,0
ld a,(de)
cp '+' ;look for leading plus or minus on input
jr z,in2
cp '-'
jr nz,in3
ld b,1
in2: inc de
in3: push bc
push hl
call fpin ;input fp number
jp c,inerr
pop hl
dec hl
pop af
ld (hl),a
call gc
cp ','
ret nz ;done if no more
call gci ;eat the comma
ld a,b ;get the terminator to a
cp ','
jr z,in1 ;get the next input value from string
; get new line from user
ld b,'?'
call chout
jr inp0
ncrlf: call gci
jr linp ;now get line
inerr: ld hl,ermin ;696eh 'in'
jp error
;
; evaluate an expression from text
; hl take op table addr of previous operator (not changed)
; result value left on top of arg stack, argf left true
;
exprb: ld b,0
expb1: ld hl,opbol
xor a
ld (reltyp),a
; zero in b means principal operator may not be relational
expr: push bc
push hl ;push optba
xor a
ld (argf),a
expr1: ld a,(argf)
or a
jr nz,expr2
call var ;is there a variable?
call nc,pshas ;yes, push onto arg stack
jr nc,expr2
call const ;is there a fp constant?
jr nc,expr2 ;yes
call gc
cp lparrw ;is there a ( ?
ld hl,oplpar
jp z,xlpar ;yes
; isn't or shouldn't be an argument
expr2: call gc
cp 0e0h ;check for reserved word operator
jr nc,xop ; e0 or >
cp 0c0h ;check for built in function
jp nc,xbilt ; c0 - df
; illegal expression character
pop hl ;get optaba
ld a,(argf)
or a
jp z,e1
xdon1: pop af
ld hl,reltyp ;check if legal principal operation
cp (hl)
ret z
jp e1
xop: and 1fh ;cleans off rw bits
push af
ld a,(argf) ;test for argf true
ld l,a
ld a,(argf+1)
ld h,a
pop af
dec l
jr z,xop1
; argf was false, unary ops only possibility
cp '-'-opbase
jr z,xopm
cp '+'-opbase
jp nz,e1
call gci ;eat the '+'
jr expr1
xopm: ld a,uminu-opbase
xop1: call opadr
pop de ;previous optba
ld a,(de)
cp (hl)
jr nc,xdon1 ;non-increasing precedence
; increasing precedence case
push de ;save previous optba
push hl ;save current optba
call gci ;to gobble operator
pop hl
push hl
ld b,0 ;specify non-relational
call expr
pop hl
; hl has optba addr
; set up args and perform operation action
xop2: push hl
ld a,(hl)
push af
ld a,(astka)
ld l,a
ld a,(astka+1)
ld h,a
pop af
ld b,h
ld c,l
and 1
jr nz,xop21
; decrement stack pointer by one value binary case
ld de,fpsiz
add hl,de
push af
ld a,l
ld (astka),a
ld a,h
ld (astka+1),a
pop af
ld d,h
ld e,l
xop21: ld hl,expr1
EX_SP_HL ;change return link
inc hl ;skip over precidence
call lhli ;load action address
jp (hl)
;
; action routine convention
; de left arg and result for binary
; bc right arg for binary, arg and result for unary
; built in function processing
;
xbilt: call gci ;eat token
and 3fh ;clean off rw bits
push af
ld a,(argf) ;built in function must come after operator
ld l,a
ld a,(argf+1)
ld h,a
pop af
dec l
jp z,e1
call opadr ;optba to hl
xlpar: push hl
ld b,lparrw
call eatc
call exprb
ld b,')'
call eatc
pop hl ;code for built-in function
jr xop2
; compute optable address for operator in acc
opadr: ld c,a
ld b,0
ld hl,optab
add hl,bc
add hl,bc
add hl,bc ;optab entry addr is 3*op+base
ret
;
; preprocessor, un-preprocessor
; preprocess line in ibuf back into ibuf
; sets carry if line has no line number
; leaves correct length of line after preprocessing in ibcn
; if there is a line number, it is located at ibln=ibuf-2
; txa is clobbered
;
pp: ld hl,ibuf ;first character of input line
ld a,l
ld (txa),a ;so gci will work
ld a,h
ld (txa+1),a
call intger ;sets carry if no line number
push af ;save state of carry bit for returning
ld a,l
ld (ibln),a ;store line number value (even if none)
ld a,h
ld (ibln+1),a
ld a,(txa) ;addr of next char in ibuf
ld l,a
ld a,(txa+1)
ld h,a
ld c,4 ;set up initial value for count
ld de,ibuf ;initialize write pointer
; come here to continue preprocessing line
ppl: push de
ld de,rwt ;base of rwt
ppl1: push hl ;save text addr
ld a,(de) ;rw value for this entry in rwt
ld b,a ;save in b in case of match
ppl2: inc de ;advance entry pointer to next byte
call hl2lower
ld a,(de) ;get next char from entry
cp (hl) ;compare with char in text
; jr z,ppl0
; and 0dfh ;see if case different
; cp (hl)
jr nz,ppl3
ppl0: inc hl ;advance text pointer
jr ppl2 ;continue comparison
; come here when comparison of byte failed
ppl3:
; or 20h
cp 128
jr nc,ppl6 ;jump if found match
; scan to beginning of next entry
ppl4: inc de ;advance entry pointer
ld a,(de) ;next byte is either char or rw byte
cp 128
jr c,ppl4 ;keep scanning if not rw byte
; now see if at end of table, and fail or return condition
pop hl ;recover original text pointer
xor 255 ;check for end of table byte
jr nz,ppl1 ;continue scan of table
; didn't find an entry at the given text addr
pop de
ld a,(hl) ;get text char
cp cr ;check for end of line
jr z,ppl88 ;go clean up & return
ld (de),a
inc de
inc c
inc hl ;advance text pointer
cp '"' ;check for quoted string possibility
jr nz,ppl ;restart rwt search at next character position
; here we have a quoted string, so eat till endquote
ppl5: ld a,(hl) ;next char
cp cr
jr z,ppl88 ;no string endquote, let interpreter worry
ld (de),a
inc de
inc c
inc hl ;advance text pointer
cp '"'
jr z,ppl ;begin rwt scan from new character position
jr ppl5
; found match so put rw value in text
ppl6: pop af ;remove unneeded test pointer from stack
pop de
ld a,b
ld (de),a
inc de
inc c
cp gotorw ;is it a goto?
jr z,ppl7 ;yes
cp gosubrw ;is it a gosub?
jr z,ppl7 ;yes
cp restorw ;is it a restore?
jr z,ppl7 ;yes
cp thenrw ;is it a then?
jr z,ppl7 ;yes
jr ppl
;look for line number to compress
ppl7: push hl
ld a,l
ld (txa),a
ld a,h
ld (txa+1),a
push bc
push de
call intger ;carry set if no line number
pop de
pop bc
jr c,ppl79
pop af
ld a,' '
ld (de),a
inc de
inc c
ld a,linent
ld (de),a
inc de
inc c
ld a,l
ld (de),a
inc de
inc c
ld a,h
ld (de),a
inc de
inc c
ld a,(txa)
ld l,a
ld a,(txa+1)
ld h,a
ld a,(hl)
cp ',' ;is this a ON x GOSUB x,x,x?
jp nz,ppl
inc hl
ld (de),a
inc de
inc c
jp ppl7
;ppl8: ld a,(hl)
; inc hl
; cp cr ;end of line?
; jr z,ppl80 ;yes
; cp ' ' ;space?
; jr z,ppl8 ;yes
; cp '1' ;is it a line number?
; jr c,ppl79 ;no
; cp '9'+1 ;is it " ?
; jr nc,ppl79 ;no
ppl79: pop hl
jp ppl
ppl80: pop hl
; come here when done
ppl88: ld a,cr
ld (de),a
ld hl,ibcnt ;set up count in case line has line number
ld (hl),c
pop af ;restore carry condition (line number flag)
ret
hl2lower:
ld a,(hl)
cp 'A'
ret c
cp 'Z'+1
ret nc
or 20h
ld (hl),a
ret
;
; un-preprocess line addr in hl to de buffer
; return source addr of cr in hl on return
;
uppl: inc hl ;skip over count byte
push hl ;save source text pointer
call lhli ;load line # value
call cns ;convert line #
ld a,' '
ld (de),a ;put blank after line number
inc de ;increment dest pointer
pop hl
inc hl ; " source "
upp0: inc hl
ld a,(hl) ;next token in source
cp 128
jr nc,upp2 ;jump if token is rw
ld (de),a ;put char in buffer
cp cr ;check for done
ret z
cp linent ;is it a line number token?
jr nz,upp1 ;no
inc hl
push hl
call lhli ;load line # value
call cns ; convert line #
pop hl
inc hl
dec de
upp1:
inc de ;advance dest buffer addr
jr upp0
; come here when rw byte detected in source
upp2: push hl ;save source pointer
ld hl,rwt ;base of rwt
upp3: cp (hl) ;see if rw matched rwt entry
inc hl ;advance rwt pointer
jr nz,upp3 ;continue looking if not found
; found match, entry pointer locates first char
upp4: ld a,(hl) ;char of rw
cp 128 ;check for done
jr nc,upp5
ld (de),a
inc de
inc hl
jr upp4
; come here if done with rw transfer
upp5: pop hl ;source pointer
jr upp0
;
; constants and tables
;
signon: .byte "GameBoy Basic V1.21",term
rdys: .byte "Ok",term
ers: .byte " error",term
ins: .byte " in ",term
stops: .byte "Break",term
trues: .byte "true",term
falses: .byte "false",term
;
.byte -1 ;flags end of sine coefficient list
.byte 0
.byte 1*16
.word 0
.byte 0
fpone: .byte 129 ;exponent
; sine coefficient list
; note: the floating pnt 1 above is part of this table
.byte 16h
.byte 66h
.byte 67h
.byte 1
.byte 128 ;-.166667 e 0 (-1/3)
.byte 83h
.byte 33h
.byte 33h
.byte 0
.byte 128-2 ;.833333 e-2 (1/5)
.byte 19h
.byte 84h
.byte 13h
.byte 1
.byte 128-3 ;-.198413 e-3 (-1/7)
.byte 27h
.byte 55h
.byte 73h
.byte 0
.byte 128-5 ;.275573 e-5 (1/9)
.byte 25h
.byte 05h
.byte 21h
.byte 1
sinx: .byte 128-7 ;-.250521 e-7 (-1/11)
; cosine coefficient list
.byte -1 ;marks end of list
.byte 0
.byte 10h
.byte 00h
.byte 00h
.byte 0
.byte 128+1 ;.100000 e 1 (1/1)
.byte 50h
.byte 00h
.byte 00h
.byte 1
matub: .byte 128 ;-.500000 e 0 (-1/2)
.byte 41h
.byte 66h
.byte 67h
.byte 0
rands: .byte 128-1 ;.416667 e-1 (1/4)
.byte 13h
.byte 88h
.byte 89h
.byte 1
.byte 128-2 ;.138889 e-2 (-1/6)
.byte 24h
.byte 80h
.byte 16h
.byte 0
.byte 128-4 ;.248016 e-4 (1/8)
.byte 27h
.byte 55h
.byte 73h
.byte 1
cosx: .byte 128-6 ;.275573 e-6 (-1/10)
.byte 20h
.word 0
.byte 0
fptwo: .byte 129
.byte 15h
.byte 70h
.byte 80h
.byte 0
pic2: .byte 128+1 ;pi/2 .157080 e 1
.byte 63h
.byte 66h
.byte 20h
.byte 0
pic1: .byte 128 ;2/pi .636620 e 0
lcstka: .word cstkl
.byte 13h
.byte 10h
.byte 72h
.byte 0
snd2: .byte 128+6
;
; statement table
;
cmndd: .word let
.word next
.word sif
.word sgoto
.word gosub
.word retrn
.word read
.word data
.word sfor
.word print
.word input
.word dim
.word stop
.word bend
.word restor
.word rem
.word cclear
.word crun
.word clist
.word new
.word abc
.word cls
.word renum
.word locat
.word loadp
.word save
.word free
.word poke
.word delay
.word screen
.word set_color
.word draw_point
.word draw_line
.word auto
.word sound
.word servo
.word setLink
.word SetRegBC
.word SetRegDE
.word SetMemTop
;
; r/w word table format is reserved word followed by chr
; of reserved word. last entry is followed by 255.
; rw's that are substrings of other rw's (e.g. >) must
; follow the larger word.
;
rwt: .byte 80h
.byte "let"
.byte 81h
.byte "next"
.byte 81h
.byte "n."
.byte 82h
.byte "if"
gotorw .equ 83h
.byte gotorw
.byte "goto"
.byte gotorw
.byte "g."
gosubrw .equ 84h
.byte gosubrw
.byte "gosub"
.byte 85h
.byte "return"
.byte 86h
.byte "read"
datarw .equ 87h
.byte datarw
.byte "data"
.byte 88h
.byte "for"
.byte 88h
.byte "f."
.byte 89h
.byte "print"
.byte 89h
.byte "p."
.byte 89h
.byte "?"
.byte 8ah
.byte "input"
.byte 8ah
.byte "i."
.byte 8bh
.byte "dim"
.byte 8ch
.byte "stop"
.byte 8dh
.byte "end"
restorw .equ 8eh
.byte restorw
.byte "restore"
.byte 8fh
.byte "rem"
clrrw .equ 90h
.byte clrrw
.byte "clear"
.byte 91h
.byte "run"
.byte 91h
.byte "r."
.byte 92h
.byte "list"
.byte 92h
.byte "l."
.byte 93h
.byte "new"
.byte 94h
.byte "abc"
.byte 95h
.byte "cls"
.byte 96h
.byte "renum"
.byte 97h
.byte "locate"
.byte 98h
.byte "load"
.byte 99h
.byte "save"
.byte 9ah
.byte "free"
.byte 9bh
.byte "poke"
.byte 9ch
.byte "delay"
.byte 9ch
.byte "d."
.byte 9dh
.byte "screen"
.byte 9eh
.byte "color"
.byte 9fh
.byte "point"
.byte 0a0h
.byte "line"
.byte 0a1h
.byte "auto"
.byte 0a2h
.byte "sound"
.byte 0a3h
.byte "servo"
.byte 0a4h
.byte "link"
.byte 0a5h
.byte "regbc"
.byte 0a6h
.byte "regde"
.byte 0a7h
.byte "memtop"
irwlin: .equ 0b0h ;last initial reserved word value + 1
steprw .equ 0b0h
.byte steprw
.byte "step"
torw .equ 0b1h
.byte torw
.byte "to"
thenrw .equ 0b2h
.byte thenrw
.byte "then"
.byte thenrw
.byte "t."
tabrw .equ 0b3h
.byte tabrw
.byte "tab"
lparrw .equ '('-opbase+0e0h
.byte lparrw
.byte "("
.byte 2ah-opbase+0e0h ;*
.byte "*"
plsrw .equ '+'-opbase+0e0h
.byte plsrw
.byte "+"
minrw .equ '-'-opbase+0e0h
.byte minrw
.byte "-"
.byte 2fh-opbase+0e0h ;/
.byte "/"
.byte 37h-opbase+0e0h
.byte ">="
.byte 38h-opbase+0e0h
.byte "<="
.byte 39h-opbase+0e0h
.byte "<>"
.byte 32h-opbase+0e0h
.byte "=>"
.byte 33h-opbase+0e0h
.byte "=<"
.byte 3ch-opbase+0e0h
.byte "<"
eqrw .equ 3dh-opbase+0e0h
.byte eqrw
.byte "="
.byte 3eh-opbase+0e0h
.byte ">"
.byte 0c1h
.byte "abs"
.byte 0c6h
.byte "int"
.byte 0cdh
.byte "usr"
.byte 0ceh
.byte "rnd"
.byte 0d2h
.byte "sgn"
.byte 0d3h
.byte "sin"
.byte 0c4h
.byte "sqr"
.byte 0d7h
.byte "tan"
.byte 0d8h
.byte "cos"
.byte 0d9h
.byte "peek"
.byte 0dah
.byte "keypad"
.byte 0ffh
;
; operation table
;
optab: .byte 15
oplpar: .equ optab
.word alpar
.byte 15
.word aabs
.byte 10
.word amul
.byte 6
.word aadd
.byte 15
.word asqr
.byte 6
.word asub
.byte 15
.word aint
.byte 10
.word adiv
opbol: .byte 1
.word 0
.byte 13
.word aneg
.byte 4
.word age
.byte 4
.word ale
.byte 15
.word 0 ;not used
.byte 15
.word acall
.byte 15
.word arnd
.byte 4
.word age
.byte 4
.word ale
.byte 4
.word ane
.byte 15
.word asgn
.byte 15
.word asin
.byte 4
.word alt
.byte 4
.word aeq
.byte 4
.word agt
.byte 15
.word atan
.byte 15
.word acos
.byte 15
.word apeek
.byte 15
.word akeypad
;
; action routines for relational operators
;
agt: call relop
jr z,rfalse
jr nc,rtrue
rfalse: xor a
ld (de),a
ret
alt: call relop
jr z,rfalse
jr nc,rfalse
rtrue: ld a,255
ld (de),a
ret
aeq: call relop
jr z,rtrue
jr rfalse
ane: call relop
jr z,rfalse
jr rtrue
age: call relop
jr z,rtrue
jr nc,rtrue
jr rfalse
ale: call relop
jr z,rtrue
jr nc,rfalse
jr rtrue
; common routine for relational operator action
; left arg addr in de, saved
; right arg addr in bc
; on return nc = gt, zero set=equal
relop: push de
dec bc
dec de
ld h,b
ld l,c
ld a,(de)
sub (hl)
inc hl
inc de
jr nz,rlop1 ;test signs of args if different then ret
ld bc,fpsink
call fsub
ld a,(fpsink) ;check for zero result
or a
jr z,rlop1
ld a,(fpsink-1) ;sign of fpsink
rlca
dec a
rlop1: push af
cp 128
jr c,rlop2
pop af
scf
ccf
jr rlop3
rlop2:
pop af
scf
rlop3:
ld a,1
ld (reltyp),a ;set reltyp true
pop de
ret
;
; action routines for arithmetic operators
; (code wasters)
aadd: ld h,b
ld l,c
ld b,d
ld c,e
aadd1: call fadd
jr fpetst
asub: ld h,b
ld l,c
ld b,d
ld c,e
asub1: call fsub
jr fpetst
amul: ld h,b
ld l,c
ld b,d
ld c,e
amul1: call fmul
jr fpetst
adiv: ld h,b
ld l,c
ld b,d
ld c,e
adiv1: call fdiv
fpetst: xor a
ld (reltyp),a
ld a,(erri)
or a
ret z
ld a,(astka) ;zero result on underflow
ld l,a
ld a,(astka+1)
ld h,a
fpet1: ld (hl),0
alpar: ret
;
; unary and built in function action routines
;
aneg: ld a,(bc)
or a
jr z,aneg1
dec bc
ld a,(bc)
xor 1
ld (bc),a
aneg1: xor a
ld (reltyp),a
ret
aabs: dec bc
xor a
ld (bc),a
jr aneg1
asgn: call aneg1
ld d,b
ld e,c
ld a,(bc) ;get exponent
or a
jr nz,asgn1
ld (de),a ;make argument zero
ret
asgn1: dec bc
ld a,(bc)
or a
ld hl,fpone
jp z,vcopy
ld hl,fpnone
jp vcopy
;
; compute sin(x) x=top of argument stack
; return result in place of x
;
asin: call quadc ;compute quadrant
ld a,(astka)
ld l,a
ld a,(astka+1)
ld h,a
ld d,h
ld e,l
ld bc,ftemp
call amul1 ;ftemp=x*x
pop af
push af ;a=quadrant
rra
jr c,sin10 ;quad odd, compute cosine
; compute x*p(x*x) -- sine
ld de,ftem1
ld a,(astka)
ld l,a
ld a,(astka+1)
ld h,a
call vcopy ;ftem1=x*x
ld bc,sinx
call poly ;p(x*x)
call prepop
ld hl,ftem1
call amul1 ;x*p(x*x)
; compute sign of result
; positive for quadrants 0,1. negative for 2,3
; negate above fro negative arguments
sin5: pop af ;quadrant
ld b,a
pop af ;sign
rlca ;sign, 2 to the 1st bit
xor b ;quadrant, maybe modified for negative arg.
push af
ld a,(astka)
ld l,a
ld a,(astka+1)
ld h,a
pop af
dec hl ;ptr to sign
sub 2
cp 128
ret nc ;quadrant 0 or 1
inc (hl) ;else set result negative
ret
; compute p(x*x) -- cosine
sin10: ld bc,cosx
call poly ;p(x*x)
jr sin5
sound:
call exprb ;get frequency
ld a,(astka)
ld l,a
ld a,(astka+1)
ld h,a
ld de,ftemp
call vcopy ;save x in ftemp
call prepop
ld hl,snd2 ;131072
call vcopy ;put 131072 on stack
call prepop
ld hl,ftemp ; tos=131072/ftemp
call adiv1
call pfix
ld a,e ;de = -de
cpl
ld e,a
ld a,d
cpl
ld d,a
inc de
ld hl,2048 ;hl = 2048 - de
add hl,de
push hl
ld b,','
call eatc
call exprb
call pfix
pop hl
ld a,d
or e ;is duration 0?
jr z,sound1 ;yes
; ld a,77h ;turn sound on
; ld (0ff24h),a
ld a,0ffh
ld (0ff25h),a
; ld a,82h
; ld (0ff26h),a
; ld a,84h ;set sound duty
; ld (0ff16h),a
; ld a,0f0h ;set envelope
; ld (0ff17h),a
ld a,l ;set frequency
ld (0ff18h),a
ld a,h
and 7
or 80h
ld (0ff19h),a
inc de
ld a,d
or a ;is duration 65535?
jr z,sound2 ;yes
dec de
call dely1 ;delay for duration
sound1:
xor a ;turn all sound off
ld (0ff25h),a
sound2:
ret
;
; compute cos(x) x=top of argument stack
; return result in place of x
; cos(x)=sin(x+pi/2)
;
acos: call prepop
ld hl,pic2 ;pi/2
call aadd1 ;tos=tos+pi/2
jp asin
; compute tan(x) x=top of argument stack
; return result in place of x
; tan(x)=sin(x)/cos(x)
;
atan: ld a,(astka)
ld l,a
ld a,(astka+1)
ld h,a
call pshas ;push copy of x onto arg stack
call acos ;cos(x)
ld de,ftem2
call popa1 ;ftem2=cos(x)
call asin
call prepop
ld hl,ftem2
jp adiv1 ;sin(x)/cos(x)
;
; compute sqr(x) x=top of argument stack
; return result in place of x
;
asqr: ld a,(astka)
ld l,a
ld a,(astka+1)
ld h,a
ld de,ftemp
call vcopy ;save x in ftemp
; compute exponent of first guess as exponent of x/2
ld a,(astka)
ld l,a
ld a,(astka+1)
ld h,a
ld a,(hl)
or a
ret z ;x=0
sub 128
cp 128
jr nc,sqr5 ;negative exponent
rrca
and 127
jr sqr6
sqr5: cpl
inc a
rrca
and 127
cpl
inc a
sqr6:
add a,128
ld (hl),a
; test for negative argument
dec hl
ld a,(hl)
ld hl,ermif ;6e61h 'na'
or a
jp nz,error ;neg argument
; do newton iterations
; newguess =( x/oldguess + oldguess ) /2
ld a,6 ;do 6 iterations
sqr20: push af ;set new iteration count
ld bc,ftem1
ld de,ftemp ;ftemp is 'x'
ld a,(astka) ;guess
ld l,a
ld a,(astka+1)
ld h,a
call adiv1 ;ftem1=x/guess
ld de,ftem1
ld a,(astka)
ld l,a
ld a,(astka+1)
ld h,a
ld b,h
ld c,l
call aadd1 ;tos=(x/guess)+guess
call prepop
ld hl,fptwo
call adiv1 ;tos=(x/guess+guess)/2
pop af
dec a ;decrement count
jr nz,sqr20 ;do another iteration
ret
;
; compute rnd(x) x=top of argument stack
; frand is updated to new random value
; a random number in the range 0<rnd<1 is returned in place
;
arnd: call prepop
ld de,frand
ld hl,frand
call amul1 ;tos=frand*frand
; set exponent=0
ld a,(astka)
ld l,a
ld a,(astka+1)
ld h,a
ld (hl),128 ;exponent=128 (0 in internal form)
; permute digits of x as
; 123456 into 345612
ld bc,-4
add hl,bc
ld b,(hl) ;save 12
inc hl
inc hl
call permu ;56=12
call permu ;34=56
call permu ;12=34
; normalize number
rnd5: ld a,(astka) ;tos
ld l,a
ld a,(astka+1)
ld h,a
ld bc,-fpsiz+1
add hl,bc
ld a,(hl) ;first digit pair
and 15*16
jr nz,rnd10 ;number is normalized
; shift left one digit
ld a,(astka)
ld l,a
ld a,(astka+1)
ld h,a
ld a,(hl) ;exponent
dec a
ld (exp),a
call load ;tos into temp
ld b,4
call left ;shift left
call prepop
call store
jr rnd5 ;test if normalized
; save new random # in frand cell
rnd10: ld de,frand
ld a,(astka)
ld l,a
ld a,(astka+1)
ld h,a
jp vcopy ;frand=tos
; permute pair of digit pairs
permu: ld a,(hl)
ld (hl),b
ld b,a
dec hl
ret
;
; evaluate p(x) using horners method (x is in ftemp)
; coefficient list pointer is in bc
; result replaces number on top of argument stack (y)
poly: ld a,(astka)
ld l,a
ld a,(astka+1)
ld h,a
push hl ;de=ptr to y
ld l,e
ld h,d
pop de
ld h,b
ld l,c ;hl ptr to coefficient list
call vcopy ;y=first coefficient
; multiply by x
poly1: push hl ;save coeff list pointer
call prepop
ld hl,ftemp
call amul1 ;y=y*x
; add next coeff
call prepop
pop hl
push hl ;hl=coeff. list pointer
call aadd1 ;y=y+coeff.
; bump pointer to next coefficient
pop hl ;coeff. pointer
ld bc,-fpsiz-1
add hl,bc ;next coef sign
ld a,(hl)
inc hl ;ptr to exponent
cp 128
jr c,poly1 ;process next coefficient
ret ;negative sign (-1) - ends list
;
; prepare for operation
;
prepop: ld a,(astka)
ld e,a
ld a,(astka+1)
ld d,a
ld b,d
ld c,e
ret
;
; quadrant computation
; pops top of argument stack
; compute/gets sine of argument, quadrant of argument
; and index into quadrant
;
; exits with:
; sp pointing to quadrant, mod 4
; sp+2 pointing to sign of argument
; top of argument stack has index into quadrant
quadc: ld a,(astka)
ld l,a
ld a,(astka+1)
ld h,a
dec hl ;point to sign
ld b,(hl)
xor a
ld (hl),a ;arg. sign=0
ld h,b
pop de ;pop return addr
push hl ;put sign on stack
push de ;push return
; compute quadrant of abs(x)
ld a,(astka)
ld l,a
ld a,(astka+1)
ld h,a
call pshas ;put copy of arg. onto stack
call prepop
ld hl,pic1 ;2/pi
call amul1 ;tos=x*2/pi
call prepop
call aint ;tos=int(x*2/pi)
ld a,(astka)
ld l,a
ld a,(astka+1)
ld h,a
call pshas ;another copy
call pfix ;pop tos to de
ld a,e
push af ;quadrant
call prepop
ld hl,pic2
call amul1 ;tos=int(x*2/pi)
ld de,ftemp
call popa1 ;ftemp=tos
call prepop
ld hl,ftemp
call asub1 ;tos=tos-ftemp
pop af ;a=quadrant, low order byte
and 3 ;mod 4
pop hl
push af ;save quadrant on stack
jp (hl) ;return
; "regbc"
SetRegBC:
call exprb ;get value for DE regs for USR
call pfix
ld a,e
ld (callRegC),a
ld a,d
ld (callRegB),a
ret
; "regde"
SetRegDE:
call exprb ;get value for DE regs for USR
call pfix
ld a,e
ld (callRegE),a
ld a,d
ld (callRegD),a
ret
; "memtop"
SetMemTop:
call exprb ;get value for top of RAM memory
call pfix
ld a,e
ld (memtop),a
ld a,d
ld (memtop+1),a
jp cclear ;clear all variable space
; x=peek(x)
; return memory byte
;
apeek: call pfix ;get the address in de
ld a,(de)
acal2: ld l,a
ld h,0
jr acal3
; used to call user routine
acall: call pfix ;get the address
ld l,e
ld h,d
ld bc,acal3 ;return link for user routine
push bc
ld a,(callRegC) ;get user arguments
ld c,a
ld a,(callRegB)
ld b,a
ld a,(callRegE)
ld e,a
ld a,(callRegD)
ld d,a
jp (hl)
;Return HL as a floating point number on arg stack
acal3: ld de,cnsbuf
call cns
ld a,cr
ld (de),a
ld de,cnsbuf
ld hl,fpsink
call fpin
ld de,fpsink
jp psha1 ;put the returned user value on arg stack
;
; int function action routine
aint: ld a,(bc)
sub 129
cp 128
jr c,aint1
; zero if value less than one
xor a
ld (bc),a
ret
; exp > 0
aint1: sub fpnib-1
ret nc
ld d,a ;count
dec bc
aint2: dec bc
ld a,(bc)
and 0f0h
ld (bc),a
inc d
ret z
xor a
ld (bc),a
inc d
jr nz,aint2
ret
;
; dimension matrix
; symtab addr in hl, hl not clobbered
; de contains size in # of elements
;
dims: push hl
inc de
push de
ld hl,0
ld c,fpsiz
call radd ;multiply nelts by bytes per value
ld e,l
ld d,h
ld a,(mata)
ld l,a
ld a,(mata+1)
ld h,a
push hl
add hl,de
call stov ;check that storage not exhausted
ld a,l
ld (mata),a ;up date matrix free pointer
ld a,h
ld (mata+1),a
pop bc ;base addr
pop de ;nelts
pop hl ;symtab addr
push hl
ld (hl),d
dec hl
ld (hl),e
dec hl
ld (hl),b
dec hl
ld (hl),c ;symtab entry now set up
pop hl
ret
;
; find variable optionally subscripted in text
; sets carry if not found
; returns addr of variable in hl
; updates txa if found
;
var: call alpha ;is first char a letter?
ret c ;no
call name2
call gc
cp lparrw
jr z,var1 ;test for subscripted
; must be scalar variable
call stlk ;returns entry addr in hl
; jr c,varsk1
; call true
or a
ret
;varsk1:
; call false
; or a ;clear carry
; ret
; must be subscripted
var1: call gci ;gobble left parenthesis
ld a,80h
or c
ld c,a ;set type to matrix
call stlk
push hl ;symbol table
ld de,10 ;default matrix size
call c,dims ;default dimension matrix
call exprb ;evaluate subscript expression
call pfix ;de now has integer
ld b,')'
call eatc ;gobble right parenthesis
pop hl
dec hl
call dcmp ;bounds check index
jp nc,e5
dec hl
dec hl
call lhli ;get base addr
ld c,fpsiz
inc de ;because base addr is to element-1
jp radd ;add index, clear carry
;
; junk on end of statement, test if at eof.
; exit: de is unaffected
; eats char & line count after cr
; leaves new txa in hl
; sets carry if eof
;
joe: call gci
cp ':'
ret z
cp cr
jp nz,e1
ld a,(hl)
dec a
jr z,joe2
inc hl
inc hl
inc hl ;skip over count & line #
joe1: ld a,l
ld (txa),a
ld a,h
ld (txa+1),a
ret
joe2: scf
jr joe1
;
; get name from text
; exit: carry set if name not found
; if name found, it is returned in bc.
; if no digit in name, c=0.
name1: call alpha
ret c
name2: ld b,a
ld c,0
call dig
ccf
ret nc
ld c,a
or a ;clear carry
ret
;
; symbol table lookup
; bc contains name and class
; if not found then create zero'ed entry & set carry
; hl has address on ret
;
stlk:
ld a,(memtop)
ld l,a
ld a,(memtop+1)
ld h,a
ld de,-stesiz ;set up base and inc for search loop
stlk0: ld a,(hl)
or a ;end of table ?
jr z,stlk2 ;yes, add to table
cp b
jr nz,stlk1 ;test if alpha compares
dec hl
ld a,(hl) ;look for digit
cp c
dec hl
ret z ;carry clear on ret
inc hl
inc hl
stlk1: add hl,de ;didn't compare, dec pointer
jr stlk0
; add entry to symtab
stlk2: ld (hl),b
dec hl
ld (hl),c
inc hl
push hl
ld l,e
ld h,d
pop de
add hl,de
ld a,l
ld (stb),a ;store new end of symtab pointer
ld a,h
ld (stb+1),a
dec de
dec de
push hl
ld l,e
ld h,d
pop de
scf
ret
;
; gobbles new text character if alphabetic
; set carry if not
; next char in 'a' on failure
;
alpha: call gc
cp 'a'
ret c
cp 'z'+1
ccf
ret c
jr digt1
; gobbles next text char if digit
; sets carry if not
; next char in 'a' on failure
dig:
call gc
cp '0'
ret c
cp '9'+1
ccf
ret c
digt1: inc hl
push af
ld a,l
ld (txa),a
ld a,h
ld (txa+1),a
pop af
ret
;
; copys fpsiz bytes at addr hl to addr de
; on exit hl points to adr-1 of last byte copied
;
vcopy: ld c,fpsiz
vcop1: ld a,(hl)
ld (de),a
dec hl
dec de
dec c
jr nz,vcop1
ret
;
; push value addr by hl onto arg stack
; sets argf, clears carry
;
pshas: ld e,l
ld d,h
psha1: ld a,(astka)
ld l,a
ld a,(astka+1)
ld h,a
ld bc,-fpsiz
add hl,bc
ld a,l
ld (astka),a ;dec arg stack pointer
ld a,h
ld (astka+1),a
push hl ;exchange de & hl
ld l,e
ld h,d
pop de
call vcopy
ld a,1
ld (argf),a ;clear argf
or a ;clear carry
ret
;
; pop arg stack
; hl contains addr to put popped value at
;
popas: push hl
ld l,e
ld h,d
pop de
popa1: ld a,(astka)
ld l,a
ld a,(astka+1)
ld h,a
push hl
ld bc,fpsiz
add hl,bc
ld a,l
ld (astka),a ;inc stack pointer
ld a,h
ld (astka+1),a
pop hl
jp vcopy
;
; push frame onto control stack
; takes minus amount to sub from cstka in de
; does overflow test and returns old cstka-1
;
pshcs: ld a,(cstka)
ld l,a
ld a,(cstka+1)
ld h,a
push hl
add hl,de
ld a,l
ld (cstka),a
ld a,h
ld (cstka+1),a
push hl
ld l,e
ld h,d
pop de
ld hl,lcstka ;addr contains cstkl
call dcmp
jp c,e4
pop hl
dec hl
ret
;
; storage overflow test
; test that value in hl is between mata & stb
; does not clobber hl
;
stov: push hl
ld l,e
ld h,d
pop de
ld hl,mata
call dcmp
jr c,e8
ld hl,stb
call dcmp
push hl
ld l,e
ld h,d
pop de
ret c
e8: ld hl,ermso ; 736fh 'so'
jp error
;
; increment txa if next non-blank char is equal to b
; else syntax error
;
eatc: call gci
cp b
ret z
jp e1
;
; put next non-blank char in 'a'
;
gc: call gci
dec hl
push af
ld a,l
ld (txa),a
ld a,h
ld (txa+1),a
pop af
ret
;
; get line number from program
;
gln:
ld a,(txa)
ld l,a
ld a,(txa+1)
ld h,a
gln1:
ld a,(hl)
inc hl
cp ' '
jr z,gln1
cp linent ;is this a line # token?
jr nz,glnerr ;no
ld e,(hl)
inc hl
ld d,(hl)
inc hl
ld a,l
ld (txa),a
ld a,h
ld (txa+1),a
ld l,e
ld h,d
or a ;clear carry flag
ret
glnerr: scf
ret
;
; put next non-blank char in 'a' & inc txa
;
gci: ld a,(txa)
ld l,a
ld a,(txa+1)
ld h,a
gci0: ld a,(hl)
inc hl
cp ' '
jr z,gci0
push af
ld a,l
ld (txa),a
ld a,h
ld (txa+1),a
pop af
ret
;
; repeat add
; adds de to hl c times
;
radd: add hl,de
dec c
jr nz,radd
ret
;
prntcr: ld c,cr
jr prn1
;
prnt: ld c,term
;
; print message addressed by hl
; char in c specifies terminator.
; exit: hl points to term addr
;
prn1: ld a,(hl) ;get next char
ld b,a ;for chout
cp c ;end of message test
ret z
cp cr
jp z,e1 ;never print a cr in this routine
call chout
inc hl
jr prn1
;
; 16 bit unsigned compare
; compare de against value addressed by hl
;
dcmp: ld a,e
sub (hl)
inc hl
ld a,d
sbc a,(hl)
dec hl
ret nz
ld a,e
sub (hl)
or a ;clear carry
ret
;
; indirect load hl thru hl
;
lhli: push af
ld a,(hl)
inc hl
ld h,(hl)
ld l,a
pop af
ret
;
; get fp constant from text
; pushes value on arg stack & sets argf flag
; sets carry if not found
;
const: ld a,(txa) ;prepare call fpin
ld l,a
ld a,(txa+1)
ld h,a
push hl
ld l,e
ld h,d
pop de
ld hl,fpsink
call fpin
ret c
dec de
ld a,e
ld (txa),a ;now points to terminator
ld a,d
ld (txa+1),a
ld de,fpsink
call psha1
xor a
inc a ;set a to 1 & clear carry
ld (argf),a
ret
;
; direct statement checking routine
;
dirt: ld a,(dirf)
or a
ret z
ld hl,ermdi ; 6469h 'di'
jp error
;
; Set eof address
; This needs to be done after a file load
;
findeof:
ld a,(bofa)
ld l,a
ld a,(bofa+1)
ld h,a
ld b,0
finde1: ld c,(hl)
ld a,c
cp eof ;at eof yet?
jr z,finde2 ;yes
add hl,bc
jr finde1
finde2: ld a,l
ld (eofa),a
ld a,h
ld (eofa+1),a
ret
;
; find text line with line # given in de
; returns text addr count byte in hl
;
findln: ld a,(bofa)
ld l,a
ld a,(bofa+1)
ld h,a
ld b,0
find1: ld c,(hl)
ld a,c
cp eof
jr z,lerr
inc hl
call dcmp
dec hl
ret z
add hl,bc
jr find1
lerr: ld hl,ermln ; 6c6eh 'ln'
jp error
;
; fix floating to positive integer
; return integer value in de
; fp value from top of arg stack, pop arg stack
;
pfix: ld a,(astka)
ld l,a
ld a,(astka+1)
ld h,a
ld b,h
ld c,l
push hl
call aint
ld hl,fpsink
call popas
pop hl
ld c,(hl) ;exponent
dec hl
ld a,(hl) ;sign
or a
jp nz,e5 ;negative no good
ld de,-fpsiz+1
add hl,de
ld de,0
ld a,c
or a
ret z
dec c ;set up for loop close test
pfix4: inc hl
ld a,(hl)
rrca
rrca
rrca
rrca
call mul10
jp c,e5
dec c
ld a,c
cp 128
ret c ;return if C is positive
ld a,(hl)
call mul10
jp c,e5
dec c
ld a,c
cp 128
jr nc,pfix4 ;jump if C is negative
ret
;
; take next digit in a (mask to 0fh), accumulate to de
;
mul10: push af
ld a,l
ld (miscW1),a
ld a,h
ld (miscW1+1),a
pop af
ld h,d ;get original value in hl
ld l,e
add hl,hl ;double it
ret c
add hl,hl ;quaddruple it
ret c
add hl,de ;add original for result of 5 x
ret c
add hl,hl ;result is 10 x
ret c
ld e,l
ld d,h
push af
ld a,(miscW1)
ld l,a
ld a,(miscW1+1)
ld h,a
pop af
and 0fh
add a,e
ld e,a
ld a,d
adc a,0 ;propogate the carry
ld d,a
ret
;
; Get integer from text
;
; Return:
; set carry if not found
; return integer in hl
; return terminator in a
;
intger: call dig
ret c
ld de,0
jr intg2
intg1: call dig
ld h,d
ld l,e
ccf
ret nc
intg2: sub '0'
call mul10
jr nc,intg1
ret
;
; convert string to integer
; de = addr of string
; exit:
; de = updated
; hl = converted value
;csn:
; ld hl,0
;csn1: ld a,(de)
; inc de
; cp ' ' ;is it a space?
; jr z,csn1 ;yes
;
; cp '0' ;is it a digit?
; jr c
;
; convert integer to string
; de = addr of string
; hl = value to convert
; exit: de = updated value
;
cns:
xor a ;set for no leading zeroes
ld bc,-10000
call rsub
ld bc,-1000
call rsub
ld bc,-100
call rsub
ld bc,-10
call rsub
ld bc,-1
call rsub
ret nz
ld a,'0'
ld (de),a
inc de
ret
;
; Take value in hl sub # in bc the
; most possible times.
; Put value on string at de.
; If a=0 then don't put zero on string.
; Return non-zero if a put on string
;
rsub: push de
ld d,-1
di ;<----+
rsub1: push hl ; |
inc sp ; |
inc sp ; |
inc d ; |
add hl,bc ; +---- Kill interrupts since we're
jr c,rsub1 ; | unusually messing with stack.
; |
dec sp ; |
dec sp ; |
ei ;<----+
pop hl
ld b,d
pop de
or b ;a gets 0 if a was 0 and b is 0
ret z
ld a,'0'
add a,b
ld (de),a
inc de
ret
;
; input character from terminal
;
;inchar: push bc
; push de
; push hl
;vkeyin: call $-$
; pop hl
; pop de
; pop bc
; and 7fh ;strip parity bit
; cp esc
; jp z,cmnd1
; ld b,a
; ret
;
inl0: call crlf
inline: ld hl,ibuf
ld c,linlen
inl1: ld b,GBB_RDY ;Send input ready char.
call chout ;Only needed by external terminal.
call inchar
cp 8
jr z,inl2 ;backspace
ld (hl),a
call chout ;echo
ld a,b
cp '@' ;line deletion
jr z,inl0
ld b,lf ;in case we are done
cp cr
jr z,chout ;do lf then return
inc hl
dec c
jr nz,inl1
ld hl,ermll ;6c6ch 'll'
jp error
inl2: ld a,c
; ld b,bell
cp linlen
jr z,inl1
ld b,8
call chout
ld b,' '
call chout
ld b,8
dec hl
inc c
inl3: call chout
jr inl1
;
; output to screen
;
chout:
ld a,b
cp 10
jr z,chchk
call SerialTransmit
cp 8 ;Is it 00 - 07 ?
jr c,chchk ;yes, don't display control chars
call outch
chchk: cp cr
jr nz,chlf ;not cr, is it lf?
xor a
jp pstor ;return phead to zero
;
chlf: cp ' ' ;no phead inc if control char
ret c
ld a,(phead)
inc a
pstor: ld (phead),a
ret
;
crlf2: call crlf
crlf: ld b,13
; call chout
; ld b,10
jp chout
;
; get integer from terminal
; de contains string to print first
; hl has 1 less than acceptable lower bound
; this routine goes to start if bad #
; integer value returned in hl
;
gint: push hl
push hl
ld l,e
ld h,d
pop de
ld a,(phead)
or a
call nz,crlf
call prnt
call inline
ld hl,ibuf
ld a,l
ld (txa),a
ld a,h
ld (txa+1),a
call intger
jp c,start
cp cr
jp nz,start
pop de
ld a,l
ld (ibuf),a ;use ibuf as a temp
ld a,h
ld (ibuf+1),a
ld hl,ibuf
call dcmp
jp nc,start
ld a,(ibuf) ;get the value back to hl
ld l,a
ld a,(ibuf+1)
ld h,a
ld a,(hl)
cpl
ld (hl),a ;try to store there
cp (hl)
jp nz,start ;bad or missing memory
ret
;
; output fp number addr by hl
;
fpout: ld bc,-digit-1
add hl,bc
ld b,h
ld c,l
ld hl,abuf ;output buffer
ld a,(infes) ;output format
ld (fes),a ;store it
ld e,digit
ld (hl),0 ;clear round-off overflow buffer
inc hl ;abuf+1
;
nxt: ld a,(bc) ;get digit and unpack
ld d,a
rra
rra
rra
rra
and 0fh ;remove bottom digit
ld (hl),a ;store top digit in output buffer (abuf)
inc hl
ld a,d ;now get bottom digit
and 0fh
ld (hl),a ;store it
inc hl
inc bc
dec e
jr nz,nxt
ld a,(bc)
ld (fsign),a ;store sign of number
xor a
ld (hl),a ;clear round-off buffer (abuf+13) 12 digit no rnd
ld hl,xsign ;exponent sign store
ld (hl),a ;clear xsign
;
fix: inc bc ;get exponent
ld a,(bc)
or a ;exponent zero?
jr z,zro
sub 128 ;remove normalizing bias
jr nz,fix2
inc (hl) ;inc xsign to negative flag (1)later zero
fix2:
cp 128
jr c,chk13
cpl ;it's a negative exponent
inc (hl) ;inc xsign to negative (1)
zro: inc a
chk13: ld hl,expo ;exponent temp store
ld (hl),a
ld e,a
cp digit*2
ld hl,fes ;format temp byte
jr c,chkxo
chk40: ld a,1 ;force exponential printout
or (hl) ;set format for xout
ld (hl),a
;
chkxo: ld a,(hl) ;check if exponential printout
rra
jr nc,chkx3
and 0fh
cp digit*2
jr c,chkx2
ld a,digit*2-1 ;max digits
chkx2: ld d,a
inc a
jr round
;
chkx3: and 0fh ;add exponent & decimal places
ld d,a
add a,e
cp digit*2+1
ld b,a
jr c,chkxn
ld a,(hl)
and 40h
jr nz,chk40
;
chkxn: ld a,(xsign) ;check exponent sign
or a
jr nz,xneg ;it's negative
ld a,b
jr round
;
xneg: ld a,d ;sub exponent & decimal place count
sub e
jr nc,xn2
xn1: ld a,(infes)
cp 128
jp c,zero
and 0eh
jp z,zero
rrca
ld e,a
dec e
ld c,1
ld hl,abuf-1
jr nrnd
xn2: jr z,xn1
jr round
;
;
clean: ld b,1fh ;clear flags
and b
cp digit*2+1
ret c
ld a,digit*2+1 ;max digits out
ret
;
; this routine is used to round data to the
; specified decimal place
round: call clean
ld c,a
ld b,0
ld hl,abuf+1
add hl,bc ;get round-off addr
ld a,l
ld (addt),a
ld a,h
ld (addt+1),a
ld a,(hl)
cp 5 ;round if >=5
jr c,trl1
;
less1: dec hl
inc (hl) ;round up
ld a,(hl)
or a
jr z,trl2
cp 10 ;check if rounded number >9
jr nz,trail
ld (hl),0
jr less1
;
; this routine eliminates trailing zeros
trail: ld a,(addt)
ld l,a
ld a,(addt+1)
ld h,a
trl1: dec hl
trl2: ld a,(fes) ;check if trailing zeros are wanted
rla
jr c,fprnt ;yes, go print data
trl3: ld a,(hl)
or a ;is it a zero?
jr nz,fprnt ;no, go print
dec hl
dec c ;yes, fix output digit count
ld a,c
cp 128
jp nc,zeron ;jump if C is negative
jr trl3
;
; print format routines
fprnt: ld hl,abuf
ld a,(hl) ;check if rounded up to 1
or a
jr z,nrnd ;jump if not
ld b,1
ld a,(xsign) ;is exponent negative?
or a
jr z,posr
ld b,-1
;
posr: ld a,(expo) ;get exponent
or a
jr nz,po2 ;is it zero? (e+0)
ld (xsign),a
ld b,1
po2: add a,b ;fix exponent count
ld (expo),a
inc e
inc c
dec hl
;
nrnd: inc hl
ld a,c
cp digit*2+1 ;check for maximum digits out
jr nz,nrnd1
dec c
nrnd1: ld a,(fsign) ;check if neg #
rra
jr nc,prin2 ;go output radix & number
call neg ;output (-)
jr pri21
;
prin2: call space ;output a space
pri21: ld a,(fes) ;get output format
rra ;check if exponential output format
jr c,xprin
ld a,(xsign) ;get exp sign
or a ;check if neg exp
jr z,posit
ld a,c
or a
jr nz,prin4 ;output radix & number
jp zero ;no digits after radix, output zero & done
;
prin4: call radix ;print decimal point
prin6: xor a
or e
jr z,prin5 ;jump if no zeros to print
call zero ;force print a zero
dec e
jr nz,prin6
;
prin5: call nout ;print ascii digit
jr nz,prin5
ret
;
posit: call nout
dec e ;bump exp count
jr nz,posit
ld a,c ;check if more digits to output
or a
ret z ;no, done
cp 128
ret nc
jr prin4 ;now print decimal point
;
; exponential format output
xprin: call nout
jr z,ndec ;integer?
call radix ;no. print decimal point
xpri2: call nout
jr nz,xpri2
;
ndec: ld b,'e' ;print 'e'
call chout
ld a,(xsign)
or a
jr z,xpri3
call neg ;print exp sign (-)
ld a,(expo)
inc a
jr xout2
xpri3: ld b,'+' ;exp (+)
call chout
;
; convert the exponent from binary-to-ascii
; and print the result.
xout: ld a,(expo)
dec a
xout2: ld c,100
ld d,0
call conv
cp '0' ;skip leading zeros
jr z,xo21
inc d
call chout
xo21: ld a,e
ld c,10
call conv
cp '0'
jr nz,xo3
dec d
jr nz,xo4
xo3: call chout
xo4: ld a,e
add a,'0' ;add ascii bias
ld b,a
jp chout
;
conv: ld b,'0'-1
conv1: inc b
sub c
jr nc,conv1
add a,c
ld e,a
ld a,b
ret
;
; change bcd digit to ascii & print
nout: ld a,(hl)
add a,'0'
ld b,a
call chout
inc hl
dec c ;dec total digits printed count
ret
; print fp zero
zeron: ld b,' '
call chout
jr zero
;
; common symbol loading routines
neg: ld b,'-'
jp chout
zero: ld b,'0'
jp chout
space: ld b,' '
jp chout
radix: ld b,'.'
jp chout
; converts fp string at de, update de past terminator
; puts terminator in b, puts fp # at addr in hl
; sets carry if not found
fpin:
push hl
ld l,e
ld h,d
dec hl
ld a,l
ld (adds),a
ld a,h
ld (adds+1),a
call ibscn ;get first non-space
cp '&'
jr z,fpin6
dec hl
call ibscn2 ;add back to buffer
call fpins
pop hl
jp nc,entr3
ret
; get hex number from input
fpin6:
call ibscn ;get 'h'
cp 'h' ;is it hex?
jp nz,e1 ;no
call getnib
jp c,e1 ;bad hex number
ld e,a
ld d,0
ld b,4
fpin7: call getnib
jp c,fpin8
dec b
jp z,e7 ;overflow
push hl ;de = de * 16
ld l,e
ld h,d
add hl,hl
add hl,hl
add hl,hl
add hl,hl
ld e,l
ld d,h
pop hl
add a,e ;add a to de
ld e,a
ld a,0
adc a,d
ld d,a
jr fpin7
fpin8:
push hl
ld l,e ;put hex number in hl
ld h,d
ld de,cnsbuf ;convert it to a ascii decimal string
call cns
ld a,cr
ld (de),a
ld de,cnsbuf-1
ld a,e
ld (adds),a
ld a,d
ld (adds+1),a
call fpins
pop de
pop hl
push de
call entr3
pop de
; inc de
ld a,(de)
ld b,a
inc de
ret
getnib:
call ibscn
sub '0'
cp '9'+1-'0'
ccf
ret nc
sub 'a'-'0'
cp 'f'+'1'-'a'-'0'
ccf
ret c
add a,10
ret
;fpin:
; push hl
; push de
;
; ld l,e
; ld h,d
;
; dec hl
;
; ld a,l
; ld (adds),a
; ld a,h
; ld (adds+1),a
fpins:
push de
ld hl,opst ;clear temporary storage areas & bc buffer
ld c,digit+6
call clear
;
scanc: ld de,0
ld hl,bcs ;bc=pack buffer
scan0: ld a,l
ld (bcadd),a ;pack buffer pointer
ld a,h
ld (bcadd+1),a
scanp: ld hl,scanp
push hl ;used for return from other routines
xor a
ld (xsign),a ;clear exp sign byte
;
scang: call ibscn
jr c,scanx ;found a #, go pack it
cp '.' ;radix?
jr z,scan5 ;process radix pointers
cp 'e' ;exp?
jp z,excon ;found 'e'', go process exp #
;this char not legal in #
ld b,a ;move terminator to b
ld a,(opst) ;check if any digits yet
and 10h
jp nz,entr2
;legal fp number not found
fpin1: pop hl ;rid of scanp link
pop de ;text pointer
scf
ret
;found decimal point
scan5: xor a ;found radix process radix pointers for exp
or d ;any digits yet?
jr nz,scan6
add a,0c0h ;set ecnt - stop counting digits
or e ;no int digits, bit 7 is count (or don't) flag
ld e,a ;bit 6 is negative exp flag
ret
scan6: ld a,80h ;set ecnt to count digits
or e
ld e,a
ret
;
scanx: and 0fh ;found number - remove ascii bias
ld b,a
ld hl,opst ;set first char flag
ld a,30h
or (hl)
ld (hl),a
xor a
or b ;is char zero?
jr nz,pack
or d ;leading zero? ie; any int digits?
jr nz,pack
or e
ld e,a
ret z ;if counting yet,
inc e ;ecnt+1-count zeros for exp count
ret
;
; bcd pack digits into pair bc
;
pack: ld a,e
rla
jr c,pack1
inc e
pack1: ld a,e
ld (ecnt),a ;digit count for exp count
inc d ;total digit count (d has top/bot flag bit 7)
ld a,d
and 7fh ;remove top/bot flag
cp digit*2+1 ;limit input digits
ret nc
ld a,d
cp 128
jr nc,botm
;
top: or 80h ;set msb for top flag
ld d,a
ld a,(bcadd) ;get bc addr
ld l,a
ld a,(bcadd+1)
ld h,a
ld a,b
rlca
rlca
rlca
rlca
ld (hl),a ;save char in bc
ret
;
botm: and 7fh ;strip msb (bottom flag)
ld d,a
ld a,b
ld a,(bcadd)
ld l,a
ld a,(bcadd+1)
ld h,a
ld a,b
or (hl) ;or in top number
ld (hl),a ;put number back in bc
inc hl
pop bc
jp scan0
ibscn: ld a,(adds) ;input buffer pointer
ld l,a
ld a,(adds+1)
ld h,a
ibscn1: inc hl ;get next byte
ld a,(hl)
cp ' '
jr z,ibscn1
ibscn2: push af
ld a,l
ld (adds),a
ld a,h
ld (adds+1),a
pop af
; check for ascii numbers
nmchk: cp '9'+1
ret nc
cp '0'
ccf
ret
;
; adjust a number in bc buffer & return value
entr2: ld de,0
ent1: push bc ;terminator
call fixe ;normalize floating point #
pop bc ;terminator
pop de ;scanp link
pop de ;old text addr
or a
ret
pop de ;ret addr
entr3:
ld e,l
ld d,h
ld c,digit+2
ld hl,bcs+digit+1
call vcopy
push af
ld a,(adds)
ld l,a
ld a,(adds+1)
ld h,a
pop af
push hl
ld l,e
ld h,d
pop de
inc de
or a
ret
; clear storage areas
; hl = starting address
; c = count
clear: xor a
clear1: ld (hl),a
inc hl
dec c
jr nz,clear1
ret
;
; convert ascii exponent of number in the input buffer
; to binary. normalize exponent according to the input
; format of the number.
excon: call ibscn ;get character
jr c,exc3
cp plsrw ;check for unary sign
jr z,exc4
cp '+'
jr z,exc4
cp minrw
jr z,exc2
cp '-'
jr nz,fperr ;no sign or number?
exc2: ld a,1
ld (xsign),a ;save sign
exc4: call ibscn
jr nc,fperr ;no number?
exc3: call ascdc ;convert ascii to binary
jr ent1 ;normalize # & return
;
; convert ascii to binary
; three consecutive numbers <128 may be converted
ascdc: push hl
ld l,e
ld h,d
pop de
ld hl,0
asc1: ld a,(de) ;get chr from input buffer, no spaces allowed
call nmchk ;check if #
jr nc,asc2
sub '0' ;remove ascii bias
ld b,h
ld c,l
add hl,hl
add hl,hl
add hl,bc
add hl,hl
ld c,a
ld b,0
add hl,bc
inc de
jr asc1
asc2: push hl
ld l,e
ld h,d
pop de
ld b,a ;save terminator
ld a,l
ld (adds),a ;save ibuf addr
ld a,h
ld (adds+1),a
ld a,d
or a
jr nz,fperr ;too big >255
ld a,e
rla
jr c,fperr ;too big >127
rra
ret
fperr: pop bc ;ascdc ret link
jp fpin1
;
; normalize input buffer
fixe: push hl
ld l,e
ld h,d
pop de
ld a,(bcs)
or a ;is it zero?
jr z,zz2
call chkpn ;set exp pos/neg
add a,80h ;add exp bias
zz2: ld (bcs+digit+1),a;store normalized exp in bc
ret
;
chkpn: ld a,(ecnt) ;get exp count-set in 'scan' routine
ld e,a
and 3fh ;strip bits 7&8
ld b,a
ld a,(xsign)
or a
jr z,lpos ;exponent is positive
inc h ;set sign in h
ld a,40h ;l is neg
and e ;check if e is negative
jr z,epos
ld a,l ;both e&l neg
ld l,b
call bpos1
cpl
inc a
ret ;back to fixe
;
epos: ld a,l ;e&l neg
epos1: cpl
inc a
add a,b
ret ;to fixe
;
lpos: ld a,40h ;exponent positive
and e ;is e negative?
jr z,bpos
ld a,b
ld b,l
jr epos1
;
bpos: ld a,b ;e&l pos
bpos1: add a,l
cp 128
ret c
pop hl
jr fperr
.byte 10h
.word 0
.byte 1
fpnone: .byte 129
;
; four function floating point bcd
;
; bc = de # hl
; # is +,-,*, or /.
; <bc>=address of result
; <de>=address of 1st argument
; <hl>=address of 2nd argument
; all addresses on entry point to the exponent part of #.
; each # consists of (2*digit) packed decimal digits,
; a sign, and a biased binary exponent. the exponent range
; is 10**-127 to 10**127. the number 0 is represented by
; the exponent 0. the numbers are stored in memory as
; digit bytes of decimal digits starting at the low order
; address. all numbers are assumed to be normalized.
;
; floating point addition
;
fadd: push bc
call expck ;fetch arguments
ld c,0
adsum: dec de
push hl
ld l,e
ld h,d
pop de
ld a,(sign)
xor (hl) ;form sign of result
ld b,a
push hl
ld l,e
ld h,d
pop de
ld a,(de)
dec de
xor c
ld (sign),a
ld hl,rctrl ;rounding control flag
ld a,(hl)
or a
inc hl
ld a,(hl) ;get rounding digit
jr z,ads8
rlca
rlca
rlca
rlca
ads8: add a,0b0h ;force carry if digit > 5
ld a,b
rra
jr c,ads1 ;have sub
rla ;restore carry
call add0 ;perform addition
jr nc,ads2
ld b,4
call right
ld hl,exp
inc (hl) ;inc exp
jp z,over
ads2: pop bc ;get results addr
jp store ;save results
zerex: pop hl
jr ads2
add0: ld hl,buf+digit-1
ld b,digit
add1: ld a,(de)
adc a,(hl)
daa
ld (hl),a
dec hl
dec de
dec b
jr nz,add1
ret nc
inc (hl)
ret
;
; floating point subtraction
;
fsub: push bc
call expck ;get arguments
ld a,(sign)
xor 1 ;complement sign
ld (sign),a
jr adsum
ads1: rla ;restore carry
ccf ;complement for rounding
call sub0 ;subtract arguments
ld hl,sign
jr c,ads4
ld a,(hl) ;get sign
xor 1 ;complement
ld (hl),a
ads7: dec hl
ld b,digit
ads3: ld a,9ah
sbc a,(hl) ;complement result
add a,0
daa
ld (hl),a
dec hl
dec b
ccf
jr nz,ads3
ads4: ld hl,buf
ld bc,digit
ads5: ld a,(hl)
or a
jr nz,ads6
inc hl
inc b
inc b
dec c
jr nz,ads5
xor a
ld (exp),a
jr ads2
ads6: cp 10h
jr nc,ads9
inc b
ads9: ld hl,exp
ld a,(hl)
sub b
jp z,under
jp c,under
ld (hl),a
ld a,b
rlca
rlca
ld b,a
call left
jr ads2
sub0: ld hl,buf+digit-1
ld b,digit
sub1: ld a,99h
adc a,0
sub (hl)
push hl
ld l,e
ld h,d
pop de
add a,(hl)
daa
push hl
ld l,e
ld h,d
pop de
ld (hl),a
dec hl
dec de
dec b
jr nz,sub1
ret
;
; floating point multiply
;
fmul: push bc
ld a,(hl)
or a ;argument = 0?
jr z,fmul1+2
ld a,(de)
or a ;argument = 0?
jr z,fmul1+2
add a,(hl) ;form result exponent
jr c,fmovr
cp 128
jp c,under ;jump if A is positive
jr fmul1
fmovr:
cp 128
jp nc,over
fmul1: sub 128 ;remove excess bias
ld (exp),a ;save exponent
dec de
dec hl
ld a,(de)
xor (hl) ;form result sign
dec hl
dec de
push hl
ld hl,sign ;get sign addr
ld (hl),a ;save sign
dec hl
xor a
ld b,digit+2
fmul2: ld (hl),a ;zero working buffer
dec hl
dec b
jr nz,fmul2
ld a,(exp)
or a
jp z,zerex
ld c,digit
ld hl,hold1+digit
; get multiplier into holding register
fmul3: ld a,(de)
ld (hl),a ;put in register
dec hl
dec de
dec c
jr nz,fmul3
ld (hl),c
dec hl
ld b,250 ;set loop count
fmul4: ld de,digit+1
ld c,e
add hl,de
push hl
ld l,e
ld h,d
pop de
add hl,de ;hl=next holding register
inc b
ld a,b
cp 128
jr c,fmul8 ;finished
fmul5: ld a,(de) ;get digits
adc a,a ;times 2
daa
ld (hl),a ;put in holding register
dec de
dec hl
dec c
jr nz,fmul5
inc b ;inc loop count
jr nz,fmul4
; form 10x by adding 8x & 2x
; first get 8x
inc hl
ld de,hold5 ;next holding register
ld c,digit+1
ld b,c
fmul6: ld a,(hl)
ld (de),a
inc hl
inc de
dec c
jr nz,fmul6
ld hl,hold2+digit;get 2x
dec de
fmul7: ld a,(de)
adc a,(hl) ;form 10x
daa
ld (de),a
dec de
dec hl
dec b
jr nz,fmul7
ld b,249
push hl
ld l,e
ld h,d
pop de
jr fmul4
fmul8: push hl
ld l,e
ld h,d
pop de
inc hl
ld (hl),digit+1 ;set next loop count
; perform accumulation of product
fmul9: pop bc ;get multiplier
ld hl,hold8+digit+1
dec (hl) ;dec loop count
jr z,fmu14 ;finished
ld a,(bc)
dec bc
push bc
dec hl
push hl
ld l,e
ld h,d
pop de
fmu10: add a,a ;check for bit in carry
jr c,fmu11 ;found a bit
jr z,fmu12 ;zero, finished this digit
ld hl,-digit-1
add hl,de ;point to next holding register
push hl
ld l,e
ld h,d
pop de
jr fmu10
fmu11: ld c,a
or a ;clear carry
call add0 ;accumulate product
ld a,(de)
add a,(hl)
daa
ld (hl),a
ld a,c
dec de
jr fmu10
; rotate right 1 byte
fmu12: ld b,8
call right
jr fmul9
fmu14: ld a,(buf)
and 0f0h ;check if normalized
jr z,fmu17
ld a,d
and 0f0h
ld hl,sign-1
jr fmu18
fmu17: ld b,4
ld hl,exp
dec (hl)
jp z,under
call left ;normalize
ld a,d ;get digit shifted off
; perform rounding
rrca
rrca
rrca
rrca
fmu18: cp 50h
jr c,fmu16
inc a
and 0fh
ld c,digit
fmu15: adc a,(hl)
daa
ld (hl),a
ld a,0
dec hl
dec c
jr nz,fmu15
; check for rounding overflow
jp nc,ads2 ;no overflow
inc hl
ld (hl),10h
ld hl,exp
inc (hl)
jp nz,ads2
jp over
; rounding not needed
fmu16: and 0fh
add a,(hl)
ld (hl),a
jp ads2
;
; floating point division
;
fdiv: push bc
ld a,(hl) ;fetch divisor exp
or a ;divide by 0?
jp z,divz
ld a,(de)
or a ;dividend = 0?
jp z,insp
sub (hl)
jr c,divun
cp 128
jp nc,over
jr fdi1
divun: cp 128
jp c,under ;jump if positive
fdi1: add a,129 ;form quotient exp
ld (expd),a
push hl
ld l,e
ld h,d
pop de
push de
call load ;fetch dividend
pop de
push hl
ld l,e
ld h,d
pop de
ld a,(sign)
dec hl
xor (hl) ;form quotient sign
ld (signd),a
push hl
ld l,e
ld h,d
pop de
dec de
ld bc,hold1
div0: ld l,digit+digit
div1: push bc
push hl
ld c,0 ;quotient digit = 0
div3: scf ;set carry
ld hl,buf+digit-1
ld b,digit
div4: ld a,99h
adc a,0
push hl
ld l,e
ld h,d
pop de
sub (hl)
push hl
ld l,e
ld h,d
pop de
add a,(hl)
daa
ld (hl),a
dec hl
dec de
dec b
jr nz,div4
ld a,(hl)
ccf
sbc a,0
ld (hl),a
rra
ld hl,digit
add hl,de
push hl
ld l,e
ld h,d
pop de
inc c ;inr quotient
rla
jr nc,div3
or a ;clear carry
call add0 ;restore dividend
ld hl,digit
add hl,de
push hl
ld l,e
ld h,d
pop de
push bc
ld b,4
call left ;shift dividend
pop bc
dec c
pop hl
ld h,c
pop bc
ld a,l
jr nz,div5
cp digit+digit
jr nz,div5
ld hl,expd
dec (hl)
call z,under
jr div0
div5: rra
ld a,h
jr nc,div6
ld a,(bc)
rlca
rlca
rlca
rlca
add a,h
ld (bc),a ;store quotient
inc bc
jr div7
div6: ld (bc),a ;store quotient
div7: dec l ;dec digit count
jr nz,div1
ld hl,expd
pop bc
jr storo
; fetch & align arguments for
; addition & subtraction
expck: ld a,(de)
sub (hl) ;difference of exps
ld c,0
jr nc,expc1
inc c
push hl
ld l,e
ld h,d
pop de
cpl
inc a
expc1: ld b,a
ld a,(de)
ld (exp),a
ld a,b
cp digit+digit
jr c,expc2
ld a,digit+digit
expc2: rlca
rlca
ld b,a
and 4
ld (rctrl),a ;set rounding control
push bc
push de
call load ;load smaller value
ld a,8*digit+16
sub b
cp 8*digit+16
jr z,expc3
and 0f8h
rra
rra
rra
add a,e
ld e,a
ld a,d
adc a,0
ld d,a
ld a,(de) ;get rounding digit
ld (rdigi),a ;save
expc3: call right ;align values
pop de
pop bc
ret
; load argument into buffer
load: ld de,sign
ld c,digit+1
dec hl
load1: ld a,(hl)
ld (de),a
dec hl
dec de
dec c
jr nz,load1
xor a
ld (de),a
dec de
ld (de),a
ld (rdigi),a ;zero rounding digit
ret
; store results in memory
store: ld hl,exp
storo: ld e,digit+2
stor1: ld a,(hl)
ld (bc),a
dec bc
dec hl
dec e
jr nz,stor1
ret
; shift right number of digits in b/4
right: ld c,digit+1
righ1: ld hl,buf-1
ld a,b
sub 8 ;check if byte can be shifted
jr nc,righ3
dec b
push af
ld a,b
cp 128
jr c,righ5
pop af
ret
righ5:
pop af
or a
righ2: ld a,(hl)
rra
ld (hl),a
inc hl
dec c
jr nz,righ2
jr right
; shift right one byte
righ3: ld b,a
xor a
righ4: ld d,(hl)
ld (hl),a
ld a,d
inc hl
dec c
jr nz,righ4
jr right
; shift left number of digits in b/4
left: ld c,digit+1
ld hl,sign-1
lef1: ld a,b
sub 8
jr nc,lef3
dec b
push af
ld a,b
cp 128
jr c,lef5
pop af
ret
lef5:
pop af
or a
lef2: ld a,(hl)
rla
ld (hl),a
dec hl
dec c
jr nz,lef2
jr left
; shift left one byte
lef3: ld b,a
xor a
lef4: ld d,(hl)
ld (hl),a
ld a,d
dec hl
dec c
jr nz,lef4
jr left
; set flags for overflow, underflow
; and divide by zero
over: ld hl,ermfp ;6670h 'fp'
jp error
under: ld a,0ffh
ld (erri),a
insp: inc sp
inc sp
ret
divz: ld hl,ermdz
jp error
ilprc: EX_SP_HL
push af
push bc
push de
ilpr1: ld a,(hl)
inc hl
or a
jr z,ilprt2
ld b,a
call chout
jr ilpr1
ilprt2:
call crlf
pop de
pop bc
pop af
EX_SP_HL
ret
.block $8000-$ ;fill up whole 32768 block
.end