From 0bf2d80a0464612b13a89ffb0a02991d3b47703c Mon Sep 17 00:00:00 2001 From: Guy Perfect Date: Fri, 7 Aug 2020 20:04:11 -0500 Subject: [PATCH] Implementing instruction decoder --- src/core/cpu.c | 137 +++++++++++++++++++++++ src/core/include/vue.h | 96 ++++++++++++++++ src/core/vue.c | 11 ++ src/desktop/vue/Instruction.java | 181 +++++++++++++++++++++++++++++++ src/desktop/vue/VUE.java | 79 ++++++++++++++ 5 files changed, 504 insertions(+) create mode 100644 src/desktop/vue/Instruction.java diff --git a/src/core/cpu.c b/src/core/cpu.c index 48f51ee..f1e7e5e 100644 --- a/src/core/cpu.c +++ b/src/core/cpu.c @@ -17,6 +17,143 @@ #define CPU_DUMP 6 #define CPU_RESTORE 7 +/* Intermediate instruction IDs */ +#define BITSTRING -2 +#define FLOATENDO -3 + +/* Opcode lookup table */ +static const int8_t LOOKUP_OPCODE[] = { + VUE_MOV_REG, 1, VUE_ADD_REG, 1, VUE_SUB , 1, VUE_CMP_REG, 1, + VUE_SHL_REG, 1, VUE_SHR_REG, 1, VUE_JMP , 1, VUE_SAR_REG, 1, + VUE_MUL , 1, VUE_DIV , 1, VUE_MULU , 1, VUE_DIVU , 1, + VUE_OR , 1, VUE_AND , 1, VUE_XOR , 1, VUE_NOT , 1, + VUE_MOV_IMM,-2, VUE_ADD_IMM,-2, VUE_SETF , 2, VUE_CMP_IMM,-2, + VUE_SHL_IMM, 2, VUE_SHR_IMM, 2, VUE_CLI , 2, VUE_SAR_IMM, 2, + VUE_TRAP , 2, VUE_RETI , 2, VUE_HALT , 2, VUE_ILLEGAL, 0, + VUE_LDSR , 2, VUE_STSR , 2, VUE_SEI , 2, BITSTRING , 2, + VUE_BCOND , 3, VUE_BCOND , 3, VUE_BCOND , 3, VUE_BCOND , 3, + VUE_BCOND , 3, VUE_BCOND , 3, VUE_BCOND , 3, VUE_BCOND , 3, + VUE_MOVEA ,-5, VUE_ADDI ,-5, VUE_JR , 4, VUE_JAL , 4, + VUE_ORI , 5, VUE_ANDI , 5, VUE_XORI , 5, VUE_MOVHI , 5, + VUE_LD_B , 6, VUE_LD_H , 6, VUE_ILLEGAL, 0, VUE_LD_W , 6, + VUE_ST_B , 6, VUE_ST_H , 6, VUE_ILLEGAL, 0, VUE_ST_W , 6, + VUE_IN_B , 6, VUE_IN_H , 6, VUE_CAXI , 6, VUE_IN_W , 6, + VUE_OUT_B , 6, VUE_OUT_H , 6, FLOATENDO , 7, VUE_OUT_W , 6 +}; + +/* Bit string lookup table */ +static const int8_t LOOKUP_BITSTRING[] = { + VUE_SCH0BSU, VUE_SCH0BSD, VUE_SCH1BSU, VUE_SCH1BSD, + VUE_ILLEGAL, VUE_ILLEGAL, VUE_ILLEGAL, VUE_ILLEGAL, + VUE_ORBSU , VUE_ANDBSU , VUE_XORBSU , VUE_MOVBSU , + VUE_ORNBSU , VUE_ANDNBSU, VUE_XORNBSU, VUE_XORNBSU +}; + +/* Floating-point and Nintendo lookup table */ +static const int8_t LOOKUP_FLOATENDO[] = { + VUE_CMPF_S , VUE_ILLEGAL, VUE_CVT_WS , VUE_CVT_SW , + VUE_ADDF_S , VUE_SUBF_S , VUE_MULF_S , VUE_DIVF_S , + VUE_XB , VUE_XH , VUE_REV , VUE_TRNC_SW, + VUE_MPYHW , VUE_ILLEGAL, VUE_ILLEGAL, VUE_ILLEGAL +}; + + + +/***************************************************************************** + * Instruction Functions * + *****************************************************************************/ + +/* Decoder for Format I */ +static void cpuFormatI(VUE_INST *inst) { + inst->reg2 = inst->bits >> 21 & 31; + inst->reg1 = inst->bits >> 16 & 31; +} + +/* Decoder for Format II */ +static void cpuFormatII(VUE_INST *inst, int extend) { + int32_t imm = inst->bits >> 16 & 31; + inst->reg2 = inst->bits >> 21 & 31; + inst->imm = extend ? SIGN_EXTEND(5, imm) : imm; +} + +/* Decoder for Format III */ +static void cpuFormatIII(VUE_INST *inst) { + int32_t disp = inst->bits >> 16 & 0x1FF; + inst->opcode = 0x20; + inst->cond = inst->bits >> 25 & 15; + inst->disp = SIGN_EXTEND(9, disp); +} + +/* Decoder for Format IV */ +static void cpuFormatIV(VUE_INST *inst) { + int32_t disp = inst->bits & 0x3FFFFFF; + inst->disp = SIGN_EXTEND(26, disp); +} + +/* Decoder for Format V */ +static void cpuFormatV(VUE_INST *inst, int extend) { + int32_t imm = inst->bits & 0xFFFF; + inst->reg2 = inst->bits >> 21 & 31; + inst->reg1 = inst->bits >> 16 & 31; + inst->imm = extend ? SIGN_EXTEND(16, imm) : imm; +} + +/* Decoder for Format VI */ +static void cpuFormatVI(VUE_INST *inst) { + int32_t disp = inst->bits & 0xFFFF; + inst->reg2 = inst->bits >> 21 & 31; + inst->reg1 = inst->bits >> 16 & 31; + inst->disp = SIGN_EXTEND(16, disp); +} + +/* Decoder for Format VII */ +static void cpuFormatVII(VUE_INST *inst) { + inst->reg2 = inst->bits >> 21 & 31; + inst->reg1 = inst->bits >> 16 & 31; + inst->subopcode = inst->bits >> 10 & 63; +} + +/* Decode an instruction from its binary encoding */ +static void cpuDecode(VUE_INST *inst, int32_t bits) { + int extend; + + /* Configure instance fields */ + inst->bits = bits; + inst->opcode = bits >> 26 & 63; + inst->id = inst->opcode << 1 | 1; + inst->format = LOOKUP_OPCODE[inst->id + 1]; + inst->id = LOOKUP_OPCODE[inst->id]; + + /* Determine whether to sign-extend the immediate operand */ + if ((extend = inst->format < 0)) + inst->format = -inst->format; + + /* Determine the size in bytes of the instruction */ + inst->size = inst->format < 4 ? 2 : 4; + if (inst->size == 2) + inst->bits &= 0xFFFF0000; + + /* Decode by format */ + switch (inst->format) { + case 0: return; /* Nothing to do */ + case 1: cpuFormatI (inst ); break; + case 2: cpuFormatII (inst, extend); break; + case 3: cpuFormatIII(inst ); break; + case 4: cpuFormatIV (inst ); break; + case 5: cpuFormatV (inst, extend); break; + case 6: cpuFormatVI (inst ); break; + case 7: cpuFormatVII(inst ); break; + } + + /* Resolve final instruction ID by subopcode */ + if (inst->id == FLOATENDO) + inst->id = inst->subopcode >= 16 ? VUE_ILLEGAL : + LOOKUP_FLOATENDO[inst->subopcode]; + else if (inst->id == BITSTRING) + inst->id = inst->imm >= 16 ? VUE_ILLEGAL : + LOOKUP_BITSTRING[inst->imm ]; +} + /***************************************************************************** diff --git a/src/core/include/vue.h b/src/core/include/vue.h index b462497..0c79a42 100644 --- a/src/core/include/vue.h +++ b/src/core/include/vue.h @@ -54,6 +54,85 @@ extern "C" { #define VUE_SP 3 #define VUE_TP 5 +/* Instruction IDs */ +#define VUE_ILLEGAL -1 +#define VUE_ADD_IMM 0 +#define VUE_ADD_REG 1 +#define VUE_ADDF_S 2 +#define VUE_ADDI 3 +#define VUE_AND 4 +#define VUE_ANDBSU 5 +#define VUE_ANDI 6 +#define VUE_ANDNBSU 7 +#define VUE_BCOND 8 +#define VUE_CAXI 9 +#define VUE_CLI 10 +#define VUE_CMP_IMM 11 +#define VUE_CMP_REG 12 +#define VUE_CMPF_S 13 +#define VUE_CVT_SW 14 +#define VUE_CVT_WS 15 +#define VUE_DIV 16 +#define VUE_DIVF_S 17 +#define VUE_DIVU 18 +#define VUE_HALT 19 +#define VUE_IN_B 20 +#define VUE_IN_H 21 +#define VUE_IN_W 22 +#define VUE_JAL 23 +#define VUE_JMP 24 +#define VUE_JR 25 +#define VUE_LD_B 26 +#define VUE_LD_H 27 +#define VUE_LD_W 28 +#define VUE_LDSR 29 +#define VUE_MOV_IMM 30 +#define VUE_MOV_REG 31 +#define VUE_MOVBSU 32 +#define VUE_MOVEA 33 +#define VUE_MOVHI 34 +#define VUE_MPYHW 35 +#define VUE_MUL 36 +#define VUE_MULF_S 37 +#define VUE_MULU 38 +#define VUE_NOT 39 +#define VUE_NOTBSU 40 +#define VUE_OR 41 +#define VUE_ORBSU 42 +#define VUE_ORI 43 +#define VUE_ORNBSU 44 +#define VUE_OUT_B 45 +#define VUE_OUT_H 46 +#define VUE_OUT_W 47 +#define VUE_RETI 48 +#define VUE_REV 49 +#define VUE_SAR_IMM 50 +#define VUE_SAR_REG 51 +#define VUE_SCH0BSD 52 +#define VUE_SCH0BSU 53 +#define VUE_SCH1BSD 54 +#define VUE_SCH1BSU 55 +#define VUE_SEI 56 +#define VUE_SETF 57 +#define VUE_SHL_IMM 58 +#define VUE_SHL_REG 59 +#define VUE_SHR_IMM 60 +#define VUE_SHR_REG 61 +#define VUE_ST_B 62 +#define VUE_ST_H 63 +#define VUE_ST_W 64 +#define VUE_STSR 65 +#define VUE_SUB 66 +#define VUE_SUBF_S 67 +#define VUE_TRAP 68 +#define VUE_TRNC_SW 69 +#define VUE_XB 70 +#define VUE_XH 71 +#define VUE_XOR 72 +#define VUE_XORBSU 73 +#define VUE_XORI 74 +#define VUE_XORNBSU 75 + /***************************************************************************** @@ -63,6 +142,21 @@ extern "C" { /* Boolean */ typedef int vbool; +/* Instruction state */ +typedef struct { + int32_t bits; /* Binary encoding */ + int32_t disp; /* Displacement for jumps and branches */ + int32_t imm; /* Immediate operand */ + uint8_t cond; /* Condition for Bcond */ + int8_t format; /* Binary format */ + int8_t id; /* Library-specific identifier */ + uint8_t opcode; /* Instruction opcode */ + uint8_t reg1; /* Source/right register */ + uint8_t reg2; /* Destination/left register */ + uint8_t size; /* Number of bytes in encoding */ + uint8_t subopcode; /* Instruction subopcode */ +} VUE_INST; + /* Emulation state */ typedef struct { @@ -127,6 +221,8 @@ typedef struct { uint16_t ecr_fecc; /* Fatal Error Cause Code */ } cpu; + /* Additional fields */ + VUE_INST inst; /* Instruction state */ } VUE; diff --git a/src/core/vue.c b/src/core/vue.c index c5444dc..99b6643 100644 --- a/src/core/vue.c +++ b/src/core/vue.c @@ -2,6 +2,17 @@ #include + +/***************************************************************************** + * Macros * + *****************************************************************************/ + +/* Sign-extend a value */ +#define SIGN_EXTEND(bits, value) \ + ((value) & 1 << (bits - 1) ? (value) | (~(1 << bits) + 1) : (value)) + + + /***************************************************************************** * Constants * *****************************************************************************/ diff --git a/src/desktop/vue/Instruction.java b/src/desktop/vue/Instruction.java new file mode 100644 index 0000000..a224f7a --- /dev/null +++ b/src/desktop/vue/Instruction.java @@ -0,0 +1,181 @@ +package vue; + +// Instruction state and decoder +public class Instruction { + + // Instruction fields + public int bits; // Binary encoding + public int cond; // Condition for Bcond + public int disp; // Displacement for jumps and branches + public int format; // Binary format + public int id; // Library-specific identifier + public int imm; // Immediate operand + public int opcode; // Instruction opcode + public int reg1; // Source/right register + public int reg2; // Destination/left register + public int size; // Number of bytes in encoding + public int subopcode; // Instruction subopcode + + + + /////////////////////////////////////////////////////////////////////////// + // Constants // + /////////////////////////////////////////////////////////////////////////// + + // Intermediate instruction IDs + private static final int BITSTRING = -2; + private static final int FLOATENDO = -3; + + // Opcode lookup table + private static final byte[] LOOKUP_OPCODE = { + VUE.MOV_REG, 1, VUE.ADD_REG, 1, VUE.SUB , 1, VUE.CMP_REG, 1, + VUE.SHL_REG, 1, VUE.SHR_REG, 1, VUE.JMP , 1, VUE.SAR_REG, 1, + VUE.MUL , 1, VUE.DIV , 1, VUE.MULU , 1, VUE.DIVU , 1, + VUE.OR , 1, VUE.AND , 1, VUE.XOR , 1, VUE.NOT , 1, + VUE.MOV_IMM,-2, VUE.ADD_IMM,-2, VUE.SETF , 2, VUE.CMP_IMM,-2, + VUE.SHL_IMM, 2, VUE.SHR_IMM, 2, VUE.CLI , 2, VUE.SAR_IMM, 2, + VUE.TRAP , 2, VUE.RETI , 2, VUE.HALT , 2, VUE.ILLEGAL, 0, + VUE.LDSR , 2, VUE.STSR , 2, VUE.SEI , 2, BITSTRING , 2, + VUE.BCOND , 3, VUE.BCOND , 3, VUE.BCOND , 3, VUE.BCOND , 3, + VUE.BCOND , 3, VUE.BCOND , 3, VUE.BCOND , 3, VUE.BCOND , 3, + VUE.MOVEA ,-5, VUE.ADDI ,-5, VUE.JR , 4, VUE.JAL , 4, + VUE.ORI , 5, VUE.ANDI , 5, VUE.XORI , 5, VUE.MOVHI , 5, + VUE.LD_B , 6, VUE.LD_H , 6, VUE.ILLEGAL, 0, VUE.LD_W , 6, + VUE.ST_B , 6, VUE.ST_H , 6, VUE.ILLEGAL, 0, VUE.ST_W , 6, + VUE.IN_B , 6, VUE.IN_H , 6, VUE.CAXI , 6, VUE.IN_W , 6, + VUE.OUT_B , 6, VUE.OUT_H , 6, FLOATENDO , 7, VUE.OUT_W , 6 + }; + + // Bit string lookup table + private static final byte[] LOOKUP_BITSTRING = { + VUE.SCH0BSU, VUE.SCH0BSD, VUE.SCH1BSU, VUE.SCH1BSD, + VUE.ILLEGAL, VUE.ILLEGAL, VUE.ILLEGAL, VUE.ILLEGAL, + VUE.ORBSU , VUE.ANDBSU , VUE.XORBSU , VUE.MOVBSU , + VUE.ORNBSU , VUE.ANDNBSU, VUE.XORNBSU, VUE.XORNBSU + }; + + // Floating-point and Nintendo lookup table + private static final byte[] LOOKUP_FLOATENDO = { + VUE.CMPF_S , VUE.ILLEGAL, VUE.CVT_WS , VUE.CVT_SW , + VUE.ADDF_S , VUE.SUBF_S , VUE.MULF_S , VUE.DIVF_S , + VUE.XB , VUE.XH , VUE.REV , VUE.TRNC_SW, + VUE.MPYHW , VUE.ILLEGAL, VUE.ILLEGAL, VUE.ILLEGAL + }; + + + + /////////////////////////////////////////////////////////////////////////// + // Static Methods // + /////////////////////////////////////////////////////////////////////////// + + // Determine the size of an instruction given its opcode + public static int size(int opcode) { + return LOOKUP_OPCODE[opcode << 1 | 1] < 4 ? 2 : 4; + } + + + + /////////////////////////////////////////////////////////////////////////// + // Constructors // + /////////////////////////////////////////////////////////////////////////// + + // Default constructor + Instruction() { } + + + + /////////////////////////////////////////////////////////////////////////// + // Public Methods // + /////////////////////////////////////////////////////////////////////////// + + // Decode an instruction from its binary encoding + public void decode(int bits) { + + // Configure instance fields + this.bits = bits; + opcode = bits >> 26 & 63; + id = opcode << 1 | 1; + format = LOOKUP_OPCODE[id + 1]; + id = LOOKUP_OPCODE[id]; + + // Determine whether to sign-extend the immediate operand + boolean extend = format < 0; + if (extend) + format = -format; + + // Determine the size in bytes of the instruction + size = format < 4 ? 2 : 4; + if (size == 2) + this.bits &= 0xFFFF0000; + + // Decode by format + switch (format) { + case 0: return; // Nothing to do + case 1: formatI ( ); break; + case 2: formatII (extend); break; + case 3: formatIII( ); break; + case 4: formatIV ( ); break; + case 5: formatV (extend); break; + case 6: formatVI ( ); break; + case 7: formatVII( ); break; + } + + // Resolve final instruction ID by subopcode + if (id == FLOATENDO) + id = subopcode >= 16 ? VUE.ILLEGAL : LOOKUP_FLOATENDO[subopcode]; + else if (id == BITSTRING) + id = imm >= 16 ? VUE.ILLEGAL : LOOKUP_BITSTRING[imm ]; + } + + + + /////////////////////////////////////////////////////////////////////////// + // Private Methods // + /////////////////////////////////////////////////////////////////////////// + + // Decoder for Format I + private void formatI() { + reg2 = bits >> 21 & 31; + reg1 = bits >> 16 & 31; + } + + // Decoder for Format II + private void formatII(boolean extend) { + reg2 = bits >> 21 & 31; + imm = extend ? bits << 11 >> 27 : bits >> 16 & 31; + } + + // Decoder for Format III + private void formatIII() { + opcode = 0x20; + cond = bits >> 25 & 15; + disp = bits << 7 >> 25; + } + + // Decoder for Format IV + private void formatIV() { + disp = bits << 6 >> 6; + } + + // Decoder for Format V + private void formatV(boolean extend) { + reg2 = bits >> 21 & 31; + reg1 = bits >> 16 & 31; + imm = extend ? bits << 16 >> 16 : bits & 0x0000FFFF; + } + + // Decoder for Format VI + private void formatVI() { + reg2 = bits >> 21 & 31; + reg1 = bits >> 16 & 31; + disp = bits << 16 >> 16; + } + + // Decoder for Format VII + private void formatVII() { + reg2 = bits >> 21 & 31; + reg1 = bits >> 16 & 31; + subopcode = bits >> 10 & 63; + } + +} diff --git a/src/desktop/vue/VUE.java b/src/desktop/vue/VUE.java index 72076ae..c35c957 100644 --- a/src/desktop/vue/VUE.java +++ b/src/desktop/vue/VUE.java @@ -43,6 +43,85 @@ public abstract class VUE { public static final int SP = 3; public static final int TP = 5; + // Instruction IDs + public static final int ILLEGAL = -1; + public static final int ADD_IMM = 0; + public static final int ADD_REG = 1; + public static final int ADDF_S = 2; + public static final int ADDI = 3; + public static final int AND = 4; + public static final int ANDBSU = 5; + public static final int ANDI = 6; + public static final int ANDNBSU = 7; + public static final int BCOND = 8; + public static final int CAXI = 9; + public static final int CLI = 10; + public static final int CMP_IMM = 11; + public static final int CMP_REG = 12; + public static final int CMPF_S = 13; + public static final int CVT_SW = 14; + public static final int CVT_WS = 15; + public static final int DIV = 16; + public static final int DIVF_S = 17; + public static final int DIVU = 18; + public static final int HALT = 19; + public static final int IN_B = 20; + public static final int IN_H = 21; + public static final int IN_W = 22; + public static final int JAL = 23; + public static final int JMP = 24; + public static final int JR = 25; + public static final int LD_B = 26; + public static final int LD_H = 27; + public static final int LD_W = 28; + public static final int LDSR = 29; + public static final int MOV_IMM = 30; + public static final int MOV_REG = 31; + public static final int MOVBSU = 32; + public static final int MOVEA = 33; + public static final int MOVHI = 34; + public static final int MPYHW = 35; + public static final int MUL = 36; + public static final int MULF_S = 37; + public static final int MULU = 38; + public static final int NOT = 39; + public static final int NOTBSU = 40; + public static final int OR = 41; + public static final int ORBSU = 42; + public static final int ORI = 43; + public static final int ORNBSU = 44; + public static final int OUT_B = 45; + public static final int OUT_H = 46; + public static final int OUT_W = 47; + public static final int RETI = 48; + public static final int REV = 49; + public static final int SAR_IMM = 50; + public static final int SAR_REG = 51; + public static final int SCH0BSD = 52; + public static final int SCH0BSU = 53; + public static final int SCH1BSD = 54; + public static final int SCH1BSU = 55; + public static final int SEI = 56; + public static final int SETF = 57; + public static final int SHL_IMM = 58; + public static final int SHL_REG = 59; + public static final int SHR_IMM = 60; + public static final int SHR_REG = 61; + public static final int ST_B = 62; + public static final int ST_H = 63; + public static final int ST_W = 64; + public static final int STSR = 65; + public static final int SUB = 66; + public static final int SUBF_S = 67; + public static final int TRAP = 68; + public static final int TRNC_SW = 69; + public static final int XB = 70; + public static final int XH = 71; + public static final int XOR = 72; + public static final int XORBSU = 73; + public static final int XORI = 74; + public static final int XORNBSU = 75; + ///////////////////////////////////////////////////////////////////////////