/* ".LST" file output for gpasm
Copyright 1998-2005 James Bowman, Craig Franklin
Copyright 2012 Borut Ražem
Copyright 2016 Molnár Károly
*/
#include "stdhdr.h"
#include "libgputils.h"
#include "directive.h"
#include "gpasm.h"
#include "cod.h"
#include "coff.h"
#include "lst.h"
#define STRINGIFY(s) _str(s)
#define _str(s) #s
#define IS_EEPROM ((IS_EEPROM8) || (IS_EEPROM16))
#define IS_BYTE ((IS_PIC16E_CORE) || (IS_EEPROM))
#define MEM_USED_CHAR 'X'
#define MEM_UNUSED_CHAR '-'
#define MAC_PARM_STR_MAX_LENGTH 256
typedef struct {
const symbol_t *sym;
enum lst_sym_type_e {
LST_SYMBOL,
LST_DEFINITION,
LST_MACRO
} type;
} lst_symbol_t;
/*------------------------------------------------------------------------------------------------*/
static void
_lst_check_page_start(void)
{
if ((state.lst.lines_per_page != 0) &&
((state.lst.line_of_page == 0) || (state.lst.line_of_page > state.lst.lines_per_page))) {
lst_page_start();
}
}
/*------------------------------------------------------------------------------------------------*/
static unsigned
_lst_spaces(unsigned Num)
{
unsigned i = Num;
_lst_check_page_start();
while (i-- != 0) {
putc(' ', state.lst.f);
}
return Num;
}
/*------------------------------------------------------------------------------------------------*/
static void
_lst_eol(void)
{
if (state.lst.f) {
putc('\n', state.lst.f);
state.lst.line_number++;
state.lst.line_of_page++;
cod_lst_line(COD_NORMAL_LST_LINE);
}
}
/*------------------------------------------------------------------------------------------------*/
/* Print part of a line. Output must not contain newline. Needs call to lst_eol at end of line. */
static unsigned _cdecl _lst_printf(const char *Format, ...) {
int r = 0;
va_list args;
if (state.lst.f) {
_lst_check_page_start();
va_start(args, Format);
r = vfprintf(state.lst.f, Format, args);
va_end(args);
}
assert(r >= 0);
return (unsigned)r;
}
/*------------------------------------------------------------------------------------------------*/
static void
_lst_putc(char Ch)
{
if (state.lst.f) {
putc(Ch, state.lst.f);
}
}
/*------------------------------------------------------------------------------------------------*/
/* find relocation by address */
static gp_reloc_t * _find_reloc_by_address(unsigned Address) {
gp_reloc_t *p;
for (p = state.obj.section->relocation_list.first; p; p = p->next) {
if (p->address == Address) {
break;
}
}
return p;
}
/*------------------------------------------------------------------------------------------------*/
/* get previous relocation type */
static uint16_t
_prev_reloc_type(void)
{
gp_reloc_t *p;
if (state.obj.section->relocation_list.first == state.obj.section->relocation_list.last) {
return 0;
}
p = state.obj.section->relocation_list.last->prev;
assert(p);
return ((p->address == p->next->address) ? p->type : 0);
}
/*------------------------------------------------------------------------------------------------*/
/* print word value with undefined nibbles replaced by "?" */
/* enable assertions
* #define DO_ASSERT */
/* disable assertions */
#undef DO_ASSERT
#ifdef DO_ASSERT
#define ASSERT(expr) assert(expr)
#else
#define ASSERT(expr) ((void)0)
#endif
static unsigned
_print_reloc(uint16_t Type, uint16_t Current_value, unsigned Index)
{
proc_class_t pclass = state.device.pclass;
switch (Type) {
case RELOC_CALL: {
if ((pclass == PROC_CLASS_PIC12) || (pclass == PROC_CLASS_PIC12E) || (pclass == PROC_CLASS_PIC12I) ||
(pclass == PROC_CLASS_SX) || (pclass == PROC_CLASS_PIC16E)) {
ASSERT((Current_value & PIC12_BMSK_CALL) == 0);
return _lst_printf("%02X?? ", (Current_value & 0xff00) >> 8);
}
else if ((pclass == PROC_CLASS_PIC14) || (pclass == PROC_CLASS_PIC14E) || (pclass == PROC_CLASS_PIC14EX)) {
ASSERT((Current_value & PIC14_BMSK_CALL) == 0);
return _lst_printf("%X??? ", (Current_value & 0xf000) >> 12);
}
else if (pclass == PROC_CLASS_PIC16) {
ASSERT((Current_value & PIC16_BMSK_CALL) == 0);
return _lst_printf("???? ");
}
else if (pclass == PROC_CLASS_PIC16E) {
ASSERT((Current_value & PIC16E_BMSK_CALL0) == 0);
return _lst_printf("%02X?? ", (Current_value & 0xff00) >> 8);
}
else {
ASSERT(0);
return 0;
}
break;
}
/*..................................*/
case RELOC_GOTO: {
if ((pclass == PROC_CLASS_PIC12) || (pclass == PROC_CLASS_PIC12E) || (pclass == PROC_CLASS_PIC12I) ||
(pclass == PROC_CLASS_SX)) {
ASSERT((Current_value & PIC12_BMSK_GOTO) == 0);
return _lst_printf("%X??? ", (Current_value & 0xf000) >> 12);
}
else if ((pclass == PROC_CLASS_PIC14) || (pclass == PROC_CLASS_PIC14E) || (pclass == PROC_CLASS_PIC14EX)) {
ASSERT((Current_value & PIC14_BMSK_GOTO) == 0);
return _lst_printf("%X??? ", (Current_value & 0xf000) >> 12);
}
else if (pclass == PROC_CLASS_PIC16) {
ASSERT((Current_value & PIC16_BMSK_GOTO) == 0);
return _lst_printf("???? ");
}
else if (pclass == PROC_CLASS_PIC16E) {
ASSERT((Current_value & PIC16E_BMSK_GOTO0) == 0);
return _lst_printf("%02X?? ", (Current_value & 0xff00) >> 8);
}
else {
ASSERT(0);
return 0;
}
break;
}
/*..................................*/
case RELOC_LOW:
/* On non-16bits devices DB directive generates values with
* low byte != 0 if more then one byte is defined, for example
* DB 0x12, 0x34 generates 0x1234, so the following assertion fails
* in such cases.
* TODO: This should be solved in DB directive handling function
* do_db(), file directive.c.
* ASSERT((Current_value & 0xff) == 0); */
return _lst_printf("%02X?? ", (Current_value & 0xff00) >> 8);
break;
/*..................................*/
case RELOC_HIGH:
case RELOC_LFSR2:
case RELOC_UPPER:
case RELOC_CONDBRA:
ASSERT((Current_value & 0xff) == 0);
return _lst_printf("%02X?? ", (Current_value & 0xff00) >> 8);
break;
/*..................................*/
case RELOC_P: {
char buf[5] = "????";
if (RELOC_F != _prev_reloc_type()) {
sprintf(&buf[2], "%02X", Current_value & 0x00ff);
}
ASSERT((Current_value & 0x1f00) == 0);
return _lst_printf("%s ", buf);
break;
}
/*..................................*/
case RELOC_BANKSEL: {
if (pclass == PROC_CLASS_PIC12) {
ASSERT((Current_value & PIC12_BMSK_BxF) == 0); /* 04A4-04E4 or 05A4-05E4 */
return _lst_printf("%02X?? ", (Current_value & 0xff00) >> 8);
}
else if ((pclass == PROC_CLASS_PIC12E) || (pclass == PROC_CLASS_PIC12I)) {
ASSERT((Current_value & PIC12E_BMSK_MOVLB) == 0);
return _lst_printf("%03X? ", (Current_value & 0x0fff0) >> 4);
}
else if (pclass == PROC_CLASS_PIC14) {
ASSERT((Current_value & PIC14_BMSK_BxF) == 0); /* 1283-1303 or 1683-1703 */
return _lst_printf("%X??? ", (Current_value & 0xf000) >> 12);
}
else if (pclass == PROC_CLASS_PIC14E) {
ASSERT((Current_value & PIC14E_BMSK_MOVLB) == 0); /* 0020-003F */
return _lst_printf("%02X?? ", (Current_value & 0xff00) >> 8);
}
else if (pclass == PROC_CLASS_PIC14EX) {
ASSERT((Current_value & PIC14EX_BMSK_MOVLB) == 0); /* 0140-017F */
return _lst_printf("%02X?? ", (Current_value & 0xff00) >> 8);
}
else if (pclass == PROC_CLASS_PIC16) {
ASSERT((Current_value & PIC16_BMSK_MOVLB) == 0); /* 0100-010F */
return _lst_printf("%03X? ", (Current_value & 0xfff0) >> 4);
}
else if (pclass == PROC_CLASS_PIC16E) {
ASSERT((Current_value & PIC16E_BMSK_MOVLB) == 0); /* 0100-010F */
return _lst_printf("%03X? ", (Current_value & 0xfff0) >> 4);
}
return _lst_printf("???? ");
break;
}
/*..................................*/
case RELOC_ALL:
return _lst_printf("???? ");
break;
/*..................................*/
case RELOC_IBANKSEL: {
if (pclass == PROC_CLASS_PIC14) {
ASSERT((Current_value & PIC12_BMSK_BxF) == 0);
return _lst_printf("1?83 "); /* 1383 or 1783 */
}
else if ((pclass == PROC_CLASS_PIC14E) || (pclass == PROC_CLASS_PIC14EX)) {
ASSERT((Current_value & PIC12_BMSK_BxF) == 0);
return _lst_printf("%X??? ", (Current_value & 0xf000) >> 12); /* 120A-118A or 160A-158A */
}
else if (pclass == PROC_CLASS_PIC16) {
ASSERT((Current_value & 0x00ff) == 0);
return _lst_printf("%02X?? ", (Current_value & 0xff00) >> 8);
}
else {
ASSERT(0);
return 0;
}
break;
}
/*..................................*/
case RELOC_F: {
if (pclass == PROC_CLASS_SX) {
ASSERT((Current_value & 0x0007) == 0);
return _lst_printf("%03X? ", (Current_value & 0xfff0) >> 4);
}
else if ((pclass == PROC_CLASS_PIC12) || (pclass == PROC_CLASS_PIC12E) || (pclass == PROC_CLASS_PIC12I)) {
ASSERT((Current_value & MASK_PIC12_FILE) == 0);
}
else if ((pclass == PROC_CLASS_PIC14) || (pclass == PROC_CLASS_PIC14E) || (pclass == PROC_CLASS_PIC14EX)) {
ASSERT((Current_value & MASK_PIC14_FILE) == 0);
}
else if ((pclass == PROC_CLASS_PIC16) || (pclass == PROC_CLASS_PIC16E)) {
ASSERT((Current_value & MASK_PIC16_FILE) == 0);
}
else {
ASSERT(0);
return 0;
}
return _lst_printf("%02X?? ", (Current_value & 0xff00) >> 8);
break;
}
/*..................................*/
case RELOC_TRIS_3BIT:
ASSERT((Current_value & PIC12_BMSK_TRIS) == 0);
return _lst_printf("%03X? ", (Current_value & 0x00f0) >> 4);
break;
/*..................................*/
case RELOC_TRIS:
ASSERT((Current_value & 0x001f) == 0);
return _lst_printf("%02X?? ", (Current_value & 0xff00) >> 8);
break;
/*..................................*/
case RELOC_MOVLR: {
if (pclass == PROC_CLASS_PIC16) {
ASSERT((Current_value & PIC16_BMSK_MOVLR) == 0);
return _lst_printf("%02X?%X ", (Current_value & 0xff00) >> 8, Current_value & 0x000f); /* 010.-01F. */
}
else {
ASSERT(0);
return 0;
}
break;
}
/*..................................*/
case RELOC_MOVLB: {
if ((pclass == PROC_CLASS_PIC12E) || (pclass == PROC_CLASS_PIC12I)) {
ASSERT((Current_value & PIC12E_BMSK_MOVLB) == 0);
return _lst_printf("%03X? ", (Current_value & 0xfff0) >> 4);
}
else if (pclass == PROC_CLASS_PIC14E) {
ASSERT((Current_value & PIC14E_BMSK_MOVLB) == 0);
return _lst_printf("%02X?? ", (Current_value & 0xff00) >> 8);
}
else if (pclass == PROC_CLASS_PIC14EX) {
ASSERT((Current_value & PIC14EX_BMSK_MOVLB) == 0);
return _lst_printf("%02X?? ", (Current_value & 0xff00) >> 8);
}
else if (pclass == PROC_CLASS_PIC16) {
ASSERT((Current_value & PIC16_BMSK_MOVLB) == 0);
return _lst_printf("%03X? ", (Current_value & 0xfff0) >> 4); /* 01.0-01.F */
}
else if (pclass == PROC_CLASS_PIC16E) {
ASSERT((Current_value & PIC16E_BMSK_MOVLB) == 0);
return _lst_printf("%03X? ", (Current_value & 0xfff0) >> 4);
}
else {
ASSERT(0);
return 0;
}
break;
}
/*..................................*/
case RELOC_GOTO2:
/* This is only used for PIC16E (pic18). */
case RELOC_FF1:
case RELOC_FF2:
/* removed assertion since it fails during sdcc pic16 library
* compilation: do_insn, case INSN_CLASS_FF
* ASSERT((Current_value & 0x0fff) == 0); */
return _lst_printf("%X??? ", (Current_value & 0xf000) >> 12);
break;
/*..................................*/
case RELOC_LFSR1:
return _lst_printf("%02X?? ", (Current_value & 0xff00) >> 8);
break;
/*..................................*/
case RELOC_BRA: {
if ((pclass == PROC_CLASS_PIC14E) || (pclass == PROC_CLASS_PIC14EX)) {
ASSERT((Current_value & PIC14E_BMSK_RBRA9) == 0);
}
else if (pclass == PROC_CLASS_PIC16E) {
ASSERT((Current_value & PIC16E_BMSK_RBRA11) == 0);
}
else {
ASSERT(0);
return 0;
}
return _lst_printf("%X??? ", (Current_value & 0xf000) >> 12);
break;
}
/*..................................*/
case RELOC_ACCESS: {
if (pclass == PROC_CLASS_PIC16E) {
ASSERT((Current_value & 0x00ff) == 0);
return _lst_printf("%02X?? ", (Current_value & 0xff00) >> 8);
}
else {
ASSERT(0);
return 0;
}
break;
}
/*..................................*/
case RELOC_PAGESEL_WREG: {
if (Index == 0) {
/* movlw PAGE_VALUE */
if ((pclass == PROC_CLASS_PIC12) || (pclass == PROC_CLASS_PIC12E) || (pclass == PROC_CLASS_PIC12I)) {
ASSERT((Current_value & PIC12_BMSK_MOVLW) == 0);
return _lst_printf("%02X?? ", (Current_value & 0xff00) >> 8); /* 0C00 -- movlw ... */
}
else if (pclass == PROC_CLASS_PIC14) {
ASSERT((Current_value & PIC14_BMSK_MOVLW) == 0);
return _lst_printf("%02X?? ", (Current_value & 0xff00) >> 8); /* 3000 -- movlw ... */
}
else {
ASSERT(0);
return 0;
}
}
else {
/* movwf register */
if ((pclass == PROC_CLASS_PIC12) || (pclass == PROC_CLASS_PIC12E) || (pclass == PROC_CLASS_PIC12I)) {
ASSERT((Current_value & PIC12_BMSK_FILE) == 0);
return _lst_printf("%02X?? ", (Current_value & 0xff00) >> 8); /* 0023 -- movwf STATUS */
}
else if (pclass == PROC_CLASS_PIC14) {
ASSERT((Current_value & PIC14_BMSK_FILE) == 0);
return _lst_printf("%02X?? ", (Current_value & 0xff00) >> 8); /* 008A -- movwf PCLATH */
}
else {
ASSERT(0);
return 0;
}
}
break;
}
/*..................................*/
case RELOC_PAGESEL_BITS: {
if ((pclass == PROC_CLASS_PIC12) || (pclass == PROC_CLASS_PIC12E) || (pclass == PROC_CLASS_PIC12I)) {
ASSERT((Current_value & PIC12_BMSK_BxF) == 0);
return _lst_printf("%02X?? ", (Current_value & 0xff00) >> 8); /* 04A3-04E3 or 05A3-05E3 */
}
else if (pclass == PROC_CLASS_PIC14) {
ASSERT((Current_value & PIC14_BMSK_BxF) == 0);
return _lst_printf("%X??? ", (Current_value & 0xf000) >> 12); /* 120A-118A or 160A-158A */
}
else {
ASSERT(0);
return 0;
}
break;
}
/*..................................*/
case RELOC_PAGESEL_MOVLP: {
if ((pclass == PROC_CLASS_PIC14E) || (pclass == PROC_CLASS_PIC14EX)) {
ASSERT((Current_value & PIC14E_BMSK_MOVLP) == 0);
return _lst_printf("%02X?? ", (Current_value & 0xff00) >> 8);
}
else {
ASSERT(0);
return 0;
}
break;
}
/*..................................*/
/* unimplemented relocations */
case RELOC_PAGESEL:
case RELOC_SCNSZ_LOW:
case RELOC_SCNSZ_HIGH:
case RELOC_SCNSZ_UPPER:
case RELOC_SCNEND_LOW:
case RELOC_SCNEND_HIGH:
case RELOC_SCNEND_UPPER:
case RELOC_SCNEND_LFSR1:
case RELOC_SCNEND_LFSR2:
default:
return 0;
}
}
/*------------------------------------------------------------------------------------------------*/
static unsigned
_lst_data(unsigned Position, MemBlock_t *M, unsigned Byte_addr, unsigned Bytes_emitted,
uint16_t Reloc_type)
{
uint8_t emit_byte;
uint16_t emit_word;
unsigned start_addr;
unsigned lst_bytes;
bool is_eeprom_area;
unsigned n;
lst_bytes = 0;
is_eeprom_area = (gp_processor_is_eeprom_byte_addr(state.processor, Byte_addr) >= 0) ? true : false;
/* When in a idata or byte packed section or eeprom area, print byte by byte. */
if (IS_EEPROM8 || is_eeprom_area || (state.obj.new_sect_flags & (STYP_DATA | STYP_BPACK))) {
while ((Bytes_emitted > lst_bytes) && ((Position + 3) <= LST_LINENUM_POS)) {
gp_mem_b_get(M, Byte_addr, &emit_byte, NULL, NULL);
Position += _lst_printf("%02X ", emit_byte);
++Byte_addr;
++lst_bytes;
}
}
else { /* non-code pack section */
/* list first byte on odd address */
if ((Bytes_emitted != 0) && (Byte_addr & 1)) {
gp_mem_b_get(M, Byte_addr, &emit_byte, NULL, NULL);
Position += _lst_printf("%02X ", emit_byte);
++Byte_addr;
++lst_bytes;
}
/* list full words */
start_addr = Byte_addr;
while (((Bytes_emitted - lst_bytes) > 1) && ((Position + 5) <= LST_LINENUM_POS)) {
state.device.pclass->i_memory_get(M, Byte_addr, &emit_word, NULL, NULL);
/* Display '?' for undefined bytes if it is a relocatable code. */
if (Reloc_type != 0) {
n = _print_reloc(Reloc_type, emit_word, (Byte_addr - start_addr) / 2);
Position += (n == 0) ? _lst_printf("%04X ", emit_word) : n;
}
else {
Position += _lst_printf("%04X ", emit_word);
}
Byte_addr += 2;
lst_bytes += 2;
}
if (((Bytes_emitted - lst_bytes) == 1) && ((Position + 3) <= LST_LINENUM_POS)) {
gp_mem_b_get(M, Byte_addr, &emit_byte, NULL, NULL);
Position += _lst_printf("%02X ", emit_byte);
++Byte_addr;
++lst_bytes;
}
}
/* append appropriate spacing */
_lst_spaces(LST_LINENUM_POS - Position);
return lst_bytes;
}
/*------------------------------------------------------------------------------------------------*/
static void
_cod_symbol_table(void)
{
const symbol_t **lst;
size_t sym_count;
sym_count = gp_sym_get_symbol_count(state.stGlobal);
if (sym_count == 0) {
return;
}
if (!state.mpasm_compatible) {
lst = gp_sym_clone_symbol_array(state.stGlobal, gp_sym_version_compare_fn);
}
else {
lst = gp_sym_clone_symbol_array(state.stGlobal, gp_sym_compare_fn);
}
assert(lst);
cod_write_symbols(lst, sym_count);
free((void*)lst);
}
/*------------------------------------------------------------------------------------------------*/
void lst_init() {
state.lst.line_of_page = 0;
state.lst.page = 0;
state.lst.lines_per_page = 59;
state.lst.line_number = 1;
state.lst.memory_map = true;
state.lst.symbol_table = true;
state.lst.lst_state = gpasm_state::Lst::LST_IN_MEM;
/* Determine state.start_date. */
gp_date_string(state.lst.start_date, sizeof(state.lst.start_date));
if (!state.cmd_line.macro_expand){
state.lst.expand = true;
}
state.lst.force = state.cmd_line.lst_force;
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. */
state.lst.line_width = 132; /* Default line width is 132. */
if (state.lst_file != OUT_NAMED) {
snprintf(state.lst_file_name, sizeof(state.lst_file_name), "%s.lst", state.base_file_name);
}
if (state.lst_file == OUT_SUPPRESS) {
state.lst.f = NULL;
state.lst.enabled = false;
unlink(state.lst_file_name);
}
else {
state.lst.f = fopen(state.lst_file_name, "wt");
if (state.lst.f == NULL) {
perror(state.lst_file_name);
exit(1);
}
state.lst.enabled = true;
}
cod_lst_line(COD_FIRST_LST_LINE);
}
/*------------------------------------------------------------------------------------------------*/
void lst_close() {
cod_lst_line(COD_LAST_LST_LINE);
state.lst.lst_state = gpasm_state::Lst::LST_IN_NONE;
if (state.lst.f) {
lst_line(NULL);
lst_line("Errors : %5d", state.num.errors);
lst_line("Warnings : %5d reported, %5d suppressed", state.num.warnings, state.num.warnings_suppressed);
lst_line("Messages : %5d reported, %5d suppressed", state.num.messages, state.num.messages_suppressed);
lst_line(NULL);
putc('\f', state.lst.f);
fclose(state.lst.f);
state.lst.f = NULL;
}
}
/*------------------------------------------------------------------------------------------------*/
void
lst_throw(void)
{
if (state.lst.f) {
state.lst.page++;
fprintf(state.lst.f,
"%s%s %*.*s %-28sPAGE %2d\n%s\n%s\n",
(state.lst.page == 1) ? "" : "\f",
GPASM_VERSION_STRING,
(int)(45 - sizeof(GPASM_VERSION_STRING)),
(int)(45 - sizeof(GPASM_VERSION_STRING)),
state.src_file_name,
state.lst.start_date,
state.lst.page,
state.lst.title_name,
state.lst.subtitle_name);
state.lst.line_of_page = 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;
}
}
/*------------------------------------------------------------------------------------------------*/
static void
_mem_header(void)
{
lst_line("LOC OBJECT CODE LINE SOURCE TEXT");
lst_line(" VALUE");
}
/*------------------------------------------------------------------------------------------------*/
static void
_symbol_table_header(void)
{
lst_line("SYMBOL TABLE");
if (!state.mpasm_compatible) {
lst_line("%-32s %-10s %-8s %-11s %s", " LABEL", " TYPE", " VALUE", " VALUE", " VALUE");
lst_line("%-32s %-10s %-8s %-11s %s", "", "", " (hex)", " (dec)", " (text)");
}
else {
lst_line("%-32s %-8s", " LABEL", " VALUE");
}
}
/*------------------------------------------------------------------------------------------------*/
static void _memory_map_header() {
lst_line("MEMORY USAGE MAP ('%c' = Used, '%c' = Unused)", MEM_USED_CHAR, MEM_UNUSED_CHAR);
}
/*------------------------------------------------------------------------------------------------*/
void lst_page_start() {
lst_throw();
switch (state.lst.lst_state) {
case gpasm_state::Lst::LST_IN_MEM:
_mem_header();
break;
case gpasm_state::Lst::LST_IN_SYMTAB:
_symbol_table_header();
break;
case gpasm_state::Lst::LST_IN_MAP:
_memory_map_header();
break;
default:
lst_line(NULL);
break;
}
lst_line(NULL);
}
/*------------------------------------------------------------------------------------------------*/
void _cdecl lst_line(const char *Format, ...) {
va_list args;
if (state.lst.f) {
if (Format) {
_lst_check_page_start();
va_start(args, Format);
vfprintf(state.lst.f, Format, args);
va_end(args);
}
_lst_eol();
}
}
/*------------------------------------------------------------------------------------------------*/
void
lst_err_line(const char *Type, unsigned Code, const char *Format, va_list Args)
{
if (state.lst.f) {
_lst_check_page_start();
fprintf(state.lst.f, "%s[%03d]%s: ", Type, Code, (strcmp(Type, "Error") == 0) ? " " : "");
vfprintf(state.lst.f, Format, Args);
_lst_eol();
}
}
/*------------------------------------------------------------------------------------------------*/
#define MEM_IS_USED(M, I) \
(((M)->memory) ? (IS_BYTE ? (gp_mem_b_offset_is_used(M, I)) : \
(gp_mem_i_offset_is_used_le(M, (I) * 2) == W_USED_ALL)) : false)
#define NUM_PER_LINE 64
#define NUM_PER_BLOCK 16
void
lst_memory_map(MemBlock_t *M)
{
unsigned max_mem;
unsigned base;
unsigned i;
unsigned j;
int addr_digits;
bool row_is_used;
char row_map[NUM_PER_LINE];
char ch;
unsigned used;
state.lst.lst_state = gpasm_state::Lst::LST_IN_MAP;
lst_line(NULL);
lst_line(NULL);
_memory_map_header();
lst_line(NULL);
addr_digits = (state.device.pclass) ? state.device.pclass->addr_digits : 4;
while (M) {
max_mem = I_MEM_MAX >> (uint8_t)!IS_BYTE;
base = IMemAddrFromBase(M->base) >> (uint8_t)!IS_BYTE;
for (i = 0; i < max_mem; i += NUM_PER_LINE) {
row_is_used = false;
for (j = 0; j < NUM_PER_LINE; j++) {
if (MEM_IS_USED(M, i + j)) {
ch = MEM_USED_CHAR;
row_is_used = true;
}
else {
ch = MEM_UNUSED_CHAR;
}
row_map[j] = ch;
}
if (row_is_used) {
if (state.show_full_addr && (IS_PIC16E_CORE)) {
/* Gpasm mode: Print all address digits. */
_lst_printf("%0*X :", addr_digits, (i + base));
}
else {
/* MPASM(X) compatible: Print only lower 4 address digits. */
_lst_printf("%04X :", (i + base) & 0xffff);
}
for (j = 0; j < NUM_PER_LINE; j++) {
if ((j % NUM_PER_BLOCK) == 0) {
_lst_putc(' ');
}
_lst_putc(row_map[j]);
}
_lst_eol();
_lst_check_page_start();
}
}
M = M->next;
}
lst_line(NULL);
lst_line("All other memory blocks unused.");
lst_line(NULL);
/* it seems that MPASM includes config bytes into program memory usage
* count for 16 bit cores. See gpasm testsuite:
* gpasm/testsuite/gpasm.mchip/listfiles/configX.lst */
#define IS_PIC16 (IS_PIC16_CORE) || (IS_PIC16E_CORE)
if (IS_EEPROM) {
lst_line("Memory Bytes Used: %5i", gp_mem_b_used(state.i_memory));
}
else {
used = gp_processor_insn_from_byte_p(state.processor, (!(IS_PIC16) && (state.processor)) ?
b_range_memory_used(state.i_memory, 0,
gp_processor_byte_from_insn_c(state.device.pclass,
state.processor->prog_mem_size)) :
gp_mem_b_used(state.i_memory));
lst_line("Program Memory %s Used: %5i", IS_BYTE ? "Bytes" : "Words", used);
if ((state.processor) && (state.processor->prog_mem_size >= 0)) {
lst_line("Program Memory %s Free: %5u",
IS_BYTE ? "Bytes" : "Words",
((int)used <= state.processor->prog_mem_size) ? (state.processor->prog_mem_size - used) : 0);
}
}
lst_line(NULL);
}
/*------------------------------------------------------------------------------------------------*/
#define ADDR_LEN 7
void
lst_format_line(const char *Src_line, unsigned Value)
{
unsigned emitted;
unsigned emitted_lines;
unsigned byte_addr;
unsigned bytes_emitted;
unsigned lst_bytes;
const char *addr_fmt;
unsigned pos;
uint16_t reloc_type;
MemBlock_t *m;
uint32_t addr;
uint16_t word;
gp_reloc_t *reloc;
assert(Src_line);
emitted = 0;
emitted_lines = 0;
bytes_emitted = 0;
addr_fmt = (IS_PIC16E_CORE) ? "%06X " : (IS_EEPROM ? "%04X " : "%04X ");
pos = 0;
m = state.i_memory;
byte_addr = state.lst.line.was_byte_addr;
if ((state.mode == MODE_RELOCATABLE) && (state.obj.section) &&
(state.obj.new_sect_flags & STYP_TEXT) && (state.obj.section->relocation_list.last)) {
addr = state.obj.section->address + state.obj.section->relocation_list.last->address;
if (addr > byte_addr) {
/* already passed it, go back to the history */
reloc = _find_reloc_by_address(byte_addr);
reloc_type = (reloc) ? reloc->type : 0;
}
else if (addr == byte_addr) {
reloc_type = state.obj.section->relocation_list.last->type;
}
else {
reloc_type = 0;
}
}
else {
reloc_type = 0;
}
switch (state.lst.line.linetype) {
case gpasm_state::Lst::Line::LTY_INSN:
emitted_lines = emitted = state.byte_addr - byte_addr;
break;
case gpasm_state::Lst::Line::LTY_DATA: {
emitted = state.byte_addr - byte_addr;
if ((SECTION_FLAGS & (STYP_TEXT | (state.mpasm_compatible ? STYP_BPACK : 0))) == STYP_TEXT) {
/* generate line numbers for data directives in program memory;
* in mpasm compatibility mode code_pack doesn't generate line numbers */
emitted_lines = emitted;
}
break;
}
case gpasm_state::Lst::Line::LTY_RES: {
if (SECTION_FLAGS & STYP_DATA) {
/* generate data listing for idata */
emitted = state.byte_addr - byte_addr;
}
else if (!IS_RAM_ORG) {
/* generate line numbers for res directives in program memory */
emitted_lines = emitted = state.byte_addr - byte_addr;
}
break;
}
case gpasm_state::Lst::Line::LTY_IDLOCS:
/* always 8 bytes (4 words) */
emitted = 8;
break;
default:
break;
}
coff_add_linenum(emitted_lines);
/* Don't write to file if list is disabled with NOLIST directive */
if (!state.lst.enabled) {
return;
}
byte_addr = 0;
switch (state.lst.line.linetype) {
case gpasm_state::Lst::Line::LTY_EQU:
case gpasm_state::Lst::Line::LTY_SET:
pos += _lst_printf(" %08X", Value);
_lst_spaces(LST_LINENUM_POS - pos);
break;
case gpasm_state::Lst::Line::LTY_SET4:
pos += _lst_printf(" %04X", Value & 0xffff);
_lst_spaces(LST_LINENUM_POS - pos);
break;
case gpasm_state::Lst::Line::LTY_ORG:
pos += _lst_printf(addr_fmt, gp_processor_insn_from_byte_p(state.processor, state.byte_addr));
_lst_spaces(LST_LINENUM_POS - pos);
break;
case gpasm_state::Lst::Line::LTY_IDLOCS:
/* not used for 16 bit devices, config is used */
m = state.c_memory;
pos += _lst_printf(addr_fmt, gp_processor_insn_from_byte_p(state.processor, state.device.id_location));
lst_bytes = _lst_data(pos, m, state.device.id_location, emitted, reloc_type);
byte_addr = state.device.id_location + lst_bytes;
bytes_emitted = emitted - lst_bytes;
break;
case gpasm_state::Lst::Line::LTY_DATA:
case gpasm_state::Lst::Line::LTY_RES:
pos += _lst_printf(addr_fmt, state.lst.line.was_byte_addr);
goto lst_data;
case gpasm_state::Lst::Line::LTY_INSN:
pos += _lst_printf(addr_fmt, gp_processor_insn_from_byte_p(state.processor, state.lst.line.was_byte_addr));
lst_data:
lst_bytes = _lst_data(pos, m, state.lst.line.was_byte_addr, emitted, reloc_type);
byte_addr = state.lst.line.was_byte_addr + lst_bytes;
bytes_emitted = emitted - lst_bytes;
break;
case gpasm_state::Lst::Line::LTY_CONFIG: {
if (IS_PIC16E_CORE) {
/* The config data is byte addressable, but we only want to print words in the list file. */
if (state.lst.config_address == CONFIG4L) {
/* Special case */
state.device.pclass->i_memory_get(state.c_memory, state.lst.config_address, &word, NULL, NULL);
pos += _lst_printf(addr_fmt, state.lst.config_address);
pos += _lst_printf("%04X", word);
_lst_spaces(LST_LINENUM_POS - pos);
}
else if ((state.lst.config_address & 1) == 0) {
/* if it is an even address don't print anything */
_lst_spaces(LST_LINENUM_POS);
}
else {
state.device.pclass->i_memory_get(state.c_memory, state.lst.config_address - 1, &word, NULL, NULL);
pos += _lst_printf(addr_fmt, state.lst.config_address - 1);
pos += _lst_printf("%04X", word);
_lst_spaces(LST_LINENUM_POS - pos);
}
}
else {
state.device.pclass->i_memory_get(state.c_memory, state.lst.config_address, &word, NULL, NULL);
pos += _lst_printf(addr_fmt, gp_processor_insn_from_byte_p(state.processor, state.lst.config_address));
pos += _lst_printf("%04X", word);
_lst_spaces(LST_LINENUM_POS - pos);
}
break;
}
case gpasm_state::Lst::Line::LTY_SEC:
case gpasm_state::Lst::Line::LTY_DIR:
case gpasm_state::Lst::Line::LTY_NONE:
default:
_lst_spaces(LST_LINENUM_POS);
break;
}
if (state.stGlobal == state.stTop) {
_lst_printf("%05d ", state.src_list.last->line_number);
}
else {
_lst_printf(" M ");
}
/* Now copy source line to listing, expanding tabs as required. */
{
int src_column = 0; /* current source line column */
int lst_column = LST_SRC_POS; /* current listing column after the SRC_POS */
const char *p = Src_line;
while (*p != '\0') {
if (*p == '\t') {
int len = state.lst.tabstop - (src_column % state.lst.tabstop);
while (len-- > 0) {
if (lst_column >= state.lst.line_width) {
_lst_eol();
_lst_spaces(LST_SRC_POS);
lst_column = LST_SRC_POS;
}
++lst_column;
++src_column;
putc(' ', state.lst.f);
}
}
else {
if (lst_column >= state.lst.line_width) {
_lst_eol();
_lst_spaces(LST_SRC_POS);
lst_column = LST_SRC_POS;
}
++lst_column;
++src_column;
putc(*p, state.lst.f);
}
++p;
}
}
/* Tell the .cod file that the next line(s) has an opcode(s) */
state.cod.emitting = emitted;
_lst_eol();
if (bytes_emitted > 0) {
while (bytes_emitted > 0) {
/* data left to print on separate lines */
pos = _lst_spaces(ADDR_LEN);
lst_bytes = _lst_data(pos, m, byte_addr, bytes_emitted, reloc_type);
byte_addr += lst_bytes;
bytes_emitted -= lst_bytes;
_lst_eol();
}
state.cod.emitting = 0;
}
}
/*------------------------------------------------------------------------------------------------*/
static int _cdecl _lst_symbol_verscmp(const void *P0, const void *P1) {
return strverscmp(gp_sym_get_symbol_name(((const lst_symbol_t *)P0)->sym),
gp_sym_get_symbol_name(((const lst_symbol_t *)P1)->sym));
}
/*------------------------------------------------------------------------------------------------*/
static int _cdecl _lst_symbol_cmp(const void *P0, const void *P1) {
return strcmp(gp_sym_get_symbol_name(((const lst_symbol_t *)P0)->sym),
gp_sym_get_symbol_name(((const lst_symbol_t *)P1)->sym));
}
/*------------------------------------------------------------------------------------------------*/
/* append the symbol table to the .lst file */
void lst_symbol_table(void) {
const pnode_t *list;
const pnode_t *head;
const char *string;
const symbol_t **clone;
size_t sym_count;
lst_symbol_t *lst;
lst_symbol_t *ps;
size_t count;
size_t i;
const char *name;
const void *ptr;
const variable_t *var;
numstring_t num_type;
long val;
const macro_head_t *hd;
char *mac_parms;
size_t mac_parm_length;
state.lst.lst_state = gpasm_state::Lst::LST_IN_SYMTAB;
_symbol_table_header();
lst_line(NULL);
_cod_symbol_table();
count = gp_sym_get_symbol_count(state.stGlobal) + gp_sym_get_symbol_count(state.stDefines) +
gp_sym_get_symbol_count(state.stMacros);
if (count == 0) {
return;
}
ps = lst = new lst_symbol_t[count];
clone = gp_sym_clone_symbol_array(state.stGlobal, NULL);
if (clone) {
sym_count = gp_sym_get_symbol_count(state.stGlobal);
for (i = 0; i < sym_count; i++) {
ps->sym = clone[i];
ps->type = lst_symbol_t::LST_SYMBOL;
++ps;
}
free((void*)clone);
}
clone = gp_sym_clone_symbol_array(state.stDefines, NULL);
if (clone) {
sym_count = gp_sym_get_symbol_count(state.stDefines);
for (i = 0; i < sym_count; i++) {
ps->sym = clone[i];
ps->type = lst_symbol_t::LST_DEFINITION;
++ps;
}
free((void*)clone);
}
clone = gp_sym_clone_symbol_array(state.stMacros, NULL);
if (clone) {
sym_count = gp_sym_get_symbol_count(state.stMacros);
for (i = 0; i < sym_count; i++) {
ps->sym = clone[i];
ps->type = lst_symbol_t::LST_MACRO;
++ps;
}
free((void*)clone);
}
assert(ps == &lst[count]);
if (!state.mpasm_compatible) {
qsort(lst, count, sizeof(lst_symbol_t), _lst_symbol_verscmp);
}
else {
qsort(lst, count, sizeof(lst_symbol_t), _lst_symbol_cmp);
}
for (i = 0; i < count; i++) {
name = gp_sym_get_symbol_name(lst[i].sym);
ptr = gp_sym_get_symbol_annotation(lst[i].sym);
switch (lst[i].type) {
case lst_symbol_t::LST_SYMBOL: {
/* symbol */
var = (const variable_t *)ptr;
if (!state.mpasm_compatible) {
if (var) {
if (FlagIsClr(var->flags, VATRR_HAS_NO_VALUE)) {
lst_line("%-32s %-10s %08X %11d", name, value_type_to_str(var, false), var->value, var->value);
}
else {
lst_line("%-32s %-10s %8s %-11s", name, value_type_to_str(var, false), "HAS NO", "HAS NO");
}
}
else {
lst_line("%-32s", name);
}
}
else {
lst_line("%-32s %08X", name, (var) ? var->value : 0);
}
break;
}
case lst_symbol_t::LST_DEFINITION: {
/* define */
list = (const pnode_t *)ptr;
if (list) {
assert(PnIsList(list));
head = PnListHead(list);
assert(PnIsString(head));
string = PnString(head);
}
else {
string = NULL;
}
if (!state.mpasm_compatible) {
if (string) {
val = gp_strtol(string, &num_type);
if (num_type) {
/* This definition contains is just a decimal number. */
lst_line("%-32s %-10s %08lX %11ld %s", name, "DEFINITION", val, val, string);
}
else {
/* This definition contains a general text (not just number). */
lst_line("%-32s %-10s %8s %11s %s", name, "DEFINITION", "", "", string);
}
}
else {
lst_line("%-32s %-10s", name, "DEFINITION");
}
} /* if (!state.mpasm_compatible) */
else {
lst_line("%-32s %s", name, (string) ? string : "");
}
break;
}
case lst_symbol_t::LST_MACRO: {
/* define */
if (!state.mpasm_compatible) {
hd = (const macro_head_t *)ptr;
if (hd) {
mac_parm_length = 0;
mac_parms = macro_params_to_string(NULL, MAC_PARM_STR_MAX_LENGTH, &mac_parm_length, hd->parms);
if (mac_parms) {
if (mac_parm_length > 0) {
lst_line("%-32s %-10s %8s %11s %s", name, "MACRO", "", "", mac_parms);
}
else {
lst_line("%-32s %-10s", name, "MACRO");
}
free(mac_parms);
}
else {
lst_line("%-32s %-10s", name, "MACRO");
}
}
else {
lst_line("%-32s %-10s", name, "MACRO");
}
}
else {
lst_line("%-32s", name);
}
break;
}
}
}
free(lst);
}
/*------------------------------------------------------------------------------------------------*/
/*
* Preprocessed file generator.
*/
void
preproc_init(void)
{
const char *name;
name = state.preproc.preproc_file_name;
if (name) {
if ((name[0] == '-') && (name[1] == '\0')) {
state.preproc.f = stdout;
}
else if ((state.preproc.f = fopen(name, "wt")) == NULL) {
perror(name);
exit(1);
}
}
}
/*------------------------------------------------------------------------------------------------*/
void
preproc_emit(void)
{
if (state.preproc.f) {
if (state.preproc.do_emit && asm_enabled()) {
fprintf(state.preproc.f, "%s\n", state.preproc.curr_src_line.line);
}
else {
state.preproc.do_emit = true;
}
}
}
Detected encoding: UTF-8 | 0
|