From 404934479fb1fe897a61b5d6d3571a5ef95ded6e Mon Sep 17 00:00:00 2001 From: Safiire <safiire@gmail.com> Date: Sun, 22 Feb 2015 05:59:03 -0800 Subject: [PATCH] Intermediate commit --- data/opcodes.yaml | 2 +- lib/assembler.rb | 73 ++++++++++++++++++++++++++++++++++++----- lib/directive.rb | 15 +++++++-- nsf_player.asm | 82 ++++++++++++++++++++++++++++++++++++++++++++++ some_beeps.nsf | Bin 0 -> 5931 bytes whatever.inc | 2 ++ 6 files changed, 162 insertions(+), 12 deletions(-) create mode 100644 nsf_player.asm create mode 100644 some_beeps.nsf create mode 100644 whatever.inc diff --git a/data/opcodes.yaml b/data/opcodes.yaml index 43e14aa..ecbb676 100644 --- a/data/opcodes.yaml +++ b/data/opcodes.yaml @@ -280,7 +280,7 @@ :boundry_add: false :cpy: - :description: "ComPare X register" + :description: "ComPare Y register" :flags: - :s - :c diff --git a/lib/assembler.rb b/lib/assembler.rb index 3475179..bb58969 100644 --- a/lib/assembler.rb +++ b/lib/assembler.rb @@ -5,6 +5,9 @@ module Assembler6502 ## Let's simulate the entire 0xFFFF addressable memory space ## In the NES, and create reading and writing methods for it. class MemorySpace + INESHeaderSize = 0x10 + ProgROMSize = 0x4000 + CharROMSize = 0x2000 #### ## Create a completely zeroed memory space @@ -84,7 +87,6 @@ module Assembler6502 fail(SyntaxError, "Already got ines header") unless @ines_header.nil? @ines_header = parsed_line puts "\tGot iNES Header" - #memory.write(0x0, parsed_line.emit_bytes) when Org address = parsed_line.address @@ -99,22 +101,22 @@ module Assembler6502 puts "\tSaving instruction with unresolved symbols #{parsed_line}, for second pass" unresolved_instructions << parsed_line else - puts "\tWriting instruction #{parsed_line} to memory" + puts "\tWriting instruction #{parsed_line}" memory.write(parsed_line.address, parsed_line.emit_bytes) end address += parsed_line.length - puts "\tAdvanced address to %X" % address when IncBin - fail("\tI Don't support .incbin yet") - + puts "\t Including binary file #{parsed_line.filepath}" + memory.write(parsed_line.address, parsed_line.emit_bytes) + address += parsed_line.size when DW if parsed_line.unresolved_symbols? - puts "\tSaving .dw directive with unresolved symbols #{parsed_line}, for second pass" + puts "\tSaving #{parsed_line} directive with unresolved symbols, for second pass" unresolved_instructions << parsed_line else - puts "\tWriting .dw #{parsed_line.inspect} to memory" + puts "\tWriting #{parsed_line} to memory" memory.write(address, parsed_line.emit_bytes) end address += 2 @@ -136,11 +138,12 @@ module Assembler6502 end end - print "Second pass: Resolving Symbols..." + puts "Second pass: Resolving Symbols..." unresolved_instructions.each do |instruction| if instruction.unresolved_symbols? instruction.resolve_symbols(labels) end + puts "\tResolved #{instruction}" memory.write(instruction.address, instruction.emit_bytes) end puts 'Done' @@ -155,7 +158,7 @@ module Assembler6502 ## I am guessing the ROM size should be 1 bank of 16KB cartridge ROM ## plus the 16 byte iNES header. If the ROM is written into memory ## beginning at 0xC000, this should reach right up to the interrupt vectors - def assemble + def assemble_old virtual_memory = assemble_in_virtual_memory ## First we need to be sure we have an iNES header @@ -190,6 +193,58 @@ module Assembler6502 #nes_rom.emit_bytes end + + #### + ## Another try at using the header to decide which segments + ## go into the final ROM image, and which order. + def assemble + virtual_memory = assemble_in_virtual_memory + + ## First we need to be sure we have an iNES header + fail(INESHeaderNotFound) if @ines_header.nil? + + ## Now, we should decide how big the ROM image will be. + ## And reserve memory build the image in + nes_rom_size = MemorySpace::INESHeaderSize + nes_rom_size += @ines_header.prog * MemorySpace::ProgROMSize + nes_rom_size += @ines_header.char * MemorySpace::CharROMSize + nes_rom = MemorySpace.new(nes_rom_size) + puts "ROM will be #{nes_rom_size} bytes" + + ## Write the ines header to the ROM + nes_rom.write(0x0, @ines_header.emit_bytes) + puts "Wrote 16 byte ines header" + + ## If prog rom is >= 1 write the 16kb chunk from 0x8000 + if @ines_header.prog >= 1 + nes_rom.write(0x10, virtual_memory.read(0x8000, MemorySpace::ProgROMSize)) + puts "Wrote 16KB byte prog rom 1" + end + + ## If prog rom is == 2 write the 16kb chunk from 0xC000 + if @ines_header.prog == 2 + nes_rom.write(0x10 + 0x4000, virtual_memory.read(0xC000, MemorySpace::ProgROMSize)) + puts "Wrote 16KB byte prog rom 2" + end + fail("Can only have 2 prog rom slots") if @ines_header.prog > 2 + + ## If char rom is >= 1 write the 8kb chunk from 0x0000 + if @ines_header.char >= 1 + char_start = 0x10 + (@ines_header.prog * MemorySpace::ProgROMSize) + nes_rom.write(char_start, virtual_memory.read(0x0000, MemorySpace::CharROMSize)) + puts "Wrote 8KB byte char rom 1" + end + + ## If char rom is == 2 write the 8kb chunk from 0x2000 + if @ines_header.char >= 1 + char_start = 0x10 + (@ines_header.prog * MemorySpace::ProgROMSize) + MemorySpace::CharROMSize + nes_rom.write(char_start, virtual_memory.read(0x2000, MemorySpace::CharROMSize)) + puts "Wrote 8KB byte char rom 2" + end + + nes_rom.emit_bytes + end + end end diff --git a/lib/directive.rb b/lib/directive.rb index 94c15e9..822d8e1 100644 --- a/lib/directive.rb +++ b/lib/directive.rb @@ -49,12 +49,15 @@ module Assembler6502 #### ## This is to include a binary file class IncBin + attr_reader :address, :filepath class FileNotFound < StandardError; end #### ## Initialize with a file path - def initialize(filepath) + def initialize(filepath, address) + @filepath = filepath + @address = address unless File.exists?(filepath) fail(FileNotFound, ".incbin can't find #{filepath}") end @@ -97,6 +100,14 @@ module Assembler6502 end end + def to_s + if @value.kind_of?(Symbol) + sprintf("$%.4X | .dw #{@value}", @address) + else + sprintf("$%.4X | .dw $%.4X", @address, @value) + end + end + def emit_bytes fail('Need to resolve symbol in .dw directive') if unresolved_symbols? [@value & 0xFFFF].pack('S').bytes @@ -155,7 +166,7 @@ module Assembler6502 Org.new($1.to_i(16)) when /^\.incbin "([^"]+)"$/ - IncBin.new($1) + IncBin.new($1, address) when /^\.dw\s+\$([0-9A-F]{1,4})$/ DW.new($1.to_i(16), address) diff --git a/nsf_player.asm b/nsf_player.asm new file mode 100644 index 0000000..92b0ae1 --- /dev/null +++ b/nsf_player.asm @@ -0,0 +1,82 @@ +; Create an iNES header +.ines {"prog": 2, "char": 0, "mapper": 0, "mirror": 1} + +; The supermario.nsf file is 17084 bytes, this includes a 0x80 byte header. +; It is supposed to be loaded into memory 0x8000, but we don't want that +; header, so let's include the nsf to 0x8000 - 0x80 so it lines up properly + +.org $7F80 +.incbin "super_mario.nsf" + +; Had to start this prog segment a bit later because the mario nsf is > 16KB +.org $C300 +start: + CLD + SEI + LDA #$00 + STA $2000 + +; Wait for 2 vblanks +wait_vb1: + LDA $2002 + BPL wait_vb1 + +wait_vb2: + LDA $2002 + BPL wait_vb2 + +; Clear out the sound registers + LDA #$00 + LDX #$00 +clear_sound_registers: + STA $4000, X + INX + CPX #$0F + BNE clear_sound_registers + + LDA #$10 + STA $4010 + LDA #$00 + STA $4011 + STA $4012 + STA $4013 + +; Enable sound channels (except DMC) + LDA #$0F + STA $4015 + +; Reset frame counter and clock divider + LDA #$C0 + STA $4017 + +; Set song and NTSC + LDA #$00 ; Song 0 + LDX #$00 ; NTSC + JSR $8000 + +; Enable Vblank NMI + LDA #$80 + STA $2000 + +forever: + JMP forever + +nmi: + LDA $2002 + LDA #$00 + STA $2000 + LDA $80 + STA $2000 + JSR $8000 + RTI + +irq: + RTI + +.ascii "The end of prog2" + +.org $FFFA + .dw nmi + .dw start + .dw irq + diff --git a/some_beeps.nsf b/some_beeps.nsf new file mode 100644 index 0000000000000000000000000000000000000000..eb1ada8721c2efbdf9cc374bff2a31cfded068a8 GIT binary patch literal 5931 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 M{owEVw%ud?A6irrUjP6A literal 0 HcmV?d00001 diff --git a/whatever.inc b/whatever.inc new file mode 100644 index 0000000..856242f --- /dev/null +++ b/whatever.inc @@ -0,0 +1,2 @@ + + ޭޭޭޭޭޭޭޭ \ No newline at end of file