Task: Call Assembly Language Code from Your BASIC Program
Needed: A BASIC cartridge or Altirra emulator
Time: 10-15 minutes
In my previous post on writing, compiling, saving, debugging, and running assembly language programs with the MAC/65 assembler, I referred the reader to Chapter 5 of the book Atari Roots for additional ways to run assembly programs. One important way to execute assembly programs is from within BASIC. The ability add your own assembly code to BASIC programs was an amazing feature of these old programming languages and greatly extends the usefulness of interpreted languages that are much slower than assembly. Once you know some assembly language programming this is really easy. I provide here a simple example to highlight this feature. I recommend reading the previous post first.
The first step to adding assembly code to BASIC is convert the mnemonics (e.g. LDA, STA, etc.) to decimal values. Fortunately, the book Atari Assembly Language Programmer’s Guide by Moose and Lorenz has a table in the back (see pp. 329-331) that has all the codes. I have provided these below at the end of the post (note the quality is not good but that is how it is in the book). Here is our assembly code (first column) from the last post with the decimal values added for each mnemonic (second column) and the decimal values for the integers we are adding (the 2s) and for the memory address $CB (the 203). Note that we have to add a PLA at the beginning of the program to fix the stack (specific to BASIC). Failing to add the PLA will cause the code to crash (I have confirmed this). This is explained at the beginning of Chapter 8 of Atari Roots and in this article in Page 6 magazine.
LDA #2 169 2
ADC #2 105 2
STA $CB 133 203
If you aren’t very familiar with assembly, finding the right decimal value can be tricky for some of the mnemonics. For example, the decimal value for LDA depends on the type of memory addressing that is used. We are using ‘Immediate’ addressing with LDA #2 so the code for LDA is 169. Familiarity with the addressing modes is necessary.
The second step is to create a BASIC program that reads in the assembly program from a DATA statement, places it in memory, and then executes it using the USR function. Here is some simple code that does this and then prints the result of adding 2+2 from memory location CB (203). Lines 20 to 40 read in the decimal values for our assembly code in the DATA statement in line 100. We are putting the code in page 6 of memory that starts at memory location 1536 (6 pages * 256 bytes per page). Line 50 is the USR function that starts executing the code at location 1536. It proceeds through memory until it encounters our RTS (decimal 96) at memory location 1545. After it hits the RTS it returns focus to BASIC. BASIC then prints the contents of memory location 203 (in page 0) in line 70 and then loops forever in line 80. That is it!
10 GRAPHICS 0
20 FOR I=0 TO 9
30 READ DAT:POKE 1536+I,DAT
40 NEXT I
60 POSITION 0,0:PRINT “2+2=”
70 POSITION 4,0:PRINT PEEK(203)
80 GOTO 80
100 DATA 104,216,24,169,2,105,2,133,203,96
Open Altirra and load BASIC. I used Turbo BASIC XL. You can also load the built-in BASIC from Altirra from the File->Attach special cartridge menu.
Open the BASIC code in your PC text editor or web browser and copy the text to your clipboard. Click on the View tab of Altirra and choose the paste text option from the bottom of the list. Altirra will slowly paste the text into the BASIC command line. It is important to keep focus on the Altirra window or the paste will stop and it will lose some characters.
This is a really useful tool to have if you enjoy coding in BASIC. As I discussed in a post about making games in BASIC, every cycle counts in the loop where you are moving players and missiles around the screen. The more game calculations you can move to assembly the better.
As I have pointed out in earlier posts, keeping machine language routines in page 6 of memory can get tricky if your code exceeds 256 bytes. As I hinted at earlier, putting your machine language code in strings can be a better way to go since BASIC handles the placement of strings in memory and the manipulation of strings in BASIC is quite fast. This was also pointed out on the Atari 8-Bit Computing Facebook page by Bradley Bell who mentioned Michael Martin’s blog post on how to do this. Strings were a very common approach and you will see this technique in a lot of the magazines and books from back in the day. I plan to do a post on this approach soon.
Here are decimal conversion tables for the assembly mnemonics: