#include "config.h"

#include <orc/orcprogram.h>
#include <orc/orcdebug.h>
#include <orc/orcinternal.h>

#include "orc/orcemulateopcodes.h"

static OrcStaticOpcode opcodes[] = {

  /* byte ops */
  { "absb", 0, { 1 }, { 1 }, emulate_absb },
  { "addb", 0, { 1 }, { 1, 1 }, emulate_addb },
  { "addssb", 0, { 1 }, { 1, 1 }, emulate_addssb },
  { "addusb", 0, { 1 }, { 1, 1 }, emulate_addusb },
  { "andb", 0, { 1 }, { 1, 1 }, emulate_andb },
  { "andnb", 0, { 1 }, { 1, 1 }, emulate_andnb },
  { "avgsb", 0, { 1 }, { 1, 1 }, emulate_avgsb },
  { "avgub", 0, { 1 }, { 1, 1 }, emulate_avgub },
  { "cmpeqb", 0, { 1 }, { 1, 1 }, emulate_cmpeqb },
  { "cmpgtsb", 0, { 1 }, { 1, 1 }, emulate_cmpgtsb },
  { "copyb", ORC_STATIC_OPCODE_COPY, { 1 }, { 1 }, emulate_copyb },
  { "loadb", ORC_STATIC_OPCODE_LOAD, { 1 }, { 1 }, emulate_loadb },
  { "loadoffb", ORC_STATIC_OPCODE_LOAD|ORC_STATIC_OPCODE_SCALAR, { 1 }, { 1, 4 }, emulate_loadoffb },
  { "loadupdb", ORC_STATIC_OPCODE_LOAD|ORC_STATIC_OPCODE_ITERATOR, { 1 }, { 1 }, emulate_loadupdb },
  { "loadupib", ORC_STATIC_OPCODE_LOAD|ORC_STATIC_OPCODE_ITERATOR, { 1 }, { 1 }, emulate_loadupib },
  { "loadpb", ORC_STATIC_OPCODE_LOAD|ORC_STATIC_OPCODE_SCALAR|ORC_STATIC_OPCODE_INVARIANT, { 1 }, { 1 }, emulate_loadpb },
  { "ldresnearb", ORC_STATIC_OPCODE_LOAD|ORC_STATIC_OPCODE_SCALAR, { 1 }, { 1, 4, 4 }, emulate_ldresnearb },
  { "ldresnearl", ORC_STATIC_OPCODE_LOAD|ORC_STATIC_OPCODE_SCALAR, { 4 }, { 4, 4, 4 }, emulate_ldresnearl },
  { "ldreslinb", ORC_STATIC_OPCODE_LOAD|ORC_STATIC_OPCODE_SCALAR, { 1 }, { 1, 4, 4 }, emulate_ldreslinb },
  { "ldreslinl", ORC_STATIC_OPCODE_LOAD|ORC_STATIC_OPCODE_SCALAR, { 4 }, { 4, 4, 4 }, emulate_ldreslinl },
  { "maxsb", 0, { 1 }, { 1, 1 }, emulate_maxsb },
  { "maxub", 0, { 1 }, { 1, 1 }, emulate_maxub },
  { "minsb", 0, { 1 }, { 1, 1 }, emulate_minsb },
  { "minub", 0, { 1 }, { 1, 1 }, emulate_minub },
  { "mullb", 0, { 1 }, { 1, 1 }, emulate_mullb },
  { "mulhsb", 0, { 1 }, { 1, 1 }, emulate_mulhsb },
  { "mulhub", 0, { 1 }, { 1, 1 }, emulate_mulhub },
  { "orb", 0, { 1 }, { 1, 1 }, emulate_orb },
  { "shlb", ORC_STATIC_OPCODE_SCALAR, { 1 }, { 1, 1 }, emulate_shlb },
  { "shrsb", ORC_STATIC_OPCODE_SCALAR, { 1 }, { 1, 1 }, emulate_shrsb },
  { "shrub", ORC_STATIC_OPCODE_SCALAR, { 1 }, { 1, 1 }, emulate_shrub },
  { "signb", 0, { 1 }, { 1 }, emulate_signb },
  { "storeb", ORC_STATIC_OPCODE_STORE, { 1 }, { 1 }, emulate_storeb },
  { "subb", 0, { 1 }, { 1, 1 }, emulate_subb },
  { "subssb", 0, { 1 }, { 1, 1 }, emulate_subssb },
  { "subusb", 0, { 1 }, { 1, 1 }, emulate_subusb },
  { "xorb", 0, { 1 }, { 1, 1 }, emulate_xorb },

  /* word ops */
  { "absw", 0, { 2 }, { 2 }, emulate_absw },
  { "addw", 0, { 2 }, { 2, 2 }, emulate_addw },
  { "addssw", 0, { 2 }, { 2, 2 }, emulate_addssw },
  { "addusw", 0, { 2 }, { 2, 2 }, emulate_addusw },
  { "andw", 0, { 2 }, { 2, 2 }, emulate_andw },
  { "andnw", 0, { 2 }, { 2, 2 }, emulate_andnw },
  { "avgsw", 0, { 2 }, { 2, 2 }, emulate_avgsw },
  { "avguw", 0, { 2 }, { 2, 2 }, emulate_avguw },
  { "cmpeqw", 0, { 2 }, { 2, 2 }, emulate_cmpeqw },
  { "cmpgtsw", 0, { 2 }, { 2, 2 }, emulate_cmpgtsw },
  { "copyw", ORC_STATIC_OPCODE_COPY, { 2 }, { 2 }, emulate_copyw },
  { "div255w", 0, { 2 }, { 2 }, emulate_div255w },
  { "divluw", 0, { 2 }, { 2, 2 }, emulate_divluw },
  { "loadw", ORC_STATIC_OPCODE_LOAD, { 2 }, { 2 }, emulate_loadw },
  { "loadoffw", ORC_STATIC_OPCODE_LOAD|ORC_STATIC_OPCODE_SCALAR, { 2 }, { 2, 4 }, emulate_loadoffw },
  { "loadpw", ORC_STATIC_OPCODE_LOAD|ORC_STATIC_OPCODE_SCALAR|ORC_STATIC_OPCODE_INVARIANT, { 2 }, { 2 }, emulate_loadpw },
  { "maxsw", 0, { 2 }, { 2, 2 }, emulate_maxsw },
  { "maxuw", 0, { 2 }, { 2, 2 }, emulate_maxuw },
  { "minsw", 0, { 2 }, { 2, 2 }, emulate_minsw },
  { "minuw", 0, { 2 }, { 2, 2 }, emulate_minuw },
  { "mullw", 0, { 2 }, { 2, 2 }, emulate_mullw },
  { "mulhsw", 0, { 2 }, { 2, 2 }, emulate_mulhsw },
  { "mulhuw", 0, { 2 }, { 2, 2 }, emulate_mulhuw },
  { "orw", 0, { 2 }, { 2, 2 }, emulate_orw },
  { "shlw", ORC_STATIC_OPCODE_SCALAR, { 2 }, { 2, 2 }, emulate_shlw },
  { "shrsw", ORC_STATIC_OPCODE_SCALAR, { 2 }, { 2, 2 }, emulate_shrsw },
  { "shruw", ORC_STATIC_OPCODE_SCALAR, { 2 }, { 2, 2 }, emulate_shruw },
  { "signw", 0, { 2 }, { 2 }, emulate_signw },
  { "storew", ORC_STATIC_OPCODE_STORE, { 2 }, { 2 }, emulate_storew },
  { "subw", 0, { 2 }, { 2, 2 }, emulate_subw },
  { "subssw", 0, { 2 }, { 2, 2 }, emulate_subssw },
  { "subusw", 0, { 2 }, { 2, 2 }, emulate_subusw },
  { "xorw", 0, { 2 }, { 2, 2 }, emulate_xorw },

  /* long ops */
  { "absl", 0, { 4 }, { 4 }, emulate_absl },
  { "addl", 0, { 4 }, { 4, 4 }, emulate_addl },
  { "addssl", 0, { 4 }, { 4, 4 }, emulate_addssl },
  { "addusl", 0, { 4 }, { 4, 4 }, emulate_addusl },
  { "andl", 0, { 4 }, { 4, 4 }, emulate_andl },
  { "andnl", 0, { 4 }, { 4, 4 }, emulate_andnl },
  { "avgsl", 0, { 4 }, { 4, 4 }, emulate_avgsl },
  { "avgul", 0, { 4 }, { 4, 4 }, emulate_avgul },
  { "cmpeql", 0, { 4 }, { 4, 4 }, emulate_cmpeql },
  { "cmpgtsl", 0, { 4 }, { 4, 4 }, emulate_cmpgtsl },
  { "copyl", ORC_STATIC_OPCODE_COPY, { 4 }, { 4 }, emulate_copyl },
  { "loadl", ORC_STATIC_OPCODE_LOAD, { 4 }, { 4 }, emulate_loadl },
  { "loadoffl", ORC_STATIC_OPCODE_LOAD|ORC_STATIC_OPCODE_SCALAR, { 4 }, { 4, 4 }, emulate_loadoffl },
  { "loadpl", ORC_STATIC_OPCODE_LOAD|ORC_STATIC_OPCODE_SCALAR|ORC_STATIC_OPCODE_INVARIANT, { 4 }, { 4 }, emulate_loadpl },
  { "maxsl", 0, { 4 }, { 4, 4 }, emulate_maxsl },
  { "maxul", 0, { 4 }, { 4, 4 }, emulate_maxul },
  { "minsl", 0, { 4 }, { 4, 4 }, emulate_minsl },
  { "minul", 0, { 4 }, { 4, 4 }, emulate_minul },
  { "mulll", 0, { 4 }, { 4, 4 }, emulate_mulll },
  { "mulhsl", 0, { 4 }, { 4, 4 }, emulate_mulhsl },
  { "mulhul", 0, { 4 }, { 4, 4 }, emulate_mulhul },
  { "orl", 0, { 4 }, { 4, 4 }, emulate_orl },
  { "shll", ORC_STATIC_OPCODE_SCALAR, { 4 }, { 4, 4 }, emulate_shll },
  { "shrsl", ORC_STATIC_OPCODE_SCALAR, { 4 }, { 4, 4 }, emulate_shrsl },
  { "shrul", ORC_STATIC_OPCODE_SCALAR, { 4 }, { 4, 4 }, emulate_shrul },
  { "signl", 0, { 4 }, { 4 }, emulate_signl },
  { "storel", ORC_STATIC_OPCODE_STORE, { 4 }, { 4 }, emulate_storel },
  { "subl", 0, { 4 }, { 4, 4 }, emulate_subl },
  { "subssl", 0, { 4 }, { 4, 4 }, emulate_subssl },
  { "subusl", 0, { 4 }, { 4, 4 }, emulate_subusl },
  { "xorl", 0, { 4 }, { 4, 4 }, emulate_xorl },

  { "loadq", ORC_STATIC_OPCODE_LOAD, { 8 }, { 8 }, emulate_loadq },
  { "loadpq", ORC_STATIC_OPCODE_LOAD|ORC_STATIC_OPCODE_SCALAR|ORC_STATIC_OPCODE_INVARIANT, { 8 }, { 8 }, emulate_loadpq },
  { "storeq", ORC_STATIC_OPCODE_STORE, { 8 }, { 8 }, emulate_storeq },
  { "splatw3q", 0, { 8 }, { 8 }, emulate_splatw3q },
  { "copyq", ORC_STATIC_OPCODE_COPY, { 8 }, { 8 }, emulate_copyq },
  { "cmpeqq", 0, { 8 }, { 8, 8 }, emulate_cmpeqq },
  { "cmpgtsq", 0, { 8 }, { 8, 8 }, emulate_cmpgtsq },
  { "andq", 0, { 8 }, { 8, 8 }, emulate_andq },
  { "andnq", 0, { 8 }, { 8, 8 }, emulate_andnq },
  { "orq", 0, { 8 }, { 8, 8 }, emulate_orq },
  { "xorq", 0, { 8 }, { 8, 8 }, emulate_xorq },
  { "addq", 0, { 8 }, { 8, 8 }, emulate_addq },
  { "subq", 0, { 8 }, { 8, 8 }, emulate_subq },
  { "shlq", ORC_STATIC_OPCODE_SCALAR, { 8 }, { 8, 8 }, emulate_shlq },
  { "shrsq", ORC_STATIC_OPCODE_SCALAR, { 8 }, { 8, 8 }, emulate_shrsq },
  { "shruq", ORC_STATIC_OPCODE_SCALAR, { 8 }, { 8, 8 }, emulate_shruq },

  { "convsbw", 0, { 2 }, { 1 }, emulate_convsbw },
  { "convubw", 0, { 2 }, { 1 }, emulate_convubw },
  { "splatbw", 0, { 2 }, { 1 }, emulate_splatbw },
  { "splatbl", 0, { 4 }, { 1 }, emulate_splatbl },

  { "convswl", 0, { 4 }, { 2 }, emulate_convswl },
  { "convuwl", 0, { 4 }, { 2 }, emulate_convuwl },
  { "convslq", 0, { 8 }, { 4 }, emulate_convslq },
  { "convulq", 0, { 8 }, { 4 }, emulate_convulq },

  { "convwb", 0, { 1 }, { 2 }, emulate_convwb },
  { "convhwb", 0, { 1 }, { 2 }, emulate_convhwb },
  { "convssswb", 0, { 1 }, { 2 }, emulate_convssswb },
  { "convsuswb", 0, { 1 }, { 2 }, emulate_convsuswb },
  { "convusswb", 0, { 1 }, { 2 }, emulate_convusswb },
  { "convuuswb", 0, { 1 }, { 2 }, emulate_convuuswb },

  { "convlw", 0, { 2 }, { 4 }, emulate_convlw },
  { "convhlw", 0, { 2 }, { 4 }, emulate_convhlw },
  { "convssslw", 0, { 2 }, { 4 }, emulate_convssslw },
  { "convsuslw", 0, { 2 }, { 4 }, emulate_convsuslw },
  { "convusslw", 0, { 2 }, { 4 }, emulate_convusslw },
  { "convuuslw", 0, { 2 }, { 4 }, emulate_convuuslw },

  { "convql", 0, { 4 }, { 8 }, emulate_convql },
  { "convsssql", 0, { 4 }, { 8 }, emulate_convsssql },
  { "convsusql", 0, { 4 }, { 8 }, emulate_convsusql },
  { "convussql", 0, { 4 }, { 8 }, emulate_convussql },
  { "convuusql", 0, { 4 }, { 8 }, emulate_convuusql },

  { "mulsbw", 0, { 2 }, { 1, 1 }, emulate_mulsbw },
  { "mulubw", 0, { 2 }, { 1, 1 }, emulate_mulubw },
  { "mulswl", 0, { 4 }, { 2, 2 }, emulate_mulswl },
  { "muluwl", 0, { 4 }, { 2, 2 }, emulate_muluwl },
  { "mulslq", 0, { 8 }, { 4, 4 }, emulate_mulslq },
  { "mululq", 0, { 8 }, { 4, 4 }, emulate_mululq },

  /* accumulators */
  { "accw", ORC_STATIC_OPCODE_ACCUMULATOR, { 2 }, { 2 }, emulate_accw },
  { "accl", ORC_STATIC_OPCODE_ACCUMULATOR, { 4 }, { 4 }, emulate_accl },
  { "accsadubl", ORC_STATIC_OPCODE_ACCUMULATOR, { 4 }, { 1, 1 }, emulate_accsadubl },

  { "swapw", 0, { 2 }, { 2 }, emulate_swapw },
  { "swapl", 0, { 4 }, { 4 }, emulate_swapl },
  { "swapwl", 0, { 4 }, { 4 }, emulate_swapwl },
  { "swapq", 0, { 8 }, { 8 }, emulate_swapq },
  { "swaplq", 0, { 8 }, { 8 }, emulate_swaplq },
  { "select0wb", 0, { 1 }, { 2 }, emulate_select0wb },
  { "select1wb", 0, { 1 }, { 2 }, emulate_select1wb },
  { "select0lw", 0, { 2 }, { 4 }, emulate_select0lw },
  { "select1lw", 0, { 2 }, { 4 }, emulate_select1lw },
  { "select0ql", 0, { 4 }, { 8 }, emulate_select0ql },
  { "select1ql", 0, { 4 }, { 8 }, emulate_select1ql },
  { "mergelq", 0, { 8 }, { 4, 4 }, emulate_mergelq },
  { "mergewl", 0, { 4 }, { 2, 2 }, emulate_mergewl },
  { "mergebw", 0, { 2 }, { 1, 1 }, emulate_mergebw },
  { "splitql", 0, { 4, 4 }, { 8 }, emulate_splitql },
  { "splitlw", 0, { 2, 2 }, { 4 }, emulate_splitlw },
  { "splitwb", 0, { 1, 1 }, { 2 }, emulate_splitwb },

  /* float ops */
  { "addf", ORC_STATIC_OPCODE_FLOAT, { 4 }, { 4, 4 }, emulate_addf },
  { "subf", ORC_STATIC_OPCODE_FLOAT, { 4 }, { 4, 4 }, emulate_subf },
  { "mulf", ORC_STATIC_OPCODE_FLOAT, { 4 }, { 4, 4 }, emulate_mulf },
  { "divf", ORC_STATIC_OPCODE_FLOAT, { 4 }, { 4, 4 }, emulate_divf },
  { "sqrtf", ORC_STATIC_OPCODE_FLOAT, { 4 }, { 4 }, emulate_sqrtf },
  { "maxf", ORC_STATIC_OPCODE_FLOAT, { 4 }, { 4, 4 }, emulate_maxf },
  { "minf", ORC_STATIC_OPCODE_FLOAT, { 4 }, { 4, 4 }, emulate_minf },
  { "cmpeqf", ORC_STATIC_OPCODE_FLOAT_SRC, { 4 }, { 4, 4 }, emulate_cmpeqf },
  { "cmpltf", ORC_STATIC_OPCODE_FLOAT_SRC, { 4 }, { 4, 4 }, emulate_cmpltf },
  { "cmplef", ORC_STATIC_OPCODE_FLOAT_SRC, { 4 }, { 4, 4 }, emulate_cmplef },
  { "convfl", ORC_STATIC_OPCODE_FLOAT_SRC, { 4 }, { 4 }, emulate_convfl },
  { "convlf", ORC_STATIC_OPCODE_FLOAT_DEST, { 4 }, { 4 }, emulate_convlf },

  /* double ops */
  { "addd", ORC_STATIC_OPCODE_FLOAT, { 8 }, { 8, 8 }, emulate_addd },
  { "subd", ORC_STATIC_OPCODE_FLOAT, { 8 }, { 8, 8 }, emulate_subd },
  { "muld", ORC_STATIC_OPCODE_FLOAT, { 8 }, { 8, 8 }, emulate_muld },
  { "divd", ORC_STATIC_OPCODE_FLOAT, { 8 }, { 8, 8 }, emulate_divd },
  { "sqrtd", ORC_STATIC_OPCODE_FLOAT, { 8 }, { 8 }, emulate_sqrtd },
  { "maxd", ORC_STATIC_OPCODE_FLOAT, { 8 }, { 8, 8 }, emulate_maxd },
  { "mind", ORC_STATIC_OPCODE_FLOAT, { 8 }, { 8, 8 }, emulate_mind },
  { "cmpeqd", ORC_STATIC_OPCODE_FLOAT_SRC, { 8 }, { 8, 8 }, emulate_cmpeqd },
  { "cmpltd", ORC_STATIC_OPCODE_FLOAT_SRC, { 8 }, { 8, 8 }, emulate_cmpltd },
  { "cmpled", ORC_STATIC_OPCODE_FLOAT_SRC, { 8 }, { 8, 8 }, emulate_cmpled },
  { "convdl", ORC_STATIC_OPCODE_FLOAT_SRC, { 4 }, { 8 }, emulate_convdl },
  { "convld", ORC_STATIC_OPCODE_FLOAT_DEST, { 8 }, { 4 }, emulate_convld },
  { "convfd", ORC_STATIC_OPCODE_FLOAT, { 8 }, { 4 }, emulate_convfd },
  { "convdf", ORC_STATIC_OPCODE_FLOAT, { 4 }, { 8 }, emulate_convdf },

  { "orf", ORC_STATIC_OPCODE_FLOAT, { 4 }, { 4, 4 }, emulate_orf },
  { "andf", ORC_STATIC_OPCODE_FLOAT, { 4 }, { 4, 4 }, emulate_andf },
  { "convwf", ORC_STATIC_OPCODE_FLOAT_DEST, { 4 }, { 2 }, emulate_convwf },
  { "" }
};

void
orc_opcode_sys_init (void)
{
  orc_opcode_register_static (opcodes, "sys");
}
