Write your c64 ASM code

  • The syntax is roughly modelled on that of TASS64, but only for the fundamentals i.e.
    • * refers to current address location, and can be read from or written to
    • All programs should start with a *=.... line to set the starting address
    • .byte values must be hexadecimal only, and single byte hexadecimal must always include 2 characters. i.e. $0e will work, but $e won’t work.
    • Similarly, for immediate values. i.e. #$01 will work. #$1 won’t work.
library(r64)

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

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

      ldx #$00        ; 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 in one step

  • If you’re willing to trust the compiler, then use r64::compile() to convert ASM into bytes.
  • Still have to extract the bytes from the prg_df data.frame to view and save.
prg_df <- r64::compile(asm)

r64::extract_prg_bytes(prg_df)
#>  [1] 01 08 0c 08 0a 00 9e 20 32 30 38 30 00 00 00 00 00 00 00 00 00 00 00
#> [24] 00 00 00 00 00 00 00 00 00 00 a9 93 20 d2 ff a2 00 bd 35 08 29 3f 9d
#> [47] 00 04 e8 e0 0e d0 f3 60 c8 45 4c 4c 4f 20 23 52 53 54 41 54 53 21

Compile in multiple steps (for debugging purposes)

  • When debugging the output, you can manually run the compilation steps and view the output at each stage.
  • r64 isn’t a complete or bug-free assembler by any means!
line_tokens <- r64::create_line_tokens(asm)

prg_df      <- r64::create_prg_df(line_tokens)
prg_df      <- r64::process_symbols(prg_df)
prg_df      <- r64::process_zero_padding(prg_df)

r64::extract_prg_bytes(prg_df)
#>  [1] 01 08 0c 08 0a 00 9e 20 32 30 38 30 00 00 00 00 00 00 00 00 00 00 00
#> [24] 00 00 00 00 00 00 00 00 00 00 a9 93 20 d2 ff a2 00 bd 35 08 29 3f 9d
#> [47] 00 04 e8 e0 0e d0 f3 60 c8 45 4c 4c 4f 20 23 52 53 54 41 54 53 21

Save to file

prg_filename <- "../prg/helloworld.prg"

r64::save_prg(prg_df, prg_filename)

Compare the output with a more complete compiler (TASS64)

  • If you’re not using any R-specific features, then for most simple cases you can compile your ASM in TASS64 as well and compare the byte output. They should be identical.
tass <- r64::TASS$new(asm = asm)
tass$compile()
tass$get_prg()

identical(r64::extract_prg_bytes(prg_df), tass$get_prg())

Run code in an emulator

system(paste("/usr/local/opt/vice/x64.app/Contents/MacOS/x64 -VICIIfilter 0 -silent", prg_filename), wait=FALSE)