class LadderDrive::AsmLine

Constants

MNEMONIC_DEF
OPERAND_TYPE_NONE
OPERAND_TYPE_TYPE_AND_NUMBER
OPERAND_TYPE_TYPE_AND_NUMBER_NUMBER

Attributes

address[R]
codes[R]
endian[R]
line[R]

Public Class Methods

new(line, address = 0, endian = nil) click to toggle source
# File lib/ladder_drive/asm.rb, line 85
def initialize line, address = 0, endian = nil
  @endian = endian || Asm::LITTLE_ENDIAN
  @line = line.upcase.chomp
  @codes = []
  @address = address
  parse
end

Public Instance Methods

dump() click to toggle source
# File lib/ladder_drive/asm.rb, line 97
def dump
  @codes.map do |c|
    c.to_s(16).rjust(2, "0")
  end
  .join(" ")
  .ljust(12)
end
dump_line() click to toggle source
# File lib/ladder_drive/asm.rb, line 93
def dump_line
  "#{dump}\t#{line}"
end
next_address() click to toggle source
# File lib/ladder_drive/asm.rb, line 105
def next_address
  address + codes.size
end

Private Instance Methods

counter_value(value) click to toggle source
# File lib/ladder_drive/asm.rb, line 246
def counter_value value
  raise SyntaxError.new "It must be required count value." unless /^\d+$/ =~ value

  v = value.to_i
  case endian
  when Asm::LITTLE_ENDIAN
    codes = [v & 0xff, (v & 0xff00) >> 8]
  when Asm::BIG_ENDIAN
    codes = [(v & 0xff00) >> 8, v & 0xff]
  end
end
encode_mnemonic(mnemonic) click to toggle source
# File lib/ladder_drive/asm.rb, line 172
def encode_mnemonic mnemonic
  mnemonic_dict[mnemonic]
end
mnemonic_dict() click to toggle source
# File lib/ladder_drive/asm.rb, line 157
def mnemonic_dict
  @@mnemonic_dict ||= begin
    h = {}
    MNEMONIC_DEF.dup.split(/\n/)[2..-1].each_with_index do |line, upper|
      line.split(/\|/)[2..-1].each_with_index do |mnemonic, lower|
        mnemonic.strip!
        next if mnemonic.nil? || mnemonic.length == 0
        code = (upper << 4) | lower
        h[mnemonic] = code
      end
    end
    h
  end
end
operand_type(mnemonic) click to toggle source
# File lib/ladder_drive/asm.rb, line 128
def operand_type mnemonic
  case mnemonic
  when /LD/, /AND/, /ANI/, /OR[^B]?$/, /OUT/, "SET", "RST", "PLS", "PLF", "FF", /SF(L|R)/
    OPERAND_TYPE_TYPE_AND_NUMBER
  else
    OPERAND_TYPE_NONE
  end
end
parse() click to toggle source
# File lib/ladder_drive/asm.rb, line 115
def parse
  /([^#]*)/ =~ line
  a = $1.split(/\s+/)
  mnemonic, operand1, operand2 = a
  if mnemonic
    @codes << encode_mnemonic(mnemonic)
    case operand_type(mnemonic)
    when OPERAND_TYPE_TYPE_AND_NUMBER
      @codes += parse_type_and_number(mnemonic, operand1, operand2)
    end
  end
end
parse_type_and_number(mnemonic, operand, value) click to toggle source
# File lib/ladder_drive/asm.rb, line 176
def parse_type_and_number mnemonic, operand, value
  /([[:alpha:]]*)(\d+[0-9A-Fa-f]*)\.?(\d*)?/ =~ operand
  suffix = $1
  number = $2
  bit = $3
  len = 16
  case suffix
  when "X", "Y"
    number = number.to_i(16)
  else
    number = number.to_i
  end
  type_code = %W(X Y M - C T L SC CC TC D NOP - CS TS H SD).index(suffix)
  raise "undefind suffix: #{suffix}" if type_code.nil?

  case (type_code & 0xc) >> 2
  when 0, 1
    type_code |= 0x80
  else
    type_code |= 0xa0
  end

  if number < 256
    codes = [type_code, number]
  else
    case endian
    when Asm::LITTLE_ENDIAN
      codes = [type_code | 0x10, number & 0xff, (number & 0xff00) >> 8]
    when Asm::BIG_ENDIAN
      codes = [type_code | 0x10, (number & 0xff00) >> 8, number & 0xff]
    end
  end

  # If mnemonic is out/outi and device type is timer or counter, append time or count.
  case mnemonic
  when /OUT/
    case suffix
    when 'T'
      codes += time_value(value)
    when 'C'
      codes += counter_value(value)
    end
  end

  codes
end
time_value(value) click to toggle source
# File lib/ladder_drive/asm.rb, line 223
def time_value value
  raise SyntaxError.new "It must be required time value." unless /^\d*\.?\d*$/ =~ value

  t = value.to_f
  g = 0
  codes = []
  while t < 16384 && g <= 3
    t *= 10.0
    g += 1
  end
  t /= 10.0
  g -= 1
  v = (g << 14) | t.to_i

  case endian
  when Asm::LITTLE_ENDIAN
    codes = [v & 0xff, (v & 0xff00) >> 8]
  when Asm::BIG_ENDIAN
    codes = [(v & 0xff00) >> 8, v & 0xff]
  end
  codes #rdlsf@de
end