mirror of
https://github.com/avrdudes/avrdude.git
synced 2026-09-24 01:56:25 +03:00
Use memory labels for lds/sts
This commit is contained in:
161
src/disasm.c
161
src/disasm.c
@@ -39,10 +39,10 @@
|
||||
#include "avrdude.h"
|
||||
#include "libavrdude.h"
|
||||
|
||||
#define TYPE_BYTE 1
|
||||
#define TYPE_WORD 2
|
||||
#define TYPE_ASTRING 3
|
||||
#define TYPE_STRING 4
|
||||
#define TYPE_BYTE 1 // 1 byte
|
||||
#define TYPE_WORD 2 // 2 bytes
|
||||
#define TYPE_ASTRING 3 // Autoaligned string
|
||||
#define TYPE_STRING 4 // String
|
||||
|
||||
|
||||
static void zap_symbols() {
|
||||
@@ -60,12 +60,18 @@ static void zap_symbols() {
|
||||
static int symbol_sort(const void *v1, const void *v2) {
|
||||
const Disasm_symbol *p1 = v1, *p2 = v2;
|
||||
int diff;
|
||||
|
||||
if((diff = p1->type - p2->type))
|
||||
return diff;
|
||||
return p1->address - p2->address;
|
||||
}
|
||||
|
||||
static int symbol_qsort_stable(const void *v1, const void *v2) {
|
||||
int diff = symbol_sort(v1, v2);
|
||||
if(diff)
|
||||
return diff;
|
||||
return (char *) v1 - (char *) v2; // Keep original order if same keys (stable sort)
|
||||
}
|
||||
|
||||
static int find_symbol(int type, int address) {
|
||||
Disasm_symbol key, *found;
|
||||
|
||||
@@ -141,7 +147,6 @@ static int tagfile_readline(char *line, int lineno) {
|
||||
}
|
||||
subtype = token[0];
|
||||
|
||||
// Either B(yte), W(ord), A(utoterminated string) or S(tring)
|
||||
switch(subtype) {
|
||||
case 'B':
|
||||
subtype = TYPE_BYTE;
|
||||
@@ -217,37 +222,32 @@ static const char *shortrname(const Register_file *rf, int nr, int i) {
|
||||
return s;
|
||||
}
|
||||
|
||||
static void add_register(int io_off, int addr, const char *name, int suffix) {
|
||||
add_symbol(io_off+addr, 'M', TYPE_BYTE, 1, regname(io_off? "MEM_": "", name, suffix), NULL);
|
||||
if(addr < 0x40 && io_off) // Only keep I/O addresses separate if memory addresses have an offset
|
||||
add_symbol(addr, 'I', TYPE_BYTE, 1, regname(io_off? "IO_": "", name, suffix), NULL);
|
||||
}
|
||||
|
||||
// Initialise cx->dis_symbols from part register file
|
||||
static void init_regfile(const AVRPART *p) {
|
||||
int nr = 0, offset = 0;
|
||||
int nr = 0, io_off = cx->dis_io_offset;
|
||||
const Register_file *rf = avr_locate_register_file(p, &nr);
|
||||
|
||||
if(rf) {
|
||||
AVRMEM *mem = avr_locate_io(p);
|
||||
if(mem)
|
||||
offset = mem->offset;
|
||||
const char *mpre = offset? "MEM_": "";
|
||||
const char *ipre = offset? "IO_": "";
|
||||
for(int i = 0; i< nr; i++) {
|
||||
int addr = offset + rf[i].addr;
|
||||
int sub = rf[i].size == 2? TYPE_WORD: TYPE_BYTE;
|
||||
int count = rf[i].size > 2? rf[i].size: 1;
|
||||
add_symbol(addr, 'M', sub, count, regname(mpre, rf[i].reg, -1), NULL);
|
||||
const char *rname = offset? shortrname(rf, nr, i): rf[i].reg;
|
||||
const char *rname = io_off? shortrname(rf, nr, i): rf[i].reg;
|
||||
|
||||
if(rf[i].addr < 0x40) {
|
||||
if(rf[i].size == 1)
|
||||
add_symbol(rf[i].addr, 'I', TYPE_BYTE, 1, regname(ipre, rname, -1), NULL);
|
||||
else if(rf[i].size == 2) {
|
||||
add_symbol(rf[i].addr, 'I', TYPE_BYTE, 1, regname(ipre, rname, 'l'), NULL);
|
||||
add_symbol(rf[i].addr+1, 'I', TYPE_BYTE, 1, regname(ipre, rname, 'h'), NULL);
|
||||
} else if(rf[i].size > 2) {
|
||||
for(int k = 0; k < rf[i].size; k++)
|
||||
add_symbol(rf[i].addr+k, 'I', TYPE_BYTE, 1, regname(ipre, rname, k), NULL);
|
||||
}
|
||||
if(rf[i].size == 1) {
|
||||
add_register(io_off, rf[i].addr, rname, -1);
|
||||
} else if(rf[i].size == 2) {
|
||||
add_register(io_off, rf[i].addr, rname, 'l');
|
||||
add_register(io_off, rf[i].addr+1, rname, 'h');
|
||||
} else if(rf[i].size > 2) {
|
||||
for(int k = 0; k < rf[i].size; k++)
|
||||
add_register(io_off, rf[i].addr+k, rname, k);
|
||||
}
|
||||
}
|
||||
qsort(cx->dis_symbols, cx->dis_symbolN, sizeof(Disasm_symbol), symbol_sort);
|
||||
qsort(cx->dis_symbols, cx->dis_symbolN, sizeof(Disasm_symbol), symbol_qsort_stable);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,7 +274,7 @@ int disasm_init_tagfile(const AVRPART *p, const char *fname) {
|
||||
}
|
||||
|
||||
fclose(inf);
|
||||
qsort(cx->dis_symbols, cx->dis_symbolN, sizeof(Disasm_symbol), symbol_sort);
|
||||
qsort(cx->dis_symbols, cx->dis_symbolN, sizeof(Disasm_symbol), symbol_qsort_stable);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
@@ -282,32 +282,39 @@ error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static const char *resolve_mem_address(int address) {
|
||||
for(int i = 0; i < cx->dis_symbolN; i++) {
|
||||
if(cx->dis_symbols[i].type != 'M')
|
||||
continue;
|
||||
if(cx->dis_symbols[i].address > address)
|
||||
break;
|
||||
// Width of memory a symbol covers (only valid for I/O and memory symbols)
|
||||
static int symbol_width(Disasm_symbol *s) {
|
||||
return s->count * (s->subtype == TYPE_WORD? 2: 1);
|
||||
}
|
||||
|
||||
int start = cx->dis_symbols[i].address;
|
||||
int size = cx->dis_symbols[i].subtype == TYPE_WORD? 2: 1;
|
||||
int end = cx->dis_symbols[i].address + cx->dis_symbols[i].count * size - 1;
|
||||
// Returns the first symbol for that address with the smallest width
|
||||
static Disasm_symbol *symbol_address(int type, int address) {
|
||||
int k = find_symbol(type, address), m = k;
|
||||
|
||||
if(address >= start && address <= end) {
|
||||
if(cx->dis_symbols[i].count == 1) { // Single variable
|
||||
if(size == 1)
|
||||
return str_ccprintf("%s", cx->dis_symbols[i].name);
|
||||
return str_ccprintf("_%s8(%s)", address == start? "lo": "hi", cx->dis_symbols[i].name);
|
||||
}
|
||||
// Array
|
||||
if(size == 1)
|
||||
return str_ccprintf("%s[%d]", cx->dis_symbols[i].name, address - start);
|
||||
return str_ccprintf("_%s8(%s[%d])", (address - start)%2? "hi": "lo",
|
||||
cx->dis_symbols[i].name, (address - start)/2);
|
||||
}
|
||||
}
|
||||
if(k < 0)
|
||||
return NULL;
|
||||
|
||||
return NULL;
|
||||
// Determine m as a matching symbol that has smallest width
|
||||
Disasm_symbol *s = cx->dis_symbols;
|
||||
int w, width = symbol_width(s+k);
|
||||
|
||||
for(int i = k-1; i >= 0 && symbol_sort(s+i, s+k) == 0; i--)
|
||||
if((w = symbol_width(s+i)) <= width) // Want first entry of those with same min width
|
||||
m = i, width = w;
|
||||
for(int i = k+1; i < cx->dis_symbolN && symbol_sort(s+i, s+k) == 0; i++)
|
||||
if((w = symbol_width(s+i)) < width) // < is deliberate, see above
|
||||
m = i, width = w;
|
||||
|
||||
return s+m;
|
||||
}
|
||||
|
||||
static const char *resolve_address(int type, int address) {
|
||||
Disasm_symbol *s = symbol_address(type == 'I' && !cx->dis_io_offset? 'M': type, address);
|
||||
|
||||
if(s && s->name)
|
||||
s->used = 1;
|
||||
|
||||
return s? s->name: NULL;
|
||||
}
|
||||
|
||||
// Increase cycle number by 1 if it's a 3 byte PC
|
||||
@@ -397,7 +404,7 @@ static void lineout(const char *code, const char *comment,
|
||||
int match = 0;
|
||||
|
||||
for(int i = 0; i < cx->dis_jumpcallN; i++) {
|
||||
if((cx->dis_jumpcalls[i].to) == here) {
|
||||
if(cx->dis_jumpcalls[i].to == here) {
|
||||
if(!match++)
|
||||
cx->dis_para = 1;
|
||||
disasm_out("; Referenced from L%0*x by %s\n", cx->dis_addrwidth,
|
||||
@@ -513,7 +520,7 @@ static int process_data(const char *buf, int buflen, int pos, int offset) {
|
||||
switch(s->subtype) {
|
||||
case TYPE_BYTE:
|
||||
case TYPE_WORD:
|
||||
ret += process_num(buf, buflen, s->subtype, pos+ret, offset);
|
||||
ret += process_num(buf, buflen, s->subtype == TYPE_WORD? 2: 1, pos+ret, offset);
|
||||
break;
|
||||
case TYPE_ASTRING:
|
||||
case TYPE_STRING:
|
||||
@@ -533,19 +540,6 @@ static int process_data(const char *buf, int buflen, int pos, int offset) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const char *resolve_io_register(int Number) {
|
||||
for(int i = 0; i < cx->dis_symbolN; i++) {
|
||||
if(cx->dis_symbols[i].type != 'I')
|
||||
continue;
|
||||
if(cx->dis_symbols[i].address == Number) {
|
||||
cx->dis_symbols[i].used = 1;
|
||||
return cx->dis_symbols[i].name;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void emit_used_io_registers() {
|
||||
int maxlen = 0;
|
||||
|
||||
@@ -557,7 +551,7 @@ void emit_used_io_registers() {
|
||||
}
|
||||
|
||||
for(int i = 0; i < cx->dis_symbolN; i++)
|
||||
if(cx->dis_symbols[i].used)
|
||||
if(cx->dis_symbols[i].used && (cx->dis_io_offset || cx->dis_symbols[i].type == 'M'))
|
||||
disasm_out(".equ %s,%*s 0x%02x\n", cx->dis_symbols[i].name,
|
||||
(int) (maxlen-strlen(cx->dis_symbols[i].name)), "", cx->dis_symbols[i].address);
|
||||
}
|
||||
@@ -573,9 +567,9 @@ static void register_jumpcall(int from, int to, int mnemo, unsigned char is_func
|
||||
Disasm_jumpcall *jc = cx->dis_jumpcalls;
|
||||
int N = cx->dis_jumpcallN;
|
||||
|
||||
// Already entered this JC?
|
||||
// Already entered this jumpcall?
|
||||
for(int i = 0; i < N; i++)
|
||||
if(jc[i].from == from && jc[N].to == to && jc[N].mnemo == mnemo)
|
||||
if(jc[i].from == from && jc[i].to == to && jc[i].mnemo == mnemo)
|
||||
return;
|
||||
|
||||
if(N % 1024 == 0)
|
||||
@@ -610,8 +604,12 @@ static void correct_is_funct(void) {
|
||||
cx->dis_jumpcalls[j].is_func = cur_is_func;
|
||||
}
|
||||
|
||||
static int jumpcall_sort(const void *p1, const void *p2) {
|
||||
return ((Disasm_jumpcall *) p1)->to - ((Disasm_jumpcall *) p2)->to;
|
||||
static int jumpcall_sort(const void *v1, const void *v2) {
|
||||
const Disasm_jumpcall *p1 = v1, *p2 = v2;
|
||||
int diff;
|
||||
if((diff = p1->to - p2->to))
|
||||
return diff;
|
||||
return p1->from - p2->from;
|
||||
}
|
||||
|
||||
static void enumerate_labels(void) {
|
||||
@@ -762,7 +760,7 @@ static void disassemble(const char *buf, int addr, int opcode, AVR_opcode mnemo,
|
||||
|
||||
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, *amemaddr = NULL, *regname = NA? resolve_io_register(RA): NULL;
|
||||
const char *kmemaddr = NULL, *amemaddr = NULL, *regname = NA? resolve_address('I', RA): NULL;
|
||||
|
||||
if(Na) {
|
||||
/*
|
||||
@@ -771,7 +769,7 @@ static void disassemble(const char *buf, int addr, int opcode, AVR_opcode mnemo,
|
||||
* ADDR[7:0] ← (/a[4], a[4], a[6], a[5], a[3], a[2], a[1], a[0])
|
||||
*/
|
||||
Ra = (Ra & 0xf) | ((Ra >> 1) & 0x30) | ((Ra & 0x10) << 2) | (((Ra & 0x10) ^ 0x10) << 3);
|
||||
amemaddr = resolve_mem_address(Ra);
|
||||
amemaddr = resolve_address('M', Ra);
|
||||
}
|
||||
|
||||
switch(Nk) {
|
||||
@@ -794,7 +792,7 @@ static void disassemble(const char *buf, int addr, int opcode, AVR_opcode mnemo,
|
||||
is_relative = 1;
|
||||
break;
|
||||
case 16: // lds/sts
|
||||
kmemaddr = resolve_mem_address(Rk);
|
||||
kmemaddr = resolve_address('M', Rk);
|
||||
break;
|
||||
case 22:
|
||||
if(cx->dis_flashsz && 2*Rk > cx->dis_flashsz)
|
||||
@@ -843,12 +841,12 @@ static void disassemble(const char *buf, int addr, int opcode, AVR_opcode mnemo,
|
||||
add_operand(lc, "%s", regname);
|
||||
else
|
||||
add_operand(lc, "0x%02x", RA);
|
||||
lc += strlen(lc);
|
||||
break;
|
||||
case 'a':
|
||||
add_operand(lc, "0x%02x", Ra);
|
||||
if(amemaddr)
|
||||
add_comment(line, str_ccprintf("%s", amemaddr));
|
||||
add_operand(lc, "%s", amemaddr);
|
||||
else
|
||||
add_operand(lc, "0x%02x", Ra);
|
||||
break;
|
||||
case 'k':
|
||||
if(is_jumpcall) {
|
||||
@@ -864,9 +862,10 @@ static void disassemble(const char *buf, int addr, int opcode, AVR_opcode mnemo,
|
||||
add_operand(lc, "0x%0*x", awd, target);
|
||||
}
|
||||
} else {
|
||||
add_operand(lc, "0x%0*x", swd, Rk);
|
||||
if(kmemaddr)
|
||||
add_comment(line, str_ccprintf("%s", kmemaddr));
|
||||
add_operand(lc, "%s", kmemaddr);
|
||||
else
|
||||
add_operand(lc, "0x%0*x", swd, Rk);
|
||||
}
|
||||
break;
|
||||
case 'b':
|
||||
@@ -994,7 +993,7 @@ int disasm_init(const AVRPART *p) {
|
||||
}
|
||||
|
||||
cx->dis_cycle_index = avr_get_cycle_index(p);
|
||||
|
||||
cx->dis_io_offset = (mem = avr_locate_io(p))? mem->offset: 0;
|
||||
init_regfile(p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1829,7 +1829,7 @@ typedef struct {
|
||||
|
||||
// Static variables from disasm.c
|
||||
int dis_initopts, dis_flashsz, dis_flashsz2, dis_addrwidth, dis_sramwidth;
|
||||
int dis_pass, dis_para, dis_cycle_index;
|
||||
int dis_pass, dis_para, dis_cycle_index, dis_io_offset;
|
||||
Disasm_options dis_opts;
|
||||
int dis_jumpcallN, dis_symbolN, *dis_jumpable, dis_start, dis_end;
|
||||
Disasm_jumpcall *dis_jumpcalls;
|
||||
|
||||
Reference in New Issue
Block a user