flat assembler
Message board for the users of flat assembler.

Index > Non-x86 architectures > MOS 6502 Assembler: For NES, C64, Atari

Author
Thread Post new topic Reply to topic
m3ntal



Joined: 08 Dec 2013
Posts: 296
m3ntal 18 Feb 2014, 08:56
MOS 6502 assembler created with FASM preprocessor: For NES/Nintendo, Commodore 64, Atari 2600/7800 and more.

6502.INC
Code:
; $$$$$$$$$$$$$$$ Z6502 ASSEMBLER $$$$$$$$$$$$$$$$
; *************** STAR^2 SOFTWARE ****************
; ?????????????????? 6502.INC ????????????????????

;                   MMM"""AMV
;                   M'   AMV
;                   '   AMV
;                     AMV   ,
;     .6*"          AMV   ,M   MOS
;   ,M'            AMVmmmmMM
;  ,Mbmmm.    M******  ,pP""Yq.   pd*"*b.
;  6M'  `Mb. .M       6W'    `Wb (O)   j8
;  MI     M8 |bMMAg.  8M      M8     ,;j9
;  WM.   ,M9      `Mb YA.    ,A9  ,-='
;   WMbmmd9        jM  `Ybmmd9'  Ammmmmmm
;           (O)  ,M9
;            6mmm9

; a               - accumulator
; x, y            - general
; status          - flags: SV_BDIZC
; program counter
; stack register

; $00-$FF     - zero page memory
; $0100-$01FF - stack, 1K

; in some emulators:

; $FE         - random byte
; $FF         - last ASCII key
; $0200-$05FF - screen, 32x32

; syntax is standard except replace # with =
; for immediate operands:

; lda =$7F  ; a=i (immediate, prefix with =)
; lda $7F   ; a=[$7F] (zero page)
; lda $7FAA ; a=[$7FAA] (absolute)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

macro verify a {
  if ?s eq 0
    'Error: ' a
  end if
}

macro verify.i i {
  if ~ i eqtype 0
    'Number expected:' i
  end if
}

macro verify.n n, min, max {
  if n<min | n>max
    'Number exceeds range:' min-max
  end if
} 

macro verify.u8 n  { verify.n n, 0, 255 } 
macro verify.i8 n  { verify.n n, -128, 127 }
macro verify.u16 n { verify.n n, 0, 65535 } 

;;;;;;;;;;;;;; ONE-BYTE INSTRUCTIONS ;;;;;;;;;;;;;

macro brk { db $00 } ; non-maskable interrupt
macro clc { db $18 } ; clear carry
macro cld { db $D8 } ; clear decimal
macro cli { db $58 } ; clear interrupt
macro clv { db $B8 } ; clear overflow
macro dex { db $CA } ; x--
macro dey { db $88 } ; y--
macro inx { db $E8 } ; x++
macro iny { db $C8 } ; y++
macro nop { db $EA } ; no operation
macro pha { db $48 } ; push a
macro php { db $08 } ; push status
macro pla { db $68 } ; pull/pop a
macro plp { db $28 } ; pull/pop status
macro rti { db $40 } ; return from interrupt
macro rts { db $60 } ; return from subroutine
macro sec { db $38 } ; set carry
macro sed { db $F8 } ; set decimal
macro sei { db $78 } ; set interrupt
macro tax { db $AA } ; x=a
macro tay { db $A8 } ; y=a
macro tsx { db $BA } ; x=s
macro txa { db $8A } ; a=x
macro txs { db $9A } ; s=x
macro tya { db $98 } ; a=y

;;;;;;;;;;;;;;;;;;;;; BRANCH ;;;;;;;;;;;;;;;;;;;;;

macro jmp [a] {
 common
 define ?s 0
  match (x), a \{ ; indirect
    db $6C
    dw x
    define ?s 1
  \}
  match =0 x,\    ; absolute
   ?s a \{
    db $4C
    dw x
  \}
}

macro bxx o, a
 { db o, (255-($-a)) and $FF }

macro beq a { bxx $F0, a }
macro bne a { bxx $D0, a }
macro bcc a { bxx $90, a }
macro bcs a { bxx $B0, a }
macro bvc a { bxx $50, a }
macro bvs a { bxx $70, a }
macro bmi a { bxx $30, a }
macro bpl a { bxx $10, a }

; jmp to subroutine

macro jsr a {
  db $20
  dw a         ; absolute
}

;;;;;;;; LDA, STA, ADC, SBC, ORA, CMP, ETC ;;;;;;;

; opc =$44     ; immediate (=i)
; opc $AA      ; zero page
; opc $7F, x   ; zero page, x
; opc $4FFF    ; absolute
; opc $88BB, x ; absolute, x
; opc $24EE, y ; absolute, y
; opc ($AC, x) ; (indirect, x)
; opc ($DC), y ; (indirect), y

macro o1.6502 name, aaa, [p] {
 common
  local i, mode, size
  define ?s 0
  match =0 ==a, ?s p \{      ; immediate
    i=a
    mode=010b
    size=1
    if name eq sta
      'Error: ' a
    end if
    define ?s 1
  \}
  match =0 (a=,=x), ?s p \{  ; (indirect, x)
    i=a
    mode=000b
    size=1
    define ?s 1
  \}
  match =0 (a)=,=y, ?s p \{  ; (indirect), y
    i=a
    mode=100b
    size=1
    define ?s 1
  \}
  match =0 a=,b, ?s p \{     ; ?, ?
    i=a
    verify.i a               ; i, ?
    verify.u16 a
    if b eq x                ; i, x
      if a<256               ; zero page, x
        mode=101b
        size=1
      else                   ; absolute, x
        mode=111b
        size=2
      end if
    else if b eq y           ; absolute, y
      mode=110b
      size=2
    else
      'Error: ' b
    end if
    define ?s 1
  \}
  match =0 a, ?s p \{
    i=a
    verify.u16 a
    if a<256                 ; zero page
      mode=001b
      size=1
    else                     ; absolute
      mode=011b
      size=2
    end if
    define ?s 1
  \}
  verify name
  db (aaa shl 5) or \
   (mode shl 2) or 1
  if size=1
    db i
  else
    dw i
  end if
}

macro ora [p] { common o1.6502 ora, 000b, p }
macro and [p] { common o1.6502 and, 001b, p }
macro eor [p] { common o1.6502 eor, 010b, p }
macro adc [p] { common o1.6502 adc, 011b, p }
macro sta [p] { common o1.6502 sta, 100b, p }
macro lda [p] { common o1.6502 lda, 101b, p }
macro cmp [p] { common o1.6502 cmp, 110b, p }
macro sbc [p] { common o1.6502 sbc, 111b, p }

;;;;;;;;;;;;;;;;;;;; INC, DEC ;;;;;;;;;;;;;;;;;;;;

; opc $80      ; zero page
; opc $80, x   ; zero page, x
; opc $A000    ; absolute
; opc $8000, x ; absolute, x

macro o2.6502.a name, aaa, [p] {
 common
  local i, mode, size
  define ?s 0
  match =0 a=,=x,\      ; ?, x
   ?s p \{
    i=a
    if i<256
      size=1
      mode=101b
    else
      size=2
      mode=111b
    end if
    define ?s 1
  \}
  match =0 a, ?s p \{   ; x
    i=a
    if i<256
      size=1
      mode=001b
    else
      size=2
      mode=011b
    end if
    define ?s 1
  \}
  verify name
  verify.u16 i
  db (aaa shl 5) or \
   (mode shl 2) or 2
  if size=1             ; zero page
    db i
  else                  ; absolute
    dw i
  end if
}

macro inc [p] { common o2.6502.a inc, 111b, p }
macro dec [p] { common o2.6502.a dec, 110b, p }

;;;;;;;;;;;;;;; ASL, LSR, ROL, ROR ;;;;;;;;;;;;;;;

; opc          ; accumulator
; opc $80      ; zero page
; opc $80, x   ; zero page, x
; opc $A000    ; absolute
; opc $8000, x ; absolute, x

macro o2.6502.b name, aaa, [p] {
 common
  local i, mode, size
  define ?s 0
  match =0 a=,=x,\      ; ?, x
   ?s p \{
    i=a
    if i<256
      size=1
      mode=101b
    else
      size=2
      mode=111b
    end if
    define ?s 1
  \}
  match =0 _a, ?s p \{  ; x
    if _a eq a          ; accumulator
      size=1
      mode=010b
    else
      i=_a
      if i<256
        size=1
        mode=001b
      else
        size=2
        mode=011b
      end if
    end if
    define ?s 1
  \}
  if ?s eq 0            ; accumulator
    size=1
    mode=010b
    define ?s 1
  end if
  verify name
  db (aaa shl 5) or \
   (mode shl 2) or 2
  if mode<>010b         ; not accumulator?
    verify.u16 i
    if size=1           ; zero page
      db i
    else                ; absolute
      dw i
    end if
  end if
}

macro asl [p] { common o2.6502.b asl, 000b, p }
macro rol [p] { common o2.6502.b rol, 001b, p }
macro lsr [p] { common o2.6502.b lsr, 010b, p }
macro ror [p] { common o2.6502.b ror, 011b, p }

;;;;;;;;;;;;;;;;;;;; STX, LDX ;;;;;;;;;;;;;;;;;;;;

; opc =$44     ; immediate (=i)
; opc $80      ; zero page
; opc $80, y   ; zero page, y
; opc $AAAA    ; absolute

macro o2.6502.c name, aaa, [p] {
 common
  local i, mode, size
  define ?s 0
  match =0 ==a, ?s p \{      ; immediate
    i=a
    mode=000b
    size=1
    if name eq stx
      'Error: ' a
    end if
    define ?s 1
  \}
  match =0 a=,b, ?s p \{     ; ?, ?
    i=a
    verify.i a               ; i, ?
    verify.u16 a
    if b eq y                ; i, y
      if a<256               ; zero page, y
        mode=101b
        size=1
      else                   ; absolute, y
        mode=111b
        size=2
        if name eq stx
          'Error: ' a
        end if
      end if
    else
      'Error: ' b
    end if
    define ?s 1
  \}
  match =0 a, ?s p \{
    i=a
    verify.i i
    verify.u16 i
    if i<256                 ; zero page
      mode=001b
      size=1
    else
      mode=011b              ; absolute
      size=2
    end if
    define ?s 1
  \}
  verify name
  db (aaa shl 5) or \
   (mode shl 2) or 2
  if size=1
    db i
  else
    dw i
  end if
}

macro stx [p] { common o2.6502.c stx, 100b, p }
macro ldx [p] { common o2.6502.c ldx, 101b, p }

;;;;;;;;;;;;;;;;;;;; STY, LDY ;;;;;;;;;;;;;;;;;;;;

; opc =$44     ; immediate (=i)
; opc $AA      ; zero page
; opc $7F, x   ; zero page, x
; opc $4FFF    ; absolute
; opc $88BB, x ; absolute, x

macro o0.6502 name, aaa, [p] {
 common
  local i, mode, size
  define ?s 0
  match =0 ==a, ?s p \{      ; immediate
    i=a
    mode=000b
    size=1
    if name eq sty
      'Error: ' a
    end if
    define ?s 1
  \}
  match =0 a=,b, ?s p \{     ; ?, ?
    i=a
    verify.i a               ; i, ?
    verify.u16 a
    if b eq x                ; i, x
      if a<256               ; zero page, x
        mode=101b
        size=1
      else                   ; absolute, x
        mode=111b
        size=2
      end if
    else
      'Error: ' b
    end if
    define ?s 1
  \}
  match =0 a, ?s p \{
    i=a
    verify.u16 a
    if a<256                 ; zero page
      mode=001b
      size=1
    else                     ; absolute
      mode=011b
      size=2
    end if
    define ?s 1
  \}
  verify name
  db (aaa shl 5) or \
   (mode shl 2)
  if size=1
    db i
  else
    dw i
  end if
}

macro sty [p] { common o0.6502 sty, 100b, p }
macro ldy [p] { common o0.6502 ldy, 101b, p }

;;;;;;;;;;;;;;;;;;;; CPX, CPY ;;;;;;;;;;;;;;;;;;;;

; opc =$44     ; immediate (=i)
; opc $AA      ; zero page
; opc $4FFF    ; absolute

macro o0.6502.a name, aaa, [p] {
 common
  local i, mode, size
  define ?s 0
  match =0 ==a, ?s p \{      ; immediate
    i=a
    mode=000b
    size=1
    define ?s 1
  \}
  match =0 a, ?s p \{
    i=a
    verify.u16 a
    if a<256                 ; zero page
      mode=001b
      size=1
    else                     ; absolute
      mode=011b
      size=2
    end if
    define ?s 1
  \}
  verify name
  db (aaa shl 5) or \
   (mode shl 2)
  if size=1
    db i
  else
    dw i
  end if
}

macro cpx [p] { common o0.6502.a cpx, 111b, p }
macro cpy [p] { common o0.6502.a cpy, 110b, p }

;;;;;;;;;;;;;;;;;;;;;;; BIT ;;;;;;;;;;;;;;;;;;;;;;

macro bit a {
  define ?s 0
  verify.u16 a
  if a eqtype 0
    if a<256    ; zero page
      db $24
      db a
    else        ; absolute
      db $2C
      dw a
    end if
    define ?s 1
  end if
  verify bit
}    
TEST.ASM
Code:
; test 6502 instructions

format binary as 'BIN'
include '6502.inc'

lda =0
beq @f

lda =$44     ; immediate
lda $AA      ; zero page
lda $7F, x   ; zero page, x
lda $4FFF    ; absolute
lda $88BB, x ; absolute, x
lda $24EE, y ; absolute, y
lda ($AC, x) ; (indirect, x)
lda ($DC), y ; (indirect), y
@@:

ldx =$44     ; immediate
ldx $80      ; zero page
ldx $80, y   ; zero page, y
ldx $AAAA    ; absolute
ldx $AAAA, y ; absolute, y

ldy =$44     ; immediate
ldy $80      ; zero page
ldy $80, x   ; zero page, x
ldy $AAAA    ; absolute

sta $AA      ; zero page
sta $7F, x   ; zero page, x
sta $4FFF    ; absolute
sta $88BB, x ; absolute, x
sta $24EE, y ; absolute, y
sta ($AC, x) ; (indirect, x)
sta ($DC), y ; (indirect), y
bne @f

stx $80      ; zero page
stx $80, y   ; zero page, y
stx $AAAA    ; absolute

sty $80      ; zero page
sty $80, x   ; zero page, x
sty $AAAA    ; absolute

inc $80      ; zero page memory
inc $80, x   ; zero page, x
inc $A000    ; absolute memory
inc $8000, x ; absolute, x

dec $80      ; zero page memory
dec $80, x   ; zero page, x
dec $A000    ; absolute memory
dec $8000, x ; absolute, x

adc =$44     ; immediate
adc $AA      ; zero page
adc $7F, x   ; zero page, x
adc $4FFF    ; absolute
adc $88BB, x ; absolute, x
adc $24EE, y ; absolute, y
adc ($AC, x) ; (indirect, x)
adc ($DC), y ; (indirect), y

sbc =$44     ; immediate
sbc $AA      ; zero page
sbc $7F, x   ; zero page, x
sbc $4FFF    ; absolute
sbc $88BB, x ; absolute, x
sbc $24EE, y ; absolute, y
sbc ($AC, x) ; (indirect, x)
sbc ($DC), y ; (indirect), y

cmp =$44     ; immediate
cmp $AA      ; zero page
cmp $7F, x   ; zero page, x
cmp $4FFF    ; absolute
cmp $88BB, x ; absolute, x
cmp $24EE, y ; absolute, y
cmp ($AC, x) ; (indirect, x)
cmp ($DC), y ; (indirect), y

cpx =$88     ; immediate
cpx $BB      ; zero page
cpx $3CCC    ; absolute
cpy =$88     ; immediate
cpy $BB      ; zero page
cpy $3CCC    ; absolute

and =$44     ; immediate
and $AA      ; zero page
and $7F, x   ; zero page, x
and $4FFF    ; absolute
and $88BB, x ; absolute, x
and $24EE, y ; absolute, y
and ($AC, x) ; (indirect, x)
and ($DC), y ; (indirect), y

ora =$44     ; immediate
ora $AA      ; zero page
ora $7F, x   ; zero page, x
ora $4FFF    ; absolute
ora $88BB, x ; absolute, x
ora $24EE, y ; absolute, y
ora ($AC, x) ; (indirect, x)
ora ($DC), y ; (indirect), y

eor =$44     ; immediate
eor $AA      ; zero page
eor $7F, x   ; zero page, x
eor $4FFF    ; absolute
eor $88BB, x ; absolute, x
eor $24EE, y ; absolute, y
eor ($AC, x) ; (indirect, x)
eor ($DC), y ; (indirect), y

asl          ; accumulator (implied)
asl a        ; accumulator (optional)
asl $80      ; zero page
asl $80, x   ; zero page, x
asl $A000    ; absolute
asl $8000, x ; absolute, x

lsr          ; accumulator (implied)
lsr a        ; accumulator (optional)
lsr $80      ; zero page
lsr $80, x   ; zero page, x
lsr $A000    ; absolute
lsr $8000, x ; absolute, x

rol          ; accumulator (implied)
rol a        ; accumulator (optional)
rol $80      ; zero page
rol $80, x   ; zero page, x
rol $A000    ; absolute
rol $8000, x ; absolute, x

ror          ; accumulator (implied)
ror a        ; accumulator (optional)
ror $80      ; zero page
ror $80, x   ; zero page, x
ror $A000    ; absolute
ror $8000, x ; absolute, x

bit $50      ; zero page
bit $4000    ; absolute

beq @f
bne @f
bcc @f
bcs @f
bvc @f
bvs @f
bmi @f
bpl @f
@@:

brk
clc
cld
cli
clv
dex
dey
inx
iny
nop
pha
php
pla
plp
rti
rts
sec
sed
sei
tax
tay
tsx
txa
txs
tya    


Assemble with FASMW. Verify instructions: Online 6502 Disassembler. Open TEST.BIN with hex editor (HxD?), copy and paste the bytes into "code:" then click "disassemble".


Last edited by m3ntal on 21 Feb 2014, 06:09; edited 5 times in total
Post 18 Feb 2014, 08:56
View user's profile Send private message Reply with quote
m3ntal



Joined: 08 Dec 2013
Posts: 296
m3ntal 18 Feb 2014, 09:07
6502 assembler featured in original Terminator movie (1984):

Image
Post 18 Feb 2014, 09:07
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20451
Location: In your JS exploiting you and your system
revolution 18 Feb 2014, 10:44
m3ntal wrote:
TEST.ASM
IMO this is the most important part of any assembler. Without a verification process it is hard to know if things are working as expected.

Does it test complete coverage of all instructions and variants?
Post 18 Feb 2014, 10:44
View user's profile Send private message Visit poster's website Reply with quote
m3ntal



Joined: 08 Dec 2013
Posts: 296
m3ntal 18 Feb 2014, 11:55
Quote:
Does it test complete coverage of all instructions and variants?
No, only tested to the extent of TEST.ASM. To my knowledge, it supports nearly all original documented 6502 instructions, but I can't guarantee anything. No variants defined (6507, 6510, 2A03, 6502B). I have written some examples for NES, though, which has a Ricoh 2A03 8-BIT and SNES has a 16-BIT version of it.
Post 18 Feb 2014, 11:55
View user's profile Send private message Reply with quote
m3ntal



Joined: 08 Dec 2013
Posts: 296
m3ntal 18 Feb 2014, 23:29
Updated 6502+TEST: Forgot ldx =i/mmediate + absolute, y.

For (expressions), use numeric constants to avoid conflict with (indirect) addressing modes:
Code:
q=((p+offset)/256)
lda q    
Post 18 Feb 2014, 23:29
View user's profile Send private message Reply with quote
m3ntal



Joined: 08 Dec 2013
Posts: 296
m3ntal 19 Feb 2014, 13:57
Nintendo/NES example. Tested in Nestopia and FCE Ultra:


Description:
Filesize: 38.62 KB
Viewed: 42647 Time(s)

z6502.jpg


Description:
Download
Filename: z6502_nes.zip
Filesize: 9.21 KB
Downloaded: 1172 Time(s)

Post 19 Feb 2014, 13:57
View user's profile Send private message Reply with quote
shutdownall



Joined: 02 Apr 2010
Posts: 517
Location: Munich
shutdownall 22 Mar 2014, 18:37
This is interesting for Apple II as well. It is only macrobased as I can see.

Perhaps I will integrate it in the instruction set of my retro edition of FASM (ZX-IDE) which now supports Sinclair only. I want to do something in near future with old Apples. Cool
Post 22 Mar 2014, 18:37
View user's profile Send private message Send e-mail Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.