;******************************** ;* 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 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 /. ; =address of result ; =address of 1st argument ; =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