Before you keep reading this article I recommend to open the previous one in another tab to use it as a reference for this one. To open the previous article on another tab click here.
So, as a first exercise to play with MO6/PC128 commutable memory let’s learn how to hack the BASIC 128 Interpreter which is fun and will help us to understand more how memory is being mapped.
Please note: Don’t just read what follows, try it on your MO6/PC128 for real. If you don’t have one then get the dcmoto emulator. In this article here I tell you how to install dcmoto emulator on Windows, Linux, BSD and macOS, so no excuses! The most important thing you can do to help yourself to learn Computer Science for real is to test everything in practice and never assume an article or a book is correct by definition.
Playing with commutable memory
From the initial menu of the MO6 or PC 128 let’s choose option 1 and get into the BASIC 128 Interpreter.
As we learned from the previous article, commutable memory allows us to access more memory than the 6809E can address by switching (commuting) memory pages. We can do that in BASIC 128 using the command BANK. Before we start playing with it let’s see how we can display which bank is active (and, in this case, which one is also the one active by default). To display which memory bank is active type:
The output will be: 6
This means BASIC 128 sets BANK 6 as default bank for the memory area between $6000 and $9FFF. There is a reason for that… it sets BANK 6 because it’s the most far from BANK 1. BANK 1 is very special in BASIC 128, it’s used as starting point to store our BASIC program.
Let’s check that. Because we are in BANK 6 let’s see what’s the content of memory address $6002, to do this in BASIC we can use the instruction PEEK:
Please note: In Microsoft SIMIV BASIC to specify an hexadecimal number we need to use the prefix &H before the number.
If we have just started the computer and did not load anything in memory before the test above, the output of this command will most likely be 0 (zero).
So, lets create a very minimalistic and useless program to test our understanding of the memory mapping on the MO6/PC 128:
10 REM A USELESS PROGRAM
This program is very useless as it simply sets a comment at line 10, however it’s actually very useful to hack the BASIC 128… 😉
Now let’s repeat the previous PEEK command and see if the value of &H6002 has changed. We’ll immediately observe that nothing has changed.
Let’s change the commuted memory bank to BANK 1 and repeat the PEEK command again. To commute (or switch) a memory bank in BASIC 128 we can use the following instruction:
(where 1 is the Bank 1). Now let’s check again the value at location &H6002:
This time the output will be different, it will show us an 11 (eleven), this is a code used by the BASIC 128 to define the beginning of a program. The reason the output has changed is because the BASIC interpreter has requested to the MO6/PC128 Monitor Routines to “swap” the memory page (6 with 1) mapped on addresses between &H6000 and &H9FFF and so, when executing PEEK instruction it now picks the value contained in a different memory page.
Let’s check our program code by executing a LIST command:
Program is ok and we can see our line 10 and the comment.
Now let’s set location &H6002 value from 11 to 0, to do this we can use the instruction POKE:
The output will be just an OK (which means “Ok I set the value at the specified memory address as you wanted”), so let’s LIST our program again using LIST command and… wow the program is gone!
Don’t panic lol, let’s set the value stored in &H6002 back to 11 and see what happens:
And then list our program again…
The entire program is back! Ok, let’s leave it for now and let’s learn more by running a peek at the next location:
This time we’ll get a 10, let’s try the next location then:
The output is going to be interesting this time, the output will be 140
This value is interesting because it’s actually the Token value of the instruction REM in SIMIV BASIC 128! How do I know that? It’s simple and we’ll see how to understand this in a minute, meanwhile let’s keep reading the next memory location’s value:
We’ll get a 32, this is the ASCII Standard value for the Space Character, so let’s read the next memory location value:
This time the value is 65 which is the ASCII Standard value for the letter A. Ok, next one:
Again 32 (so space character) and if we start to put all these values together in their corresponding ASCII characters we get our comment back A USELESS PROGRAM. I’ll let you keep trying to read all the bytes until a zero value is reported (the zero means end of the line).
If you are not familiar with the ASCII standard: You can display the character by adding CHR$(PEEK(&6008)) function around the peek function. Do not use CHR$ for the line-number location and the BASIC instruction (the REM Token code) location.
So in the end we’ll have something like:
10 140 A USELESS PROGRAM
If you want to confirm that the 10 is the line number then try to renumber your source code with the command:
And then read again the value at location &H6003 and see it will show you 20 this time.
So the 140 must be the token value for the instruction REM! 😉
You can test this by replacing the REM instruction with a PRINT like:20 PRINT A
and check again the value at &H6004.
We can switch back bank to 6 and check these memory locations. If you do that, you’ll see that PEEK command will show you again all zeros when on a different BANK (or different values if you had your MO6/PC128 running other stuff before following this article).
A question at this point would be: So, if only one bank is active at the time mapped to location between &H6000 and &9FFFF, how does the BASIC interpreter store my program from BANK 1 onwards no matter which BANK is active? The answer is simple, the BASIC interpreter switches the BANK transparently when it detects the user has typed a line-number (or has executed a specific command to manipulate the program source code). Then it does what it has to do to the source and then switches back BANK to what the user has set (or the default if the user hasn’t set any) before returning control to the user.
We can simulate this behaviour in our BASIC programs too. For example, copy content from BANK 1 to, let’s say, BANK 4. To avoid overwriting the BASIC code in BANK 1 we can use a BASIC loop directly from the editor like the following:
FOR ADDR=&H6000 TO &H9FFF:BANK 1:BV=PEEK(ADDR):BANK 4:POKE ADDR,BV:NEXT
The code above will switch to bank 1, read the value at the address &H6000 (and on each iteration the address will be incremented by 1 extra byte), switch to BANK 6 and then store it on the same address on BANK 6.
“Ok I am confused now… If only one bank can be active per time, how can the program above work??” Simple, the program above works because its code is being stored in the BASIC Buffers area (between $2100 and $5FFF) and so are the values stored in BV variable, so, when switching BANK to 4 the BASIC Interpreter can still read the value in BV and still has the whole mini program available. This is why BASIC’s buffers are NOT stored in the commutable memory! 😉
Ok last example/exercise for this article is a famous trick on the MO6/PC 128, which allowed little hackers like me (at the time) to remove protection from protected programs written in BASIC.
This so called protection was a simple mechanism offered by Microsoft SIMIV BASIC to protect the source code of a BASIC program to allow its commercial distribution and protect the program creator’s copyright.
1. Set memory bank back to default, bank 6:
2. Load your BASIC protected program.
If you don’t have one, don’t despair, you can create a BASIC protected program by saving it with the option ,P:
Then erase your program from memory with the instruction:
And, finally, load your protected program with:
3. Let’s check that the SIMIV BASIC protection is working by typing LIST command that will generate an error message “Protected Program” when the loaded program is protected:
4. Let’s start hacking the protection. First of all let’s execute the command NEW to tell the BASIC Interpreter to delete the loaded program (this won’t erase the source from memory, it will only set the value in location &H6002 to zero):
5. Switch active bank to 1:
6. Execute the following loop from the BASIC editor:
FOR ADDR=&H6004 TO &H9FFF:IF PEEK(ADDR)=0 THEN POKE &H6002,ADDR-&H6000 ELSE NEXT
7. Now list the program source by executing LIST command again and voila! Protection is gone 🙂
Modern Computing Inheritance
As promised in the beginning of these Vintage Computing articles, here is the Modern Computing byte of knowledge that we get from commutable memory:
Commutable Memory principle is in fact at the base of modern Operating Systems’ SWAP Memory. Modern OS swap unused memory pages from central memory to the disk in order to make space for Applications that require more memory.
This is it for now, thanks for reading and, if you enjoyed this post, please support my blog by visiting my on-line hacking and engineering merchandise shop on redbubble.com by clicking here, thank you!