1
0
mirror of https://github.com/safiire/n65.git synced 2024-12-12 00:29:03 +00:00
n65/lib/directive.rb

155 lines
3.0 KiB
Ruby
Raw Normal View History

require 'json'
2015-02-18 03:05:37 +00:00
module Assembler6502
####
## This class can setup an iNES Header
class INESHeader
####
## Construct with the right values
def initialize(prog = 0x1, char = 0x0, mapper = 0x0, mirror = 0x1)
@prog, @char, @mapper, @mirror = prog, char, mapper, mirror
end
####
## Emit the header bytes, this is not exactly right, but it works for now.
def emit_bytes
[0x4E, 0x45, 0x53, 0x1a, @prog, @char, @mapper, @mirror, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]
end
end
####
## This is an .org directive
class Org
attr_reader :address
####
## Initialized with start address
def initialize(address)
@address = address
end
end
####
## This is to include a binary file
class IncBin
class FileNotFound < StandardError; end
####
## Initialize with a file path
def initialize(filepath)
unless File.exists?(filepath)
fail(FileNotFound, ".incbin can't find #{filepath}")
end
@data = File.read(filepath).unpack('C*')
end
####
## What is the size of the read data?
def size
@data.size
end
####
## Emit bytes
def emit_bytes
@data
end
end
####
## Data Word
class DW
attr_reader :address
class WordTooLarge < StandardError; end
def initialize(value, address)
@value = value
@address = address
end
def unresolved_symbols?
@value.kind_of?(Symbol)
end
def resolve_symbols(labels)
if unresolved_symbols? && labels[@value] != nil
@value = labels[@value].address
end
end
def emit_bytes
fail('Need to resolve symbol in .dw directive') if unresolved_symbols?
[@value & 0xFFFF].pack('S').bytes
end
end
####
## Just a bunch of bytes
class Bytes
def initialize(bytes)
@bytes = bytes.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
end
def emit_bytes
@bytes
end
end
2015-02-18 03:05:37 +00:00
####
## This parses an assembler directive
class Directive
####
## This will return a new Directive, or nil if it is something else.
def self.parse(directive_line, address)
sanitized = Assembler6502.sanitize_line(directive_line)
case sanitized
when /^\.ines (.+)$/
header = JSON.parse($1)
INESHeader.new(header['prog'], header['char'], header['mapper'], header['mirror'])
when /^\.org\s+\$([0-9A-F]{4})$/
Org.new($1.to_i(16))
2015-02-18 03:05:37 +00:00
when /^\.incbin "([^"]+)"$/
IncBin.new($1)
when /^\.dw\s+\$([0-9A-F]{1,4})$/
DW.new($1.to_i(16), address)
when /^\.dw\s+([A-Za-z_][A-Za-z0-9_]+)/
DW.new($1.to_sym, address)
when /^\.bytes\s+(.+)$/
Bytes.new($1)
when /^\./
fail(SyntaxError, "Syntax Error in Directive '#{sanitized}'")
end
2015-02-18 03:05:37 +00:00
end
end
end