#ifndef INSTRUCTION_H #define INSTRUCTION_H /** * Values used for software-only identification instruction types. Values not * tied to machine language. Guaranteed unique. */ enum INST_TYPE { INST_TYPE_R, INST_TYPE_NI, INST_TYPE_WI, INST_TYPE_JR, INST_TYPE_JI, INST_TYPE_B }; /** * Masks for all four instruction types. Not guaranteed unique */ #define MASK_INST_RTYPE (0x0000) #define MASK_INST_NITYPE (0x4000) #define MASK_INST_WITYPE (0x8000) #define MASK_INST_JTYPE (0xC000) /** * ALU operation types * R-type and I-type take 3-bit ALU oper as bits: * xx___xxx xxxxxxxx */ enum OPER { OPER_ADD = 0, OPER_SUB = 1, OPER_SHL = 2, OPER_SHR = 3, OPER_AND = 4, OPER_OR = 5, OPER_XOR = 6, OPER_MUL = 7, }; #define OPER_SHAMT (11) #define MASK_OPER(x) ((x) << OPER_SHAMT) static const char *oper_to_human[] = { [OPER_ADD] = "add", [OPER_SUB] = "sub", [OPER_SHL] = "shl", [OPER_SHR] = "shr", [OPER_AND] = "and", [OPER_OR ] = "or", [OPER_XOR] = "xor", [OPER_MUL] = "mul" }; /** * Masks for jump and branch conditions * J-type instructions (jump, branch) take these as follows: * xxx___xx xxxxxxxx */ enum JCOND { JB_UNCOND = 0x0, JB_NEVER = 0x1, JB_ZERO = 0x2, JB_NZERO = 0x3, JB_CARRY = 0x4, JB_NCARRY = 0x5, JB_CARRYZ = 0x6, JB_NCARRYZ = 0x7 }; #define JB_SHAMT (10) #define MASK_JB_COND(x) ((x) << JB_SHAMT) #define MASK_IS_JUMP (0 << 13) #define MASK_IS_BRANCH (1 << 13) #define MASK_JI (0x0 << 8) #define MASK_JR (0x1 << 8) #define MASK_JUMP_REGISTER(x) ((x) << 5) static const char *j_to_human[] = { [JB_UNCOND] = "jmp", [JB_NEVER] = "jn", [JB_ZERO] = "jz", [JB_NZERO] = "jnz", [JB_CARRY] = "jc", [JB_NCARRY] = "jnc", [JB_CARRYZ] = "jcz", [JB_NCARRYZ] = "jncz" }; static const char *b_to_human[] = { [JB_UNCOND] = "bra", [JB_NEVER] = "bn", [JB_ZERO] = "bz", [JB_NZERO] = "bnz", [JB_CARRY] = "bc", [JB_NCARRY] = "bnc", [JB_CARRYZ] = "bcz", [JB_NCARRYZ] = "bncz" }; /** * Register numbers used in all manner of instructions in varying positions */ enum REG { REG_0 = 0, REG_1 = 1, REG_2 = 2, REG_3 = 3, REG_4 = 4, REG_5 = 5, REG_6 = 6, REG_H = 7 }; static const char *reg_to_human[] = { [REG_0] = "$0", [REG_1] = "$1", [REG_2] = "$2", [REG_3] = "$3", [REG_4] = "$4", [REG_5] = "$5", [REG_6] = "$6", [REG_H] = "$H", }; /** * Offset macro to turn REG_* into mask for register operands of R-type and * I-type instructions */ /* destination reg: xxxxx___ xxxxxxxx */ #define REG_DEST_OFFSET (8) #define MASK_REG_DEST(x) ((x) << REG_DEST_OFFSET) /* left reg: xxxxxxxx ___xxxxx */ #define REG_LEFT_OFFSET (5) #define MASK_REG_LEFT(x) ((x) << REG_LEFT_OFFSET) /* right reg (R-type only): xxxxxxxx xxx___xx */ #define REG_RIGHT_OFFSET (2) #define MASK_REG_RIGHT(x) ((x) << REG_RIGHT_OFFSET) /* five LSb are narrow immediate value */ #define MASK_NI_IMM(x) ((x) & 0x1F) /* 10 LSb is branch offset */ #define MASK_B_OFFSET(x) ((x) & 0x3FF) #endif /* INSTRUCTION_H */