C64jasm object literals

The latest c64jasm v0.6.0 added support for JavaScript style object literals. This turned out to be surprisingly useful! Here we’ll go over this feature and some tricks that it enables.

This post assumes you’re already familiar with the c64jasm assembler (see: c64jasm manual).

Object literals

An object in JavaScript and c64jasm is just a dict that maps keys to values. For example, in JavaScript:

const options = {
    filename: "main.asm",
    indent: 4
};

The equivalent in c64jasm syntax would be:

How is this useful in assembler?

Turns out object literals can be quite useful for a few things:

  • Named parameters for macro calls
  • Keeping track of zeropage addresses
  • Implicitly parametrize macro expansion

Named parameters: C64jasm supports only positional arguments in macro calls. However, just like in JavaScript, objects are a great substitute for named parameters:

Zero-page addresses: If you’ve written any decent amounts of 6502 assembly, you may have ran into problems keeping track of what’s in the zeropage. Perhaps you first started out by just keeping all the addresses in your head or code comments:

This is hard to read and easily breaks on modification. Instead, I tend to declare my zeropage allocation in variables:

You can express the above equivalently using an object literal:

Turns out, the latter form combines well with macro expansion.

Macros and zeropage temporaries

Consider the below mul_imm macro that multiplies a 16-bit value by 3. It needs 2 bytes of zeropage memory to hold a temporary value (zp_tmp0). It’s hardcoded to store the tempory in zeropage addresses $20-$21.

What if the code calling this macro is also using zeropage $20-$21? The values in $20-$21 will get clobbered by the macro. You also probably cannot use this macro in an IRQ as the IRQ might then clobber $20-21 while your main code is running and using the same memory.

We could of course pass in a 3rd parameter zp_tmp0 that’d specify the temp zeropage location. But this is ugly even with one 16-bit zeropage temp and only gets worse in macros needing many temporaries.

Let’s parametrize zeropage temp locations in mul_imm by adding a zp macro argument that holds the zeropage allocation:

Better but still noisy.

Now here’s the kicker: we can drop the zp argument from mul_imm declaration and rely on a convention that zp is passed implicitly in the enclosing scope at the macro call site.

In code:

Update 2019-08-09: Implicit parameters by the sort of “dynamic scoping” shown here does not work as of c64jasm 0.7.0. When a macro is expanded, any symbols in the macro will use bindings from where the macro was declared, not where it’s expanded. Use global variables instead. See this gist for an example on how to do this cleanly.

Wrap-up

This post walked through a couple of tricks that became possible in the latest c64jasm v0.6.0 release. If you’re feeling adventurous, read more here. Or try it in your browser!