From 41c18a2d18ac61ffc094e8d5f67ef3a115ace4c3 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Mon, 22 Jul 2024 12:50:46 +0100 Subject: [PATCH] Warn when opcodes have undefined results, eg, ld r26, X+ --- src/avr_opcodes.c | 30 +++++++++++++++--------------- src/disasm.c | 34 +++++++++++++++++++++++----------- src/libavrdude.h | 42 +++++++++++++++++++++++++----------------- 3 files changed, 63 insertions(+), 43 deletions(-) diff --git a/src/avr_opcodes.c b/src/avr_opcodes.c index 4a0e35e6..4ef94fb9 100644 --- a/src/avr_opcodes.c +++ b/src/avr_opcodes.c @@ -312,19 +312,19 @@ const AVR_opcode_data avr_opcodes[164] = { {OP_ID(ld_1), 0xfe0f, 0x900c, 1, OP_AVR2, "1001 000d dddd 1100", OTY_XFRX|OTY_RALL, "ld", "Rd, X", "Load Indirect", "Rd <-- (X)", "--------", {"2", "2", "2", "1/2"}, ""}, - {OP_ID(ld_2), 0xfe0f, 0x900d, 1, OP_AVR2, "1001 000d dddd 1101", OTY_XFRX|OTY_RALL, + {OP_ID(ld_2), 0xfe0f, 0x900d, 1, OP_AVR2, "1001 000d dddd 1101", OTY_XFRX|OTY_RALL|OTY_XWRN, "ld", "Rd, X+", "Load Indirect and Post-Increment", "Rd <-- (X), X <-- X + 1", "--------", {"2", "2", "2", "2/3"}, ""}, - {OP_ID(ld_3), 0xfe0f, 0x900e, 1, OP_AVR2, "1001 000d dddd 1110", OTY_XFRX|OTY_RALL, + {OP_ID(ld_3), 0xfe0f, 0x900e, 1, OP_AVR2, "1001 000d dddd 1110", OTY_XFRX|OTY_RALL|OTY_XWRN, "ld", "Rd, -X", "Load Indirect and Pre-Decrement", "X <-- X - 1, Rd <-- (X)", "--------", {"2", "3", "2", "2/3"}, ""}, {OP_ID(ld_4), 0xfe0f, 0x8008, 1, OP_AVR2, "1000 000d dddd 1000", OTY_XFRX|OTY_RALL, "ld", "Rd, Y", "Load Indirect", "Rd <-- (Y) <-- (Y)", "--------", {"2", "2", "2", "1/2"}, "alias for ldd Rd, Y+0"}, - {OP_ID(ld_5), 0xfe0f, 0x9009, 1, OP_AVR2, "1001 000d dddd 1001", OTY_XFRX|OTY_RALL, + {OP_ID(ld_5), 0xfe0f, 0x9009, 1, OP_AVR2, "1001 000d dddd 1001", OTY_XFRX|OTY_RALL|OTY_YWRN, "ld", "Rd, Y+", "Load Indirect and Post-Increment", "Rd <-- (Y), Y <-- Y + 1", "--------", {"2", "2", "2", "2/3"}, ""}, - {OP_ID(ld_6), 0xfe0f, 0x900a, 1, OP_AVR2, "1001 000d dddd 1010", OTY_XFRX|OTY_RALL, + {OP_ID(ld_6), 0xfe0f, 0x900a, 1, OP_AVR2, "1001 000d dddd 1010", OTY_XFRX|OTY_RALL|OTY_YWRN, "ld", "Rd, -Y", "Load Indirect and Pre-Decrement", "Y <-- Y - 1 Rd <-- (Y)", "--------", {"2", "3", "2", "2/3"}, ""}, {OP_ID(ldd_1), 0xd208, 0x8008, 1, OP_AVR2nRC, "10q0 qq0d dddd 1qqq", OTY_XFRX|OTY_RALL, @@ -333,10 +333,10 @@ const AVR_opcode_data avr_opcodes[164] = { {OP_ID(ld_7), 0xfe0f, 0x8000, 1, OP_AVR1, "1000 000d dddd 0000", OTY_XFRX|OTY_RALL, "ld", "Rd, Z", "Load Indirect", "Rd <-- (Z)", "--------", {"2", "2", "2", "1/2"}, "alias for ldd Rd, Z+0"}, - {OP_ID(ld_8), 0xfe0f, 0x9001, 1, OP_AVR1, "1001 000d dddd 0001", OTY_XFRX|OTY_RALL, + {OP_ID(ld_8), 0xfe0f, 0x9001, 1, OP_AVR1, "1001 000d dddd 0001", OTY_XFRX|OTY_RALL|OTY_ZWRN, "ld", "Rd, Z+", "Load Indirect and Post-Increment", "Rd <-- (Z), Z <-- Z + 1", "--------", {"2", "2", "2", "2/3"}, ""}, - {OP_ID(ld_9), 0xfe0f, 0x9002, 1, OP_AVR1, "1001 000d dddd 0010", OTY_XFRX|OTY_RALL, + {OP_ID(ld_9), 0xfe0f, 0x9002, 1, OP_AVR1, "1001 000d dddd 0010", OTY_XFRX|OTY_RALL|OTY_ZWRN, "ld", "Rd, -Z", "Load Indirect and Pre-Decrement", "Z <-- Z - 1, Rd <-- (Z)", "--------", {"2", "3", "2", "2/3"}, ""}, {OP_ID(ldd_2), 0xd208, 0x8000, 1, OP_AVR2nRC, "10q0 qq0d dddd 0qqq", OTY_XFRX|OTY_RALL, @@ -348,19 +348,19 @@ const AVR_opcode_data avr_opcodes[164] = { {OP_ID(st_1), 0xfe0f, 0x920c, 1, OP_AVR2, "1001 001r rrrr 1100", OTY_XFRX|OTY_RALL, "st", "X, Rr", "Store Indirect", "(X) <-- Rr", "--------", {"2", "1", "1", "1"}, ""}, - {OP_ID(st_2), 0xfe0f, 0x920d, 1, OP_AVR2, "1001 001r rrrr 1101", OTY_XFRX|OTY_RALL, + {OP_ID(st_2), 0xfe0f, 0x920d, 1, OP_AVR2, "1001 001r rrrr 1101", OTY_XFRX|OTY_RALL|OTY_XWRN, "st", "X+, Rr", "Store Indirect and Post-Increment", "(X) <-- Rr, X <-- X + 1", "--------", {"2", "1", "1", "1"}, ""}, - {OP_ID(st_3), 0xfe0f, 0x920e, 1, OP_AVR2, "1001 001r rrrr 1110", OTY_XFRX|OTY_RALL, + {OP_ID(st_3), 0xfe0f, 0x920e, 1, OP_AVR2, "1001 001r rrrr 1110", OTY_XFRX|OTY_RALL|OTY_XWRN, "st", "-X, Rr", "Store Indirect and Pre-Decrement", "X <-- X - 1, (X) <-- Rr", "--------", {"2", "2", "1", "1"}, ""}, {OP_ID(st_4), 0xfe0f, 0x8208, 1, OP_AVR2, "1000 001r rrrr 1000", OTY_XFRX|OTY_RALL, "st", "Y, Rr", "Store Indirect", "(Y) <-- Rr", "--------", {"2", "1", "1", "1"}, "alias for std Y+0, Rr"}, - {OP_ID(st_5), 0xfe0f, 0x9209, 1, OP_AVR2, "1001 001r rrrr 1001", OTY_XFRX|OTY_RALL, + {OP_ID(st_5), 0xfe0f, 0x9209, 1, OP_AVR2, "1001 001r rrrr 1001", OTY_XFRX|OTY_RALL|OTY_YWRN, "st", "Y+, Rr", "Store Indirect and Post-Increment", "(Y) <-- Rr, Y <-- Y + 1", "--------", {"2", "1", "1", "1"}, ""}, - {OP_ID(st_6), 0xfe0f, 0x920a, 1, OP_AVR2, "1001 001r rrrr 1010", OTY_XFRX|OTY_RALL, + {OP_ID(st_6), 0xfe0f, 0x920a, 1, OP_AVR2, "1001 001r rrrr 1010", OTY_XFRX|OTY_RALL|OTY_YWRN, "st", "-Y, Rr", "Store Indirect and Pre-Decrement", "Y <-- Y - 1, (Y) <-- Rr", "--------", {"2", "2", "1", "1"}, ""}, {OP_ID(std_1), 0xd208, 0x8208, 1, OP_AVR2nRC, "10q0 qq1r rrrr 1qqq", OTY_XFRX|OTY_RALL, @@ -369,10 +369,10 @@ const AVR_opcode_data avr_opcodes[164] = { {OP_ID(st_7), 0xfe0f, 0x8200, 1, OP_AVR1, "1000 001r rrrr 0000", OTY_XFRX|OTY_RALL, "st", "Z, Rr", "Store Indirect", "(Z) <-- Rr", "--------", {"2", "1", "1", "1"}, "alias for std Z+0, Rr"}, - {OP_ID(st_8), 0xfe0f, 0x9201, 1, OP_AVR1, "1001 001r rrrr 0001", OTY_XFRX|OTY_RALL, + {OP_ID(st_8), 0xfe0f, 0x9201, 1, OP_AVR1, "1001 001r rrrr 0001", OTY_XFRX|OTY_RALL|OTY_ZWRN, "st", "Z+, Rr", "Store Indirect and Post-Increment", "(Z) <-- Rr, Z <-- Z + 1", "--------", {"2", "1", "1", "1"}, ""}, - {OP_ID(st_9), 0xfe0f, 0x9202, 1, OP_AVR1, "1001 001r rrrr 0010", OTY_XFRX|OTY_RALL, + {OP_ID(st_9), 0xfe0f, 0x9202, 1, OP_AVR1, "1001 001r rrrr 0010", OTY_XFRX|OTY_RALL|OTY_ZWRN, "st", "-Z, Rr", "Store Indirect and Pre-Decrement", "Z <-- Z - 1, (Z) <-- Rr", "--------", {"2", "2", "1", "1"}, ""}, {OP_ID(std_2), 0xd208, 0x8200, 1, OP_AVR2nRC, "10q0 qq1r rrrr 0qqq", OTY_XFRX|OTY_RALL, @@ -384,7 +384,7 @@ const AVR_opcode_data avr_opcodes[164] = { {OP_ID(lpm_2), 0xfe0f, 0x9004, 1, OP_AVR25, "1001 000d dddd 0100", OTY_XFRX|OTY_RALL, "lpm", "Rd, Z", "Load Program Memory", "Rd <-- (Z)", "--------", {"3", "3", "3", "n/a"}, ""}, - {OP_ID(lpm_3), 0xfe0f, 0x9005, 1, OP_AVR25, "1001 000d dddd 0101", OTY_XFRX|OTY_RALL, + {OP_ID(lpm_3), 0xfe0f, 0x9005, 1, OP_AVR25, "1001 000d dddd 0101", OTY_XFRX|OTY_RALL|OTY_ZWRN, "lpm", "Rd, Z+", "Load Program Memory and Post- Increment", "Rd <-- (Z), Z <-- Z + 1", "--------", {"3", "3", "3", "n/a"}, ""}, {OP_ID(elpm_1), 0xffff, 0x95d8, 1, OP_AVR_L, "1001 0101 1101 1000", OTY_XFRX, @@ -393,7 +393,7 @@ const AVR_opcode_data avr_opcodes[164] = { {OP_ID(elpm_2), 0xfe0f, 0x9006, 1, OP_AVR_L, "1001 000d dddd 0110", OTY_XFRX|OTY_RALL, "elpm", "Rd, Z", "Extended Load Program Memory", "Rd <-- (RAMPZ:Z)", "--------", {"3", "3", "3", "n/a"}, ""}, - {OP_ID(elpm_3), 0xfe0f, 0x9007, 1, OP_AVR_L, "1001 000d dddd 0111", OTY_XFRX|OTY_RALL, + {OP_ID(elpm_3), 0xfe0f, 0x9007, 1, OP_AVR_L, "1001 000d dddd 0111", OTY_XFRX|OTY_RALL|OTY_ZWRN, "elpm", "Rd, Z+", "Extended Load Program Memory and Post-Increment", "Rd <-- (RAMPZ:Z), Z <-- Z + 1", "--------", {"3", "3", "3", "n/a"}, ""}, {OP_ID(spm), 0xffff, 0x95e8, 1, OP_AVR25, "1001 0101 1110 1000", OTY_XFRX, @@ -589,7 +589,7 @@ const AVR_opcode_data avr_opcodes[164] = { {"1-3", "1-3", "1-3", "1/2"}, ""}, }; -// Return whether or not the giveb 16-bit opcode has a 16-bit address argument +// Return whether or not the given 16-bit opcode has a 16-bit address argument int is_opcode32(int op) { return (op & 0xfe0e) == 0x940e || // call diff --git a/src/disasm.c b/src/disasm.c index e3a4ef7b..7c7ad5cc 100644 --- a/src/disasm.c +++ b/src/disasm.c @@ -152,7 +152,7 @@ void disassemble(const char *buf, int addr, int opcode, AVR_opcode mnemo, Disasm // Apply register formula int regword = 0; - switch(oc->type & OTY_RMASK) { + switch(oc->type & OTY_REG_MASK) { case OTY_REVN: // Even registers r0, r2, ..., r30 Rd *= 2, Rr *= 2; regword = 1; // movw @@ -175,6 +175,27 @@ void disassemble(const char *buf, int addr, int opcode, AVR_opcode mnemo, Disasm Ra = (Ra & 0xf) | ((Ra >> 1) & 0x30) | ((Ra & 0x10) << 2) | (((Ra & 0x10) ^ 0x10) << 3); } + int awd = cx->dis_addrwidth, swd = cx->dis_sramwidth; + snprintf(line->code, 256, "%-7s ", oc->opcode); + char *c = line->code + strlen(line->code); + *line->comment = 0; + + // Check for opcodes with undefined results + switch(oc->type & OTY_WARN_MASK) { + case OTY_XWRN: + if(Rd == 26 || Rd == 27 || Rr == 26 || Rr == 27) + add_comment(line, "Warning: the result of this operation is undefined\n"); + break; + case OTY_YWRN: + if(Rd == 28 || Rd == 29 || Rr == 28 || Rr == 29) + add_comment(line, "Warning: the result of this operation is undefined\n"); + break; + case OTY_ZWRN: + if(Rd == 30 || Rd == 31 || Rr == 30 || Rr == 31) + add_comment(line, "Warning: the result of this operation is undefined\n"); + break; + } + int target = 0, offset = 0, is_jumpcall = 0, is_relative = 0; int is_function = !!(oc->type & OTY_EXTERNAL); // call/rcall affects stack memory const char *kmemaddr = NULL, *memaddr, *regname; @@ -207,16 +228,8 @@ void disassemble(const char *buf, int addr, int opcode, AVR_opcode mnemo, Disasm Register_JumpCall(addr, target, mnemo, is_function); is_jumpcall = 1; break; - default: - pmsg_warning("OPCODE_%s has an unexpected number %d of k bits\n", - oc->idname, Nk); } - int awd = cx->dis_addrwidth, swd = cx->dis_sramwidth; - snprintf(line->code, 256, "%-7s ", oc->opcode); - char *c = line->code + strlen(line->code); - *line->comment = 0; - for(const char *o = oc->operands; *o && c-line->code < 255; o++) { switch(*o) { case 'R': @@ -370,8 +383,7 @@ int disasm(const char *buf, int buflen, int addr, int leadin, int leadout) { Pos += oplen; } else { - term_out(".word 0x%02x%02x ; Invalid opcode at 0x%04x\n", - buf[Pos + 1] & 0xff, buf[Pos] & 0xff, disasm_wrap(Pos + addr)); + term_out(".word 0x%02x%02x ; Invalid opcode\n", buf[Pos+1] & 0xff, buf[Pos] & 0xff); Pos += 2; } } diff --git a/src/libavrdude.h b/src/libavrdude.h index 5c4f0be2..6d12beb6 100644 --- a/src/libavrdude.h +++ b/src/libavrdude.h @@ -1583,30 +1583,38 @@ typedef enum { #define PART_ALL (PART_AVR_XM|OP_AVR_L|OP_AVR_XL) // All but RC (the latter conflicts) // Opcode types -#define OTY_RMASK 7 // Register formula mask +#define OTY_REG_MASK 7 // Register formula mask #define OTY_RNONE 0 // No registers addressed in this opcode #define OTY_RALL 1 // Opcode can use all 32 registers (both Rd, Rr) #define OTY_REVN 2 // Opcode only uses even registers (Rd *= 2, Rr *= 2) #define OTY_RUPP 3 // Opcode only uses upper registers (Rd += 16, Rr += 16) #define OTY_RW24 4 // Opcode only uses r24, r26, r28, r30 (Rd = Rd *2 + 24) -#define OTY_EXTERNAL 0x010 // Opcode might r/w either I/O region or memory -#define OTY_ALBI 0x020 // Arithmetic, logic or bitwise operation -#define OTY_ALBX 0x030 // Arithmetic, logic or bitwise operation (external) -#define OTY_XFRI 0x040 // Data transfer (only affecting registers) -#define OTY_XFRX 0x050 // Data transfer (between external I/O or memory and regs) -#define OTY_JMPI 0x080 // Jump to potentially anywhere in flash (jmp, ijmp, eijmp) -#define OTY_JMPX 0x090 // Jump to potentially anywhere in flash (calls and ret/i) -#define OTY_RJMI 0x100 // Relative jump rjmp, range [-4094, 4096] bytes -#define OTY_RJMX 0x110 // Relative call rcall, range [-4094, 4096] bytes -#define OTY_BRAI 0x200 // Conditional branch, range [-126, 128] bytes -#define OTY_SKPI 0x400 // Conditional skip, range [0, 4] bytes (cpse, sbrc, sbrs) -#define OTY_SKPX 0x410 // Conditional skip, range [0, 4] bytes (sbic, sbis) -#define OTY_MCUI 0x800 // nop and wdr -#define OTY_MCUX 0x810 // sleep and break +#define OTY_EXTERNAL 0x008 // Opcode might r/w either I/O region or memory -#define OTY_ALIAS 0x1000 // Opcode is a strict alias for another one, eg, sbr == ori -#define OTY_CONSTRAINT 0x2000 // Opcode has constraints: Rr == Rd (tst, clr, lsl, rol) +#define OTY_TYPE_MASK 0x78 // OPCODE type mask +#define OTY_ITYPE_MASK 0x70 // OPCODE type mask matching OTY_xxxI types +#define OTY_MCUI 0x00 // nop and wdr +#define OTY_MCUX 0x08 // sleep and break +#define OTY_ALBI 0x10 // Arithmetic, logic or bitwise operation +#define OTY_ALBX 0x18 // Arithmetic, logic or bitwise operation (external) +#define OTY_XFRI 0x20 // Data transfer (only affecting registers) +#define OTY_XFRX 0x28 // Data transfer (between external I/O or memory and regs) +#define OTY_JMPI 0x30 // Jump to potentially anywhere in flash (jmp, ijmp, eijmp) +#define OTY_JMPX 0x38 // Jump to potentially anywhere in flash (calls and ret/i) +#define OTY_RJMI 0x40 // Relative jump rjmp, range [-4094, 4096] bytes +#define OTY_RJMX 0x48 // Relative call rcall, range [-4094, 4096] bytes +#define OTY_BRAI 0x50 // Conditional branch, range [-126, 128] bytes +#define OTY_SKPI 0x60 // Conditional skip, range [0, 4] bytes (cpse, sbrc, sbrs) +#define OTY_SKPX 0x68 // Conditional skip, range [0, 4] bytes (sbic, sbis) + +#define OTY_ALIAS 0x100 // Opcode is a strict alias for another one, eg, sbr == ori +#define OTY_CONSTRAINT 0x200 // Opcode has constraints: Rr == Rd (tst, clr, lsl, rol) + +#define OTY_WARN_MASK 0xc00 // OPCODE warning mask +#define OTY_XWRN 0x400 // Operand register must not be r27/r28 +#define OTY_YWRN 0x800 // Operand register must not be r29/r30 +#define OTY_ZWRN 0xc00 // Operand register must not be r29/r30 typedef struct { AVR_opcode mnemo; // Eg, OPCODE_add