From ee643af3ef311d3aa6bdb56064d62a5cfdd5ec31 Mon Sep 17 00:00:00 2001 From: Safiire Date: Sun, 22 Mar 2015 15:52:13 -0700 Subject: [PATCH] Binary literals are now working --- examples/demo.asm | 52 +++++++++++++++++++++++++++++---------------- examples/mario2.asm | 34 +++++++++++++++++++++-------- lib/instruction.rb | 44 +++++++++++++++++++++----------------- lib/parser.rb | 1 + lib/regexes.rb | 33 ++++++++++++++++++++++++++++ nes_lib/nes.sym | 6 +++--- 6 files changed, 120 insertions(+), 50 deletions(-) create mode 100644 lib/regexes.rb diff --git a/examples/demo.asm b/examples/demo.asm index 8617cb1..73f4c2e 100644 --- a/examples/demo.asm +++ b/examples/demo.asm @@ -65,17 +65,17 @@ bpl wait_vb2 ; Now we want to initialize the hardware to a known state - lda #$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 + sta $0, x + sta $100, x + sta $200, x + sta $300, x + sta $400, x + sta $500, x + sta $600, x + sta $700, x inx bne clear_segments @@ -85,8 +85,8 @@ ; Disable all graphics and vblank nmi lda #$00 - sta nes.ppu.control1 - sta nes.ppu.control2 + sta nes.ppu.control + sta nes.ppu.mask jsr init_graphics jsr init_input @@ -101,14 +101,30 @@ ;;;; -; Set basic PPU registers. Load background from $0000, -; sprites from $1000, and the name table from $2000. -; These literals would make more sense in binary. +; nes.ppu.control: bitpattern is VPHB SINN +; V: NMI enable +; P: PPU master/slave (this does nothing on the NES) +; H: Sprite height 0 = 8x8, 1 = 8x16 +; B: Background pattern table address (0: $0000; 1: $1000) +; S: Sprite pattern table address for 8x8 sprites (0: $0000; 1: $1000; ignored in 8x16 mode) +; I: VRAM address increment per CPU read/write of nes.vram.io (0: add 1, going across; 1: add 32, going down) +; NN: Base nametable address (0 = $2000; 1 = $2400; 2 = $2800; 3 = $2C00) +; +; Equivalently, bits 0 and 1 are the most significant bit of the scrolling coordinates +; +; nes.ppu.mask: bitpattern is BGRs bMmG +; BGR: Color emphasis bits +; s: Sprite enable +; b: Background enable +; M: Background left column enable +; m: Sprite left column enable +; G: Greyscale +; .scope init_ppu - lda #$88 - sta nes.ppu.control1 - lda #$1E - sta nes.ppu.control2 + lda #%10001000 ; NMI enable, 8x8 tile, Background: $0000, Sprites: $1000, Address increment: 1, Nametable: $2000 + sta nes.ppu.control + lda #%00011110 ; No color emphasis, Enable sprites, Enable Background, Enable sprite and bg left column, no greyscale + sta nes.ppu.mask rts . diff --git a/examples/mario2.asm b/examples/mario2.asm index 786c405..8d7d946 100644 --- a/examples/mario2.asm +++ b/examples/mario2.asm @@ -66,8 +66,8 @@ ; Disable all graphics and vblank nmi lda #$00 - sta nes.ppu.control1 - sta nes.ppu.control2 + sta nes.ppu.control + sta nes.ppu.mask ; Call subroutines to initialize the graphics jsr load_palette @@ -83,14 +83,30 @@ ;;;; -; Set basic PPU registers. Load background from $0000, -; sprites from $1000, and the name table from $2000. -; These literals would make more sense in binary. +; nes.ppu.control: bitpattern is VPHB SINN +; V: NMI enable +; P: PPU master/slave (this does nothing on the NES) +; H: Sprite height 0 = 8x8, 1 = 8x16 +; B: Background pattern table address (0: $0000; 1: $1000) +; S: Sprite pattern table address for 8x8 sprites (0: $0000; 1: $1000; ignored in 8x16 mode) +; I: VRAM address increment per CPU read/write of nes.vram.io (0: add 1, going across; 1: add 32, going down) +; NN: Base nametable address (0 = $2000; 1 = $2400; 2 = $2800; 3 = $2C00) +; +; Equivalently, bits 0 and 1 are the most significant bit of the scrolling coordinates +; +; nes.ppu.mask: bitpattern is BGRs bMmG +; BGR: Color emphasis bits +; s: Sprite enable +; b: Background enable +; M: Background left column enable +; m: Sprite left column enable +; G: Greyscale +; .scope init_ppu - lda #$88 - sta nes.ppu.control1 - lda #$1E - sta nes.ppu.control2 + lda #%10001000 ; NMI enable, 8x8 tile, Background: $0000, Sprites: $1000, Address increment: 1, Nametable: $2000 + sta nes.ppu.control + lda #%00011110 ; No color emphasis, Enable sprites, Enable Background, Enable sprite and bg left column, no greyscale + sta nes.ppu.mask rts . diff --git a/lib/instruction.rb b/lib/instruction.rb index 309e379..55a11f3 100644 --- a/lib/instruction.rb +++ b/lib/instruction.rb @@ -1,4 +1,5 @@ require_relative 'opcodes' +require_relative 'regexes' module Assembler6502 @@ -14,14 +15,8 @@ module Assembler6502 class AddressOutOfRange < StandardError; end class ArgumentTooLarge < StandardError; end - Mnemonic = '([A-Za-z]{3})' - Hex8 = '\$([A-Fa-f0-9]{2})' - Hex16 = '\$([A-Fa-f0-9]{4})' - Immediate = '\#\$([0-9A-Fa-f]{2})' - Sym = '([a-zZ-Z_][a-zA-Z0-9_\.]+)' - Branches = '(BPL|BMI|BVC|BVS|BCC|BCS|BNE|BEQ|bpl|bmi|bvc|bvs|bcc|bcs|bne|beq)' - XReg = '[Xx]' - YReg = '[Yy]' + ## Include Regexes + include Regexes AddressingModes = { :relative => { @@ -47,63 +42,63 @@ module Assembler6502 :zero_page => { :example => 'AAA $FF', :display => '%s $%.2X', - :regex => /^#{Mnemonic}\s+#{Hex8}$/, + :regex => /^#{Mnemonic}\s+#{Num8}$/, :regex_label => /^#{Mnemonic}\s+#{Sym}\s+zp$/ }, :zero_page_x => { :example => 'AAA $FF, X', :display => '%s $%.2X, X', - :regex => /^#{Mnemonic}\s+#{Hex8}\s?,\s?#{XReg}$/, + :regex => /^#{Mnemonic}\s+#{Num8}\s?,\s?#{XReg}$/, :regex_label => /^#{Mnemonic}\s+#{Sym}\s?,\s?#{XReg}\s+zp$/ }, :zero_page_y => { :example => 'AAA $FF, Y', :display => '%s $%.2X, Y', - :regex => /^#{Mnemonic}\s+#{Hex8}\s?,\s?#{YReg}$/, + :regex => /^#{Mnemonic}\s+#{Num8}\s?,\s?#{YReg}$/, :regex_label => /^#{Mnemonic}\s+#{Sym}\s?,\s?#{YReg} zp$/ }, :absolute => { :example => 'AAA $FFFF', :display => '%s $%.4X', - :regex => /^#{Mnemonic}\s+#{Hex16}$/, + :regex => /^#{Mnemonic}\s+#{Num16}$/, :regex_label => /^#{Mnemonic}\s+#{Sym}$/ }, :absolute_x => { :example => 'AAA $FFFF, X', :display => '%s $%.4X, X', - :regex => /^#{Mnemonic}\s+#{Hex16}\s?,\s?#{XReg}$/, + :regex => /^#{Mnemonic}\s+#{Num16}\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?#{YReg}$/, + :regex => /^#{Mnemonic}\s+#{Num16}\s?,\s?#{YReg}$/, :regex_label => /^#{Mnemonic}\s+#{Sym}\s?,\s?#{YReg}$/ }, :indirect => { :example => 'AAA ($FFFF)', :display => '%s ($%.4X)', - :regex => /^#{Mnemonic}\s+\(#{Hex16}\)$/, + :regex => /^#{Mnemonic}\s+\(#{Num16}\)$/, :regex_label => /^#{Mnemonic}\s+\(#{Sym}\)$/ }, :indirect_x => { :example => 'AAA ($FF, X)', :display => '%s ($%.2X, X)', - :regex => /^#{Mnemonic}\s+\(#{Hex8}\s?,\s?#{XReg}\)$/, + :regex => /^#{Mnemonic}\s+\(#{Num8}\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?#{YReg}$/, + :regex => /^#{Mnemonic}\s+\(#{Num8}\)\s?,\s?#{YReg}$/, :regex_label => /^#{Mnemonic}\s+\(#{Sym}\)\s?,\s?#{YReg}$/ } } @@ -123,9 +118,18 @@ module Assembler6502 unless match_data.nil? ## We must have a straight instruction without symbols, construct ## an Instruction from the match_data, and return it - _, op, arg = match_data.to_a - arg = arg.to_i(16) unless arg.nil? - return Instruction.new(op, arg, mode) + _, op, arg_hex, arg_bin = match_data.to_a + + ## Until I think of something better, it seems that the union regex + ## puts a hexidecimal argument in one capture, and a binary in the next + ## This is annoying, but still not as annoying as using Treetop to parse + if arg_hex != nil + return Instruction.new(op, arg_hex.to_i(16), mode) + elsif arg_bin != nil + return Instruction.new(op, arg_bin.to_i(2), mode) + else + return Instruction.new(op, nil, mode) + end else ## Can this addressing mode even use labels? diff --git a/lib/parser.rb b/lib/parser.rb index a6042f4..c570c2d 100644 --- a/lib/parser.rb +++ b/lib/parser.rb @@ -16,6 +16,7 @@ module Assembler6502 require_relative 'directives/space' + #### ## This class determines what sort of line of code we ## are dealing with, parses one line, and returns an diff --git a/lib/regexes.rb b/lib/regexes.rb new file mode 100644 index 0000000..8cff0b5 --- /dev/null +++ b/lib/regexes.rb @@ -0,0 +1,33 @@ + + +module Assembler6502 + + #### + ## All the regexes used to parse in one module + module Regexes + ## Mnemonics + Mnemonic = '([A-Za-z]{3})' + Branches = '(BPL|BMI|BVC|BVS|BCC|BCS|BNE|BEQ|bpl|bmi|bvc|bvs|bcc|bcs|bne|beq)' + + ## Numeric Literals + Hex8 = '\$([A-Fa-f0-9]{1,2})' + Hex16 = '\$([A-Fa-f0-9]{3,4})' + + Bin8 = '%([01]{1,8})' + Bin16 = '%([01]{9,16})' + + Num8 = Regexp.union(Regexp.new(Hex8), Regexp.new(Bin8)).to_s + Num16 = Regexp.union(Regexp.new(Hex16),Regexp.new(Bin16)).to_s + + Immediate = "\##{Num8}" + + ## Symbols, must begin with a letter, and supports dot syntax + Sym = '([a-zA-Z][a-zA-Z\d_\.]*)' + + + ## The X or Y register + XReg = '[Xx]' + YReg = '[Yy]' + end + +end diff --git a/nes_lib/nes.sym b/nes_lib/nes.sym index 7c722bb..cf20242 100644 --- a/nes_lib/nes.sym +++ b/nes_lib/nes.sym @@ -13,9 +13,9 @@ .scope nes .scope ppu .org $2000 - .space control1 1 ; $2000 - .space control2 1 ; $2001 - .space status 1 ; $2002 + .space control 1 ; $2000 + .space mask 1 ; $2001 + .space status 1 ; $2002 .org $2005 .space scroll 1 ; $2005 .