c64asm

{c64asm} is a c64 6502 assembler written in R.

The syntax for the assembly code closely follows that of TASS.

{c64asm} includes syntax extensions which allow for easier integration of pre-computed values and data segments directly from R.

c64 / 6502

The Commodore 64 (c64) is an 8-bit home computer running on a Motorola 6510 (a variant of the 6502).

The c64 supports 16 colours, 8 hardware sprites and a maximum resolution of 320x200 pixels.

It includes co-processors for sound (SID chip) and video (VIC-II) chip.

6502 machine code:

{c64asm} Features

General features

For integration with R

Limitations

Installation

# devtools::install_github('coolbutuseless/c64asm')
install.packages("c64asm", repos = c('https://coolbutuseless.r-universe.dev', 'https://cloud.r-project.org'))

Documentation

The documentation for the package is available online at coolbutuseless.github.io (thanks to pkgdown)

Vignettes

The code for the vignettes is also available in the prg/ directory of this repository.

A simple 6502 program

The following c64/6502 ASM code will clear the screen and then write Hello #rstats! at the top

asm <- '
*=$0801
  .byte $0c, $08, $0a, $00, $9e, $20  ; 10 SYS 2080
  .byte $32, $30, $38, $30, $00, $00
  .byte $00

*=$0820
      lda #$93        ; Clear the screen
      jsr $ffd2

      ldx #$0        ; initialise the offset pointer into our message
loop  lda message,x   ; load a character and write it to screen 
      and #$3f        ; Manually place chars on screen
      sta $0400,x
      inx
      cpx #$0e
      bne loop

      rts

message
    .text "Hello #rstats!"
'

Compile the program and show the compiled program bytes

prg <- c64asm::compile(asm)
prg
##  [1] 01 08 0c 08 0a 00 9e 20 32 30 38 30 00 00 00 00 00 00 00 00 00 00 00 00 00
## [26] 00 00 00 00 00 00 00 00 a9 93 20 d2 ff a2 00 bd 35 08 29 3f 9d 00 04 e8 e0
## [51] 0e d0 f3 60 c8 45 4c 4c 4f 20 23 52 53 54 41 54 53 21

Run c64 programs using VICE

library(c64vice)

c64vice::run_prg(prg)

Breakdown of assembly process

The compiler makes a few passes through the data to resolve symbol values.

The c64asm::compile() function is just a wrapper which calls the following 4 functions

  1. line_tokens <- c64asm::create_line_tokens(asm)
    • For each line in the input break it into tokens.
    • Filter any rows that contain no instructions
  2. prg_df <- c64asm::create_prg_df(line_tokens)
    • Create a data.frame from line_tokens
    • This is the key data structure for the compilation process
    • The compilation process is just a matter of manipulating this data.frame and merging with information about the instructions
  3. prg_df <- c64asm::process_symbols(prg_df)
    • Resolve labels to their actual addresses
    • Replace any defined variables with their values
  4. prg_df <- c64asm::process_zero_padding(prg_df)
    • If there are gaps between blocks of code, insert sequences of zero bytes 5, prg <- c6asm::extract_prg_bytes(prg_df)
    • Extract the vector of raw bytes which represent the c64 PRG executable

The actual contents of the c64 prg executable file is the sequence of values in the hexbytes column.

c64-verse