(*opcode hash table, formati ukazov in mnemoniki*)
type mnemonic =
  (* Format 1 *)
  | FIX | FLOAT | HIO | NORM | SIO | TIO

  (* Format 2 *)
  | ADDR | CLEAR | COMPR | DIVR | MULR | RMO
  | SHIFTL | SHIFTR | SUBR | SVC | TIXR

  (* Format 3/4 *)
  | ADD | ADDF | AND | COMP | COMPF | DIV
  | J | JEQ | JGT | JLT | JSUB | LDA | LDB | LDCH | LDF
  | LDL | LDS | LDT | LDX | LPS | MUL | OR | RD
  | RSUB | STA | STB | STCH | STF | STL | STS | STSW
  | STT | STX | SUB | SUBF | TD | TIX | WD

type format =
  | F1
  | F2
  | F3_4

type info = {
  mnemonic : mnemonic;
  format : format;
}

(* Opcode table *)

let table : (int, info) Hashtbl.t = Hashtbl.create 128

let () =
  let add op mnemonic format =
    Hashtbl.add table op { mnemonic; format }
  in

  (*Format 1 Instructions*)
  add 0xC4 FIX   F1;
  add 0xC0 FLOAT F1;
  add 0xC8 HIO   F1;
  add 0xC1 NORM  F1;
  add 0xF0 SIO   F1;
  add 0xF8 TIO   F1;

  (*Format 2 Instructions*)
  add 0x90 ADDR    F2;
  add 0xB4 CLEAR   F2;
  add 0xA0 COMPR   F2;
  add 0x9C DIVR    F2;
  add 0x98 MULR    F2;
  add 0xAC RMO     F2;
  add 0xA4 SHIFTL  F2;
  add 0xA8 SHIFTR  F2;
  add 0x94 SUBR    F2;
  add 0xB0 SVC     F2;
  add 0xB8 TIXR    F2;

  (*Format 3/4 Instructions*)
  add 0x18 ADD   F3_4;
  add 0x58 ADDF F3_4;
  add 0x40 AND  F3_4;
  add 0x28 COMP F3_4;
  add 0x88 COMPF F3_4;
  add 0x24 DIV  F3_4;
  add 0x3C J    F3_4;
  add 0x30 JEQ  F3_4;
  add 0x34 JGT  F3_4;
  add 0x38 JLT  F3_4;
  add 0x48 JSUB F3_4;
  add 0x00 LDA  F3_4;
  add 0x68 LDB  F3_4;
  add 0x50 LDCH F3_4;
  add 0x70 LDF  F3_4;
  add 0x08 LDL  F3_4;
  add 0x6C LDS  F3_4;
  add 0x74 LDT  F3_4;
  add 0x04 LDX  F3_4;
  add 0xD0 LPS  F3_4;
  add 0x20 MUL  F3_4;
  add 0x44 OR   F3_4;
  add 0xD8 RD   F3_4;
  add 0x4C RSUB F3_4;
  add 0x0C STA  F3_4;
  add 0x78 STB  F3_4;
  add 0x54 STCH F3_4;
  add 0x80 STF  F3_4;
  add 0x14 STL  F3_4;
  add 0x7C STS  F3_4;
  add 0xE8 STSW F3_4;
  add 0x84 STT  F3_4;
  add 0x10 STX  F3_4;
  add 0x1C SUB  F3_4;
  add 0x5C SUBF F3_4;
  add 0xE0 TD   F3_4;
  add 0x2C TIX  F3_4;
  add 0xDC WD   F3_4;
()

(*mnemonic to string*)
let string_of_mnemonic = function
  (* Format 1 *)
  | FIX -> "FIX"
  | FLOAT -> "FLOAT"
  | HIO -> "HIO"
  | NORM -> "NORM"
  | SIO -> "SIO"
  | TIO -> "TIO"

  (* Format 2 *)
  | ADDR -> "ADDR"
  | CLEAR -> "CLEAR"
  | COMPR -> "COMPR"
  | DIVR -> "DIVR"
  | MULR -> "MULR"
  | RMO -> "RMO"
  | SHIFTL -> "SHIFTL"
  | SHIFTR -> "SHIFTR"
  | SUBR -> "SUBR"
  | SVC -> "SVC"
  | TIXR -> "TIXR"

  (* Format 3/4 *)
  | ADD -> "ADD"
  | ADDF -> "ADDF"
  | AND -> "AND"
  | COMP -> "COMP"
  | COMPF -> "COMPF"
  | DIV -> "DIV"
  | J -> "J"
  | JEQ -> "JEQ"
  | JGT -> "JGT"
  | JLT -> "JLT"
  | JSUB -> "JSUB"
  | LDA -> "LDA"
  | LDB -> "LDB"
  | LDCH -> "LDCH"
  | LDF -> "LDF"
  | LDL -> "LDL"
  | LDS -> "LDS"
  | LDT -> "LDT"
  | LDX -> "LDX"
  | LPS -> "LPS"
  | MUL -> "MUL"
  | OR -> "OR"
  | RD -> "RD"
  | RSUB -> "RSUB"
  | STA -> "STA"
  | STB -> "STB"
  | STCH -> "STCH"
  | STF -> "STF"
  | STL -> "STL"
  | STS -> "STS"
  | STSW -> "STSW"
  | STT -> "STT"
  | STX -> "STX"
  | SUB -> "SUB"
  | SUBF -> "SUBF"
  | TD -> "TD"
  | TIX -> "TIX"
  | WD -> "WD"


let format_str format = match format with
  | F1 -> "F1" | F2 -> "F2" | F3_4 -> "F3/4"