#pragma once

#define USE_STL 0

#if USE_STL
#include <vector>
template <typename T>
using vector = std::vector<T>;
#else
#include "min_stl.hpp"
template <typename T>
using vector = min::vector<T>;
#endif


// < 64 op code
// 32 reg
// 6 + 5 + 5 -> 16 bits
// 8-bit codes?  VLC - variable length codes, or fixed?
// 8-bit -> 16 ops, 4 regs
//          some ops that don't take regs could be shared
//           - 12 ops with 2 2-bit reg#
//           - 7 ops with 1 2-bit reg#
//           - 36 ops with no regs
// Add,Sub,Shl,Shr,Mul,Div,Mod,Or,Xor,And,MovRR,Cmp  - 12 with a pair of regs
// Not,Ioctl,Jmp,Je,Jne,Push,Pop - 7 with a single reg  (jumps are very short)
// Nop,Ret - 2 with no reg
// Others not able to be coded in 8-bits:
//    Call,LongJmp
//    MovIR,MovMR,MovCR,MovI0,MovM0,MovC0,MovIM,MovRM,Mov0M,MovMM,MovCM
//
enum OpCode
{
  Nop,
  
  Add,
  // Adc,
  Sub,
  // Sbb,
  // Inc
  // Dec,
  Shl,
  Shr,
  // Sal,
  // Sar,
  Mul,
  Div,
  Mod,

  Not,
  Or,
  Xor,
  And,

  MovIR,  // imm20       -> reg
  MovRR,  // reg         -> reg
  // 0R,  // reg0        -> reg
  MovMR,  // mem[r]      -> reg
  MovCR,  // const[r]    -> reg

  MovI0,  // imm25       -> reg0
  // R0,  // reg         -> reg0
  // 00,  // reg0        -> reg0
  MovM0,  // mem[addr]   -> reg0
  MovC0,  // const[addr] -> reg0

  MovIM,  // imm20       -> mem[r]
  MovRM,  // reg         -> mem[r]
  Mov0M,  // reg0        -> mem[addr]
  MovMM,  // mem[r]      -> mem[r]
  MovCM,  // const[r]    -> mem[r]

  Cmp,

  // fAdd,
  // fSub,
  // fMul,
  // fDiv,
  // fMod,
  // fCmp,
  // fLoad,
  // fStore,

  Ioctl,
  Call,
  Jmp,
  Je,
  Jne,

  // Jc,
  // Jb,
  // Jo,

  Push,
  Pop,

  // PushF,
  // PopF,

  // PushA,
  // PopA,

  Ret,

  // In,
  // Out,

  // Nop,
  // Reset,
  // Cpuid
}; // 33
// over 32


enum SystemCalls
{
  Syscall_exit,
  Syscall_putc,
};

struct ProgramHeader
{
  uint32_t                m_headerSize;
  uint32_t                m_textOffset;
  uint32_t                m_textSize;
  uint32_t                m_textSize_x86;
  uint32_t                m_rodataOffset;
  uint32_t                m_rodataSize;
};

struct Program
{
  ProgramHeader           m_header;
  vector<uint32_t>        m_text;
  vector<uint8_t>         m_text_x86;
  vector<uint32_t>        m_rodata;
};

