module Arm
  # ADDRESSING MODE 4

  class StackInstruction < Instruction

    def initialize(first , attributes)
      super(nil)
      @attributes = attributes
      @first = first
      @attributes[:update_status] = 0 if @attributes[:update_status] == nil
      @attributes[:condition_code] = :al if @attributes[:condition_code] == nil
      @attributes[:opcode] = attributes[:opcode]
      @rn = :sp # sp register
    end

    # don't overwrite instance variables, to make assembly repeatable
    def assemble(io)
      operand = 0
      raise "invalid operand argument #{inspect}" unless (@first.is_a?(Array))
      @first.each do |r|
        raise "nil register in push, index #{r}- #{inspect}" if r.nil?
        operand = operand | (1 << reg_code(r))
      end
      val = operand
      val = val | (reg_code(@rn) <<             16)
      val = val | (is_pop <<              16 + 4) #20
      val = val | (1          <<          16 + 4 + 1)
      val = val | (@attributes[:update_status] <<  16 + 4 + 1 + 1)
      val = val | (up_down <<             16 + 4 + 1 + 1 + 1)
      val = val | (pre_post_index <<      16 + 4 + 1 + 1 + 1 + 1)#24
      val = val | instruction_code
      val = val | (cond <<                16 + 4 + 1 + 1 + 1 + 1 + 2 + 2)
      io.write_unsigned_int_32 val
    end

    def cond
      if @attributes[:condition_code].is_a?(Symbol)
        COND_CODES[@attributes[:condition_code]]
      else
        @attributes[:condition_code]
      end
    end
    def instuction_class
      0b10 # OPC_STACK
    end
    def up_down
      (opcode == :push) ?  0 :  1
    end
    alias :is_pop :up_down

    def pre_post_index
      (opcode == :push) ?  1 :  0
    end

    def regs
      @first
    end

    def to_s
      "#{opcode} [#{@first.join(', ') }] #{super}"
    end
  end

end