From eaa80000b2e37bab755ee7d3035ac54c1077f5d9 Mon Sep 17 00:00:00 2001 From: Safiire Date: Sun, 22 Feb 2015 18:49:24 -0800 Subject: [PATCH] Can use lower case instruction names and hex now --- README.md | 3 +- lib/instruction.rb | 48 ++++-- scroll.asm | 374 ++++++++++++++++++++++----------------------- 3 files changed, 221 insertions(+), 204 deletions(-) diff --git a/README.md b/README.md index 717f48a..b12bccb 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,6 @@ An NES assembler for the 6502 microprocessor written in Ruby ![Scrolling NES Demo](assembler_demo.png) Some Todos: - - Allow lower case mnemonics in source code - Understand how to deal with various mappers - Understand how to create multiple banks - Get an NSF file playing @@ -36,8 +35,10 @@ An NES assembler for the 6502 microprocessor written in Ruby - Support binary literals ie %10101010 - Anonymous Label support, (maybe, not sure if I like the idea) - Give this project a better name. + - Create an interactive read eval compile loop? Some new additions: + - Lower case mnemonics and hex digits - Ported NES101 tutor to this assembler. - Added msb and lsb byte selectors on address labels - added .org directive diff --git a/lib/instruction.rb b/lib/instruction.rb index a967265..5289caa 100644 --- a/lib/instruction.rb +++ b/lib/instruction.rb @@ -12,12 +12,14 @@ module Assembler6502 class InvalidAddressingMode < StandardError; end class AddressOutOfRange < StandardError; end - Mnemonic = '([A-Z]{3})' - Hex8 = '\$([A-Z0-9]{2})' - Hex16 = '\$([A-Z0-9]{4})' + Mnemonic = '([A-Za-z]{3})' + Hex8 = '\$([A-Fa-f0-9]{2})' + Hex16 = '\$([A-Fa-f0-9]{4})' Immediate = '\#\$([0-9A-F]{2})' 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 = { :relative => { @@ -49,13 +51,13 @@ module Assembler6502 :zero_page_x => { :example => 'AAA $FF, X', :display => '%s $%.2X, X', - :regex => /^#{Mnemonic}\s+#{Hex8}\s?,\s?X$/ + :regex => /^#{Mnemonic}\s+#{Hex8}\s?,\s?#{XReg}$/ }, :zero_page_y => { :example => 'AAA $FF, Y', :display => '%s $%.2X, Y', - :regex => /^#{Mnemonic}\s+#{Hex8}\s?,\s?Y$/ + :regex => /^#{Mnemonic}\s+#{Hex8}\s?,\s?#{YReg}$/ }, :absolute => { @@ -68,15 +70,15 @@ module Assembler6502 :absolute_x => { :example => 'AAA $FFFF, X', :display => '%s $%.4X, X', - :regex => /^#{Mnemonic}\s+#{Hex16}\s?,\s?X$/, - :regex_label => /^#{Mnemonic}\s+#{Sym}\s?,\s?X$/ + :regex => /^#{Mnemonic}\s+#{Hex16}\s?,\s?#{XReg}$/, + :regex_label => /^#{Mnemonic}\s+#{Sym}\s?,\s?#{XReg}$/ }, :absolute_y => { :example => 'AAA $FFFF, Y', :display => '%s $%.4X, Y', - :regex => /^#{Mnemonic}\s+#{Hex16}\s?,\s?Y$/, - :regex_label => /^#{Mnemonic}\s+#{Sym}\s?,\s?Y$/ + :regex => /^#{Mnemonic}\s+#{Hex16}\s?,\s?#{YReg}$/, + :regex_label => /^#{Mnemonic}\s+#{Sym}\s?,\s?#{YReg}$/ }, :indirect => { @@ -89,15 +91,15 @@ module Assembler6502 :indirect_x => { :example => 'AAA ($FF, X)', :display => '%s ($%.2X, X)', - :regex => /^#{Mnemonic}\s+\(#{Hex8}\s?,\s?X\)$/, - :regex_label => /^#{Mnemonic}\s+\(#{Sym}\s?,\s?X\)$/ + :regex => /^#{Mnemonic}\s+\(#{Hex8}\s?,\s?#{XReg}\)$/, + :regex_label => /^#{Mnemonic}\s+\(#{Sym}\s?,\s?#{XReg}\)$/ }, :indirect_y => { :example => 'AAA ($FF), Y)', :display => '%s ($%.2X), Y', - :regex => /^#{Mnemonic}\s+\(#{Hex8}\)\s?,\s?Y$/, - :regex_label => /^#{Mnemonic}\s+\(#{Sym}\)\s?,\s?Y$/ + :regex => /^#{Mnemonic}\s+\(#{Hex8}\)\s?,\s?#{YReg}$/, + :regex_label => /^#{Mnemonic}\s+\(#{Sym}\)\s?,\s?#{YReg}$/ } } @@ -235,9 +237,9 @@ module Assembler6502 arg_16 = symbols[@arg].address @arg = case @byte_selector when :> - (arg_16 & 0xFF00) >> 8 + high_byte(arg_16) when :< - arg_16 & 0xFF + low_byte(arg_16) end return @arg end @@ -301,6 +303,20 @@ module Assembler6502 [integer & 0x00FF, (integer & 0xFF00) >> 8] 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 diff --git a/scroll.asm b/scroll.asm index b075838..f4cf7a8 100644 --- a/scroll.asm +++ b/scroll.asm @@ -30,282 +30,282 @@ sprite: .org $C000 reset: - SEI - CLD + sei + cld ; Wait two VBLANKs. wait_vb1: - LDA $2002 - BPL wait_vb1 + lda $2002 + bpl wait_vb1 wait_vb2: - LDA $2002 - BPL wait_vb2 + lda $2002 + bpl wait_vb2 ; Clear out RAM. - LDA #$00 - LDX #$00 + lda #$00 + ldx #$00 clear_segments: - STA $00, X - STA $0100, X - STA $0200, X - STA $0300, X - STA $0400, X - STA $0500, X - STA $0600, X - STA $0700, X - INX - BNE clear_segments + sta $00, X + sta $0100, X + sta $0200, X + sta $0300, X + sta $0400, X + sta $0500, X + sta $0600, X + sta $0700, X + inx + bne clear_segments ; Reset the stack pointer. - LDX #$FF - TXS + ldx #$FF + txs ; Disable all graphics. - LDA #$00 - STA $2000 - STA $2001 + lda #$00 + sta $2000 + sta $2001 - JSR init_graphics - JSR init_input - JSR init_sound + jsr init_graphics + jsr init_input + jsr init_sound ; Set basic PPU registers. Load background from $0000, ; sprites from $1000, and the name table from $2000. - LDA #$88 - STA $2000 - LDA #$1E - STA $2001 - CLI + lda #$88 + sta $2000 + lda #$1E + sta $2001 + cli ; Transfer control to the VBLANK routines. forever: - JMP forever + jmp forever init_graphics: - JSR init_sprites - JSR load_palette - JSR load_name_tables - JSR init_scrolling - RTS + jsr init_sprites + jsr load_palette + jsr load_name_tables + jsr init_scrolling + rts init_input: ; The A button starts out not-pressed. - LDA #$00 - STA $01 ; $01 = A button - RTS + lda #$00 + sta $01 ; $01 = A button + rts init_sound: ; initialize sound hardware - LDA #$01 - STA $4015 - LDA #$00 - STA $4001 - LDA #$40 - STA $4017 - RTS + lda #$01 + sta $4015 + lda #$00 + sta $4001 + lda #$40 + sta $4017 + rts init_sprites: ; Clear page #2, which we'll use to hold sprite data - LDA #$00 - LDX #$00 + lda #$00 + ldx #$00 sprite_clear1: - STA $0200, X ; $0200 = sprite - INX - BNE sprite_clear1 + sta $0200, X ; $0200 = sprite + inx + bne sprite_clear1 ; initialize Sprite 0 - LDA #$70 - STA $0200 ; sprite Y coordinate - LDA #$01 - STA $0201 ; sprite + 1Pattern number - STA $0203 ; sprite+3 X coordinate + lda #$70 + sta $0200 ; sprite Y coordinate + lda #$01 + sta $0201 ; sprite + 1Pattern number + sta $0203 ; sprite+3 X coordinate ; sprite+2, color, stays 0. ; Set initial value of dx - LDA #$01 - STA $00 ; dx = $00 - RTS + lda #$01 + sta $00 ; dx = $00 + rts ; Load palette into $3F00 load_palette: - LDA #$3F - LDX #$00 - STA $2006 - STX $2006 + lda #$3F + ldx #$00 + sta $2006 + stx $2006 loady_loop: - LDA palette, X - STA $2007 - INX - CPX #$20 - BNE loady_loop - RTS + lda palette, X + sta $2007 + inx + cpx #$20 + bne loady_loop + rts ; Jam some text into the first name table (at $2400, thanks to mirroring) load_name_tables: - LDY #$00 - LDX #$04 - LDA #bg - STA $11 - LDA #$24 - STA $2006 - LDA #$00 - STA $2006 + ldy #$00 + ldx #$04 + lda #bg + sta $11 + lda #$24 + sta $2006 + lda #$00 + sta $2006 go_back: - LDA ($10), Y - STA $2007 - INY - BNE go_back - INC $11 - DEX - BNE go_back - RTS + lda ($10), Y + sta $2007 + iny + bne go_back + inc $11 + dex + bne go_back + rts ; Clear out the Name Table at $2800 (where we already are. Yay.) - LDY #$00 - LDX #$04 - LDA #$00 + ldy #$00 + ldx #$04 + lda #$00 back: - STA $2007 - INY - BNE back - DEX - BNE back - RTS + sta $2007 + iny + bne back + dex + bne back + rts init_scrolling: - LDA #$F0 - STA $02 ; scroll - RTS + lda #$F0 + sta $02 ; scroll + rts update_sprite: - LDA #>sprite - STA $4014 ; Jam page $200-$2FF into SPR-RAM + lda #>sprite + sta $4014 ; Jam page $200-$2FF into SPR-RAM - LDA $05 ; sprite+3 Is this right??? - BEQ hit_left - CMP #$F7 - BNE edge_done + lda $05 ; sprite+3 Is this right??? + beq hit_left + cmp #$F7 + bne edge_done ; Hit right - LDX #$FF - STX $00 ; dx - JSR high_c - JMP edge_done + ldx #$FF + stx $00 ; dx + jsr high_c + jmp edge_done hit_left: - LDX #$01 - STX $00 ; dx - JSR high_c + ldx #$01 + stx $00 ; dx + jsr high_c edge_done: ; update X and store it. - CLC - ADC $00 ; dx - STA $05 ; sprite+3 Is this right? - RTS + clc + adc $00 ; dx + sta $05 ; sprite+3 Is this right? + rts react_to_input: - LDA #$01 ; strobe joypad - STA $4016 - LDA #$00 - STA $4016 + lda #$01 ; strobe joypad + sta $4016 + lda #$00 + sta $4016 - LDA $4016 ; Is the A button down? + lda $4016 ; Is the A button down? AND #$01 - BEQ not_a - LDX $01 ; a - 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 - JSR reverse_dx ; only called once per press. - JMP a_done + beq not_a + ldx $01 ; a + 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 + jsr reverse_dx ; only called once per press. + jmp a_done 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: - LDA $4016 ; B does nothing - LDA $4016 ; Select does nothing - LDA $4016 ; Start does nothing - LDA $4016 ; Up - AND #$01 - BEQ not_up - LDX sprite ; Load Y value - CPX #$07 - BEQ not_up ; No going past the top of the screen - DEX - STX sprite + lda $4016 ; B does nothing + lda $4016 ; Select does nothing + lda $4016 ; Start does nothing + lda $4016 ; Up + and #$01 + beq not_up + ldx sprite ; Load Y value + cpx #$07 + beq not_up ; No going past the top of the screen + dex + stx sprite not_up: lda $4016 ; Down - AND #$01 - BEQ not_dn - LDX sprite - CPX #$DF ; No going past the bottom of the screen. - BEQ not_dn - INX - STX sprite + and #$01 + beq not_dn + ldx sprite + cpx #$DF ; No going past the bottom of the screen. + beq not_dn + inx + stx sprite not_dn: - RTS ; Ignore left and right, we don't use 'em + rts ; Ignore left and right, we don't use 'em reverse_dx: - LDA #$FF - EOR $00 ; dx - CLC - ADC #$01 - STA $00 ; dx - JSR low_c - RTS + lda #$FF + eor $00 ; dx + clc + adc #$01 + sta $00 ; dx + jsr low_c + rts scroll_screen: - LDX #$00 ; Reset VRAM - STX $2006 - STX $2006 + ldx #$00 ; Reset VRAM + stx $2006 + stx $2006 - LDX $02 ; scroll ; Do we need to scroll at all? - BEQ no_scroll - DEX - STX $02 ; scroll - LDA #$00 - STA $2005 ; Write 0 for Horiz. Scroll value + ldx $02 ; scroll ; Do we need to scroll at all? + beq no_scroll + dex + stx $02 ; scroll + lda #$00 + sta $2005 ; Write 0 for Horiz. Scroll value STX $2005 ; Write the value of 'scroll' for Vert. Scroll value no_scroll: - RTS + rts low_c: - PHA - LDA #$84 - STA $4000 - LDA #$AA - STA $4002 - LDA #$09 - STA $4003 - PLA - RTS + pha + lda #$84 + sta $4000 + lda #$AA + sta $4002 + lda #$09 + sta $4003 + pla + rts high_c: - PHA - LDA #$86 - STA $4000 - LDA #$69 - STA $4002 - LDA #$08 - STA $4003 - PLA - RTS + pha + lda #$86 + sta $4000 + lda #$69 + sta $4002 + lda #$08 + sta $4003 + pla + rts vblank: - JSR scroll_screen - JSR update_sprite - JSR react_to_input + jsr scroll_screen + jsr update_sprite + jsr react_to_input irq: - RTI + rti ; palette data palette: