Created
March 30, 2026 05:11
-
-
Save Artem-B/16c8f48c3a9e3e01c49f606482422f66 to your computer and use it in GitHub Desktop.
AVR instruction decoder
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #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