/* ".LST" file output for gpasm Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 James Bowman, Craig Franklin This file is part of gputils. gputils is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. gputils is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with gputils; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "stdhdr.h" #include "libgputils.h" #include "gpasm.h" #include "cod.h" #include "coff.h" extern int _16bit_core; void lst_throw() { if(state.lst.f) { state.lst.page++; fprintf(state.lst.f, "%s%-32s%-12s%-29sPAGE %2d\n%s\n%s\n", (state.lst.page == 1) ? "" : "\f", GPASM_VERSION_STRING, state.srcfilename, state.lst.startdate, state.lst.page, state.lst.title_name, state.lst.subtitle_name); state.lst.lineofpage = 4; cod_lst_line(COD_NORMAL_LST_LINE); cod_lst_line(COD_NORMAL_LST_LINE); cod_lst_line(COD_NORMAL_LST_LINE); state.lst.line_number += 3; } } void lst_line(char *line) { if (state.lst.f) { if (state.lst.linesperpage != 0) { if ((state.lst.lineofpage++ % state.lst.linesperpage) == 0) { lst_throw(); lst_line("LOC OBJECT CODE LINE SOURCE TEXT"); lst_line(" VALUE"); lst_line(" "); } } fprintf(state.lst.f, "%s\n", line); state.lst.line_number++; cod_lst_line(COD_NORMAL_LST_LINE); } } void lst_init() { state.lst.lineofpage = 0; state.lst.page = 0; state.lst.linesperpage = 60; state.lst.line_number = 1; state.lst.memorymap = 1; state.lst.symboltable = 1; /* Determine state.startdate */ gp_date_string(state.lst.startdate, sizeof(state.lst.startdate)); if (!state.cmd_line.macro_expand){ state.lst.expand = true; } if (state.cmd_line.lst_force) state.lst.force = true; else state.lst.force = false; state.lst.config_address = 0; state.lst.title_name[0] = '\0'; state.lst.subtitle_name[0] = '\0'; state.lst.tabstop = 8; /* Default tabstop every 8 */ if (state.lstfile != named) { strncpy(state.lstfilename, state.basefilename, sizeof(state.lstfilename)); strncat(state.lstfilename, ".lst", sizeof(state.lstfilename)); } if (state.lstfile == suppress) { state.lst.f = NULL; state.lst.enabled = false; unlink(state.lstfilename); } else { state.lst.f = fopen(state.lstfilename, "wt"); if (state.lst.f == NULL) { perror(state.lstfilename); exit(1); } state.lst.enabled = true; } cod_lst_line(COD_FIRST_LST_LINE); } void lst_memory_map(MemBlock *m) { char buf[BUFSIZ]; int i, j, base, row_used, num_per_line, num_per_block; lst_line(""); lst_line(""); lst_line("MEMORY USAGE MAP ('X' = Used, '-' = Unused)"); lst_line(""); if (_16bit_core) { /* uses byte addressing so read half as many words */ num_per_line = 32; num_per_block = 8; } else { num_per_line = 64; num_per_block = 16; } while(m) { assert(m->memory != NULL); base = (m->base << I_MEM_BITS); for (i = 0; i < MAX_I_MEM; i += num_per_line) { row_used = 0; for (j = 0; j < num_per_line; j++) { if (m->memory[i+j] & MEM_USED_MASK) { row_used = 1; break; } } if(row_used) { snprintf(buf, sizeof(buf), "%08x :", (i + base) << _16bit_core); for (j = 0; j < num_per_line; j++) { if ((j % num_per_block) == 0) { strncat(buf, " ", sizeof(buf)); } if (m->memory[i + j] & MEM_USED_MASK) { strncat(buf, "X", sizeof(buf)); if (_16bit_core) { /* each word has two bytes */ strncat(buf, "X", sizeof(buf)); } } else { strncat(buf, "-", sizeof(buf)); if (_16bit_core) { /* each word has two bytes */ strncat(buf, "-", sizeof(buf)); } } } lst_line(buf); } } m = m->next; } lst_line(""); lst_line("All other memory blocks unused."); lst_line(""); snprintf(buf, sizeof(buf), "Program Memory Words Used: %i", i_memory_used(state.i_memory)); lst_line(buf); } void lst_close() { cod_lst_line(COD_LAST_LST_LINE); if (state.lst.f) { fprintf(state.lst.f, "\n\n"); fprintf(state.lst.f, "Errors : %7d\n", state.num.errors); fprintf(state.lst.f, "Warnings : %7d reported, %7d suppressed\n", state.num.warnings, state.num.warnings_suppressed); fprintf(state.lst.f, "Messages : %7d reported, %7d suppressed\n", state.num.messages, state.num.messages_suppressed); fprintf(state.lst.f, "\f\n"); fclose(state.lst.f); } } void lst_format_line(char *src_line, int value) { char m[BUFSIZ]; char buf[BUFSIZ]; unsigned int emitted = 0; assert(src_line != NULL); switch (state.lst.line.linetype) { case equ: case set: snprintf(m, sizeof(m), " %08X", value); strncat(m, " ", sizeof(m)); break; case org: snprintf(m, sizeof(m), "%04X ", state.org << _16bit_core); strncat(m, " ", sizeof(m)); break; case idlocs: /* not used for 16 bit devices, config is used */ snprintf(m, sizeof(m), "%04X %04X %04X ", state.device.id_location, i_memory_get(state.i_memory, state.device.id_location) & 0xffff, i_memory_get(state.i_memory, state.device.id_location + 1) & 0xffff); break; case insn: snprintf(m, sizeof(m), "%04X ", state.lst.line.was_org << _16bit_core); emitted = state.org - state.lst.line.was_org; if (emitted >= 1) { snprintf(buf, sizeof(buf), "%04X ", i_memory_get(state.i_memory, state.lst.line.was_org) & 0xffff); strncat(m, buf, sizeof(m)); } else strncat(m, " ", sizeof(m)); if (emitted >= 2) { snprintf(buf, sizeof(buf), "%04X ", i_memory_get(state.i_memory, state.lst.line.was_org + 1) & 0xffff); strncat(m, buf, sizeof(buf)); } else strncat(m, " ", sizeof(m)); break; case config: if(_16bit_core) { /* config data is byte addressable, but we only want to print words in the list file. */ if (state.lst.config_address == CONFIG4L) { /* Special case */ snprintf(m, sizeof(m), "%06X %04X ", state.lst.config_address, i_memory_get(state.i_memory, state.lst.config_address >> 1) & 0xffff); } else if((state.lst.config_address & 0x1) == 0) { /* if it is an even address don't print anything */ strncpy(m, " ", sizeof(m)); } else { snprintf(m, sizeof(m), "%06X %04X ", state.lst.config_address - 1, i_memory_get(state.i_memory, (state.lst.config_address - 1) >> 1) & 0xffff); } } else { snprintf(m, sizeof(m), "%06X %04X ", state.lst.config_address, i_memory_get(state.i_memory, state.lst.config_address) & 0xffff); } break; case res: strncpy(m, " ", sizeof(m)); if (SECTION_FLAGS & STYP_TEXT) { /* generate line numbers for res directives in program memory */ emitted = state.org - state.lst.line.was_org; } break; case sec: case dir: case none: default: strncpy(m, " ", sizeof(m)); break; } if (state.stGlobal == state.stTop) { snprintf(buf, sizeof(buf), "%05d ", state.src->line_number); } else { snprintf(buf, sizeof(buf), " M "); } strncat(m, buf, sizeof(m)); /* Now copy 'l' to 'e', expanding tabs as required */ { int column = 0; char *old; char *e = m + strlen(m); old = src_line; while (*old) { if (*old == '\t') { *e++ = ' '; column++; while ((column % state.lst.tabstop) != 0) { *e++ = ' '; column++; } } else { *e++ = *old; column++; } old++; } *e = '\0'; /* terminate the new string */ } coff_linenum(emitted); /* Don't write to file is list is disabled */ if (!state.lst.enabled) return; /* Tell the .cod file that the next line(s) has an opcode(s) */ state.cod.emitting = emitted; lst_line(m); #ifdef GPUTILS_DEBUG fprintf(stderr, "%s\n\n", m); #endif if (state.lst.line.linetype == idlocs) { snprintf(m, sizeof(m), " %04X %04X ", i_memory_get(state.i_memory, state.device.id_location + 2) & 0xffff, i_memory_get(state.i_memory, state.device.id_location + 3) & 0xffff); lst_line(m); } if (emitted > 2) { int i; for (i = 2; i < emitted; i += 2) { if ((i + 1) < emitted) snprintf(m, sizeof(m), "%04X %04X %04X", ((state.lst.line.was_org + i) << _16bit_core), i_memory_get(state.i_memory, state.lst.line.was_org + i) & 0xffff, i_memory_get(state.i_memory, state.lst.line.was_org + i + 1) & 0xffff); else snprintf(m, sizeof(m), "%04X %04X", ((state.lst.line.was_org + i) << _16bit_core), i_memory_get(state.i_memory, state.lst.line.was_org + i) & 0xffff); lst_line(m); } state.cod.emitting = 0; } } /* append the symbol table to the .lst file */ void lst_symbol_table(struct symbol_table *table) { int i; const char *symbol_format = "%-32s %08X"; struct symbol **lst, **ps, *s; char buf[BUFSIZ]; lst_line("SYMBOL TABLE"); snprintf(buf, sizeof(buf), "%-32s %-8s", " LABEL", " VALUE"); lst_line(buf); lst_line(""); ps = lst = malloc(table->count * sizeof(lst[0])); for (i = 0; i < HASH_SIZE; i++) for (s = table->hash_table[i]; s; s = s->next) *ps++ = s; assert(ps == &lst[table->count]); qsort(lst, table->count, sizeof(lst[0]), symbol_compare); for (i = 0; i < table->count; i++) { struct variable *var; var = get_symbol_annotation(lst[i]); snprintf(buf, sizeof(buf), symbol_format, get_symbol_name(lst[i]), var ? var->value : 0); lst_line(buf); } cod_write_symbols(lst,table->count); } void lst_defines_table(struct symbol_table *table) { int i; const char *symbol_format = "%-32s %s"; struct symbol **lst, **ps, *s; char buf[BUFSIZ]; ps = lst = malloc(table->count * sizeof(lst[0])); for (i = 0; i < HASH_SIZE; i++) for (s = table->hash_table[i]; s; s = s->next) *ps++ = s; assert(ps == &lst[table->count]); qsort(lst, table->count, sizeof(lst[0]), symbol_compare); for (i = 0; i < table->count; i++) { char *defined_as; defined_as = get_symbol_annotation(lst[i]); snprintf(buf, sizeof(buf), symbol_format, get_symbol_name(lst[i]), defined_as); lst_line(buf); } }