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:
@@ -23,7 +23,6 @@ An NES assembler for the 6502 microprocessor written in Ruby
|
|||||||

|

|
||||||
|
|
||||||
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
|
||||||
|
@@ -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
|
||||||
|
374
scroll.asm
374
scroll.asm
@@ -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:
|
||||||
|
Reference in New Issue
Block a user