1
0
mirror of https://github.com/safiire/n65.git synced 2025-08-14 19:27:24 +00:00

Can use lower case instruction names and hex now

This commit is contained in:
Safiire
2015-02-22 18:49:24 -08:00
parent e661393e6e
commit eaa80000b2
3 changed files with 221 additions and 204 deletions

View File

@@ -23,7 +23,6 @@ An NES assembler for the 6502 microprocessor written in Ruby
![Scrolling NES Demo](assembler_demo.png) ![Scrolling NES Demo](assembler_demo.png)
Some Todos: Some Todos:
- Allow lower case mnemonics in source code
- Understand how to deal with various mappers - Understand how to deal with various mappers
- Understand how to create multiple banks - Understand how to create multiple banks
- Get an NSF file playing - Get an NSF file playing
@@ -36,8 +35,10 @@ An NES assembler for the 6502 microprocessor written in Ruby
- Support binary literals ie %10101010 - Support binary literals ie %10101010
- Anonymous Label support, (maybe, not sure if I like the idea) - Anonymous Label support, (maybe, not sure if I like the idea)
- Give this project a better name. - Give this project a better name.
- Create an interactive read eval compile loop?
Some new additions: Some new additions:
- Lower case mnemonics and hex digits
- Ported NES101 tutor to this assembler. - Ported NES101 tutor to this assembler.
- Added msb and lsb byte selectors on address labels - Added msb and lsb byte selectors on address labels
- added .org directive - added .org directive

View File

