diff --git a/cpu/cpu.h b/cpu/cpu.h
index 8efd834..15f0b52 100644
--- a/cpu/cpu.h
+++ b/cpu/cpu.h
@@ -62,6 +62,31 @@ enum IME_state
   IME_ON,
 };
 
+struct opcode {
+  const opcode_t value;
+
+  inline operator opcode_t() const
+  { return value; }
+
+  inline u8 reg8idxlo() const
+  { return value & 0x7; }
+
+  inline u8 reg8idxhi() const
+  { return (value >> 3) & 0x7; }
+
+  inline u8 reg16idx() const
+  { return (value >> 4) & 0x3; }
+
+  inline AluOp aluop() const
+  { return (AluOp)((value >> 3) & 0x7); }
+
+  inline u8 cc() const
+  { return (value >> 3) & 0x3; }
+
+  inline u16 rst_addr() const
+  { return (u16)(value & 0x38); }
+};
+
 struct Cpu_state {
   // Registers
   union {
diff --git a/cpu/decoder.cpp b/cpu/decoder.cpp
index fb6c6ba..0d6d0f7 100644
--- a/cpu/decoder.cpp
+++ b/cpu/decoder.cpp
@@ -20,7 +20,8 @@ static inline void add16(Cpu& cpu, u16& out, u16 lhs, u16 rhs)
 void Cpu::executeInstruction()
 {
   u16 currentpc = state.PC;
-  opcode_t op = readPC8();
+  opcode op{ readPC8() };
+
   int mcycles = 1;
 
 #if 0
@@ -30,41 +31,41 @@ void Cpu::executeInstruction()
   if ((op & 0xC0) == 0x40 && op != 0x76) // LD r, r'; LD r, [HL]; LD [HL], r
     {
       u8 tmp;
-      switch(op & 0x07)
+      switch(op.reg8idxlo())
         {
         case 0x6: tmp = bus->read8(state.HL); break;
-        default: tmp = state.reg8(op & 0x07); break;
+        default: tmp = state.reg8(op.reg8idxlo()); break;
         };
 
-      switch((op >> 3) & 0x7)
+      switch(op.reg8idxhi())
         {
         case 0x6: bus->write8(state.HL, tmp); break;
-        default: state.reg8((op >> 3) & 0x7) = tmp; break;
+        default: state.reg8(op.reg8idxhi()) = tmp; break;
         }
     }
   else if((op & 0xC7) == 0x06) // LD r, n
     {
       u8 imm = readPC8();
 
-      switch((op >> 3) & 0x7)
+      switch(op.reg8idxhi())
         {
         case 0x6: bus->write8(state.HL, imm); break;
-        default: state.reg8((op >> 3) & 0x7) = imm; break;
+        default: state.reg8(op.reg8idxhi()) = imm; break;
         }
     }
   else if((op & 0xCF) == 0x01) // LD rr, nn
     {
       u16 data = readPC16();
-      state.reg16((op >> 4) & 0x3) = data;
+      state.reg16(op.reg16idx()) = data;
       mcycles = 3;
     }
   else if((op & 0xCF) == 0xC5) // PUSH rr
     {
       u16 data;
-      switch((op >> 4) & 0x3)
+      switch(op.reg16idx())
         {
         case 0x3: data = state.getAF(); break;
-        default: data = state.reg16((op >> 4) & 0x3);
+        default: data = state.reg16(op.reg16idx());
         }
 
       pushStack16(data);
@@ -75,39 +76,35 @@ void Cpu::executeInstruction()
     {
       u16 data = popStack16();
 
-      switch((op >> 4) & 0x3)
+      switch(op.reg16idx())
         {
         case 0x3: state.setAF(data); break;
-        default: state.reg16((op >> 4) & 0x3) = data; break;
+        default: state.reg16(op.reg16idx()) = data; break;
         }
 
       mcycles = 4;
     }
   else if((op & 0xC0) == 0x80) // ADD, ADC, SUB, SBC, CP, AND, OR, XOR
     {
-      AluOp aluop = (AluOp)((op >> 3) & 0x3);
-      u8 reg = op & 0x7;
-
       u8 rhs;
-      switch(reg)
+      switch(op.reg8idxlo())
         {
         case 0x6: rhs = bus->read8(state.HL); mcycles = 2; break;
-        default: rhs = state.reg8(reg); break;
+        default: rhs = state.reg8(op.reg8idxlo()); break;
         }
 
-      aluop8(aluop, rhs);
+      aluop8(op.aluop(), rhs);
     }
   else if((op & 0xC7) == 0xC6) // ADD n, ADC n, SUB n, SBC n, AND n, XOR n, OR n, CP n
     {
-      AluOp aluop = (AluOp)((op >> 3) & 0x3);
-      aluop8(aluop, readPC8());
+      aluop8(op.aluop(), readPC8());
       mcycles = 2;
     }
   else if((op & 0xC6) == 0x04) // INC r; INC [HL]; DEC r; DEC [HL];
     {
       AluOp aluop = (op & 0x1) ? SUB : ADD;
 
-      switch((op >> 3) & 0x7)
+      switch(op.reg8idxhi())
         {
         case 0x6:
           {
@@ -119,7 +116,7 @@ void Cpu::executeInstruction()
           break;
         default:
           {
-            u8& reg = state.reg8((op >> 3) & 0x7);
+            u8& reg = state.reg8(op.reg8idxhi());
             aluop8(aluop, reg, 1, reg, false); break;
           }
           break;
@@ -127,14 +124,14 @@ void Cpu::executeInstruction()
     }
   else if((op & 0xC7) == 0x03) // INC rr; DEC rr
     {
-      state.reg16((op >> 4) & 0x3) += ((op & 0x08) ? -1 : 1);
+      state.reg16(op.reg16idx()) += ((op & 0x08) ? -1 : 1);
       mcycles = 2;
     }
   else if((op & 0xE7) == 0xC2) // JP cc, nn:
     {
       u16 nn = readPC16();
 
-      if (decodeCond((op >> 3) && 0x3))
+      if (decodeCond(op.cc()))
         {
           state.PC = nn;
           mcycles = 4;
@@ -147,7 +144,7 @@ void Cpu::executeInstruction()
       s8 e = readPC8();
 
       bool cond;
-      if (decodeCond((op >> 3) & 0x3))
+      if (decodeCond(op.cc()))
         {
           state.PC += e;
           mcycles = 3;
@@ -159,7 +156,7 @@ void Cpu::executeInstruction()
     {
       u16 nn = readPC16();
 
-      if(decodeCond((op >> 3) & 0x3))
+      if(decodeCond(op.cc()))
         {
           doCall(nn);
           mcycles = 6;
@@ -169,12 +166,12 @@ void Cpu::executeInstruction()
     }
   else if((op & 0xCF) == 0x09) // ADD HL, rr
     {
-      add16(*this, state.HL, state.HL, state.reg16((op >> 4) & 0x3));
+      add16(*this, state.HL, state.HL, state.reg16(op.reg16idx()));
       mcycles = 2;
     }
   else if((op & 0xE7) == 0xC0) // RET cc
     {
-      if(decodeCond((op >> 3) & 0x3))
+      if(decodeCond(op.cc()))
         {
           doRet();
           mcycles = 5;
@@ -184,29 +181,26 @@ void Cpu::executeInstruction()
     }
   else if((op & 0xC7) == 0xC7) // RST
     {
-      u16 rst_addr = op & 0x38;
-      doCall(rst_addr);
+      doCall(op.rst_addr());
     }
   else if(op == 0xCB) // PREFIX
     {
       currentpc = state.PC;
-      opcode_t prefix_op = readPC8();
+      opcode prefix_op{ readPC8() };
 
 #if 0
       printf("@0x%04x: CB opcode %02X\n", currentpc, prefix_op);
 #endif
 
-      u8 reg = prefix_op & 0x7;
-
       u8 data;
-      switch(reg)
+      switch(prefix_op.reg8idxlo())
         {
         case 0x6: data = bus->read8(state.HL); mcycles = 3; break;
-        default: data = state.reg8(reg); mcycles = 2; break;
+        default: data = state.reg8(prefix_op.reg8idxlo()); mcycles = 2; break;
         }
 
       // For BIT, RES, SET
-      u8 bit = (prefix_op >> 3) & 0x7;
+      u8 bit = prefix_op.reg8idxhi();
 
       switch(prefix_op & 0xC0)
         {
@@ -278,10 +272,10 @@ void Cpu::executeInstruction()
       // All ops except for BIT write the data back to where it came from
       if ((prefix_op & 0xC0) != 0x40)
         {
-          switch(reg)
+          switch(prefix_op.reg8idxlo())
             {
             case 0x6: bus->write8(state.HL, data); mcycles = 4; break;
-            default: state.reg8(reg) = data; break;
+            default: state.reg8(prefix_op.reg8idxlo()) = data; break;
             }
         }
     }