On a recent project I needed to read and write unsigned double byte values from memory. The standard version of BASIC does not include such commands so they must be accomplished using multiple commands. For reading a two byte value this is usually how it is done:
10 A = PEEK(&H6000)*256+PEEK(&H6001)
Variable A will now contain an unsigned two byte value starting from $6000. This is an example of writing a two byte value:
10 A=RND(65535)
20 POKE &H6000,A/256
30 POKE &H6001,256*(A/256-INT(A/256))
It turns out all this math was causing my recent project to slow down to unacceptable levels. So I had the idea of rewriting the Super Extended Color BASIC commands LPEEK and LPOKE to perform double byte reads and writes. Looking thru the commented source disassembly, I discovered that if it was acceptable to completely replace the functionality of the commands I had 27 bytes for LPEEK and 45 bytes for LPOKE to work with.
So I took the code from regular PEEK and and placed it where LPEEK was and change the opcode to read two bytes instead of one. This caused a problem, the standard return from a function subroutine converts the D register to a signed value from -32767 to 32766. I wanted an unsigned result from 0 to 65535. In the LIST command I discovered a bit of code that prints the line number to do exactly what I wanted.
0050 00001 fpa0 equ $50
002B 00002 binval equ $2b
00003
00004 # Modify LPEEK to return two bytes (unsigned)
00005 org $e573
E573 17D1CA 00006 lbsr $b740 convert FPA0 to integer in register X
E576 EC84 00007 ldd ,x read two bytes
E578 DD50 00008 std fpa0 convert Reg D to FP and return
E57A C690 00009 ldb #$90
E57C 43 00010 coma
E57D BDBC86 00011 jsr $bc86
E580 39 00012 rts
The new LPOKE function needed to read two comma separated values from the program and write the value to the address.
00014 # Modify LPOKE to store two bytes (unsigned)
00015 org $e545
E545 17D1F5 00016 lbsr $b73d eval expression return in X
E548 9F2B 00017 stx binval store address in binval
E54A BDB26D 00018 jsr $b26d syntax check for a comma
E54D 17D1ED 00019 lbsr $b73d eval expression return in X
E550 1F10 00020 tfr x,d transfer value to D
E552 9E2B 00021 ldx binval load address
E554 ED84 00022 std ,x store value in address
E556 39 00023 rts
After overlaying this code onto SECB, I now have a double byte version of PEEK and POKE. Soon I discovered I had a new slow down. I was filling buffers with the same byte, over and over. Like this:
10 FOR X = &H6000 TO &H64FF
20 POKE X, &H55
30 NEXT X
This turned out to be a slow method of filling memory. I needed a new command to quickly accomplish the same thing. I began looking for another command in SECB that I could replace. I decided to replace HPAINT.
00025 # Modify HPAINT to be a memory fill command
00026 # Example: HPAINT &H7400, &H2300, &H80
00027 # Write byte $80 to buffer in $7400 to $96FF
00028 org $ebf5
EBF5 17CB45 00029 lbsr $b73d eval expression return in X
EBF8 9F2B 00030 stx binval store address in binval
EBFA BDB26D 00031 jsr $b26d syntax check for a comma
EBFD 17CB3D 00032 lbsr $b73d eval expression return in X
EC00 3410 00033 pshs x
EC02 BDB26D 00034 jsr $b26d syntax check for a comma
EC05 BDB70B 00035 jsr $b70b eval expression return in B
EC08 9E2B 00036 ldx binval
EC0A 3520 00037 puls y
00038 loop
EC0C E780 00039 stb ,x+
EC0E 313F 00040 leay -1,y
EC10 26FA 00041 bne loop
EC12 39 00042 rts
00043 end
To test it I wrote this screen saver:
10 WIDTH 32:CLS
20 HPAINT &H3FF+RND(512),RND(128),127+RND(128)
30 GOTO 20