In GFXFLIP.BAS, instead of the ‘flip through them’ code, try this:
1000 ‘GO DO THE ROTATION 1010 GOTO 1050 1020 FOR P=2 TO 5:GOSUB 1070:PMODE 4,P:SCREEN1:NEXT 1030 IF INKEY$=”” THEN 1030 1040 FOR P=4 TO 1 STEP -1:GOSUB 1070:PMODE 4,P:SCREEN1:NEXT 1050 IF INKEY$=”” THEN 1050 1060 GOTO 1020 1070 FOR TT=0 TO 40:NEXT:RETURN “
– Juan Casto via CoCo Mailing list
So let’s take a look and see what it does. Replacing my code from 70-110 with a GOSUB to this routine gives us this:
0 'GFXFLIP2.BAS 1 'Juan Castro 10 PCLEAR 8 15 ' DRAW FIRST SCREEN 20 PMODE 4,1:PCLS:SCREEN 1,1 30 CIRCLE(128,96),50 35 ' DRAW SECOND SCREEN 40 PMODE 4,5:PCLS:SCREEN 1,1 50 LINE (10,10)-(245,171),PSET,B 60 ' FLIP THROUGH THEM 70 GOSUB 1000 110 GOTO 70
1000 'GO DO THE ROTATION 1010 GOTO 1050 1020 FOR P=2 TO 5:GOSUB 1070:PMODE 4,P:SCREEN1:NEXT 1030 IF INKEY$="" THEN 1030 1040 FOR P=4 TO 1 STEP -1:GOSUB 1070:PMODE 4,P:SCREEN1:NEXT 1050 IF INKEY$="" THEN 1050 1060 GOTO 1020 1070 FOR TT=0 TO 40:NEXT:RETURN
…and when you run it, you will see it takes the PMODE 4 screen (which is 4 blocks of graphics memory) then goes in a loop where it starts the displayed screen at block 2, then 3, then 4, then 5. With a small delay in-between each change, it shows (initially) the first PMODE 4 screen (blocks 1-4), then it toggles the memory displayed through each block until the start is block 5. This makes the screen appear to scroll up in chunks (1/4th of the screen each time). The process is then reversed to scroll back down.
A recent e-mail exchange with CoCo user Torsten D. inspired me to try something stupid.
The Radio Shack Color Computer gained the VARPTR command in the Extended BASIC ROM. As has been discussed here many times, VARPTR returns the memory location of a 5-byte variable descriptor. There are actually seven bytes total, since the two bytes before the VARPTR address is the two byte variable name.
0 'MAKE42-1.BAS 10 DIM A,B,C:A=42:B=VARPTR(A) 20 FOR C=B-2 TO B+4 30 PRINT C,PEEK(C):NEXT
Running this will show the full seven bytes required to represent the A variable:
VARPTR is returning 9792 as the location of the start of the 5-byte floating point value for the numeric A variable. The two bytes before it are the variable name: 65 (uppercase “A”) and 0 (no second letter). Had the variable name been “AA” that would be 65 65.
The five bytes of 134, 40, 0, 0 and 0 are the floating point representation of 42.0.
If you got the VARPTR address of one numeric variable, and of a second numeric variable, you could just copy those five bytes and clone the variable value:
0 'MAKE42-2.BAS 10 DIM A,B,I 20 A=42:B=0 30 PRINT "A =";A,"B =";B 40 FOR I=0 TO 4:POKE VARPTR(B)+I,PEEK(VARPTR(A)+I):NEXT 50 PRINT "A =";A,"B =";B
If you run this, you will see output showing “A = 42” and “B = 0”, followed by output showing “A = 42” and “B = 42”. The code in line 40 copies the five bytes (offset 0 to 4) from the VARPTR address of variable A into the VARPTR address of variable B.
And if you can clone a variable, you could also change a variable if you knew what five bytes represented the number you wanted. In the first example, we saw that the five bytes that represent 42.0 are 134, 40, 0, 0 and 0. Knowing that, you could do something like this:
0 'MAKE42-3.BAS 10 DIM A,V 20 PRINT "A =";A 30 V=VARPTR(A):POKE V,134:POKE V+1,40: POKE V+2,0:POKE V+3,0:POKE V+4,0 40 PRINT "A =";A
The “DIM” is not really needed in this example, but it is a good habit to get into if you want to control the order your variables exist in the variable table. Variables that need to be the fastest should be at the front of the list, and variables use infrequently or ones that can be slow can be at the end.
But I digress.
The point of this stupid code is that an “A” variable is created with 0 as its default value, then VARPTR is used to see where that variable is in memory. Five POKE commands put that floating point representation of 42.0 into that variable’s storage… So when you print A, you get a value of 42, even though A=42 (or indeed, A= ANYTHING) was nowhere in the program.
When I got my first Radio Shack TRS-80 Color Computer 1 back around 1983, I dove into the Getting Started manuals and learned all the new wonderful commands that EXTENDED COLOR BASIC offered me that my Commodore VIC-20 did not have. Commands like PLAY for music, SOUND for a beep, and graphics commands to draw CIRCLEs, LINEs and even DRAW complex objects were … amazing.
On my original tape based CoCo (EXTENDED COLOR BASIC) the high-resolution graphics memory started just after the memory used for the 32×16 text screen:
DEC HEX DESCRIPTION ----- ---- ----------- 0 0000 Color BASIC Use 512 0400 Text Screen 1536 0600 Hi-Rez Graphics
Knowing that, as I learned some 6809 assembly language I wrote routines to scroll a PMODE 4 256×192 graphics screen. I used this to do video titles for my dad. I’d create a screen using a graphics program, and load that into the second half of the graphics memory, then let my routine smooth scroll that screen into view.
I’d love to find that old source code and see how awfully inefficient it was. I bet one of you could really show me a faster way to do it.
But I digress…
DISK EXTENDED BASIC changed everything!
The next major leap in home computing for me was getting a disk drive for my CoCo. Imagine being able to store up to 156K of data on a floppy disk, and load things at such blazing speed (compared to the tape player and it’s 1500 baud rate).
It was nice… but it broke my assembly code! It turned out, when DISK BASIC was added, it used memory after the text screen for its own purposes, and shifted the high resolution graphics memory 2K further down in the memory map:
DEC HEX DESCRIPTION ----- ---- ----------- 0 0000 Color BASIC Use 512 0400 Text Screen 1536 0600 Disk BASIC Use 3584 0E00 Hi-Rez Graphics
Learning this, I adjusted my assembly routines to work on graphics screens starting at 3584 (disk systems) rather than 1536 (tape systems).
How do we know?
I wondered if there was some programmatic way to tell where the screen started. I don’t think this even dawned on me back in the 1980s, but I asked this question to the new Color Computer mailing list and quickly got an answer:
Word at $BC (GRPRAM) is start of graphics RAM. Word at $BA (BEGGRP) gets you the start of the current view window.
Bonus. Not only can you tell where graphics memory starts, but you can tell which page is displayed. With EXTENDED BASIC, you have 8 1.5K pages of graphics memory you can use. You reserve them with the PCLEAR command (it defaults to 4 pages). You can learn more about PCLEAR in this article.
PMODE 3 (128×192 4-color) and PMODE 4 (256×192 2-color) both need 4 pages, so you can have two screens in those modes. PMODE 0 uses 1 page, so you can have 8 pages in that ode.
PMODE 0 – 128×96 2-color (1536 bytes)
PMODE 1 – 128×96 4-color (3072 bytes)
PMODE 2 – 128×192 2-color (3072 bytes)
PMODE 3 – 128×192 4-color (6144 bytes)
PMODE 4 – 256×192 2-color (6144 bytes)
When you use PMODE, the first parameter is the graphics mode, and the second is which page for the screen to start on. For PMODE 4 you can do “PMODE 4,1” to get one screen of 4 pages starting at page 1, and “PMODE 4,5” to get a second screen of 4 pages starting at page 5. You can set PMODE to the first screen and draw something, then set it to the second screen and draw something different, then flip back and forth between them using PMODE. Here is a silly example:
0 'GFXFLIP.BAS 10 PCLEAR 8 15 ' DRAW FIRST SCREEN 20 PMODE 4,1:PCLS:SCREEN 1,1 30 CIRCLE(128,96),50 35 ' DRAW SECOND SCREEN 40 PMODE 4,5:PCLS:SCREEN 1,1 50 LINE (10,10)-(245,171),PSET,B 60 ' FLIP THROUGH THEM 70 PMODE 4,1:SCREEN 1,1 80 FOR A=1 TO 100:NEXT 90 PMODE 4,5:SCREEN 1,1 100 FOR A=1 TO 100:NEXT 110 GOTO 70
That program will reserve all 8 pages, then set a PMODE 4 screen starting at page 1. It draws a circle on that page. Then it sets a PMODE 4 screen starting at page 5. It draws a box on that screen. After that it just toggles between showing PMODE 4 starting at page 1, then at page 5, and the image will flicker back and forth between the circle screen and the square screen.
With low-resolution PMODE 0, you can do 8 screens of animation this way.
I wrote a second program that will print out where screen memory starts, and where the current viewed page starts.
0 ' SCRSTART.BAS 1 ' THANK YOU, JUAN CARLOS! 10 PCLEAR 8 20 FOR P=1 TO 8:PMODE 0,P 30 PRINT PEEK(&HBC)*256+PEEK(&HBD),PEEK(&HBA)*256+PEEK(&HBB) 40 NEXT P
When I run this on an tape-based EXTENDED BASIC CoCo (emulator) with no Disk Controller, it shows graphics memory starts at 1536 and then it toggles through each PMODE 0 page to show where each one would start:
And when DISK EXTENDED BASIC is used, the same program shows the memory locations starting 2K higher in memory:
Thank you, Juan Carlos, for telling me this. I wish I had known about this back then. I could have made my assembly program automatically find the start of the graphics screen rather than having to assembly separate versions for tape or disk systems.
Last year, I spent some time fooling around in Color BASIC rendering a Donkey Kong-style screen in ASCII. Since I was not using the CoCo 3 40 or 80 column screen, I was limited to the 32×16 text screen of the CoCo’s MC6847 VDG display chip.
First, here is what the arcade Donkey Kong screen looks like. (Image from Wikipedia.com)
Donkey Kong arcade (image from Wikipedia)
For my first attempt, I counted how many “blocks” across the screen it would take to render this level accurately. I did this by looking at the girder patterns where they change levels. It looked like to of the “/\/\” patterns could be a block, making 14 across the screen. I could then double that to 28, which would fit into the CoCo’s 32×16 screen with some space on each side.
I mapped it out in a text editor, and came up with this rough approximation:
12345678901234567890123456789012 H H BONUS H H 3900 H HXXXXXXX OO H H H OO.....H H H XXXXXXXXXXXXXXXXXXXXXXXXXX H XXXXXXXXXXXXXXXXXXXXXXXXXX H H XXXXXXXXXXXXXXXXXXXXXXXXXX H H H XXXXXXXXXXXXXXXXXXXXXXXXXX H H XXXXXXXXXXXXXXXXXXXXXXXXXX U H XXXXXXXXXXXXXXXXXXXXXXXXXXXX 12345678901234567890123456789012
The numbers at the top and bottom were the columns and not part of the screen.
I was then able to use each “block” location to position the ladders (“H”) close to where they should be, as well as where the barrels should go (“U” for the one at the bottom, “O” at the top for the ones next to kong at the top).
If I take that original arcade screen shot and grid it out to be 28×16, it looks like this:
This is when I learned something interesting. Look at how the “1UP”, “HIGH SCORE” and numbers line up to the blocks. Donkey Kong likely is using a 28x?? tile system. This website breaks apart the tiles that make up the game screens:
Indeed, 28 across by what looks like 32 down. As long as the screen could be done with half as many rows, it could be fairly close to the arcade. Here is what my ASCII version looks like on a CoCo emulator:
And let’s see if I can do side-by-side in WordPress:
With 32 rows in the arcade version, Mario and Pauline’s characters would be two blocks high. Since I had to half the rows to fit on the 16 row text screen, they would need to be one character block in height. A similar adjustment would have to be done for Donkey Kong.
In the arcade, Kong looks to be made up of 5×5 blocks and placed on the screen a bit lower in the grid so he stands on the top girder. From looking at arcade sprite resources, they don’t show the girder as part of the Kong graphic, so I will assume 5×5 is correct. When he is facing forward, he is centered, but when he is rolling the barrels, he extends all the way to the left or right boundary.
That is a problem, since at half height, a 5×2 row couldn’t represent Kong very well. This will be one of the major things that has to change to represent Kong on this screen. Looking at the arcade sprites, turned into the 5×4 grid, looks like this:
For my initial ASCII experiment, I came up with these:
----- @ /= |\ ----- @ <=> / \ ----- @ =\ /| -----
I kept the area 5 blocks wide, but made it 3 tall and just tried to get something close to the animation the graphical version had. Since I see Kong actually reaches down to the ground, perhaps something like this might be better:
…but I think I prefer the simplicity of the first attempt.
With every row being half the size of the arcade, instead of a rolling barrel being a full block tall, it now is half a block. I could use something like an ASCII period (“.”) I guess. And for the fireball, I could use something like an “*” or maybe “&” or “@”. It gets ugly real fast.
I am going to go think on this a bit… Comments if you have them.
On the old school 8-bit home computers, not all of them used ASCII. Commodore used a variation called PETSCII, and the Atari 8-bits used ATASCII. While the trick discussed in this article might work on other systems that have a VARPTR or similar command, this discussion will be specifically about the character set in the Radio Shack Color Computer.
ASCII 65 is the uppercase letter ‘A’
PRINT CHR$(65) A
If you POKE the value of 65 to the first position on the 32×16 text screen (location 1024), you will also see an uppercase 65.
POKE 1024,65
However, the embedded font data in the MC6847 VDG video generator chip does not follow ASCII for all of its characters. For example, CHR$(0) to CHR(31) are non printable characters. On the CoCo, two of them do something special — CHR$(8) will print a backspace and CHR$(13) will print an ENTER:
It would have been nice if the CoCo could have done a beep for CHR$(7) like Apple 2s did, or clear the screen with CHR$(12) like many other systems did, but those are the only two that do anything other than “print nothing” on the CoCo.
If you POKE around a bit…
While you will not see anything if you PRINT those characters, if you POKE those values to the screen memory you will see something. For example, you could POKE characters 0 to 31 to the first row of the 32 column text screen like this:
FOR A=0 TO 31:POKE 1024+A,A:NEXT
The character set in the video chip has 0-31 representing reverse video characters “@” (AT sign) to “<-” (left arrow). We can expand that loop to POKE the first 128 characters onto the video screen:
FOR A=0 TO 127:POKE 1024+A,A:NEXT
But for PRINTing the ASCII characters, we have already established nothing shows up for characters 0-31, but things do PRINT when for 32-128:
FOR A=32 TO 127:PRINT CHR$(A);:NEXT
I put together this sloppy program that will show the differences, 32 characters at a time, of what you get when you PRINT the character values versus POKE the character values:
0 'POKEPRNT.BAS 10 CLS
20 PRINT@0,"PRINT 0-31:" 30 FOR A=0 TO 31:PRINT CHR$(A);:NEXT 40 PRINT@64,"POKE 0-31:" 50 FOR A=0 TO 31:POKE 1120+A,A:NEXT
60 PRINT@128,"PRINT 32-63:" 70 FOR A=32 TO 63:PRINT CHR$(A);:NEXT 80 PRINT@192,"POKE 32-63:" 90 FOR A=0 TO 31:POKE 1248+A,32+A:NEXT
100 PRINT@256,"PRINT 64-95:" 110 FOR A=64 TO 95:PRINT CHR$(A);:NEXT 120 PRINT@320,"POKE 64-95:" 130 FOR A=0 TO 31:POKE 1376+A,64+A:NEXT
140 PRINT@384,"PRINT 96-127:" 150 FOR A=96 TO 127:PRINT CHR$(A);:NEXT 160 PRINT@448,"POKE 96-127:" 170 FOR A=0 TO 31:POKE 1504+A,96+A:NEXT
999 GOTO 999
Looking at this, you can see only the characters 64-95 match between PRINT and POKE.
This means that the “copy screen to a string” concept from my earlier post doesn’t really do what we might expect. It does copy the data, but if we PRINT it back, we do not get back exactly what we started with.
This is the same thing that would happen if you tried to build a string by using PEEK from screen memory. This example prints stuff on the first line of the screen, then builds a string made of up characters using the PEEK value of that first line:
0 'PEEK2STR.BAS 10 CLS 20 PRINT "HELLO, WORLD! THIS IS A TEST." 30 FOR A=1024 TO 1024+31 40 A$=A$+CHR$(PEEK(A)) 50 NEXT 60 PRINT "PEEKED STRING:" 70 PRINT A$
And running that shows this awfulness…
Yuck!
But that’s okay since there is not much use to copying TEXT data and then putting it back with PRINT. PRINT is fast, and we can easily PRINT that text data. Sure, there could be benefits if stuff being PRINTed is doing calculations and such to generate the output, but this trick won’t help there.
However, the semi graphics characters (128-256) are the same between PRINT and POKE.
0 'POKEPRT2.BAS 10 CLS 20 FOR A=0 TO 255 30 PRINT@A,CHR$(A); 40 POKE 1280+A,A 50 NEXT 60 GOTO 60
The top half is the PRINT CHR$ and the bottom half is the POKE:
Since there is no way on the CoCo to type those semi graphics characters into a string (pity, the later MC-10 could do this), we are forced to PRINT them like this:
PRINT CHR$(128);CHR$(128);CHR$(128)
That would print three black blocks. To speed things up, we could pre-generate a string of those three black blocks then we can PRINT that string very fast later:
A$=CHR$(128);CHR$(128);CHR$(128) PRINT A$
And now you know why I chose to do a “splash screen” example for my demo in part 1. I initially tried it using the TEXT characters and quickly remembered why that can’t work (as explained here).
But it’s still a neat trick.
Bonus: This is stupid
For dumb fun, here is a program that makes A$ be whatever is on the first 32 character line of the screen.
When you RUN that, doing a PRINT A$ will show a 32 character line that is whatever was on the first line of the screen. If you do a “CLS” to clear the screen and show “OK” on the top line, then PRINT A$, you will see “OK” followed by 30 reverse @ symbols, which is CHR$(96) — but in video memory, a 96 is an empty block (space).
UPDATE: I believe I have found the answer, and will share it in an upcoming post. Until then, keep those comments coming. I learn so much from all of you!
This topic has been discussed here years ago, but every time something reminds me about it, I get annoyed. While my annoyance is triggered by how it works in the CoCo’s Extended Color BASIC, past research showed the behavior was the same even in much later Microsoft Visual BASIC. But why?
INSTR is a command to return the index where a target string is found in a search string. From one of the Getting Started with Extended Color BASIC manuals, it is shown as this:
What the manual did not mention is that it can also return 1 when there is no match. See this example:
Looking for “B” in “ABC”? That’s at position 2. Good.
Looking for “X” in “ABC”? It is not there, so it returns 0. Good.
Looking for “A” in “ABC”? That’s at position 1. Good.
Looking for “” in “ABC”? Apparently “” is found at position 1. Don’t tell that to the “A” there.
Callbacks
I ran into this years ago when I was experimenting with various ways to handle key presses. You could have code block until a key was pressed, and then pass the key to INST and then use ON GOTO/GOSUB to get to the routine. Like this:
0 'INSTR.BAS 10 PRINT "A)BORT, R)ETRY, C)ONTINUE:"; 20 A$=INKEY$:IF A$="" THEN 20 30 LN=INSTR("ARC",A$) 40 IF LN>0 THEN ON LN GOSUB 1000,2000,3000 50 GOTO 10
1000 ' ABORT 1010 PRINT"ABORT":STOP
2000 ' RETRY 2010 PRINT "RETRY":RETURN
3000 ' CONTINUE 3010 PRINT "CONT":RETURN
This was a great technique when dealing with a long list of menu options.
I had tried to optimize this by eliminating the A$ and embedding it inside the INSTR (someone in the comments may have suggested this to me; not sure if I am clever enough to have thought that up):
ON INSTR("ARC",INKEY$) GOSUB 1000,2000,3000
…but if I put that in my code replacing lines 20-40, running it immediately shows me “ABORT” as if INSTR returned 1.
Because INSTR returned 1.
The workaround suggested to me (again, from smart folks in the comments) was maybe to add a bogus value as the first search string character, and have that routine do nothing.
ON INSTR("*ARC",INKEY$) GOSUB 999,1000,2000,3000
However, for my example where I show the prompt again after it returns, it sticks in a loop printing the prompt over and over again. The code thinks the first option is being selected, then calls that routine (the empty routine that is just a RETURN in line 60) and then prints the prompt again.
One quick solution is to not use RETURN and let each function decide where to go back to. When you GOSUB, BASIC has to scan forward (possibly starting at the top of the program if the line number is before the current line being parsed) to find the target. RETURN lets it “pop” back to right after the GOSUB, so that part is faster.
Also, GOSUB routines can be called from different places in the main code and they will return back to where they were called.
If these routines are never called from anywhere but the menu code, and the extra speed to GOTO back is not a problem, this this change makes it work. And, as a bonus, the fake first GOTO line can just be back to the ON INSTR again since it doesn’t need to do anything:
2026-05-03 – Corrected hex value of 64 (thanks MiaM).
Today I was tagged in a Facebook post by MC-10 (well, and CoCo) programmer, Jim Gerrie. He shared a snipped of code he was trying to get working. The concept was to have stuff on the 32 column text screen get copied into a normal string and then be able to PRINT it back.
Jim’s post (with the code that wasn’t working) with code for the MC-10 was this:
10 CLEAR1200:DIMJ,K,A$,B$:GOSUB100 20 A$=””:K=VARPTR(A$):POKEK,255:POKEK+1,0:POKEK+2,64:B$=A$ 50 CLS:PRINTB$; 60 GOTO60 100 CLS1:PRINT”THIS IS LINE ONE” 110 PRINT”THIS IS LINE TWO” 112 PRINT”THIS IS LINE THREE” 113 PRINT”THIS IS LINE FOUR” 114 PRINT”THIS IS LINE FIVE” 115 PRINT”THIS IS LINE SIX” 116 PRINT”THIS IS LINE SEVEN” 117 PRINT”THIS IS LINE EIGHT”:RETURN
Can someone explain why this program doesn’t work on my TRS-80 MC-10?! It should reassign the memory pointer of string variable A$ to the beginning of screen memory (highbyte 64 lowbyte 0) so that I can then just assign A$ to B$, which will allow me to “capture” the first 255 bytes of screen mem.
It works on the TRS-80 MODEL I/III (using its screen start at highbyte 60 lowbyte 0)!
Any help greatly appreciated.
– Jim Gerrie in the Facebook TRS-80 MC-10 Group.
I could immediately see what the program was attempting to do, and it was something that never occurred to me to try. The concept is “simple” now that I see it:
Stuff is placed on the screen (CLS, PRINT, etc.)
A string (A$) is declared (line 20) and then VARPTR is used to get the memory location of the 5-byte string descriptor for that string. At this point, A$ is zero bytes long, but it will point to somewhere inside the program memory just after the first quote in A=”” because that is where the string begins (even if it is zero bytes long).
The string descriptor is modified using POKE to change the length of the string to 255 bytes, then the start location of the string from that location inside program memory to be the start of the text screen. That was the first bug. The location being POKEd was off by one and was not modifying the string start address properly.
After this, A$ is copied into a normal string, thus saving the contents of the first string (screen memory) into the new string (in normal reserved string memory). This is where the second bug was.
Before continuing, If you need a refreshed on VARPTR, start with this article. It will show how the five byte string descriptor is used. Here is a refresh:
STRING DESCRIPTOR (5 BYTES) 0 - LENGTH OF STRING 1 - NOT USED FOR STRINGS 2 - MSB OF ADDR OF STRING IN MEMORY 3 - LSB OF ADDR OF STRING IN MEMORY 5 - ALWAYS 0 FOR A STRING
The first POKE at the address returned by VARTPR (K) was fine, setting the length to 255. But the next two pokes were at K+1 and K+2. For Color BASIC, they should have been at K+2 and K+3. Also, the values being poked were 0 and 64, which is backwards. From a quick search, the MC-10s text screen starts at the 16K mark, $4000 (16384). To verify this, I went to the online MC-10 emulator here:
…and then did POKE 16384,42. That indeed placed an inverted “*” in the top left of the text screen.
The MC-10 is a big endian processor, so the memory location should be MSB ($40) then LSB ($00). $40 in decimal is 64 in decimal (no HEX support on the MC-10, I don’t think). So the actual pokes to make a string start at the top left corner of the text screen should have been 64 and 0 rather than 0 and 64. (That is 64*256+0 to make 16384.)
Adjusting those POKEs to be at the proper spot in VARPTR and swapping the values to MSB/LSB was the first fix.
At that point, I still wasn’t getting it working. This was due to the initial string being a “hard coded” string in BASIC. When A$=”” was declared in BASIC, it made a string that pointed into the program space. I have not looked into why, but forcing the string to be in RAM by doing A$=””+”” was all I needed to change to make this work. (NOTE TO SELF: Explore this and understand what was different about the program-space string.)
Jim posted a corrected version for the MC-10:
0 CLEAR1200:DIMC1,M$,I$,AA$,BB$:GOSUB100:GOTO20 8 M$="":C1=VARPTR(M$):POKEC1,255:POKEC1+2,64:POKEC1+3,0:AA$=M$+"" 9 M$="":C1=VARPTR(M$):POKEC1,255:POKEC1+2,65:POKEC1+3,0:BB$=M$+"":RETURN 20 GOSUB8:CLS:PRINTAA$" "BB$; 60 GOTO60 100 CLS8:PRINT"THIS IS LINE ONE" 110 PRINT"THIS IS LINE TWO" 112 PRINT"THIS IS LINE THREE" 113 PRINT"THIS IS LINE FOUR" 114 PRINT"THIS IS LINE FIVE" 115 PRINT"THIS IS LINE SIX" 116 PRINT"THIS IS LINE SEVEN" 117 PRINT"THIS IS LINE EIGHT" 118 PRINT"THIS IS LINE NINE" 119 PRINT"THIS IS LINE TEN" 120 PRINT"THIS IS LINE ELEVEN" 121 PRINT"THIS IS LINE TWELVE" 122 PRINT"THIS IS LINE THIRTEEN" 123 PRINT"THIS IS LINE FOURTEEN" 124 PRINT"THIS IS LINE FIFTEEN" 125 PRINT"THIS IS LINE SIXTEEN";:RETURN
Meanwhile, I had come up with a silly program that would create some kind of image on the CoCo screen, then capture it in two strings so it could be quickly restored later. Well, almost the entire screen — a string is limited to 255 bytes so two strings captures 510 bytes of the 32×16 screen. If one were to use this trick, it could be adjusted to capture just the number of lines on the screen needed (like, the first 5 lines, or lines 10-20, etc.).
My example looked like this:
0 'SAVESCR1.BAS 10 CLEAR511:DIMS1$,S2$ 11 ' 0 = LEN OF STRING 12 ' 1 = NOT USED FOR STRING 13 ' 2 = MSB OF ADDRESS 14 ' 3 = LSB OF ADDRESS 15 ' 4 = ALWAYS 0 16 ' 1024 = 4*256+0 17 ' 1279 = 4*256+255 20 REM DRAW SCREEN 25 CLS0:C=0:FOR I=0 TO 29 STEP 2 30 SET(I*2,0,C):SET(63-I*2,30,C) 35 SET(0,30-I,C):SET(63,I,C) 40 C=C+1:IF C>7 THEN C=0 50 NEXT 55 PRINT@266,"THIS";CHR$(128)"IS";CHR$(128);"COOL"; 60 'SAVE SCREEN 65 GOSUB 1000 70 'WAIT FOR KEY 75 GOSUB 5000 80 'CLEAR SCREEN 85 CLS 5 90 'WAIT FOR KEY 95 GOSUB 5000 100 'RESTORE SCREEN 105 GOSUB 2000 110 GOTO 70
999 GOTO 999
1000 ' SAVE SCREEN 1005 Z$="":K=VARPTR(Z$):POKEK,255:POKEK+2,4:POKEK+3,0:S1$=Z$+"" 1010 Z$="":K=VARPTR(Z$):POKEK,255:POKEK+2,4:POKEK+3,255:S2$=Z$+"" 1015 RETURN
5000 ' WAIT FOR KEY 5005 IF INKEY$="" THEN 5005 5010 RETURN
I made a “save screen” subroutine at line 1000. My program starts and makes a simple splash screen (colored pixels set around the screen and a text message in the center), then calls the save screen routine which makes a temporary Z$ then modifies it to point to the start of the text screen (1024 – so values 4*256+0) and be 255 bytes long. It then copies that string to S1$. It repeats the process for the next part of the screen, which begins at 1024+255 (1279, so 4*256+255). That is saved in S2$.
Then the main program waits for a keypress, then does a CLS 5 to erase the screen to white, then after another keypress, it calls the “restore screen” subroutine which just prints the two saved strings starting at position 0 on the top left corner of the screen.
AND IT WORKS!
Now blasting bytes to the screen can be as fast as printing a string. I can think of some interesting uses for this, such as “drawing” various levels slowly during initialization, and capturing them to strings so they can be displayed later very fast.
And that gives me an idea for an old project I was playing with some years ago.
But that will have to wait for the next installment…
Just posting this so I can share the link… This was a planning file from my “ASCII Kong” program I am toying with:
---------------------------- 12345678901234567890123456789012 H H BONUS H H 3900 H HXXXXXXX OO H H H OO.....H H H XXXXXXXXXXXXXXXXXXXXXXXXXX H XXXXXXXXXXXXXXXXXXXXXXXXXX H H XXXXXXXXXXXXXXXXXXXXXXXXXX H H H XXXXXXXXXXXXXXXXXXXXXXXXXX H H XXXXXXXXXXXXXXXXXXXXXXXXXX U H XXXXXXXXXXXXXXXXXXXXXXXXXXXX 12345678901234567890123456789012 ---------------------------- ----- @ <=> / \ ----- @ /= |\ ----- @ =\ /| -----
NOTE: I originally started writing this in November 2025, but kept thinking I’d do more work on it. I haven’t gotten around to it, so here you go…
Here is a Color BASIC 6809 assembly quickie… (That ended up not being very quick by the time I finished working through all of this…)
Recently I began working on an assembly language Color BASIC extension that makes certain characters move the cursor around the screen rather than just printing those characters (similar to what my VIC-20 could do). Initially, I created the 6809 assembly routine you could load into memory and EXEC. Next I decided to let it be called from DEF USR so I could pass in parameters and return a status code like A=USR0(-1). Next next I decided I wanted it to still work with EXEC so the user could use it either way–just use defaults with EXEC, or customize things using USR.
Then I ran into a snag…
USRx(n) or EXEC?
If the USR routine ONLY expected a number parameter, the code to handle both USR and EXEC seems easy. When calling a routine with EXEC, the D register will be zero (it seems). If it wasn’t zero, I could then do the JSR INTCNV call which would process the parameter in BASIC and put it in the D register.
; Show if routine is being called with USRx(n) or EXEC
ORGADDR equ $3e00 ; Where program loads in memory.
; Absolute addresses of ROM calls. CHROUT equ $A002 INTCNV equ $B3ED GIVABF equ $B4F4
org ORGADDR
; This code expects to have been called by USRx(x) or EXEC xxxx. start cmpd #0 ; called from EXEC? beq fromexec ; if yes, goto fromexec fromusr jsr INTCNV ; else, get USR number parameter in D pshs d ; save D leax usrmsg,pcr ; display "called from USR" message bsr print puls d ; restore D addd #1 ; add one to D jmp GIVABF ; return back to USR call.
; PRINT subroutine. Prints the 0-terminated string pointed to by X plus CR. print lda ,x+ beq printdone jsr [CHROUT] bra print printdone lda #13 jsr [CHROUT] rts
usrmsg fcc "CALLED FROM USR" fcb 0
execmsg fcc "CALLED FROM EXEC" fcb 0
end
When the routine starts, it checks to see what D is set to. If 0, it assumes it was called from EXEC and jumps to code that just prints “FROM EXEC” then ends.
If not 0, it assumes it was called from USR and the code calls the ROM INTCVT routine to parse the parameter and place it in D, then it prints “FROM USR”, increments D (just so we can verify it passed something back), and returns it back to BASIC.
Here it is in operation:
And all was right in the world… Until I tried just using EXEC by itself. After using it first with the address (“EXEC &H3E00”) BASIC will remembers that address so when you just type “EXEC” next it uses the previous address:
EXEC &H3E00 FROM EXEC
EXEC ?TM ERROR
Making the user always have to provide the EXEC address each time is not optimal. My solution was clearly not a solution.
But wait! There’s more…
I also learned about Sean Conner documenting how USR can also take a string parameter instead of just a number. If you are interested in USR, be sure to check out that link. He also has a cool 6809 compiler (“a09”) I just started playing with. It has some unique features not available in other compilers I have tried.
USRx(n) or USRx(“STRING”)
With this new knowledge, I had an idea to make my USR routine also be able to take a string for a special configuration function. I could let the user specify the four characters that will move the cursor by doing something like A=USR0(“udlr”). But, if you pass in a string and it calls INTCNV, that routine will check the parameter type and, if not a number, return with a ?TM ERROR (type mismatch).
This required me to learn how to tell whether USR was being called with a number or a string.
Under Extended Color BASIC (the original Color BASIC did things differently, see Sean’s page for details), the ROM code sets up some registers when calling the USR function. Sean documented these in his excellent blog post on USR. Basically, register A would be 0 if the USR parameter was a number, or 255 if it was a string. If it was a string, register X would have the address of the string descriptor (the location in memory that VARPTR returns) and register B would be the length of the string.
That is really convenient. Now you can have code that detects if it is being called from USR with a number or a string. My test code looked like this:
; Show if USR is being called with a number or a string.
ORGADDR equ $3e00 ; Where program loads in memory.
; Absolute addresses of ROM calls. CHROUT equ $A002 INTCNV equ $B3ED GIVABF equ $B4F4
org ORGADDR
; This code expects to have been called by USRx(x) or USRx("STRING") start tsta ; A=0 is USR(0), A=255 is USR("...") bne usrstring ; if not 0, goto usrstring usrnumber pshs d,x ; save D and X leax numbermsg,pcr ; display "number" message bsr print puls d,x ; restore D and X jsr INTCNV ; else, get USR number parameter in D addd #1 ; add one to D jmp GIVABF ; return back to USR call.
usrstring leax stringmsg,pcr ; display "string" message bsr print ldd #123 ; load D with return value jmp GIVABF ; return back to USR call.
; PRINT subroutine. Prints the 0-terminated string pointed to by X plus CR. print lda ,x+ beq printdone jsr [CHROUT] bra print printdone lda #13 jsr [CHROUT] rts
stringmsg fcc "STRING" fcb 0
numbermsg fcc "NUMBER" fcb 0
end
And here it is in operation:
Now I know how to detect a USRx(number) versus EXEC, and how to detect a USRx(number) versus a USRx(string). But, this has the same problem if called by EXEC with no address:
EXEC &3E00 NUMBER
EXEC NUMBER ?TM ERROR
It appears that using EXEC with the address after it sets registers up differently than using EXEC with no address (where it uses the last address EXEC used). While both end up at the code path for USRx(number), is seems that plain EXEC thinks it is returning an invalid type and the ?TM ERROR is displayed.
EXEC or EXEC xxxx or USRx(n) or USRx(“STRING”)
Can both routines be combined? On the CoCo mailing list, this all started when I asked: Is there a way to tell if a routine was called from USR versus EXEC? It was Sean’s reply that got me going down this rabbit hole:
Maybe.
Address $9D contains the address EXEC uses to jump to your code, so that should be called address. Also, X will also be this address (implementation detail).
For Color BASIC, you need to know you are running under Color BASIC. Address $112 is the address for USR, so this should point to your code. Also, upon calling, X should be equal to $AA2F and B should be 6 (both are implementation details).
For Extended Color BASIC, you need to know you are running under Extended Color BASIC (16 bits at $8000 are $4558). Addresses $013E through $0150 contain the USRn addresses, so one of these 10 addresses should point to your code. Also, A will equal the contents of address $06. If A=0, then X=$4F; if A=255, then X is pointing elsewhere (the string descriptor).
For Disk Extended Color BASIC, you need to know you are running under Disk Extended BASIC (16 bits at $C000 are $444B). The USRn addresses are now $095F through $0971, but other than that, it’s the same as Extended Color BASIC.
Based on all that, I think the best method might be (completely untested):
mycode cmpx #mycode beq called_by_exec ; otherwise, assume called by USR/USRn
Good luck.
-spc
– Sean Conner via the CoCo Mailing List
This gave me a lot of think about. I did some tests to see what register X looked like when being called by EXEC with or without an address, as well as looking at what was stored in the $9D memory location which is the address EXEC (with no address after it) will use. I created a simple program that would print the value of the X register and the value of $9D so I could test it and see what the pattern was. This code uses an undocumented ROM call that will print the value of the D register. (I learned about this call from Sean’s pages.)
ORGADDR equ $3e00 ; Where program loads in memory.
; Absolute addresses of items in RAM variables. EXECJP equ $9d location of jump address for EXEC
; Absolute addresses of ROM calls. REGDOUT EQU $BDCC ; Convert the value in ACCD into a decimal ; number and send it to CONSOLE OUT.
org ORGADDR
start tfr x,d ; X=D jsr REGDOUT lda #32 ; space jsr [CHROUT] ldd EXECJP ; load D with EXEC address jsr REGDOUT rts
end
Now I could load this into memory, set up a DEFUSR0=&H3E00 and do some tests:
15872 ($3E00) is the start of my user program. EXEC with that address will have both X and the $9D memory location containing that value.
EXEC without an address will have 43947 ($ABAB) in X, and 15872 ($3E00) as the address of the last EXEC address specified. But what is $ABAB? Looking at the Color BASIC Unravelled book, that address is where the EXEC token is:
ABAB FDB EXEC
I did not dive into this, but I expect X was is used for the token scanning and since that was the last thing it found (no address after it to parse) that is what was in the register when it jumps to the user code.
When I tested A=USR0(0), I got a 79 in register X, and $9D still had the last EXEC address used. It then errored out with a ?TM ERROR due to this code not setting up a clean return back to a USR call.
And lastly, A=USR0(“STRING”) put 425 in register X, and $9D was still the last EXEC address used.
Now, had I done the USR calls first, that $9D would not be set up yet and it would look like this:
46154 ($B44A) appears to be the default value EXEC will use. By default, EXEC points to the routine that prints ?FC ERROR:
B44A FDB LB44A ARGUMENT OF EXEC COMMAND - SET TO ‘FC’ ERROR
So on a power cycle, typing EXEC is the same as typing EXEC &HB44A:
EXEC &HB44A ?FC ERROR
Having this value there is not useful for any of my checks since all that means is that the user has not done an EXEC with an address yet.
BUT, now that I see what happens with register X, I should be able to check it, and the $9D exec location and determine if I am being called by EXEC, EXEC xxxx, or a USRx command. Here is my test program:
ORGADDR equ $3e00 ; Where program loads in memory.
; Absolute addresses of items in RAM variables. EXECJP equ $9d location of jump address for EXEC
; Absolute addresses of ROM calls. CHROUT equ $A002
org ORGADDR
; This code expects to have been called by USRx(x). start cmpx #start ; called by "EXEC xxxx"? beq fromexec ; if yes, goto fromexec cmpx #$abab ; called by "EXEC"? bne fromusr ; if no, must be USR. goto fromusr ldx EXECJP ; get EXEC address cmpx #start ; called by "EXEC xxxx"? beq fromexec ; if yes, goto from exec fromusr leax usrmsg,pcr lbsr print rts fromexec leax execmsg,pcr lbsr print rts
; PRINT subroutine. Prints the 0-terminated string pointed to by X plus CR. print lda ,x+ beq printdone jsr [CHROUT] bra print printdone lda #13 jsr [CHROUT] rts
usrmsg fcc "FROM USR" fcb 0
execmsg fcc "FROM EXEC" fcb 0
end
And here is what it does:
I now have code that can properly (?) detect if it was called from EXEC xxxx, EXEC, or USR. This demo does not handle detecting a string parameter to USR, but … I think it proves it is possible to do it.
With a few more lines of assembly, I came up with this test program:
ORGADDR equ $3e00 ; Where program loads in memory.
; Absolute addresses of items in RAM variables. EXECJP equ $9d location of jump address for EXEC
; Absolute addresses of ROM calls. CHROUT equ $A002 INTCNV equ $B3ED GIVABF equ $B4F4
org ORGADDR
; This code can be called by USRx(n), USRx("STRING"), EXEC addr or EXEC. start cmpx #start ; called by "EXEC xxxx"? beq fromexec ; if yes, goto fromexec cmpx #$abab ; called by "EXEC"? bne fromusr ; if no, must be USR. goto fromusr ldx EXECJP ; get EXEC address cmpx #start ; called by "EXEC"? beq fromexec ; if yes, goto from exec fromusr tsta ; A=0? beq donumber ; if yes, number passed in. goto donumber. inca ; inc A so if 255 (string) it will be 0 now. beq dostring ; if A=0 (was 255), string. goto dostring. bra unknown ; else, goto unknown (this should never happen).
donumber leax numbermsg,pcr ; show "number" message bsr print jsr INTCNV ; get number that was passed in addd #1 ; add 1 to D jmp GIVABF ; return new number back to BASIC
dostring leax stringmsg,pcr ; show "string" message bsr print ldd #12345 ; load D with a return value jmp GIVABF ; return that number back to BASIC
unknown leax unknownmsg,pcr ; this should never happen lbsr print ; show "unknown" message rts
; PRINT subroutine. Prints the 0-terminated string pointed to by X plus CR. print lda ,x+ beq printdone jsr [CHROUT] bra print printdone lda #13 jsr [CHROUT] rts
execmsg fcc "FROM EXEC" fcb 0
numbermsg fcc "FROM USR(NUMBER)" fcb 0
stringmsg fcc "FROM USR(STRING)" fcb 0
unknownmsg fcc "UNKNOWN" fcb 0
end
And here is what I get after loading this into memory:
DEF USR0=&H3E00 OK
A=USR0(42) FROM USR(NUMBER) PRINT A 43
A=USR0("STRING") FROM USR(STRING) PRINT A 12345
EXEC &H3E00 FROM EXEC
EXEC FROM EXEC
I think we may have a winner! The important parts are:
start cmpx #start ; called by "EXEC xxxx"? beq fromexec ; if yes, goto fromexec cmpx #$abab ; called by "EXEC"? bne fromusr ; if no, must be USR. goto fromusr ldx EXECJP ; get EXEC address cmpx #start ; called by "EXEC"? beq fromexec ; if yes, goto from exec
If X is the address of the user program, it was called by “EXEC xxx”
If not, then if X is NOT $ABAB, it was called by USR
Else, it was $ABAB, so the EXECJP ($9D) is checked to see if it is the address of the user program. If it is, it is from EXEC.
I hope that makes sense. If not, think of it like this:
X=program start – it was called from EXEC xxxx
X=$ABAB and EXECJP=program start – it was called by EXEC.
Anything else is USR.
Now what I need from you is to double check my work and tell me if I got this right, and if this method can be relied on.
Over the years I have shared many tidbits about Color BASIC.
This is another one.
A recent post by Juan Castro to the Groups.IO Color Computer mailing list caught my attention, mostly because he called me out by name in the subject line:
As a reminder, Color BASIC allows 1 or 2 character variable names. They must start with a letter (A-Z) and the second character can be either letter (A-Z) or number (A-0). BUT, the BASIC interpreter does let you type longer names for variables, but it only honors the first two characters. Here is a screenshot from a past blog post here (which I’d link to if I was not so lazy):
Color BASIC variables may be very long, but only the first two characters are used.
This is a reminder that, if you try to use variables longer than two characters, you have to make sure you always keep the first two characters unique since “LONGVARIABLE” and “LOST” and “LO” are all the same variable to BASIC.
…but not all variable name limits are the same.
To break the rule I just said, in Color BASIC, some variable names are forbidden. A forbidden variable is one you cannot use because it is already reserved for a keyword or token. For example, FOR is a keyword:roar
FOR I=1 TO 10 PRINT I NEXT I
Because of this, even though BASIC only honors the first two characters of a variable name, you still cannot use “FOR” as a variable.
FOR=42 ?SN ERROR
But you can use “FO”, since that is not long enough to be recognized as a BASIC token or keyword.
FO=42 PRINT FO 42
There are a number of two-character tokens, such as “TO” in the FOR/NEXT statement (“FOR I=1 TO 10”), and “AS” in the Disk BASIC FIELD statement (“FIELD #1,5 AS A$”), as well as “FN” which is used in DEF FN.
AS=42 ?SN ERROR
FN=42 ?SN ERROR
TO=42 ?SN ERROR
This means if you wrote something for Color BASIC or Extended Color BASIC that uses “AS” as a variable, that would not work under Disk Extended Color BASIC.
BASIC ignores spaces
In recent years, someone pointed me to the fact that when scanning a BASIC line (either type in directly or when parsing a line of code in a program), spaces get ignored by the scanner. This means:
N M = 42 PRINT N M 42
That one surprised me when I learned it. This is probably why, when printing two variables, a semicolon is required between them:
N = 10 M = 20 PRINT N;M 10 20
And if you had done this (remember to CLEAR between these tests so variables are erased each time):
N = 10 M = 20 NM = 30 PRINT N M 30 PRINT N;M;N M 10 20 30
By the way, if you have ever wondered about that space printed in front of numeric variables when you do things like “PRINT X”, I covered why this happens in an earlier blog and included a simple patch to BASIC that removes that feature.
How to turn a forbidden variable into a non-forbidden one for fun and profit
Well, Juan Casto showed that using this “BASIC ignores spaces” quirk as a way to use forbidden variables. From his post:
Now it seems obvious. BASIC’s interpreter looks for keywords like “FOR” and will not recognize “F O R” or “FO R” as that token. The detokenizer honors the spaces.
But when it comes to variables, the spaces are ignored by the parser, so “T O” will not match as a token for “TO”, but will be processed as a variable “TO”.
Go figure.
Admittedly, space in two-character variable names look silly, but now I can finally update my old *ALLRAM* BBS to use the variable “TO$” for who a message is to:
FR$="ALLEN HUFFMAN" T O$="JUAN CASTRO" SB$="THAT'S REALLY COOL"
I suspect this was discovered by the early pioneers of BASIC, likely soon after the original Color Computer was released in 1980. If you know of a reference to this behavior from some early newsletter or magazine article, please let me know.
And as to Juan … thanks for sending me down a BASIC rabbit hole again…