As my first Nim project, I want to port a hobby project of mine (written in C) to Nim.
In my C project, I have defined a huge enum:
typedef enum {
OP_ALU = 0x80,
OP_ADD = OP_ALU | 0x0,
OP_SUB = OP_ALU | 0x1,
OP_AND = OP_ALU | 0x2,
OP_OR = OP_ALU | 0x3,
OP_XOR = OP_ALU | 0x4,
OP_LSR = OP_ALU | 0x5,
OP_CPR = OP_ALU | 0x6,
OP_STACKGROUP1 = 0x90,
OP_PUSHT = OP_STACKGROUP1 | 0x0,
OP_PUSHA = OP_STACKGROUP1 | 0x1,
OP_PUSHN = OP_STACKGROUP1 | 0x2,
OP_PUSHUSP = OP_STACKGROUP1 | 0x3,
OP_PUSHI = OP_STACKGROUP1 | 0x4,
[....]
What would be a good way to represent this in Nim?
It seems that writing
type
Opcodes* = enum
OpAlu = 0x80,
OpAdd = OpAlu or 0x00,
OpSub = OpAlu or 0x01,
OpAnd = OpAlu or 0x02,
OpOr = OpAlu or 0x03,
OpXor = OpAlu or 0x04,
OpLsr = OpAlu or 0x05,
OpCpr = OpAlu or 0x06,
does not work. how about separating them into groups, this also makes sense, as OP_ALU/OP_STACKGROUP1 are not opcodes, they're just constants or categories. maybe:
const #or enum if you switch on their values somewhere
OpAlu = 0x80
OpStackGroup1 = 0x90
OpStackGroup2 = 0xa0
...
type
OpCodes = enum
OpAdd = OpAlu,
OpSub,OpAnd,OpOr,OpXor,OpLsr,OpCpr,
OpPushT = OpStackGroup1,
OpPushA,OpPushN,OpPushUsp,OpPushI
...
or however you want to lay it out visually. i like the way you've done it but i'm not gonna type that out lol.This is how I organize VM opcodes: https://github.com/status-im/nimbus-eth1/blob/5248be1/nimbus/vm/interpreter/opcode_values.nim
For emulation or code generation, I prefer to map opcodes to functions using a macro to give a declarative syntax to them:
Hardware opcodes that maps to multiple instructions depending on addressing mode (6502 / 65816): https://github.com/mratsim/glyph/blob/8b278c5/glyph/snes/opcodes.nim#L16-L177
And for x86-64 which can have variable bytes encoding: https://github.com/mratsim/photon-jit/blob/ef19544/photon_jit/x86_64/x86_64_ops.nim#L24-L96