{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.
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
* = $0801
border = $d020
lda #<routine will store the low byte of the address of symbol routine in the A registerFor integration with R
.rtext directive to include an R string as text data.rbyte directive to include an R integer vector as bytes{...} to delimit code to be evaluated at run time to manipulate labels and variables e.g. lda {border + 1}
jmp to a location more than 128 bytes away from the current program counter.indirect indexed and indexed indirect modes using symbolic addresses seems to work, but need more tests.BUFPNT = $A6 is the pointer to the tape i/o bufferlda <BUFPNT should be used to force zero page addressing mode, otherwise lda BUFPNT would assume absolute addressing mode.
devtools::install_github('coolbutuseless/c64asm')The documentation for the package is available online at coolbutuseless.github.io (thanks to pkgdown)
helloworld - write text to the screenhelloborder - colour cycling in the border as fast as possiblehelloworld_details - a look at the intermediate assembly outputs during compilationascii - Using R-specific .rbyte directive to put characters from an R variable into the assembly codecustom_character_set - Building a custom character set in R and passing it into the assemblly code with the .rbyte directive.symbol-arithmetic - How to do arithmetic on the program counter and address labelsThe code for the vignettes is also available in the prg/ directory of this repository.
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!"
'
prg <- c64asm::compile(asm)
prgThe 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
line_tokens <- c64asm::create_line_tokens(asm)
prg_df <- c64asm::create_prg_df(line_tokens)
line_tokens
prg_df <- c64asm::process_symbols(prg_df)
prg_df <- c64asm::process_zero_padding(prg_df)
prg <- c6asm::extract_prg_bytes(prg_df)
The actual contents of the c64 prg executable file is the sequence of values in the hexbytes column.