// Based on https://git.ablecorp.us/AbleOS/holey-bytes/src/branch/trunk/spec.md

`define get_args    \
    case (w_mem_fetch)    \
        `UN:     r_arg_types_packed = `UN_ARGS;     \
        `TX:     r_arg_types_packed = `TX_ARGS;     \
        `NOP:    r_arg_types_packed = `NOP_ARGS;    \
        `ADD8:   r_arg_types_packed = `ADD8_ARGS;   \
        `ADD16:  r_arg_types_packed = `ADD16_ARGS;  \
        `ADD32:  r_arg_types_packed = `ADD32_ARGS;  \
        `ADD64:  r_arg_types_packed = `ADD64_ARGS;  \
                                                    \
        `ADDI64: r_arg_types_packed = `ADDI64_ARGS; \
        `ADDI8:  r_arg_types_packed = `ADDI8_ARGS;  \
        `ADDI16: r_arg_types_packed = `ADDI16_ARGS; \
        `ADDI32: r_arg_types_packed = `ADDI32_ARGS; \
                                                    \
        `LI8:    r_arg_types_packed = `LI8_ARGS;    \
        `LI16:   r_arg_types_packed = `LI16_ARGS;   \
        `LI32:   r_arg_types_packed = `LI32_ARGS;   \
        `LI64:   r_arg_types_packed = `LI64_ARGS;   \
        default: r_arg_types_packed = {ARG_N, ARG_N, ARG_N, ARG_N}; \
    endcase

`define exec \
    case (r_instr)  \
        `UN:     `UN_EXEC;      \
        `TX:     `TX_EXEC;      \
        `NOP:    `NOP_EXEC;     \
                                \
        `ADD8:   `ADD8_EXEC;    \
        `ADD16:  `ADD16_EXEC;   \
        `ADD32:  `ADD32_EXEC;   \
        `ADD64:  `ADD64_EXEC;   \
                                \
        `ADDI8:   `ADDI8_EXEC;  \
        `ADDI16:  `ADDI16_EXEC; \
        `ADDI32:  `ADDI32_EXEC; \
        `ADDI64:  `ADDI64_EXEC; \
                                \
        `LI8:   `LI8_EXEC;      \
        `LI16:  `LI16_EXEC;     \
        `LI32:  `LI32_EXEC;     \
        `LI64:  `LI64_EXEC;     \
    endcase

// Program execution control
`define UN      'h00
`define UN_ARGS     {ARG_N, ARG_N, ARG_N, ARG_N}
`define UN_EXEC     // TODO
`define TX      'h01
`define TX_ARGS     {ARG_N, ARG_N, ARG_N, ARG_N}
`define TX_EXEC     r_state <= DONE
`define NOP     'h02
`define NOP_ARGS    {ARG_N, ARG_N, ARG_N, ARG_N}
`define NOP_EXEC

// Register-register addition
`define ADD8    'h03
`define ADD8_ARGS   {ARG_R, ARG_R, ARG_R, ARG_N}
`define ADD8_EXEC   set_register(r_arg_regs[0], r_registers[r_arg_regs[1]] + r_registers[r_arg_regs[2]][0+:8])
`define ADD16   'h04
`define ADD16_ARGS  {ARG_R, ARG_R, ARG_R, ARG_N}
`define ADD16_EXEC  set_register(r_arg_regs[0], r_registers[r_arg_regs[1]] + r_registers[r_arg_regs[2]][0+:16])
`define ADD32   'h05
`define ADD32_ARGS  {ARG_R, ARG_R, ARG_R, ARG_N}
`define ADD32_EXEC  set_register(r_arg_regs[0], r_registers[r_arg_regs[1]] + r_registers[r_arg_regs[2]][0+:32])
`define ADD64   'h06
`define ADD64_ARGS  {ARG_R, ARG_R, ARG_R, ARG_N}
`define ADD64_EXEC  set_register(r_arg_regs[0], r_registers[r_arg_regs[1]] + r_registers[r_arg_regs[2]][0+:64])

// Merged divide-remainder
`define DIRU8   'h20

// Unary register operations
`define NEG     'h28
`define NOT     'h29

// Register-immediate addition
`define ADDI8   'h2D
`define ADDI8_ARGS  {ARG_R, ARG_R, ARG_B, ARG_N}
`define ADDI8_EXEC  set_register(r_arg_regs[0], r_registers[r_arg_regs[1]] + r_arg_imm[0+:8])
`define ADDI16  'h2E
`define ADDI16_ARGS {ARG_R, ARG_R, ARG_H, ARG_N}
`define ADDI16_EXEC set_register(r_arg_regs[0], r_registers[r_arg_regs[1]] + r_arg_imm[0+:16])
`define ADDI32  'h2F
`define ADDI32_ARGS {ARG_R, ARG_R, ARG_W, ARG_N}
`define ADDI32_EXEC set_register(r_arg_regs[0], r_registers[r_arg_regs[1]] + r_arg_imm[0+:32])
`define ADDI64  'h30
`define ADDI64_ARGS {ARG_R, ARG_R, ARG_D, ARG_N}
`define ADDI64_EXEC set_register(r_arg_regs[0], r_registers[r_arg_regs[1]] + r_arg_imm[0+:64])

// Register-immediate bitshifts
`define SLUI8   'h38

// Register copies
`define CP      'h46

// Load immediate
`define LI set_register(r_arg_regs[0], r_arg_imm)

`define LI8     'h48
`define LI8_ARGS    {ARG_R, ARG_B, ARG_N, ARG_N}
`define LI8_EXEC    `LI
`define LI16    'h49
`define LI16_ARGS   {ARG_R, ARG_H, ARG_N, ARG_N}
`define LI16_EXEC   `LI
`define LI32    'h4A
`define LI32_ARGS   {ARG_R, ARG_W, ARG_N, ARG_N}
`define LI32_EXEC   `LI
`define LI64    'h4B
`define LI64_ARGS   {ARG_R, ARG_D, ARG_N, ARG_N}
`define LI64_EXEC   `LI

// Conditional jump
`define JEQ     'h56