Class: C64Asm::Operand
- Inherits:
-
Object
- Object
- C64Asm::Operand
- Defined in:
- lib/c64asm/asm.rb
Overview
Operand, the most important building block
Instance Attribute Summary collapse
-
#arg ⇒ Object
readonly
Returns the value of attribute arg.
-
#label ⇒ Object
readonly
Returns the value of attribute label.
-
#mode ⇒ Object
readonly
Returns the value of attribute mode.
-
#op ⇒ Object
readonly
Returns the value of attribute op.
Instance Method Summary collapse
-
#check_mod ⇒ Object
private
Validate modifier.
-
#check_mode(mode, arg, mod) ⇒ Object
private
Validate addressing mode.
-
#initialize(op, arg = false, mod = false) ⇒ Operand
constructor
Setup and validate an operand.
-
#length ⇒ Object
Return the length of the additional operand in machine code bytes, or false.
-
#ready? ⇒ Boolean
Do we have all data in raw form.
-
#resolve(arg) ⇒ Object
Resolve addresses, if needed.
-
#to_a ⇒ Object
Turn the operand into a byte array Won’t work if we haven’t got all the necessary data yet.
-
#to_binary ⇒ Object
Turn the operand into a byte string Won’t work if we haven’t got all the necessary data yet.
-
#to_s ⇒ Object
Return pretty string representation of the operand.
-
#to_source ⇒ Object
Turn the operand into source code string.
-
#validate ⇒ Object
private
Low-level validation.
Constructor Details
#initialize(op, arg = false, mod = false) ⇒ Operand
Setup and validate an operand
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/c64asm/asm.rb', line 44 def initialize(op, arg = false, mod = false) raise OperandError, 'No such operand' unless OP_CODES.has_key? op @op = op @mode = false @arg = arg @mod = mod @label = false @ready = false opcode = OP_CODES[op] # mode resolution if opcode.has_key? :n # all immediates @mode = :n @ready = true elsif not arg and opcode.has_key? :e @mode = :e @ready = true elsif opcode.keys.length == 1 # branching and jsr @mode = opcode.keys.first elsif arg and arg.instance_of? Fixnum # for the rest, let's try figure out mode by checking argument # we treat addressing modes as of higher priority, eg. :z over :d if arg >= 0 and arg <= 255 if opcode.has_key? :z @mode = :z elsif opcode.has_key? :d @mode = :d else raise OperandError, 'No mode handling byte' end elsif arg >= 256 and arg <= 65535 if opcode.has_key? :a @mode = :a else raise OperandError, 'Argument out of range' end end end # future reference handling, aka labels if arg and arg.instance_of? Symbol # labels can point only to absolute addresses unless (has_a = opcode.has_key? :a) or opcode.has_key? :r raise OperandError, 'Used with label but no :a or :r modes' end @mode = has_a ? :a : :r @label = arg end # argument checking if @mode and not @label raise OperandError, 'Invalid argument' unless validate @ready = true end # modifier checking check_mod if mod end |
Instance Attribute Details
#arg ⇒ Object (readonly)
Returns the value of attribute arg.
41 42 43 |
# File 'lib/c64asm/asm.rb', line 41 def arg @arg end |
#label ⇒ Object (readonly)
Returns the value of attribute label.
41 42 43 |
# File 'lib/c64asm/asm.rb', line 41 def label @label end |
#mode ⇒ Object (readonly)
Returns the value of attribute mode.
41 42 43 |
# File 'lib/c64asm/asm.rb', line 41 def mode @mode end |
#op ⇒ Object (readonly)
Returns the value of attribute op.
41 42 43 |
# File 'lib/c64asm/asm.rb', line 41 def op @op end |
Instance Method Details
#check_mod ⇒ Object (private)
Validate modifier
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 |
# File 'lib/c64asm/asm.rb', line 225 def check_mod raise OperandError, 'Modifier used with non-label argument' unless @label if @mod.instance_of? Fixnum @mod = [:+, @mod] elsif @mod.instance_of? Array and @mod.length == 2 and [:/, :*, :<<, :>>, :& , :|].member? @mod.first raise OperandError, 'Arithmetic argument has to be a fixnum' unless @mod[1].instance_of? Fixnum elsif [:<, :>].member? @mod # this two modifiers make sense only for :d addressing mode if not @mode or (@mode and @mode != :d) unless OP_CODES[@op].has_key? :d raise OperandError, 'Byte modifier used with non-direct addressing mode' end @mode = :d end @mod = [@mod == :< ? :ls_byte : :ms_byte] else raise OperandError, 'Unknown modifier' end end |
#check_mode(mode, arg, mod) ⇒ Object (private)
Validate addressing mode
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 |
# File 'lib/c64asm/asm.rb', line 195 def check_mode(mode, arg, mod) raise OperandError, 'Operand was ready' if @ready raise OperandError, 'No such mode' unless OP_CODES[@op].has_key? mode @mode = mode @arg = arg @mod = mod case arg when Fixnum raise OperandError, 'Invalid argument' unless validate @ready = true when Symbol modec = @mode.to_s[0] if @mod raise OperandError, 'Label used with wrong mode' unless (modec == 'a') or (modec == 'd') else raise OperandError, 'Label used with wrong mode' unless modec == 'a' end @label = arg else raise OperandError, 'Invalid argument type' end check_mod if mod self end |
#length ⇒ Object
Return the length of the additional operand in machine code bytes, or false
164 |
# File 'lib/c64asm/asm.rb', line 164 def length; @mode ? 1 + ADDR_MODES[@mode][:len] : false; end |
#ready? ⇒ Boolean
Do we have all data in raw form
115 |
# File 'lib/c64asm/asm.rb', line 115 def ready?; @ready; end |
#resolve(arg) ⇒ Object
Resolve addresses, if needed
118 119 120 121 122 123 124 125 |
# File 'lib/c64asm/asm.rb', line 118 def resolve(arg) return true unless @label @mod ? @arg = arg.send(*@mod) : @arg = arg raise OperandError, 'Invalid argument' unless validate @ready = true end |
#to_a ⇒ Object
Turn the operand into a byte array Won’t work if we haven’t got all the necessary data yet.
171 172 173 174 175 176 177 178 179 180 181 182 183 |
# File 'lib/c64asm/asm.rb', line 171 def to_a return [] unless @ready bytes = [OP_CODES[@op][@mode][:byte]] if @arg and @arg > 255 bytes += [@arg.ls_byte, @arg.ms_byte] elsif @arg bytes += [@arg] else bytes end end |
#to_binary ⇒ Object
Turn the operand into a byte string Won’t work if we haven’t got all the necessary data yet.
187 188 189 190 191 |
# File 'lib/c64asm/asm.rb', line 187 def to_binary return '' unless @ready @mode == :r ? to_a.pack('Cc') : to_a.pack('C*') end |
#to_s ⇒ Object
Return pretty string representation of the operand
167 |
# File 'lib/c64asm/asm.rb', line 167 def to_s; "<Operand: #{to_source}>"; end |
#to_source ⇒ Object
Turn the operand into source code string
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
# File 'lib/c64asm/asm.rb', line 128 def to_source source = @op.to_s if @label if @mod case @mod.first when :+ label = @label.to_s + ('%+d' % @mod[1]) when :ls_byte label = '<' + @label.to_s when :ms_byte label = '>' + @label.to_s else label = @label.to_s + @mod.join end else label = @label.to_s end end unless @mode == :n or @mode == :e if @label source += ADDR_MODES[@mode][:src] % label else if @mode == :r source += ' *%+d' % @arg.to_s else source += ADDR_MODES[@mode][:src] % ('$' + @arg.to_s(16)) end end end source end |
#validate ⇒ Object (private)
Low-level validation
249 250 251 252 253 254 255 256 257 258 |
# File 'lib/c64asm/asm.rb', line 249 def validate if (@mode == :n and @arg) or \ (@mode == :r and not (@arg >= -128 and @arg <= 127)) or \ ([:a, :ax, :ay, :ar].member? @mode and not (@arg >= 0 and @arg <= 65535)) or \ ([:d, :z, :zx, :zy, :zxr, :zyr].member? @mode and not (@arg >= 0 and @arg <= 255)) false else true end end |