• Please review our updated Terms and Rules here

"Connecting" Assembly Code to Basic Code - USR - a Clue

AAGDOS

Experienced Member
Joined
Jul 4, 2018
Messages
104
Location
Hartford, CT
This is probably obvious to all the experienced C64 programmers here, but to a new "retro" member (myself!) I was puzzled by how to connect Basic to Assembly with the USR function.

Initially I loaded the Assembly Code at $8000 (Hex) and then composed a short Basic code to access it and see if it worked. It just showed a slew of weird characters on the screen when I ran it.

The "solution" finally came to me. I wrote and SAVED the Basic code to disk first. Then to run, I first loaded the Assembly Code, and then loaded the Basic Code, and then typed "RUN". That worked perfectly.

I assume the original Basic code was "messing with" the previously loaded Assembly code in the first tries??

Lesson learned!
 
Next step: try to find out how to load the assembly code using the same Basic program that runs it :)
 
It might be better to load your assembly code somewhere where BASIC won't accidentally clobber it. I think $8000 might be part of the region where BASIC is storing variables like strings (I didn't look this up though).

There's a 4K RAM region at $C000 that BASIC doesn't use, you might consider putting your code there. Unless the machine language monitor you're using loads there...

I think there are a couple of bytes somewhere that store the location of the end of BASIC RAM. You can reserve some memory that BASIC won't clobber if you adjust that value down.
 
If the ASM portion isn't particularly large, it's perfectly OK to bring it in as DATA statements that the BASIC code pokes in during initialization.
 
The cassette buffer and the $C000 window are the only areas of RAM safe to use alongside a BASIC program.

There are other tricks to using BASIC RAM, but normally not worthwhile. You can put your machine code at the start of BASIC RAM and relocate your BASIC program for instance. You can monkey with the size of BASIC RAM, etc. But usually the only reason to do these things is if you need more than 4K, which is pretty rare, especially if you're using BASIC as well. If you really want to get crazy you can put your assembly code at $A000 (BASIC ROM) and have a context switching routine in the cassette buffer!

I'm surprised you're using USR(). I don't think I've ever used that. Especially because I either don't transfer any data with BASIC, or I share more than one value, making USR() unuseful. I always use SYS and store values in known addresses.

Normally, you don't want to load two programs separately. Usually, you will load the machine code from the BASIC program. When you do this, your BASIC program will restart at the beginning after each LOAD. So the first lines in your program will need to redirect execution accordingly (to avoid an unwanted loop or your BASIC program clobbering variables by reinitialising them).
 
Last edited:
Or you can call the portions of BASIC that load comma-separated values. I have this macro in a lot of my xa65 files:

Code:
; skip comma, then accept 8-bit parameter to x
#define	ARG8 jsr $b7f1

; skip comma, then accept 16-bit parameter w/MSB to .a and LSB to .y
#define ARG16 jsr $aefd:jsr $ad9e:jsr $b1aa

; skip comma, then accept 16-bit parameter to $14-15
#define ARG1614	jsr $aefd:jsr $ad9e:jsr $b7f7

Then you could do something like SYS49152,X,Y. $ad9e is the famous FRMEVL (formula evaluator) which lets you emit any arbitrary BASIC expression to the floating point accumulator.
 
Besides the 196 bytes of cassette buffer at $033C - $03FF, you have 89 bytes in the area $02A7 - $02FF that are free to use even if you're using the tape recorder. It may seem like very small amounts of memory but for short routines those locations can be useful. The area at $C000 - $CFFF as mentioned is good for programs up to 4096 bytes of course.
 
Correct. Aren't there 204 bytes at the cassette buffer though? And if memory serves, you can use 210 if you steal a couple of vector locations
 
Possible, I didn't count whatever precedes $033C. For disk users it is free memory, for tape users one should be aware that your machine code routine may get overwritten if you stored it at the beginning of the cassette buffer. Many tape games though stored their own loader at the end of the cassette buffer.

For that matter, I believe I've used USR(x) on Commodore BASIC perhaps once, but just like others found that SYS usually is easier to work with, in particular if you're not really trying to implement your own math formulas that need to return a floating point value to a BASIC variable.
 
Thank you all for the good insight This will take a bit more time to "digest" as a "retro" guy. I went to the USR function because it is described in the Programmers Reference Guide, and also in the (paperback) book I had gotten on C64 Assembly Language Programming.

My "connection" interest ( Basic <-> Assembly ) stems from the 1980s on PDP 11s (LSI -11) when I interfaced laboratory equipment sending analog and digital signals to the computer. All the incoming data was handled in Assembly Language, and then passed to Fortran for more complicated data processing and display. This was fairly straight forward. There were no issues of memory management, as I recall.

I wanted to replicate this (in smaller scale) on my three Commodore 64s!

Regards all,
 
Back
Top