def asm_instr(instr)
      command = extract_command(instr)
      param = extract_param(instr)

      # Branch instructions always in relative
      # mode. No other instructions use this mode.
      # Relative mode and zero-page mode look the
      # same to addr_mode(), so we need to handle
      # this here.
      if [:bpl, :bmi, :bvc, :bvs,
          :bcc, :bcs, :bne, :beq].
         include?(command)
        mode = :rel
      else
        mode = addr_mode(param)
      end

      bytes = []
      bytes << opcode(command, mode)

      # If implied mode, it's a 1-byte instruction.
      if [:imp].include?(mode)
        return bytes
      end

      # Handle label or address / immediate value
      if param =~ /\$/ # non-labels always have a $
        # Extract hex number from param string.
        number = /[0-9a-f]{1,4}/.match(param)[0].to_i(16)
      else
        # Store a dummy value and record this location
        # to be updated in 2nd pass.
        defer_value(@pc + 1, param)
        number = mode == :rel ? 0xff : 0xffff
      end

      # These instructions take 1 byte.
      if [:imm,  :zp,   :zpx,  :zpy,
          :indx, :indy, :rel].include?(mode)
        (number <= 0xff) || (raise "#{command}'s number too big")
        return bytes << number
      # These instructions take 2 bytes.
      elsif [:abs, :absx, :absy, :ind].include?(mode)
        (number <= 0xffff) || (raise 'number too big')
        bytes << (number & 0xff) # least-sig. byte
        bytes << (number >> 8)   # most-sig. byte
      end
    end
def asm_instr(instr)
      command = extract_command(instr)
      param = extract_param(instr)

      # Branch instructions always in relative
      # mode. No other instructions use this mode.
      # Relative mode and zero-page mode look the
      # same to addr_mode(), so we need to handle
      # this here.
      if [:bpl, :bmi, :bvc, :bvs,
          :bcc, :bcs, :bne, :beq].
         include?(command)
        mode = :rel
      else
        mode = addr_mode(param)
      end

      bytes = []
      bytes << opcode(command, mode)

      # If implied mode, it's a 1-byte instruction.
      if [:imp].include?(mode)
        return bytes
      end

      # Handle label or address / immediate value
      if param =~ /\$/ # non-labels always have a $
        # Extract hex number from param string.
        number = /[0-9a-f]{1,4}/.match(param)[0].to_i(16)
      else
        # Store a dummy value and record this location
        # to be updated in 2nd pass.
        defer_value(@pc + 1, param)
        number = mode == :rel ? 0xff : 0xffff
      end

      # These instructions take 1 byte.
      if [:imm,  :zp,   :zpx,  :zpy,
          :indx, :indy, :rel].include?(mode)
        (number <= 0xff) || (raise "#{command}'s number too big")
        return bytes << number
      # These instructions take 2 bytes.
      elsif [:abs, :absx, :absy, :ind].include?(mode)
        (number <= 0xffff) || (raise 'number too big')
        bytes << (number & 0xff) # least-sig. byte
        bytes << (number >> 8)   # most-sig. byte
      end
    end
This method got nasty.