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