/* Disassembles ".HEX" files
Copyright 2001-2005 Craig Franklin
Copyright 2014-2016 Molnár Károly
*/
#include "stdhdr.h"
#include "libgputils.h"
#include "gpcfg.h"
#include "gpdasm.h"
#include "labelset.h"
#include "parse.h"
#include "scan.h"
#ifdef STDC_HEADERS
#include <stdarg.h>
#endif
#define USER_LABEL_ALIGN 15
extern int yyparse(void);
struct gpdasm_state state;
static const char *processor_name;
static gp_cfg_addr_pack_t addr_pack;
static struct {
bool is_print;
unsigned number;
int words[PIC16E_IDLOCS_SIZE];
} idlocs_pack = { 0, 0, { -1, } };
static bool prev_empty_line = false;
static char border[] = "===============================================================================";
static char out_buffer[BUFSIZ];
static const char longopts[] =
"cmnemonics\0"
"hhelp\0"
"ihex-info\0"
"jmov-fsrn\0"
"klabel-list\1FILE\0"
"llist-chips\0"
"mdump\0"
"nshow-names\0"
"oshow-config\0"
"pprocessor\1PROC\0"
"sshort\0"
"\1strict-options\0"
"tuse-tab\0"
"vversion\0"
"yextended\0"
"\2strict\0";
static const char longdesc[]=
"Decode the special mnemonics.\0"
"Show this usage message.\0"
"Show the informations of the input hex file.\0"
"In the MOVIW or MOVWI instructions show as base"
" the FSRn register instead of the INDFn. [INDFn]\0"
"A file which lists the names and addresses of"
" the labels in the disassembled program code."
" (With the -n, -o and -s options.)\0"
"List the supported processors.\0"
"Memory dump of the input hex file.\0"
"For some case of SFR, shows the name of"
" instead of the address. In addition shows"
" the labels also.\0"
"Show the CONFIG and IDLOCS - or __idlocs - directives.\0"
"Select the microcontroller.\0"
"Print short format output. (Creates a compilable"
" source. See also the -k, -n and -o options.)\0"
"Uses tabulator character in the written disassembled"
" text.\0"
"Print the gpdasm version information and exit.\0"
"Enable 18xx extended mode.\0"
"Disassemble only opcodes generated by gpasm"
" in case of instructions with several opcodes.\0"
"If this is set, then an option may not be parameter"
" of an another option. For example: -p --dump\0";
/*------------------------------------------------------------------------------------------------*/
static void _show_usage(const char*argv0) {
gp_usage(argv0,longopts,longdesc,32,79,
"For example: gpdasm -nos -k program.ulist -p12f1822 program.hex > program.dis\n");
exit(0);
}
/*------------------------------------------------------------------------------------------------*/
static size_t _unexpand(char *Dst, size_t Size, const char *Src) {
size_t in_read_idx;
size_t in_read_virt_idx;
size_t out_write_idx;
size_t first_tab;
size_t last_char;
size_t space_num;
if (Size <= 1) {
return 0;
}
--Size;
in_read_idx = 0;
in_read_virt_idx = 0;
out_write_idx = 0;
first_tab = 0;
last_char = 0;
space_num = 0;
while ((Src[in_read_idx] != '\0') && (out_write_idx < Size)) {
if (Src[in_read_idx] == ' ') {
++space_num;
}
else if (Src[in_read_idx] == '\n') {
/* This a newline character. */
Dst[out_write_idx++] = Src[in_read_idx];
in_read_virt_idx = 0;
last_char = 0;
space_num = 0;
++in_read_idx;
continue;
}
else {
/* This a not-space character. */
if (space_num > 1) {
first_tab = ((last_char + TABULATOR_SIZE) / TABULATOR_SIZE) * TABULATOR_SIZE;
if (first_tab > in_read_virt_idx) {
first_tab = 0;
}
if ((last_char + 1) < first_tab) {
if (first_tab <= in_read_virt_idx) {
Dst[out_write_idx++] = '\t';
if (out_write_idx >= Size) {
goto _exit;
}
space_num = in_read_virt_idx - first_tab;
}
while (space_num >= TABULATOR_SIZE) {
Dst[out_write_idx++] = '\t';
if (out_write_idx >= Size) {
goto _exit;
}
space_num -= TABULATOR_SIZE;
}
}
}
while (space_num > 0) {
Dst[out_write_idx++] = ' ';
if (out_write_idx >= Size) {
goto _exit;
}
--space_num;
}
Dst[out_write_idx++] = Src[in_read_idx];
last_char = in_read_idx;
}
++in_read_idx;
++in_read_virt_idx;
} /* while ((Src[in_read_idx] != '\0') && */
while (space_num >= TABULATOR_SIZE) {
Dst[out_write_idx++] = '\t';
if (out_write_idx >= Size) {
goto _exit;
}
space_num -= TABULATOR_SIZE;
}
_exit:
Dst[out_write_idx] = '\0';
return out_write_idx;
}
/*------------------------------------------------------------------------------------------------*/
static void _cdecl _ux_print(bool New_line, const char *Format, ...)
{
va_list ap;
char buffer[BUFSIZ];
const char *bptr;
size_t len;
va_start(ap, Format);
len = (size_t)vsnprintf(buffer, sizeof(buffer), Format, ap);
va_end(ap);
if ((int)len < 0) {
return;
}
bptr = buffer;
if (New_line) {
if (state.use_tab) {
_unexpand(out_buffer, sizeof(out_buffer), buffer);
bptr = out_buffer;
}
puts(bptr);
}
else {
if (state.use_tab) {
len = _unexpand(out_buffer, sizeof(out_buffer), buffer);
bptr = out_buffer;
}
printf("%s", bptr);
}
}
/*------------------------------------------------------------------------------------------------*/
static void _select_processor() {
pic_processor_t found = NULL;
if (processor_name == NULL) {
fprintf(stderr, "Error: Must select the processor.\n");
exit(1);
}
found = gp_find_processor(processor_name);
if (found) state.processor = found;
else {
fprintf(stderr, "Error: Didn't find any processor named: %s\n", processor_name);
printf("Here are the supported processors:\n");
gp_dump_processor_list(true, PROC_CLASS_UNKNOWN, PROC_CLASS_UNKNOWN, PROC_CLASS_UNKNOWN);
exit(1);
}
state.pclass = gp_processor_class(state.processor);
if (!state.pclass->instructions) {
fprintf(stderr, "Error: Unsupported processor class.\n");
exit(1);
}
state.proc_regs = gp_register_table_t::find_mcu(state.processor->names[1]);
}
/*------------------------------------------------------------------------------------------------*/
static void _write_header() {
if (!state.format) {
_ux_print(true, " processor %s\n"
" radix dec", state.processor->names[1]);
if (state.processor->header) {
_ux_print(true, "\n"
" include %s", state.processor->header);
}
}
}
/*------------------------------------------------------------------------------------------------*/
static void _write_core_sfr_list() {
if (state.format) return;
if (!state.pclass->core_sfr_table) return;
if (!state.pclass->core_sfr_number) return;
_ux_print(true, "\n"
"F\tequ\t1\n"
"W\tequ\t0");
if (state.pclass == PROC_CLASS_PIC16E) {
_ux_print(true, "A\tequ\t0\n"
"B\tequ\t1");
}
_ux_print(true, "");
const core_sfr_t *table = state.pclass->core_sfr_table;
for (int i = state.pclass->core_sfr_number; i > 0; ++table, --i) {
if ((state.pclass == PROC_CLASS_PIC14E) || (state.pclass == PROC_CLASS_PIC14EX)) {
if (!strcmp(table->name, "FSR0L")) {
_ux_print(true, "FSR0\tequ\t0x%03x", table->address);
}
else if (!strcmp(table->name, "FSR1L")) {
_ux_print(true, "FSR1\tequ\t0x%03x", table->address);
}
}
_ux_print(true, "%s\tequ\t0x%03x", table->name, table->address);
}
}
/*------------------------------------------------------------------------------------------------*/
static void _end_asm() {
if (!state.format) {
_ux_print(true, "\n"
"\tend");
}
}
/*------------------------------------------------------------------------------------------------*/
static void _write_org(int Org, int Addr_digits, const char *Title,
const char *Address_name, int Offset) {
size_t length;
char buffer[BUFSIZ];
if (!state.format) {
_ux_print(true, "");
if (Title) {
_ux_print(true, "\t; %s", Title);
}
if (Address_name) {
if (Offset > 0) {
length = snprintf(buffer, sizeof(buffer), "\torg\t(%s + 0x%0*x)", Address_name,
Addr_digits, Offset);
}
else {
length = snprintf(buffer, sizeof(buffer), "\torg\t%s", Address_name);
}
gp_exclamation(buffer, sizeof(buffer), length, "; address: 0x%0*x", Addr_digits, Org);
}else{
snprintf(buffer, sizeof(buffer), "\torg\t0x%0*x", Addr_digits, Org);
}
_ux_print(true, "\n%s\n", buffer);
prev_empty_line = true;
}
}
/*------------------------------------------------------------------------------------------------*/
static void _mark_false_addresses(MemBlock_t *Memory) {
MemBlock_t *m;
int i;
int maximum;
int org;
int insn_size;
int num_words;
uint16_t data;
m = Memory;
while (m) {
i = IMemAddrFromBase(m->base);
maximum = i + I_MEM_MAX;
insn_size = 2;
while (i < maximum) {
org = gp_processor_insn_from_byte_p(state.processor, i);
if (gp_processor_is_idlocs_org(state.processor, org) >= 0) {
insn_size = (state.pclass == PROC_CLASS_PIC16E) ? 1 : 2;
}
else if (gp_processor_is_config_org(state.processor, org) >= 0) {
insn_size = (state.pclass == PROC_CLASS_PIC16E) ? 1 : 2;
}
else if (gp_processor_is_eeprom_org(state.processor, org) >= 0) {
insn_size = 1;
}
else {
if (state.pclass->i_memory_get(m, i, &data, NULL, NULL) == W_USED_ALL) {
num_words = gp_disassemble_mark_false_addresses(m, i, state.processor);
insn_size = (num_words != 1) ? 4 : 2;
}
}
i += insn_size;
}
m = m->next;
}
}
/*------------------------------------------------------------------------------------------------*/
static void _recognize_labels_and_spec_words(MemBlock_t *Memory) {
MemBlock_t *m;
int i;
int maximum;
int index;
int org;
int offset;
int insn_size;
int num_words;
uint8_t byte;
uint16_t data;
const vector_t *vector;
gpdasm_fstate_t fstate;
const gp_cfg_device_t *dev;
gp_cfg_addr_hit_t *hit;
unsigned max_width;
unsigned type;
lset_symbol_t *sym;
if (state.show_config) {
dev = gp_cfg_find_pic_multi_name(state.processor->names, ARRAY_SIZE(state.processor->names));
if (dev == NULL) {
fprintf(stderr, "Warning: The %s processor has no entries in the config db.", state.processor->names[2]);
}
}
else {
dev = NULL;
}
m = Memory;
fstate.wreg = 0;
fstate.pclath = 0;
fstate.pclath_valid = 0xff;
addr_pack.hit_count = 0;
max_width = 0;
idlocs_pack.number = 0;
idlocs_pack.is_print = true;
while (m) {
i = IMemAddrFromBase(m->base);
maximum = i + I_MEM_MAX;
insn_size = 2;
while (i < maximum) {
org = gp_processor_insn_from_byte_p(state.processor, i);
if ((index = gp_processor_is_idlocs_org(state.processor, org)) >= 0) {
insn_size = (state.pclass == PROC_CLASS_PIC16E) ? 1 : 2;
if (state.pclass == PROC_CLASS_PIC16E) {
if (gp_mem_b_get(m, i, &byte, NULL, NULL)) {
idlocs_pack.words[index] = byte;
if (!isprint(byte)) {
idlocs_pack.is_print = false;
}
++idlocs_pack.number;
}
else {
idlocs_pack.words[index] = -1;
}
}
else {
if (state.pclass->i_memory_get(m, i, &data, NULL, NULL) == W_USED_ALL) {
sym = lset_symbol_find_addr(state.lset_root.sections[SECT_SPEC_CODE], org, -1, true);
if ((sym) && !(sym->attr & CSYM_ORG)) {
if (sym->start == (long)org) {
gp_mem_b_set_addr_name(m, i, sym->name);
sym->attr |= CSYM_USED;
}
}
idlocs_pack.words[index] = data;
++idlocs_pack.number;
}
else {
idlocs_pack.words[index] = -1;
}
}
}
else if (gp_processor_is_config_org(state.processor, org) >= 0) {
insn_size = (state.pclass == PROC_CLASS_PIC16E) ? 1 : 2;
if (dev) {
if (addr_pack.hit_count < GP_CFG_ADDR_PACK_MAX) {
if (state.pclass == PROC_CLASS_PIC16E) {
if (gp_mem_b_get(m, i, &byte, NULL, NULL)) {
hit = &addr_pack.hits[addr_pack.hit_count];
if (gp_cfg_decode_directive(dev, org, byte, hit) > 0) {
if (max_width < hit->max_dir_width) {
max_width = hit->max_dir_width;
}
++addr_pack.hit_count;
}
}
}
else {
if (state.pclass->i_memory_get(m, i, &data, NULL, NULL) == W_USED_ALL) {
hit = &addr_pack.hits[addr_pack.hit_count];
if (gp_cfg_decode_directive(dev, org, data, hit) > 0) {
if (max_width < hit->max_dir_width) {
max_width = hit->max_dir_width;
}
++addr_pack.hit_count;
}
}
}
}
else {
fprintf(stderr, "Warning: The value of GP_CFG_ADDR_PACK_MAX too little: %u",
GP_CFG_ADDR_PACK_MAX);
}
} /* if (dev) */
} /* else if (gp_processor_is_config_org(state.processor, org) >= 0) */
else if ((offset = gp_processor_is_eeprom_org(state.processor, org)) >= 0) {
if (gp_mem_b_get(m, i, &byte, NULL, NULL)) {
sym = lset_symbol_find_addr(state.lset_root.sections[SECT_SPEC_EEDATA], offset, -1, true);
if ((sym) && !(sym->attr & CSYM_ORG)) {
if (sym->start == (long)offset) {
gp_mem_b_set_addr_name(m, i, sym->name);
sym->attr |= CSYM_USED;
}
}
}
insn_size = 1;
}
else {
if (state.pclass->i_memory_get(m, i, &data, NULL, NULL) == W_USED_ALL) {
sym = lset_symbol_find_addr(state.lset_root.sections[SECT_SPEC_CODE], org, -1, true);
if ((sym) && !(sym->attr & CSYM_ORG)) {
type = (sym->attr & CSYM_DATA) ? W_CONST_DATA : 0;
if (sym->start == (long)org) {
type |= W_ADDR_T_LABEL;
gp_mem_b_set_addr_name(m, i, sym->name);
}
gp_mem_b_set_type(m, i, type);
insn_size = 2;
}
else {
if (state.pclass == PROC_CLASS_SX) {
/* Unlike the others, the address of reset vector located the top of program memory. */
org = (org == state.processor->maxrom) ? -1 : org;
}
vector = gp_processor_find_vector(state.pclass, org);
if (vector) {
gp_mem_b_set_addr_type(m, i, W_ADDR_T_LABEL, 0);
gp_mem_b_set_addr_name(m, i, vector->name);
}
num_words = gp_disassemble_find_labels(m, i, state.processor, &fstate);
insn_size = (num_words != 1) ? 4 : 2;
}
}
}
i += insn_size;
}
m = m->next;
}
addr_pack.max_dir_width = max_width;
}
/*------------------------------------------------------------------------------------------------*/
static void _stdcall _user_data_finder(MemArg_t *Argument) {
lset_symbol_t *sym;
if (Argument->arg) {
return;
}
sym = lset_symbol_find_addr(state.lset_root.sections[SECT_SPEC_DATA], (long)Argument->val, -1, true);
if (sym) {
Argument->arg = sym->name;
Argument->offs = (int)((long)Argument->val - sym->start);
/* This will be necessary for the later listing. */
sym->attr |= CSYM_USED;
}
}
/*------------------------------------------------------------------------------------------------*/
static void _recognize_registers(MemBlock_t *Memory) {
MemBlock_t *m;
int i;
int maximum;
int org;
int insn_size;
int num_words;
uint16_t data;
gpdasm_fstate_t fstate;
if (state.pclass == PROC_CLASS_SX) {
return;
}
m = Memory;
fstate.wreg = 0;
fstate.bank = 0;
fstate.bank_valid = 0xff;
fstate.proc_regs = state.proc_regs;
fstate.bsr_boundary = gp_processor_bsr_boundary(state.processor);
fstate.need_sfr_equ = false;
while (m) {
i = IMemAddrFromBase(m->base);
maximum = i + I_MEM_MAX;
insn_size = 2;
while (i < maximum) {
org = gp_processor_insn_from_byte_p(state.processor, i);
if (gp_processor_is_idlocs_org(state.processor, org) >= 0) {
insn_size = (state.pclass == PROC_CLASS_PIC16E) ? 1 : 2;
}
else if (gp_processor_is_config_org(state.processor, org) >= 0) {
insn_size = (state.pclass == PROC_CLASS_PIC16E) ? 1 : 2;
}
else if (gp_processor_is_eeprom_org(state.processor, org) >= 0) {
insn_size = 1;
}
else {
if (state.pclass->i_memory_get(m, i, &data, NULL, NULL) == W_USED_ALL) {
num_words = gp_disassemble_find_registers(m, i, state.processor, &fstate, _user_data_finder);
insn_size = (num_words != 1) ? 4 : 2;
}
}
i += insn_size;
}
m = m->next;
}
state.need_sfr_equ = fstate.need_sfr_equ;
}
/*------------------------------------------------------------------------------------------------*/
static void
_denominate_labels(MemBlock_t *Memory)
{
MemBlock_t *m;
int i;
int maximum;
unsigned type;
unsigned func_idx;
unsigned label_idx;
char buffer[BUFSIZ];
m = Memory;
func_idx = 0;
label_idx = 0;
while (m) {
i = IMemAddrFromBase(m->base);
maximum = i + I_MEM_MAX;
while (i < maximum) {
type = gp_mem_b_get_addr_type(m, i, NULL, NULL);
if (type & W_ADDR_T_FUNC) {
snprintf(buffer, sizeof(buffer), "function_%03u", func_idx);
gp_mem_b_set_addr_name(m, i, buffer);
++func_idx;
}
else if (type & W_ADDR_T_LABEL) {
snprintf(buffer, sizeof(buffer), "label_%03u", label_idx);
gp_mem_b_set_addr_name(m, i, buffer);
++label_idx;
}
i += 2;
}
m = m->next;
}
}
/*------------------------------------------------------------------------------------------------*/
static size_t
_byte_exclamation(char *Buffer, size_t Buffer_length, size_t Current_length, uint8_t Byte)
{
int l;
size_t length;
l = snprintf(&Buffer[Current_length], Buffer_length - Current_length, "%-*s0x%02x",
TABULATOR_SIZE, "db", (unsigned)Byte);
if (l <= 0) {
return Current_length;
}
length = Current_length + l;
if (isprint(Byte)) {
gp_exclamation(Buffer, Buffer_length, length, "; '%c'", Byte);
}
return length;
}
/*------------------------------------------------------------------------------------------------*/
static void
_show_config(void)
{
gp_cfg_addr_hit_t *hit;
unsigned m;
unsigned n;
if (addr_pack.hit_count == 0) {
return;
}
_ux_print(true, "");
for (m = 0; m < addr_pack.hit_count; ++m) {
hit = &addr_pack.hits[m];
for (n = 0; n < hit->pair_count; ++n) {
_ux_print(true, " CONFIG %-*s = %s", addr_pack.max_dir_width,
hit->pairs[n].directive->name, hit->pairs[n].option->name);
}
}
}
/*------------------------------------------------------------------------------------------------*/
static void
_show_idlocs(void)
{
unsigned i;
unsigned j;
int word;
bool prev_exist;
bool act_exist;
bool aligned;
char buffer[PIC16E_IDLOCS_SIZE * 2];
if (idlocs_pack.number == 0) {
return;
}
if (state.pclass == PROC_CLASS_PIC16E) {
prev_exist = false;
act_exist = false;
aligned = false;
for (i = 0, word = 0; i < PIC16E_IDLOCS_SIZE; ++i) {
act_exist = (idlocs_pack.words[i] >= 0) ? true : false;
if (i == 0) {
/* Start at the beginning. */
aligned = act_exist;
}
if ((!prev_exist) && act_exist) {
++word;
if (word > 1) {
/* There are several separate words or characters. */
break;
}
}
prev_exist = act_exist;
}
if (aligned && (word == 1)) {
/* One word and start at the beginning. */
if (idlocs_pack.is_print) {
/* Only printable characters are there in it. */
for (i = 0, j = 0; i < PIC16E_IDLOCS_SIZE; ++i) {
if ((word = idlocs_pack.words[i]) > 0) {
buffer[j++] = (char)word;
}
}
buffer[j] = '\0';
_ux_print(true, "\n"
" IDLOCS \"%s\"", buffer);
}
else {
/* Not only printable characters are there in it. */
_ux_print(true, "");
for (i = 0; i < PIC16E_IDLOCS_SIZE; ++i) {
if ((word = idlocs_pack.words[i]) >= 0) {
if (isalnum(word)) {
_ux_print(true, " __idlocs _IDLOC%u, '%c'", i, word);
}
else {
_ux_print(true, " __idlocs _IDLOC%u, 0x%02X", i, word);
}
}
}
}
} /* if (aligned && (word == 1)) */
else {
/* There are several separate words or characters, or do not start at the beginning. */
prev_exist = false;
act_exist = false;
_ux_print(true, "");
for (i = 0; i < PIC16E_IDLOCS_SIZE; ++i) {
if ((word = idlocs_pack.words[i]) >= 0) {
act_exist = true;
if (isalnum(word)) {
_ux_print(true, " __idlocs _IDLOC%u, '%c'", i, word);
}
else {
_ux_print(true, " __idlocs _IDLOC%u, 0x%02X", i, word);
}
}
else {
act_exist = false;
}
if (prev_exist && (!act_exist)) {
/* Indicates the break. */
_ux_print(true, "");
}
prev_exist = act_exist;
}
}
} /* if (state.pclass == PROC_CLASS_PIC16E) */
else {
if (idlocs_pack.number != PIC12_IDLOCS_SIZE) {
fprintf(stderr, "The IDLOCS size is not %u words!\n", PIC12_IDLOCS_SIZE);
}
word = (idlocs_pack.words[0] & 0x000F) << 12;
word |= (idlocs_pack.words[1] & 0x000F) << 8;
word |= (idlocs_pack.words[2] & 0x000F) << 4;
word |= (idlocs_pack.words[3] & 0x000F);
_ux_print(true, "\n"
" __idlocs 0x%04X", word);
}
}
/*------------------------------------------------------------------------------------------------*/
static bool
_need_section_print(const lset_section_t *Section)
{
unsigned i;
for (i = 0; i < Section->symbol_number; ++ i) {
if (Section->symbol_table[i]->attr & CSYM_USED) {
return true;
}
}
return false;
}
/*------------------------------------------------------------------------------------------------*/
static void
_list_user_labels(int Addr_digits)
{
unsigned i;
const lset_section_t *sect;
const lset_symbol_t *sym;
size_t length;
char buffer[BUFSIZ];
if (((sect = state.lset_root.sections[SECT_SPEC_DATA])) && (sect->symbol_table)) {
if (_need_section_print(sect)) {
printf("\n;%s\n; DATA address definitions\n\n", border);
for (i = 0; i < sect->symbol_number; ++i) {
sym = sect->symbol_table[i];
if (sym->attr & CSYM_USED) {
length = snprintf(buffer, sizeof(buffer), "%-*s equ 0x%0*lX",
USER_LABEL_ALIGN, sym->name, Addr_digits, sym->start);
if (sym->attr & CSYM_END) {
gp_exclamation(buffer, sizeof(buffer), length, "; size: %li bytes", sym->end - sym->start + 1);
}
_ux_print(true, "%s", buffer);
}
}
}
}
if (((sect = state.lset_root.sections[SECT_SPEC_EEDATA])) && (sect->symbol_table)) {
if (_need_section_print(sect)) {
_ux_print(true, "\n"
";%s\n"
"; EEDATA address definitions\n", border);
for (i = 0; i < sect->symbol_number; ++i) {
sym = sect->symbol_table[i];
if (sym->attr & CSYM_USED) {
length = snprintf(buffer, sizeof(buffer), "%-*s equ (__EEPROM_START + 0x%0*lX)",
USER_LABEL_ALIGN, sym->name, Addr_digits, sym->start);
if (sym->attr & CSYM_END) {
gp_exclamation(buffer, sizeof(buffer), length, "; size: %li bytes", sym->end - sym->start + 1);
}
_ux_print(true, "%s", buffer);
}
}
}
}
}
/*------------------------------------------------------------------------------------------------*/
static void
_add_constant(lset_section_t *Section, const char *Name, long Start, unsigned Attr)
{
if (lset_symbol_find_addr(Section, Start, -1, false)) {
return;
}
lset_symbol_new(Section, Name, Start, -1, CSYM_START | Attr, 0);
}
/*------------------------------------------------------------------------------------------------*/
static void
_load_processor_constants(void)
{
pic_processor_t processor;
lset_section_t *sect;
const int *pair;
int addr;
const vector_t *vec;
unsigned num;
char buf[BUFSIZ];
processor = state.processor;
/* The code section. */
if ((sect = state.lset_root.sections[SECT_SPEC_CODE]) == NULL) {
sect = lset_section_new(&state.lset_root, "CODE", 0);
}
if (sect) {
addr = processor->prog_mem_size;
if (addr > 0) {
_add_constant(sect, "__CODE_START", 0, CSYM_ORG);
_add_constant(sect, "__CODE_END", addr - 1, CSYM_ORG);
}
if ((pair = gp_processor_idlocs_exist(processor))) {
lset_symbol_new(sect, "__IDLOCS_START", pair[0], -1, CSYM_START, 0);
lset_symbol_new(sect, "__IDLOCS_END", pair[1], -1, CSYM_END, 0);
}
if ((pair = gp_processor_config_exist(processor))) {
lset_symbol_new(sect, "__CONFIG_START", pair[0], -1, CSYM_START, 0);
lset_symbol_new(sect, "__CONFIG_END", pair[1], -1, CSYM_END, 0);
}
if ((processor->pclass->vector_table) || (processor->pclass->vector_number > 0)) {
vec = processor->pclass->vector_table;
num = processor->pclass->vector_number;
for (; num; ++vec, --num) {
buf[0] = '_';
buf[1] = '_';
gp_stptoupper(&buf[2], vec->name, sizeof(buf) - 2);
if (vec->address < 0) {
/* This a SX type processor. */
addr = processor->prog_mem_size;
if (addr > 0) {
--addr;
}
}
else {
addr = vec->address;
}
_add_constant(sect, buf, addr, CSYM_ORG);
}
}
} /* if (sect) */
/* The data section. */
if ((sect = state.lset_root.sections[SECT_SPEC_DATA]) == NULL) {
sect = lset_section_new(&state.lset_root, "DATA", 0);
}
if (sect) {
if ((pair = gp_processor_common_ram_exist(processor))) {
if (lset_symbol_find_addr(sect, pair[0], pair[1], false) == NULL) {
lset_symbol_new(sect, "Common_RAM", pair[0], pair[1], CSYM_START | CSYM_END, 0);
}
}
if ((pair = gp_processor_linear_ram_exist(processor))) {
if (lset_symbol_find_addr(sect, pair[0], pair[1], false) == NULL) {
lset_symbol_new(sect, "Linear_RAM", pair[0], pair[1], CSYM_START | CSYM_END, 0);
}
}
}
/* The eedata section. */
if ((sect = state.lset_root.sections[SECT_SPEC_EEDATA]) == NULL) {
sect = lset_section_new(&state.lset_root, "EEDATA", 0);
}
if (sect) {
if ((pair = gp_processor_eeprom_exist(processor))) {
_add_constant(sect, "__EEPROM_START", pair[0], CSYM_ORG);
_add_constant(sect, "__EEPROM_END", pair[1], CSYM_ORG);
}
}
lset_sections_choose(&state.lset_root);
lset_section_make_symbol_tables(&state.lset_root);
lset_section_check_bounds(&state.lset_root);
}
/*------------------------------------------------------------------------------------------------*/
static void
_dasm(MemBlock_t *Memory)
{
MemBlock_t *m;
int i;
int maximum;
int org;
int offset;
int insn_size;
int last_loc;
int num_words;
int behavior;
int bsr_boundary;
uint16_t data;
uint8_t byte;
unsigned type;
const char *label_name;
int addr_digits;
int word_digits;
size_t length;
const lset_symbol_t *sym;
char buffer[BUFSIZ];
if (state.show_names && ((state.pclass == PROC_CLASS_PIC12) ||
(state.pclass == PROC_CLASS_PIC12E) ||
(state.pclass == PROC_CLASS_PIC12I) ||
(state.pclass == PROC_CLASS_SX) ||
(state.pclass == PROC_CLASS_PIC14) ||
(state.pclass == PROC_CLASS_PIC14E) ||
(state.pclass == PROC_CLASS_PIC14EX) ||
(state.pclass == PROC_CLASS_PIC16) ||
(state.pclass == PROC_CLASS_PIC16E))) {
if (state.pclass == PROC_CLASS_PIC16E) {
_mark_false_addresses(Memory);
}
_recognize_labels_and_spec_words(Memory);
_recognize_registers(Memory);
_denominate_labels(Memory);
}
bsr_boundary = gp_processor_bsr_boundary(state.processor);
addr_digits = state.pclass->addr_digits;
word_digits = state.pclass->word_digits;
_write_header();
if (state.show_names) {
_ux_print(true, "\n"
"; The recognition of labels and registers is not always good, therefore\n"
"; be treated cautiously the results.");
if (state.need_sfr_equ) {
_write_core_sfr_list();
}
}
if (!state.format && state.show_config) {
_show_config();
_show_idlocs();
}
if (state.show_names) {
behavior = GPDIS_SHOW_NAMES | GPDIS_SHOW_BYTES | GPDIS_SHOW_EXCLAMATION;
if (state.show_fsrn) {
behavior |= GPDIS_SHOW_FSRN;
}
_list_user_labels(addr_digits);
}
else {
behavior = GPDIS_SHOW_NOTHING;
}
m = Memory;
last_loc = 0;
while (m) {
i = IMemAddrFromBase(m->base);
maximum = i + I_MEM_MAX;
insn_size = 2;
while (i < maximum) {
org = gp_processor_insn_from_byte_p(state.processor, i);
if ((offset = gp_processor_is_idlocs_org(state.processor, org)) >= 0) {
/* This is idlocs word/bytes. Not need disassemble. */
if (state.pclass == PROC_CLASS_PIC16E) {
if (!state.show_config) {
if (gp_mem_b_get(m, i, &byte, NULL, NULL)) {
if (last_loc != (i - insn_size)) {
if (state.show_names && (offset == 0)) {
_ux_print(true, "\n"
";%s\n"
"; IDLOCS area", border);
}
_write_org(org, addr_digits, "idlocs", NULL, 0);
}
last_loc = i;
if (state.format) {
length = snprintf(buffer, sizeof(buffer), "%0*x: %02x ",
addr_digits, org, (unsigned)byte);
}
else {
length = snprintf(buffer, sizeof(buffer), " ");
}
_byte_exclamation(buffer, sizeof(buffer), length, byte);
_ux_print(true, "%s", buffer);
}
else {
last_loc = 0;
}
}
insn_size = 1;
} /* if (state.pclass == PROC_CLASS_PIC16E) */
else {
if (!state.show_config) {
if (state.pclass->i_memory_get(m, i, &data, NULL, NULL)) {
if (last_loc != (i - insn_size)) {
sym = lset_symbol_find_addr(state.lset_root.sections[SECT_SPEC_CODE], org, -1, true);
if ((sym) && (sym->attr & CSYM_ORG)) {
_write_org(org, addr_digits, "idlocs", sym->name, 0);
}
else {
_write_org(org, addr_digits, "idlocs", NULL, 0);
}
}
last_loc = i;
if (state.format) {
length = snprintf(buffer, sizeof(buffer), "%0*x: %0*x ",
addr_digits, org, word_digits, (unsigned)data);
}
else {
length = snprintf(buffer, sizeof(buffer), " ");
}
length += snprintf(buffer + length, sizeof(buffer) - length, "%-*s0x%0*x",
TABULATOR_SIZE, "dw", word_digits, (unsigned)data);
if (state.processor->idlocs_mask != 0) {
unsigned tmp = (~state.processor->idlocs_mask) & data;
gp_exclamation(buffer, sizeof(buffer), length, "; in fact: 0x%0*x", word_digits, tmp);
}
_ux_print(true, "%s", buffer);
}
else {
last_loc = 0;
}
}
insn_size = 2;
}
} /* if (gp_processor_is_idlocs_org(state.processor, org) >= 0) */
else if ((offset = gp_processor_is_config_org(state.processor, org)) >= 0) {
/* This is config word/bytes. Not need disassemble. */
if (state.pclass == PROC_CLASS_PIC16E) {
if (!state.show_config) {
if (gp_mem_b_get(m, i, &byte, NULL, NULL)) {
if (last_loc != (i - insn_size)) {
if (state.show_names && (offset == 0)) {
_ux_print(true, "\n"
";%s\n"
"; CONFIG Bits area", border);
}
_write_org(org, addr_digits, "config", NULL, 0);
}
last_loc = i;
if (state.format) {
_ux_print(false, "%0*x: %02x ", addr_digits, org, (unsigned)byte);
}
else {
_ux_print(false, " ");
}
_ux_print(true, "%-*s0x%02x", TABULATOR_SIZE, "db", (unsigned)byte);
}
else {
last_loc = 0;
}
}
insn_size = 1;
} /* if (state.pclass == PROC_CLASS_PIC16E) */
else {
if (!state.show_config) {
if (state.pclass->i_memory_get(m, i, &data, NULL, NULL)) {
if (last_loc != (i - insn_size)) {
if (state.show_names && (offset == 0)) {
_ux_print(true, "\n"
";%s\n"
"; CONFIG Bits area", border);
}
_write_org(org, addr_digits, "config", NULL, 0);
}
last_loc = i;
if (state.format) {
_ux_print(false, "%0*x: %0*x ", addr_digits, org, word_digits, (unsigned)data);
}
else {
_ux_print(false, " ");
}
_ux_print(true, "%-*s0x%0*x", TABULATOR_SIZE, "dw", word_digits, (unsigned)data);
}
else {
last_loc = 0;
}
}
insn_size = 2;
}
} /* else if (gp_processor_is_config_org(state.processor, org) >= 0) */
else if ((offset = gp_processor_is_eeprom_org(state.processor, org)) >= 0) {
if (gp_mem_b_get(m, i, &byte, NULL, &label_name)) {
if (last_loc != (i - insn_size)) {
sym = lset_symbol_find_addr(state.lset_root.sections[SECT_SPEC_EEDATA], org, -1, true);
if (state.show_names && (offset == 0)) {
_ux_print(true, "\n"
";%s\n"
"; EEDATA area", border);
}
if ((sym) && (sym->attr & CSYM_ORG)) {
_write_org(org, addr_digits, "eeprom", sym->name, 0);
}
else {
sym = lset_symbol_find_addr(state.lset_root.sections[SECT_SPEC_EEDATA],
state.processor->eeprom_addrs[0],
state.processor->eeprom_addrs[1], true);
if ((sym) && (sym->attr & CSYM_ORG)) {
_write_org(org, addr_digits, "eeprom", sym->name, offset);
}
else {
_write_org(org, addr_digits, "eeprom", NULL, offset);
}
}
}
last_loc = i;
if (state.show_names && (label_name)) {
length = snprintf(buffer, sizeof(buffer), "%s", label_name);
gp_exclamation(buffer, sizeof(buffer), length, "; address: 0x%0*x", addr_digits, org);
if (! prev_empty_line) {
_ux_print(true, "");
}
_ux_print(true, "%s\n", buffer);
prev_empty_line = true;
}
if (state.format) {
length = snprintf(buffer, sizeof(buffer), "%0*x: %02x ",
addr_digits, org, (unsigned)byte);
}
else {
length = snprintf(buffer, sizeof(buffer), " ");
}
_byte_exclamation(buffer, sizeof(buffer), length, byte);
_ux_print(true, "%s", buffer);
prev_empty_line = false;
}
else {
last_loc = 0;
}
insn_size = 1;
} /* else if (gp_processor_is_eeprom_org(state.processor, org) >= 0) */
else {
/* This is program word. */
if (state.pclass->i_memory_get(m, i, &data, NULL, &label_name) == W_USED_ALL) {
if (last_loc != (i - insn_size)) {
sym = lset_symbol_find_addr(state.lset_root.sections[SECT_SPEC_CODE], org, -1, true);
if (state.show_names && (org == 0)) {
_ux_print(true, "\n"
";%s\n"
"; CODE area", border);
}
if ((sym) && (sym->attr & CSYM_ORG)) {
_write_org(org, addr_digits, "code", sym->name, 0);
}
else {
_write_org(org, addr_digits, "code", NULL, 0);
}
}
last_loc = i;
if (state.show_names && (label_name)) {
length = snprintf(buffer, sizeof(buffer), "%s:", label_name);
gp_exclamation(buffer, sizeof(buffer), length, "; address: 0x%0*x", addr_digits, org);
if (! prev_empty_line) {
_ux_print(true, "");
}
_ux_print(true, "%s\n", buffer);
prev_empty_line = true;
}
if (state.format) {
length = snprintf(buffer, sizeof(buffer), "%0*x: %0*x ",
addr_digits, org, word_digits, (unsigned)data);
}
else {
length = snprintf(buffer, sizeof(buffer), " ");
}
type = gp_mem_b_get_type(m, i);
if (type & W_CONST_DATA) {
gp_disassemble_show_data(m, i, state.pclass, behavior, buffer, sizeof(buffer), length);
_ux_print(true, "%s", buffer);
prev_empty_line = false;
num_words = 1;
}
else {
num_words = gp_disassemble(m, i, state.pclass, bsr_boundary, state.processor->prog_mem_size,
behavior, buffer, sizeof(buffer), length);
_ux_print(true, "%s", buffer);
prev_empty_line = false;
if (num_words != 1) {
/* Some 18xx instructions use two words. */
if (state.format) {
state.pclass->i_memory_get(m, i + 2, &data, NULL, NULL);
_ux_print(true, "%0*x: %0*x", addr_digits, gp_processor_insn_from_byte_p(state.processor, i + 2),
word_digits, (unsigned)data);
prev_empty_line = false;
}
insn_size = 4;
}
else {
insn_size = 2;
}
}
}
}
i += insn_size;
}
m = m->next;
}
_end_asm();
}
/*------------------------------------------------------------------------------------------------*/
static bool
strict_options,
print_hex_info,
memory_dump,
strict,
usage;
static const char*label_list_name;
static const char*filename;
static void _stdcall onOption(void*, char c, const char*arg) {
if (strict_options) gp_checkarg(arg,longopts);
switch (c) {
case '?':
case 'h': usage = true; break;
case 'c': gp_decode_mnemonics = true; break;
case 'i': print_hex_info = true; break;
case 'j': state.show_fsrn = true; break;
case 'k': label_list_name = arg; break;
case 'l':
gp_dump_processor_list(true, PROC_CLASS_UNKNOWN, PROC_CLASS_UNKNOWN, PROC_CLASS_UNKNOWN);
exit(0);
case 'm': memory_dump = true; break;
case 'n': state.show_names = true; break;
case 'o': state.show_config = true; break;
case 'p': processor_name = arg; break;
case 's': state.format = 0; break;
case 't': state.use_tab = true; break;
case 'v':
fprintf(stderr, "%s\n", GPDASM_VERSION_STRING);
exit(0);
case 'y': gp_decode_extended = true; break;
case 2: strict = true; break;
case 1: gp_checkarg(label_list_name,longopts);
gp_checkarg(processor_name,longopts);
gp_checkarg(filename,longopts);
strict_options = true; break;
case 0: filename = arg; break;
}
}
int _cdecl main(int argc, char *argv[]) {
const int *pair;
gp_init();
state.pclass=PROC_CLASS_GENERIC; // 12 bit device
state.format=1; // output format
state.i_memory = gp_mem_i_create();
gp_getopt(argv,longopts,onOption,0);
if (!filename || usage) _show_usage(*argv);
_select_processor();
state.hex_info = gp_readhex(filename, state.i_memory);
if (state.hex_info->error) state.num.errors++;
if (strict && (state.pclass) && (state.pclass->patch_strict)) {
state.pclass->patch_strict();
}
if (print_hex_info) {
printf("hex file name: %s\n", filename);
printf("hex file format: ");
if (state.hex_info->hex_format == INHX8M) {
printf("inhx8m\n");
}
else if (state.hex_info->hex_format == INHX16) {
printf("inhx16\n");
}
else if (state.hex_info->hex_format == INHX32) {
printf("inhx32\n");
}
else {
printf("UNKNOWN\n");
}
printf("number of bytes: %i\n\n", state.hex_info->size);
}
if (label_list_name) {
open_label_source(label_list_name);
lset_init(&state.lset_root, label_list_name);
yyparse();
close_label_source();
lset_sections_choose(&state.lset_root);
lset_section_make_symbol_tables(&state.lset_root);
lset_section_check_bounds(&state.lset_root);
lset_symbol_check_absolute_limits(state.lset_root.sections[SECT_SPEC_CODE],
0, state.processor->prog_mem_size - 1);
if (state.pclass == PROC_CLASS_PIC16E) {
lset_symbol_check_align(state.lset_root.sections[SECT_SPEC_CODE], 2);
}
if (state.lset_root.sections[SECT_SPEC_EEDATA]) {
if ((pair = gp_processor_eeprom_exist(state.processor))) {
lset_symbol_check_absolute_limits(state.lset_root.sections[SECT_SPEC_EEDATA],
0, pair[1] - pair[0]);
}
else {
fprintf(stderr, "Error: The processor does not have EEPROM.\n");
exit(1);
}
}
}
else {
lset_init(&state.lset_root, NULL);
}
if (state.num.errors == 0) {
if (memory_dump) {
gp_mem_i_print(state.i_memory, state.processor);
}
else {
_load_processor_constants();
_dasm(state.i_memory);
}
}
lset_delete(&state.lset_root);
gp_mem_i_free(state.i_memory);
return ((state.num.errors > 0) ? EXIT_FAILURE : EXIT_SUCCESS);
}
Vorgefundene Kodierung: UTF-8 | 0
|