@@ -12,12 +12,14 @@ module Assembler6502
class InvalidAddressingMode < StandardError; end class InvalidAddressingMode < StandardError; end
class AddressOutOfRange < StandardError; end class AddressOutOfRange < StandardError; end
Mnemonic = '([A-Z]{3})' Mnemonic = '([A-Za-z]{3})'
Hex8 = '\$([A-Z0-9]{2})' Hex8 = '\$([A-Fa-f0-9]{2})'
Hex16 = '\$([A-Z0-9]{4})' Hex16 = '\$([A-Fa-f0-9]{4})'
Immediate = '\#\$([0-9A-F]{2})' Immediate = '\#\$([0-9A-F]{2})'
Sym = '([a-zZ-Z_][a-zA-Z0-9_]+)' Sym = '([a-zZ-Z_][a-zA-Z0-9_]+)'
Branches = '(BPL|BMI|BVC|BVS|BCC|BCS|BNE|BEQ)' Branches = '(BPL|BMI|BVC|BVS|BCC|BCS|BNE|BEQ|bpl|bmi|bvc|bvs|bcc|bcs|bne|beq)'
XReg = '[Xx]'
YReg = '[Yy]'
AddressingModes = { AddressingModes = {
:relative => { :relative => {
@@ -49,13 +51,13 @@ module Assembler6502
:zero_page_x => { :zero_page_x => {
:example => 'AAA $FF, X', :example => 'AAA $FF, X',
:display => '%s $%.2X, X', :display => '%s $%.2X, X',
:regex => /^#{Mnemonic}\s+#{Hex8}\s?,\s?X$/ :regex => /^#{Mnemonic}\s+#{Hex8}\s?,\s?#{XReg}$/
}, },
:zero_page_y => { :zero_page_y => {
:example => 'AAA $FF, Y', :example => 'AAA $FF, Y',
:display => '%s $%.2X, Y', :display => '%s $%.2X, Y',
:regex => /^#{Mnemonic}\s+#{Hex8}\s?,\s?Y$/ :regex => /^#{Mnemonic}\s+#{Hex8}\s?,\s?#{YReg}$/
}, },
:absolute => { :absolute => {
@@ -68,15 +70,15 @@ module Assembler6502
:absolute_x => { :absolute_x => {
:example => 'AAA $FFFF, X', :example => 'AAA $FFFF, X',
:display => '%s $%.4X, X', :display => '%s $%.4X, X',
:regex => /^#{Mnemonic}\s+#{Hex16}\s?,\s?X$/, :regex => /^#{Mnemonic}\s+#{Hex16}\s?,\s?#{XReg}$/,
:regex_label => /^#{Mnemonic}\s+#{Sym}\s?,\s?X$/ :regex_label => /^#{Mnemonic}\s+#{Sym}\s?,\s?#{XReg}$/
}, },
:absolute_y => { :absolute_y => {
:example => 'AAA $FFFF, Y', :example => 'AAA $FFFF, Y',
:display => '%s $%.4X, Y', :display => '%s $%.4X, Y',
:regex => /^#{Mnemonic}\s+#{Hex16}\s?,\s?Y$/, :regex => /^#{Mnemonic}\s+#{Hex16}\s?,\s?#{YReg}$/,
:regex_label => /^#{Mnemonic}\s+#{Sym}\s?,\s?Y$/ :regex_label => /^#{Mnemonic}\s+#{Sym}\s?,\s?#{YReg}$/
}, },
:indirect => { :indirect => {
@@ -89,15 +91,15 @@ module Assembler6502
:indirect_x => { :indirect_x => {
:example => 'AAA ($FF, X)', :example => 'AAA ($FF, X)',
:display => '%s ($%.2X, X)', :display => '%s ($%.2X, X)',
:regex => /^#{Mnemonic}\s+\(#{Hex8}\s?,\s?X\)$/, :regex => /^#{Mnemonic}\s+\(#{Hex8}\s?,\s?#{XReg}\)$/,
:regex_label => /^#{Mnemonic}\s+\(#{Sym}\s?,\s?X\)$/ :regex_label => /^#{Mnemonic}\s+\(#{Sym}\s?,\s?#{XReg}\)$/
}, },
:indirect_y => { :indirect_y => {
:example => 'AAA ($FF), Y)', :example => 'AAA ($FF), Y)',
:display => '%s ($%.2X), Y', :display => '%s ($%.2X), Y',
:regex => /^#{Mnemonic}\s+\(#{Hex8}\)\s?,\s?Y$/, :regex => /^#{Mnemonic}\s+\(#{Hex8}\)\s?,\s?#{YReg}$/,
:regex_label => /^#{Mnemonic}\s+\(#{Sym}\)\s?,\s?Y$/ :regex_label => /^#{Mnemonic}\s+\(#{Sym}\)\s?,\s?#{YReg}$/
} }
} }
@@ -235,9 +237,9 @@ module Assembler6502
arg_16 = symbols[@arg].address arg_16 = symbols[@arg].address
@arg = case @byte_selector @arg = case @byte_selector
when :> when :>
(arg_16 & 0xFF00) >> 8 high_byte(arg_16)
when :< when :<
arg_16 & 0xFF low_byte(arg_16)
end end
return @arg return @arg
end end
@@ -301,6 +303,20 @@ module Assembler6502
[integer & 0x00FF, (integer & 0xFF00) >> 8] [integer & 0x00FF, (integer & 0xFF00) >> 8]
end end
####
## Take the high byte of a 16-bit integer
def high_byte(word)
(word & 0xFF00) >> 8
end
####
## Take the low byte of a 16-bit integer
def low_byte(word)
word & 0xFF
end
end end
end end

View File

@@ -30,282 +30,282 @@ sprite:
.org $C000 .org $C000
reset: reset:
SEI sei
CLD cld
; Wait two VBLANKs. ; Wait two VBLANKs.
wait_vb1: wait_vb1:
LDA $2002 lda $2002
BPL wait_vb1 bpl wait_vb1
wait_vb2: wait_vb2:
LDA $2002 lda $2002
BPL wait_vb2 bpl wait_vb2
; Clear out RAM. ; Clear out RAM.
LDA #$00 lda #$00
LDX #$00 ldx #$00
clear_segments: clear_segments:
STA $00, X sta $00, X
STA $0100, X sta $0100, X
STA $0200, X sta $0200, X
STA $0300, X sta $0300, X
STA $0400, X sta $0400, X
STA $0500, X sta $0500, X
STA $0600, X sta $0600, X
STA $0700, X sta $0700, X
INX inx
BNE clear_segments bne clear_segments
; Reset the stack pointer. ; Reset the stack pointer.
LDX #$FF ldx #$FF
TXS txs
; Disable all graphics. ; Disable all graphics.
LDA #$00 lda #$00
STA $2000 sta $2000
STA $2001 sta $2001
JSR init_graphics jsr init_graphics
JSR init_input jsr init_input
JSR init_sound jsr init_sound
; Set basic PPU registers. Load background from $0000, ; Set basic PPU registers. Load background from $0000,
; sprites from $1000, and the name table from $2000. ; sprites from $1000, and the name table from $2000.
LDA #$88 lda #$88
STA $2000 sta $2000
LDA #$1E lda #$1E
STA $2001 sta $2001
CLI cli
; Transfer control to the VBLANK routines. ; Transfer control to the VBLANK routines.
forever: forever:
JMP forever jmp forever
init_graphics: init_graphics:
JSR init_sprites jsr init_sprites
JSR load_palette jsr load_palette
JSR load_name_tables jsr load_name_tables
JSR init_scrolling jsr init_scrolling
RTS rts
init_input: init_input:
; The A button starts out not-pressed. ; The A button starts out not-pressed.
LDA #$00 lda #$00
STA $01 ; $01 = A button sta $01 ; $01 = A button
RTS rts
init_sound: init_sound:
; initialize sound hardware ; initialize sound hardware
LDA #$01 lda #$01
STA $4015 sta $4015
LDA #$00 lda #$00
STA $4001 sta $4001
LDA #$40 lda #$40
STA $4017 sta $4017
RTS rts
init_sprites: init_sprites:
; Clear page #2, which we'll use to hold sprite data ; Clear page #2, which we'll use to hold sprite data
LDA #$00 lda #$00
LDX #$00 ldx #$00
sprite_clear1: sprite_clear1:
STA $0200, X ; $0200 = sprite sta $0200, X ; $0200 = sprite
INX inx
BNE sprite_clear1 bne sprite_clear1
; initialize Sprite 0 ; initialize Sprite 0
LDA #$70 lda #$70
STA $0200 ; sprite Y coordinate sta $0200 ; sprite Y coordinate
LDA #$01 lda #$01
STA $0201 ; sprite + 1Pattern number sta $0201 ; sprite + 1Pattern number
STA $0203 ; sprite+3 X coordinate sta $0203 ; sprite+3 X coordinate
; sprite+2, color, stays 0. ; sprite+2, color, stays 0.
; Set initial value of dx ; Set initial value of dx
LDA #$01 lda #$01
STA $00 ; dx = $00 sta $00 ; dx = $00
RTS rts
; Load palette into $3F00 ; Load palette into $3F00
load_palette: load_palette:
LDA #$3F lda #$3F
LDX #$00 ldx #$00
STA $2006 sta $2006
STX $2006 stx $2006
loady_loop: loady_loop:
LDA palette, X lda palette, X
STA $2007 sta $2007
INX inx
CPX #$20 cpx #$20
BNE loady_loop bne loady_loop
RTS rts
; Jam some text into the first name table (at $2400, thanks to mirroring) ; Jam some text into the first name table (at $2400, thanks to mirroring)
load_name_tables: load_name_tables:
LDY #$00 ldy #$00
LDX #$04 ldx #$04
LDA #<bg lda #<bg
STA $10 sta $10
LDA #>bg lda #>bg
STA $11 sta $11
LDA #$24 lda #$24
STA $2006 sta $2006
LDA #$00 lda #$00
STA $2006 sta $2006
go_back: go_back:
LDA ($10), Y lda ($10), Y
STA $2007 sta $2007
INY iny
BNE go_back bne go_back
INC $11 inc $11
DEX dex
BNE go_back bne go_back
RTS rts
; Clear out the Name Table at $2800 (where we already are. Yay.) ; Clear out the Name Table at $2800 (where we already are. Yay.)
LDY #$00 ldy #$00
LDX #$04 ldx #$04
LDA #$00 lda #$00
back: back:
STA $2007 sta $2007
INY iny
BNE back bne back
DEX dex
BNE back bne back
RTS rts
init_scrolling: init_scrolling:
LDA #$F0 lda #$F0
STA $02 ; scroll sta $02 ; scroll
RTS rts
update_sprite: update_sprite:
LDA #>sprite lda #>sprite
STA $4014 ; Jam page $200-$2FF into SPR-RAM sta $4014 ; Jam page $200-$2FF into SPR-RAM
LDA $05 ; sprite+3 Is this right??? lda $05 ; sprite+3 Is this right???
BEQ hit_left beq hit_left
CMP #$F7 cmp #$F7
BNE edge_done bne edge_done
; Hit right ; Hit right
LDX #$FF ldx #$FF
STX $00 ; dx stx $00 ; dx
JSR high_c jsr high_c
JMP edge_done jmp edge_done
hit_left: hit_left:
LDX #$01 ldx #$01
STX $00 ; dx stx $00 ; dx
JSR high_c jsr high_c
edge_done: ; update X and store it. edge_done: ; update X and store it.
CLC clc
ADC $00 ; dx adc $00 ; dx
STA $05 ; sprite+3 Is this right? sta $05 ; sprite+3 Is this right?
RTS rts
react_to_input: react_to_input:
LDA #$01 ; strobe joypad lda #$01 ; strobe joypad
STA $4016 sta $4016
LDA #$00 lda #$00
STA $4016 sta $4016
LDA $4016 ; Is the A button down? lda $4016 ; Is the A button down?
AND #$01 AND #$01
BEQ not_a beq not_a
LDX $01 ; a ldx $01 ; a
BNE a_done ; Only react if the A button wasn't down last time. bne a_done ; Only react if the A button wasn't down last time.
STA $01 ; Store the 1 in local variable 'a' so that we this is sta $01 ; Store the 1 in local variable 'a' so that we this is
JSR reverse_dx ; only called once per press. jsr reverse_dx ; only called once per press.
JMP a_done jmp a_done
not_a: not_a:
STA $01 ; A has been released, so put that zero into 'a'. sta $01 ; A has been released, so put that zero into 'a'.
a_done: a_done:
LDA $4016 ; B does nothing lda $4016 ; B does nothing
LDA $4016 ; Select does nothing lda $4016 ; Select does nothing
LDA $4016 ; Start does nothing lda $4016 ; Start does nothing
LDA $4016 ; Up lda $4016 ; Up
AND #$01 and #$01
BEQ not_up beq not_up
LDX sprite ; Load Y value ldx sprite ; Load Y value
CPX #$07 cpx #$07
BEQ not_up ; No going past the top of the screen beq not_up ; No going past the top of the screen
DEX dex
STX sprite stx sprite
not_up: lda $4016 ; Down not_up: lda $4016 ; Down
AND #$01 and #$01
BEQ not_dn beq not_dn
LDX sprite ldx sprite
CPX #$DF ; No going past the bottom of the screen. cpx #$DF ; No going past the bottom of the screen.
BEQ not_dn beq not_dn
INX inx
STX sprite stx sprite
not_dn: not_dn:
RTS ; Ignore left and right, we don't use 'em rts ; Ignore left and right, we don't use 'em
reverse_dx: reverse_dx:
LDA #$FF lda #$FF
EOR $00 ; dx eor $00 ; dx
CLC clc
ADC #$01 adc #$01
STA $00 ; dx sta $00 ; dx
JSR low_c jsr low_c
RTS rts
scroll_screen: scroll_screen:
LDX #$00 ; Reset VRAM ldx #$00 ; Reset VRAM
STX $2006 stx $2006
STX $2006 stx $2006
LDX $02 ; scroll ; Do we need to scroll at all? ldx $02 ; scroll ; Do we need to scroll at all?
BEQ no_scroll beq no_scroll
DEX dex
STX $02 ; scroll stx $02 ; scroll
LDA #$00 lda #$00
STA $2005 ; Write 0 for Horiz. Scroll value sta $2005 ; Write 0 for Horiz. Scroll value
STX $2005 ; Write the value of 'scroll' for Vert. Scroll value STX $2005 ; Write the value of 'scroll' for Vert. Scroll value
no_scroll: no_scroll:
RTS rts
low_c: low_c:
PHA pha
LDA #$84 lda #$84
STA $4000 sta $4000
LDA #$AA lda #$AA
STA $4002 sta $4002
LDA #$09 lda #$09
STA $4003 sta $4003
PLA pla
RTS rts
high_c: high_c:
PHA pha
LDA #$86 lda #$86
STA $4000 sta $4000
LDA #$69 lda #$69
STA $4002 sta $4002
LDA #$08 lda #$08
STA $4003 sta $4003
PLA pla
RTS rts
vblank: vblank:
JSR scroll_screen jsr scroll_screen
JSR update_sprite jsr update_sprite
JSR react_to_input jsr react_to_input
irq: irq:
RTI rti
; palette data ; palette data
palette: palette: