// Copyright 2013 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_ARM64_DECODER_ARM64_H_
#define V8_ARM64_DECODER_ARM64_H_

#include <list>

#include "src/arm64/instructions-arm64.h"
#include "src/globals.h"

namespace v8 {
namespace internal {


// List macro containing all visitors needed by the decoder class.

#define VISITOR_LIST(V)             \
  V(PCRelAddressing)                \
  V(AddSubImmediate)                \
  V(LogicalImmediate)               \
  V(MoveWideImmediate)              \
  V(Bitfield)                       \
  V(Extract)                        \
  V(UnconditionalBranch)            \
  V(UnconditionalBranchToRegister)  \
  V(CompareBranch)                  \
  V(TestBranch)                     \
  V(ConditionalBranch)              \
  V(System)                         \
  V(Exception)                      \
  V(LoadStorePairPostIndex)         \
  V(LoadStorePairOffset)            \
  V(LoadStorePairPreIndex)          \
  V(LoadStorePairNonTemporal)       \
  V(LoadLiteral)                    \
  V(LoadStoreUnscaledOffset)        \
  V(LoadStorePostIndex)             \
  V(LoadStorePreIndex)              \
  V(LoadStoreRegisterOffset)        \
  V(LoadStoreUnsignedOffset)        \
  V(LogicalShifted)                 \
  V(AddSubShifted)                  \
  V(AddSubExtended)                 \
  V(AddSubWithCarry)                \
  V(ConditionalCompareRegister)     \
  V(ConditionalCompareImmediate)    \
  V(ConditionalSelect)              \
  V(DataProcessing1Source)          \
  V(DataProcessing2Source)          \
  V(DataProcessing3Source)          \
  V(FPCompare)                      \
  V(FPConditionalCompare)           \
  V(FPConditionalSelect)            \
  V(FPImmediate)                    \
  V(FPDataProcessing1Source)        \
  V(FPDataProcessing2Source)        \
  V(FPDataProcessing3Source)        \
  V(FPIntegerConvert)               \
  V(FPFixedPointConvert)            \
  V(Unallocated)                    \
  V(Unimplemented)

// The Visitor interface. Disassembler and simulator (and other tools)
// must provide implementations for all of these functions.
class DecoderVisitor {
 public:
  virtual ~DecoderVisitor() {}

  #define DECLARE(A) virtual void Visit##A(Instruction* instr) = 0;
  VISITOR_LIST(DECLARE)
  #undef DECLARE
};


// A visitor that dispatches to a list of visitors.
class DispatchingDecoderVisitor : public DecoderVisitor {
 public:
  DispatchingDecoderVisitor() {}
  virtual ~DispatchingDecoderVisitor() {}

  // Register a new visitor class with the decoder.
  // Decode() will call the corresponding visitor method from all registered
  // visitor classes when decoding reaches the leaf node of the instruction
  // decode tree.
  // Visitors are called in the order.
  // A visitor can only be registered once.
  // Registering an already registered visitor will update its position.
  //
  //   d.AppendVisitor(V1);
  //   d.AppendVisitor(V2);
  //   d.PrependVisitor(V2);            // Move V2 at the start of the list.
  //   d.InsertVisitorBefore(V3, V2);
  //   d.AppendVisitor(V4);
  //   d.AppendVisitor(V4);             // No effect.
  //
  //   d.Decode(i);
  //
  // will call in order visitor methods in V3, V2, V1, V4.
  void AppendVisitor(DecoderVisitor* visitor);
  void PrependVisitor(DecoderVisitor* visitor);
  void InsertVisitorBefore(DecoderVisitor* new_visitor,
                           DecoderVisitor* registered_visitor);
  void InsertVisitorAfter(DecoderVisitor* new_visitor,
                          DecoderVisitor* registered_visitor);

  // Remove a previously registered visitor class from the list of visitors
  // stored by the decoder.
  void RemoveVisitor(DecoderVisitor* visitor);

  #define DECLARE(A) void Visit##A(Instruction* instr);
  VISITOR_LIST(DECLARE)
  #undef DECLARE

 private:
  // Visitors are registered in a list.
  std::list<DecoderVisitor*> visitors_;
};


template<typename V>
class Decoder : public V {
 public:
  Decoder() {}
  virtual ~Decoder() {}

  // Top-level instruction decoder function. Decodes an instruction and calls
  // the visitor functions registered with the Decoder class.
  virtual void Decode(Instruction *instr);

 private:
  // Decode the PC relative addressing instruction, and call the corresponding
  // visitors.
  // On entry, instruction bits 27:24 = 0x0.
  void DecodePCRelAddressing(Instruction* instr);

  // Decode the add/subtract immediate instruction, and call the corresponding
  // visitors.
  // On entry, instruction bits 27:24 = 0x1.
  void DecodeAddSubImmediate(Instruction* instr);

  // Decode the branch, system command, and exception generation parts of
  // the instruction tree, and call the corresponding visitors.
  // On entry, instruction bits 27:24 = {0x4, 0x5, 0x6, 0x7}.
  void DecodeBranchSystemException(Instruction* instr);

  // Decode the load and store parts of the instruction tree, and call
  // the corresponding visitors.
  // On entry, instruction bits 27:24 = {0x8, 0x9, 0xC, 0xD}.
  void DecodeLoadStore(Instruction* instr);

  // Decode the logical immediate and move wide immediate parts of the
  // instruction tree, and call the corresponding visitors.
  // On entry, instruction bits 27:24 = 0x2.
  void DecodeLogical(Instruction* instr);

  // Decode the bitfield and extraction parts of the instruction tree,
  // and call the corresponding visitors.
  // On entry, instruction bits 27:24 = 0x3.
  void DecodeBitfieldExtract(Instruction* instr);

  // Decode the data processing parts of the instruction tree, and call the
  // corresponding visitors.
  // On entry, instruction bits 27:24 = {0x1, 0xA, 0xB}.
  void DecodeDataProcessing(Instruction* instr);

  // Decode the floating point parts of the instruction tree, and call the
  // corresponding visitors.
  // On entry, instruction bits 27:24 = {0xE, 0xF}.
  void DecodeFP(Instruction* instr);

  // Decode the Advanced SIMD (NEON) load/store part of the instruction tree,
  // and call the corresponding visitors.
  // On entry, instruction bits 29:25 = 0x6.
  void DecodeAdvSIMDLoadStore(Instruction* instr);

  // Decode the Advanced SIMD (NEON) data processing part of the instruction
  // tree, and call the corresponding visitors.
  // On entry, instruction bits 27:25 = 0x7.
  void DecodeAdvSIMDDataProcessing(Instruction* instr);
};


} }  // namespace v8::internal

#endif  // V8_ARM64_DECODER_ARM64_H_