From dc60139aaad9befc6d262d031d848f6ffebaaac7 Mon Sep 17 00:00:00 2001 From: Safiire <safiire@gmail.com> Date: Sun, 29 Mar 2015 09:42:40 -0700 Subject: [PATCH] Improvement to the .bytes directive, can now take hex literals, binary literals, and symbols both zero page and 16-bit --- lib/directives/bytes.rb | 65 +++++++++++++++++++++++++++++++++++++---- music_driver.asm | 39 +++++++++++++------------ 2 files changed, 79 insertions(+), 25 deletions(-) diff --git a/lib/directives/bytes.rb b/lib/directives/bytes.rb index 8425998..6e69564 100644 --- a/lib/directives/bytes.rb +++ b/lib/directives/bytes.rb @@ -1,4 +1,5 @@ require_relative '../instruction_base' +require_relative '../regexes.rb' module Assembler6502 @@ -7,6 +8,10 @@ module Assembler6502 ## This directive to include bytes class Bytes < InstructionBase + #### Custom Exceptions + class InvalidByteValue < StandardError; end + + #### ## Try to parse an incbin directive def self.parse(line) @@ -14,11 +19,27 @@ module Assembler6502 return nil if match_data.nil? bytes_array = match_data[1].split(',').map do |byte_string| - number = byte_string.gsub('$', '') - integer = number.to_i(16) - fail(SyntaxError, "#{integer} is too large for one byte") if integer > 0xff - integer - end + + ## Does byte_string represent a numeric literal, or is it a symbol? + ## In numeric captures $2 is always binary, $1 is always hex + + case byte_string.strip + when Regexp.new("^#{Regexes::Num8}$") + $2.nil? ? $1.to_i(16) : $2.to_i(2) + + when Regexp.new("^#{Regexes::Num16}$") + value = $2.nil? ? $1.to_i(16) : $2.to_i(2) + + ## Break value up into two bytes + high = (0xff00 & value) >> 8 + low = (0x00ff & value) + [low, high] + when Regexp.new("^#{Regexes::Sym}$") + $1 + else + fail(InvalidByteValue, byte_string) + end + end.flatten Bytes.new(bytes_array) end @@ -34,7 +55,39 @@ module Assembler6502 #### ## Execute on the assembler def exec(assembler) - assembler.write_memory(@bytes_array) + + promise = assembler.with_saved_state do |saved_assembler| + @bytes_array.map! do |byte| + case byte + when Fixnum + byte + when String + value = saved_assembler.symbol_table.resolve_symbol(byte) + else + fail(InvalidByteValue, byte) + end + end + saved_assembler.write_memory(@bytes_array) + end + + begin + promise.call + rescue SymbolTable::UndefinedSymbol + ## Write the bytes but assume a zero page address for all symbols + ## And just write 0xDE for a placeholder + placeholder_bytes = @bytes_array.map do |byte| + case bytes + when Fixnum + byte + when String + 0xDE + else + fail(InvalidByteValue, byte) + end + end + assembler.write_memory(placeholder_bytes) + return promise + end end diff --git a/music_driver.asm b/music_driver.asm index 37d1422..358ad4e 100644 --- a/music_driver.asm +++ b/music_driver.asm @@ -79,20 +79,6 @@ sta nes.ppu.control sta nes.ppu.mask - ; Initialize sound engine structure - ; To read from $D000, and to write to $40** - lda #>music_buffer - sta sound_engine.stream_read_ptr_hi - lda #<music_buffer - sta sound_engine.stream_read_ptr_lo - - ; Make the first delta happen immediately - lda #$01 - sta sound_engine.delta - - lda #$40 - sta sound_engine.stream_write_ptr_hi - jsr init_sound ; Resume interrupts and NMI and loop here forever @@ -106,13 +92,28 @@ ;;;; ; Initialize the APU to enable Pulse1 -; Bitfield: ---D NT21 .scope init_sound lda #$00 - sta nes.apu.pulse1.control - sta nes.apu.pulse1.ramp_control - sta nes.apu.pulse1.ft - sta nes.apu.pulse1.ct + ldy #$00 + clear_apu: + sta nes.apu, y + iny + cpy #$10 + bne clear_apu + + lda #>music_buffer + ldx #<music_buffer + sta sound_engine.stream_read_ptr_hi + stx sound_engine.stream_read_ptr_lo + + lda #$40 + ldx #$00 + sta sound_engine.stream_write_ptr_hi + stx sound_engine.stream_write_ptr_lo + + lda #$01 + sta sound_engine.delta + lda #$01 sta nes.apu.channel_enable rts