n65/lib/n65/directives/bytes.rb

88 lines
2.3 KiB
Ruby

# frozen_string_literal: true
require_relative '../instruction_base'
require_relative '../regexes'
module N65
# This directive to include bytes
class Bytes < InstructionBase
class InvalidByteValue < StandardError; end
# Try to parse an incbin directive
def self.parse(line)
match_data = line.match(/^\.bytes\s+(.+)$/)
return nil if match_data.nil?
bytes_array = match_data[1].split(',').map do |byte_string|
# 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
raise(InvalidByteValue, byte_string)
end
end.flatten
Bytes.new(bytes_array)
end
# Initialize with a byte array
def initialize(bytes_array)
@bytes_array = bytes_array
end
# Execute on the assembler
def exec(assembler)
promise = assembler.with_saved_state do |saved_assembler|
@bytes_array.map! do |byte|
case byte
when Integer
byte
when String
saved_assembler.symbol_table.resolve_symbol(byte)
else
raise(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 Integer
byte
when String
0xDE
else
raise(InvalidByteValue, byte)
end
end
assembler.write_memory(placeholder_bytes)
promise
end
end
# Display, I don't want to write all these out
def to_s
".bytes (#{@bytes_array.length})"
end
end
end