Skip to content

Instantly share code, notes, and snippets.

@Artem-B
Created March 30, 2026 05:11
Show Gist options
  • Select an option

  • Save Artem-B/16c8f48c3a9e3e01c49f606482422f66 to your computer and use it in GitHub Desktop.

Select an option

Save Artem-B/16c8f48c3a9e3e01c49f606482422f66 to your computer and use it in GitHub Desktop.
AVR instruction decoder
#include <cstdint>
enum class InstructionID : uint16_t {
UNKNOWN = 0xFFFF,
ADC = 0x1C00,
ADD = 0x0C00,
ADIW = 0x9600,
AND = 0x2000,
ANDI = 0x7000,
ASR = 0x9405,
BCLR = 0x9488,
BRBS = 0xF000,
BRCC = 0xF400,
BREAK = 0x9598,
BREQ = 0xF001,
BRGE = 0xF404,
BRHC = 0xF405,
BRHS = 0xF005,
BRIE = 0xF007,
BRLO = 0xF000,
BRLT = 0xF004,
BRNE = 0xF401,
BRPL = 0xF402,
BRSH = 0xF400,
BRTC = 0xF406,
BRTS = 0xF006,
BRVC = 0xF403,
BRVS = 0xF003,
BST = 0xFA00,
CALL = 0x940E,
CBI = 0x9800,
CLC = 0x9488,
CLH = 0x94D8,
CLI = 0x94F8,
CLN = 0x94A8,
CLS = 0x94C8,
CLT = 0x94E8,
CLV = 0x94B8,
CLZ = 0x9498,
COM = 0x9400,
CP = 0x1400,
CPC = 0x0400,
CPSE = 0x1000,
DEC = 0x940A,
DES = 0x940B,
EICALL = 0x9519,
EIJMP = 0x9419,
EOR = 0x2400,
FMUL = 0x0308,
FMULS = 0x0380,
ICALL = 0x9509,
IJMP = 0x9409,
IN = 0xB000,
INC = 0x9403,
JMP = 0x940C,
LAC = 0x9206,
LAS = 0x9205,
LAT = 0x9207,
LDI = 0xE000,
LDS = 0xA000,
LSR = 0x9406,
MOVW = 0x0100,
MUL = 0x9C00,
MULS = 0x0200,
MULSU = 0x0300,
NEG = 0x9401,
OR = 0x2800,
OUT = 0xB800,
POP = 0x900F,
PUSH = 0x920F,
RCALL = 0xD000,
RET = 0x9508,
RETI = 0x9518,
ROR = 0x9407,
SBCI = 0x4000,
SBI = 0x9A00,
SBIC = 0x9900,
SBIS = 0x9B00,
SBIW = 0x9700,
SBR = 0x6000,
SBRC = 0xFC00,
SBRS = 0xFE00,
SEH = 0x9458,
SEI = 0x9478,
SEN = 0x9428,
SER = 0xEF0F,
SES = 0x9448,
SET = 0x9468,
SEZ = 0x9418,
STS = 0xA800,
SUB = 0x1800,
SUBI = 0x5000,
SWAP = 0x9402,
WDR = 0x95A8,
XCH = 0x9204,
};
struct DecodedInstruction {
InstructionID id;
uint8_t rd;
uint8_t rr;
uint32_t k;
uint8_t b;
uint8_t q;
bool is_32bit;
};
// Returns decoded instruction. For 32-bit instructions (like JMP/CALL), provide the second word.
DecodedInstruction decode_avr_compact(uint16_t word1, uint16_t word2 = 0) {
DecodedInstruction inst = {InstructionID::UNKNOWN, 0, 0, 0, 0, 0, false};
uint32_t opcode32 = ((uint32_t)word1 << 16) | word2; // used for 32-bit extraction
// Top 7 bits highly optimal compiled decision tree (128 root cases)
switch (word1 >> 9) {
case 0x00:
if ((word1 & 0x0100) == 0x0100) goto fmt_xxxxxxxxddddrrrr;
break;
case 0x01:
{
if ((word1 & 0x0100) == 0x0000) goto fmt_xxxxxxxxddddrrrr;
else {
switch (word1 & 0x0188) {
case 0x0100:
case 0x0108:
case 0x0180:
goto fmt_xxxxxxxxxdddxrrr;
}
}
} break;
case 0x02:
goto fmt_xxxxxxrdddddrrrr;
case 0x03:
goto fmt_xxxxxxrdddddrrrr;
case 0x06:
goto fmt_xxxxxxrdddddrrrr;
case 0x07:
goto fmt_xxxxxxrdddddrrrr;
case 0x08:
goto fmt_xxxxxxrdddddrrrr;
case 0x09:
goto fmt_xxxxxxrdddddrrrr;
case 0x0A:
goto fmt_xxxxxxrdddddrrrr;
case 0x0B:
goto fmt_xxxxxxrdddddrrrr;
case 0x0C:
goto fmt_xxxxxxrdddddrrrr;
case 0x0D:
goto fmt_xxxxxxrdddddrrrr;
case 0x0E:
goto fmt_xxxxxxrdddddrrrr;
case 0x0F:
goto fmt_xxxxxxrdddddrrrr;
case 0x10:
goto fmt_xxxxxxrdddddrrrr;
case 0x11:
goto fmt_xxxxxxrdddddrrrr;
case 0x12:
goto fmt_xxxxxxrdddddrrrr;
case 0x13:
goto fmt_xxxxxxrdddddrrrr;
case 0x14:
goto fmt_xxxxxxrdddddrrrr;
case 0x15:
goto fmt_xxxxxxrdddddrrrr;
case 0x20:
goto fmt_xxxxKKKKddddKKKK;
case 0x21:
goto fmt_xxxxKKKKddddKKKK;
case 0x22:
goto fmt_xxxxKKKKddddKKKK;
case 0x23:
goto fmt_xxxxKKKKddddKKKK;
case 0x24:
goto fmt_xxxxKKKKddddKKKK;
case 0x25:
goto fmt_xxxxKKKKddddKKKK;
case 0x26:
goto fmt_xxxxKKKKddddKKKK;
case 0x27:
goto fmt_xxxxKKKKddddKKKK;
case 0x28:
goto fmt_xxxxKKKKddddKKKK;
case 0x29:
goto fmt_xxxxKKKKddddKKKK;
case 0x2A:
goto fmt_xxxxKKKKddddKKKK;
case 0x2B:
goto fmt_xxxxKKKKddddKKKK;
case 0x2C:
goto fmt_xxxxKKKKddddKKKK;
case 0x2D:
goto fmt_xxxxKKKKddddKKKK;
case 0x2E:
goto fmt_xxxxKKKKddddKKKK;
case 0x2F:
goto fmt_xxxxKKKKddddKKKK;
case 0x30:
goto fmt_xxxxKKKKddddKKKK;
case 0x31:
goto fmt_xxxxKKKKddddKKKK;
case 0x32:
goto fmt_xxxxKKKKddddKKKK;
case 0x33:
goto fmt_xxxxKKKKddddKKKK;
case 0x34:
goto fmt_xxxxKKKKddddKKKK;
case 0x35:
goto fmt_xxxxKKKKddddKKKK;
case 0x36:
goto fmt_xxxxKKKKddddKKKK;
case 0x37:
goto fmt_xxxxKKKKddddKKKK;
case 0x38:
goto fmt_xxxxKKKKddddKKKK;
case 0x39:
goto fmt_xxxxKKKKddddKKKK;
case 0x3A:
goto fmt_xxxxKKKKddddKKKK;
case 0x3B:
goto fmt_xxxxKKKKddddKKKK;
case 0x3C:
goto fmt_xxxxKKKKddddKKKK;
case 0x3D:
goto fmt_xxxxKKKKddddKKKK;
case 0x3E:
goto fmt_xxxxKKKKddddKKKK;
case 0x3F:
goto fmt_xxxxKKKKddddKKKK;
case 0x48:
if ((word1 & 0x000F) == 0x000F) goto fmt_xxxxxxxdddddxxxx;
break;
case 0x49:
{
switch (word1 & 0x000B) {
case 0x0000:
case 0x0001:
case 0x0002:
case 0x0003:
if ((word1 & 0x0004) == 0x0004) goto fmt_xxxxxxxrrrrrxxxx;
break;
case 0x000B:
if ((word1 & 0x0004) == 0x0004) goto fmt_xxxxxxxdddddxxxx;
break;
}
} break;
case 0x4A:
{
if ((word1 & 0x010F) == 0x000B) goto fmt_xxxxxxxxKKKKxxxx;
else if ((word1 & 0x000F) == 0x0000) goto fmt_xxxxxxxdddddxxxx;
else if ((word1 & 0x000F) == 0x0001) goto fmt_xxxxxxxdddddxxxx;
else if ((word1 & 0x000F) == 0x0002) goto fmt_xxxxxxxdddddxxxx;
else if ((word1 & 0x000F) == 0x0003) goto fmt_xxxxxxxdddddxxxx;
else if ((word1 & 0x000F) == 0x0005) goto fmt_xxxxxxxdddddxxxx;
else if ((word1 & 0x000F) == 0x0006) goto fmt_xxxxxxxdddddxxxx;
else if ((word1 & 0x000F) == 0x0007) goto fmt_xxxxxxxdddddxxxx;
else if ((word1 & 0x000F) == 0x000A) goto fmt_xxxxxxxdddddxxxx;
else if ((word1 & 0x000E) == 0x000C) goto fmt_xxxxxxxkkkkkxxxkkkkkkkkkkkkkkkkk;
else if ((word1 & 0x000E) == 0x000E) goto fmt_xxxxxxxkkkkkxxxkkkkkkkkkkkkkkkkk;
else {
switch (word1 & 0x01FF) {
case 0x0009:
case 0x0018:
case 0x0019:
case 0x0028:
case 0x0048:
case 0x0058:
case 0x0068:
case 0x0078:
case 0x0088:
case 0x0098:
case 0x00A8:
case 0x00B8:
case 0x00C8:
case 0x00D8:
case 0x00E8:
case 0x00F8:
case 0x0108:
case 0x0109:
case 0x0118:
case 0x0119:
case 0x0198:
case 0x01A8:
goto fmt_xxxxxxxxxxxxxxxx;
}
}
} break;
case 0x4B:
{
switch (word1 & 0x0100) {
case 0x0000:
case 0x0100:
goto fmt_xxxxxxxxKKddKKKK;
}
} break;
case 0x4C:
{
switch (word1 & 0x0100) {
case 0x0000:
case 0x0100:
goto fmt_xxxxxxxxAAAAAbbb;
}
} break;
case 0x4D:
{
switch (word1 & 0x0100) {
case 0x0000:
case 0x0100:
goto fmt_xxxxxxxxAAAAAbbb;
}
} break;
case 0x4E:
goto fmt_xxxxxxrdddddrrrr;
case 0x4F:
goto fmt_xxxxxxrdddddrrrr;
case 0x50:
goto fmt_xxxxxkkkddddkkkk;
case 0x51:
goto fmt_xxxxxkkkddddkkkk;
case 0x52:
goto fmt_xxxxxkkkddddkkkk;
case 0x53:
goto fmt_xxxxxkkkddddkkkk;
case 0x54:
goto fmt_xxxxxkkkddddkkkk;
case 0x55:
goto fmt_xxxxxkkkddddkkkk;
case 0x56:
goto fmt_xxxxxkkkddddkkkk;
case 0x57:
goto fmt_xxxxxkkkddddkkkk;
case 0x58:
goto fmt_xxxxxAAdddddAAAA;
case 0x59:
goto fmt_xxxxxAAdddddAAAA;
case 0x5A:
goto fmt_xxxxxAAdddddAAAA;
case 0x5B:
goto fmt_xxxxxAAdddddAAAA;
case 0x5C:
goto fmt_xxxxxAArrrrrAAAA;
case 0x5D:
goto fmt_xxxxxAArrrrrAAAA;
case 0x5E:
goto fmt_xxxxxAArrrrrAAAA;
case 0x5F:
goto fmt_xxxxxAArrrrrAAAA;
case 0x68:
goto fmt_xxxxkkkkkkkkkkkk;
case 0x69:
goto fmt_xxxxkkkkkkkkkkkk;
case 0x6A:
goto fmt_xxxxkkkkkkkkkkkk;
case 0x6B:
goto fmt_xxxxkkkkkkkkkkkk;
case 0x6C:
goto fmt_xxxxkkkkkkkkkkkk;
case 0x6D:
goto fmt_xxxxkkkkkkkkkkkk;
case 0x6E:
goto fmt_xxxxkkkkkkkkkkkk;
case 0x6F:
goto fmt_xxxxkkkkkkkkkkkk;
case 0x70:
goto fmt_xxxxKKKKddddKKKK;
case 0x71:
goto fmt_xxxxKKKKddddKKKK;
case 0x72:
goto fmt_xxxxKKKKddddKKKK;
case 0x73:
goto fmt_xxxxKKKKddddKKKK;
case 0x74:
goto fmt_xxxxKKKKddddKKKK;
case 0x75:
goto fmt_xxxxKKKKddddKKKK;
case 0x76:
goto fmt_xxxxKKKKddddKKKK;
case 0x77:
if ((word1 & 0x010F) == 0x010F) goto fmt_xxxxxxxxddddxxxx;
if ((word1 & 0x0000) == 0x0000) goto fmt_xxxxKKKKddddKKKK;
break;
case 0x78:
if ((word1 & 0x0007) == 0x0001) goto fmt_xxxxxxkkkkkkkxxx;
if ((word1 & 0x0007) == 0x0003) goto fmt_xxxxxxkkkkkkkxxx;
if ((word1 & 0x0007) == 0x0004) goto fmt_xxxxxxkkkkkkkxxx;
if ((word1 & 0x0007) == 0x0005) goto fmt_xxxxxxkkkkkkkxxx;
if ((word1 & 0x0007) == 0x0006) goto fmt_xxxxxxkkkkkkkxxx;
if ((word1 & 0x0007) == 0x0007) goto fmt_xxxxxxkkkkkkkxxx;
if ((word1 & 0x0000) == 0x0000) goto fmt_xxxxxxkkkkkkksss;
break;
case 0x79:
if ((word1 & 0x0007) == 0x0001) goto fmt_xxxxxxkkkkkkkxxx;
if ((word1 & 0x0007) == 0x0003) goto fmt_xxxxxxkkkkkkkxxx;
if ((word1 & 0x0007) == 0x0004) goto fmt_xxxxxxkkkkkkkxxx;
if ((word1 & 0x0007) == 0x0005) goto fmt_xxxxxxkkkkkkkxxx;
if ((word1 & 0x0007) == 0x0006) goto fmt_xxxxxxkkkkkkkxxx;
if ((word1 & 0x0007) == 0x0007) goto fmt_xxxxxxkkkkkkkxxx;
if ((word1 & 0x0000) == 0x0000) goto fmt_xxxxxxkkkkkkksss;
break;
case 0x7A:
{
switch (word1 & 0x0007) {
case 0x0000:
case 0x0001:
case 0x0002:
case 0x0003:
case 0x0004:
case 0x0005:
case 0x0006:
goto fmt_xxxxxxkkkkkkkxxx;
}
} break;
case 0x7B:
{
switch (word1 & 0x0007) {
case 0x0000:
case 0x0001:
case 0x0002:
case 0x0003:
case 0x0004:
case 0x0005:
case 0x0006:
goto fmt_xxxxxxkkkkkkkxxx;
}
} break;
case 0x7D:
if ((word1 & 0x0008) == 0x0000) goto fmt_xxxxxxxdddddxbbb;
break;
case 0x7E:
if ((word1 & 0x0008) == 0x0000) goto fmt_xxxxxxxrrrrrxbbb;
break;
case 0x7F:
if ((word1 & 0x0008) == 0x0000) goto fmt_xxxxxxxrrrrrxbbb;
break;
}
return inst;
fmt_xxxxxxxxddddrrrr:
inst.id = static_cast<InstructionID>(word1 & 0xFF00);
inst.rd = ((word1 >> 4) & 0xF);
inst.rr = (word1 & 0xF);
return inst;
fmt_xxxxxxxxxdddxrrr:
inst.id = static_cast<InstructionID>(word1 & 0xFF88);
inst.rd = ((word1 >> 4) & 0x7);
inst.rr = (word1 & 0x7);
return inst;
fmt_xxxxxxrdddddrrrr:
inst.id = static_cast<InstructionID>(word1 & 0xFC00);
inst.rd = ((word1 >> 4) & 0x1F);
inst.rr = (word1 & 0xF) | ((word1 >> 5) & 0x10);
return inst;
fmt_xxxxKKKKddddKKKK:
inst.id = static_cast<InstructionID>(word1 & 0xF000);
inst.k = (word1 & 0xF) | ((word1 >> 4) & 0xF0);
inst.rd = ((word1 >> 4) & 0xF);
return inst;
fmt_xxxxxxxdddddxxxx:
inst.id = static_cast<InstructionID>(word1 & 0xFE0F);
inst.is_32bit = true;
inst.rd = ((opcode32 >> 4) & 0x1F);
return inst;
fmt_xxxxxxxrrrrrxxxx:
inst.id = static_cast<InstructionID>(word1 & 0xFE0F);
inst.rr = ((word1 >> 4) & 0x1F);
return inst;
fmt_xxxxxxxxxxxxxxxx:
inst.id = static_cast<InstructionID>(word1 & 0xFFFF);
inst.is_32bit = true;
return inst;
fmt_xxxxxxxxKKKKxxxx:
inst.id = static_cast<InstructionID>(word1 & 0xFF0F);
inst.is_32bit = true;
inst.k = ((opcode32 >> 4) & 0xF);
return inst;
fmt_xxxxxxxkkkkkxxxkkkkkkkkkkkkkkkkk:
inst.id = static_cast<InstructionID>(word1 & 0xFE0E);
inst.is_32bit = true;
inst.k = (opcode32 & 0x1FFFF) | ((opcode32 >> 3) & 0x3E0000);
return inst;
fmt_xxxxxxxxKKddKKKK:
inst.id = static_cast<InstructionID>(word1 & 0xFF00);
inst.k = (word1 & 0xF) | ((word1 >> 2) & 0x30);
inst.rd = ((word1 >> 4) & 0x3);
return inst;
fmt_xxxxxxxxAAAAAbbb:
inst.id = static_cast<InstructionID>(word1 & 0xFF00);
inst.k = ((word1 >> 3) & 0x1F);
inst.b = (word1 & 0x7);
return inst;
fmt_xxxxxkkkddddkkkk:
inst.id = static_cast<InstructionID>(word1 & 0xF800);
inst.rd = ((word1 >> 4) & 0xF);
inst.k = (word1 & 0xF) | ((word1 >> 4) & 0x70);
return inst;
fmt_xxxxxAAdddddAAAA:
inst.id = static_cast<InstructionID>(word1 & 0xF800);
inst.rd = ((word1 >> 4) & 0x1F);
inst.k = (word1 & 0xF) | ((word1 >> 5) & 0x30);
return inst;
fmt_xxxxxAArrrrrAAAA:
inst.id = static_cast<InstructionID>(word1 & 0xF800);
inst.rr = ((word1 >> 4) & 0x1F);
inst.k = (word1 & 0xF) | ((word1 >> 5) & 0x30);
return inst;
fmt_xxxxkkkkkkkkkkkk:
inst.id = static_cast<InstructionID>(word1 & 0xF000);
inst.k = (word1 & 0xFFF);
return inst;
fmt_xxxxxxxxddddxxxx:
inst.id = static_cast<InstructionID>(word1 & 0xFF0F);
inst.rd = ((word1 >> 4) & 0xF);
return inst;
fmt_xxxxxxkkkkkkkxxx:
inst.id = static_cast<InstructionID>(word1 & 0xFC07);
inst.k = ((word1 >> 3) & 0x7F);
return inst;
fmt_xxxxxxkkkkkkksss:
inst.id = static_cast<InstructionID>(word1 & 0xFC00);
inst.b = (word1 & 0x7);
inst.k = ((word1 >> 3) & 0x7F);
return inst;
fmt_xxxxxxxdddddxbbb:
inst.id = static_cast<InstructionID>(word1 & 0xFE08);
inst.rd = ((word1 >> 4) & 0x1F);
inst.b = (word1 & 0x7);
return inst;
fmt_xxxxxxxrrrrrxbbb:
inst.id = static_cast<InstructionID>(word1 & 0xFE08);
inst.rr = ((word1 >> 4) & 0x1F);
inst.b = (word1 & 0x7);
return inst;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment