Quelltext /~heha/hs/gputils64-210929.zip/gpasm/cod.cpp

/* ".COD" file output for gpasm
   Copyright 1998-2005	James Bowman, Scott Dattalo
   Copyright 2012	Borut Ražem
   Copyright 2016	Molnár Károly
*/

#include "stdhdr.h"

#include "libgputils.h"
#include "gpasm.h"
#include "gpmsg.h"
#include "lst.h"
#include "cod.h"

#define COD_FILE_MAX_NUM            1000

static DirBlockInfo *main_dir  = NULL;
static DirBlockInfo *dbi       = NULL;
static unsigned  _64k_base = 0;

/*------------------------------------------------------------------------------------------------*/

/*
 * _write_file_block - Write a code block that contains a list of the source files.
 */

static void _write_source_file_block(void) {
  const file_context_t *fc;
  BlockList            *fb;
  unsigned          length;
  bool            truncated;

  if (state.file_list.first == NULL) {
    return;
  }

  if (state.file_list.num_nodes >= COD_FILE_MAX_NUM) {
    /* Too many files to handle in the .cod file. */
    assert(0);
  }

  fb = NULL;
  fc = state.file_list.first;
  while (fc) {
    if ((fb == NULL) || (main_dir->file.offset >= (COD_FILE_NAMES_PER_BLOCK * COD_FILE_NAME_SIZE))) {
      fb = gp_cod_block_append(&main_dir->file, gp_cod_block_new());
    }

    /* The file id is used to define the index at which the file name is written within
     * the file code block. (The id's are sequentially assigned when the files are opened.)
     * If there are too many files, then gpasm will abort. Note: .cod files can handle
     * larger file lists...
     */

    length = gp_Pstr_from_str(&fb->block[main_dir->file.offset], COD_FILE_NAME_SIZE, fc->name, &truncated);

    if (truncated && (state.strict_level > 0)) {
      gpmsg(GPW_STRING_TRUNCATE, "(.COD)", fc->name, length);
    }

    main_dir->file.offset += COD_FILE_NAME_SIZE;

    fc = fc->next;
  }
}

/*------------------------------------------------------------------------------------------------*/

/* cod_init - Initialize the .cod file. */

void
cod_init(void)
{
  if (state.cod_file != OUT_NAMED) {
    snprintf(state.cod_file_name, sizeof(state.cod_file_name), "%s.cod", state.base_file_name);
  }

  if (state.cod_file == OUT_SUPPRESS) {
    state.cod.f       = NULL;
    state.cod.enabled = false;
    unlink(state.cod_file_name);
  }
  else {
    state.cod.f = fopen(state.cod_file_name, "wb");
    if (state.cod.f == NULL) {
      perror(state.cod_file_name);
      exit(1);
    }
    state.cod.enabled = true;
  }

  if (!state.cod.enabled) {
    main_dir = NULL;
    return;
  }

  main_dir  = gp_cod_init_dir_block(state.cod_file_name, "gpasm");
  dbi       = NULL;
  _64k_base = 0;
}

/*------------------------------------------------------------------------------------------------*/

/* cod_lst_line - Add a line of information that cross references the
 *                the opcode's address, the source file, and the list file.
 */

#define COD_LST_FIRST_LINE              7

void
cod_lst_line(unsigned List_line)
{
  source_context_t *ctx;
  uint8_t           smod_flag;
  BlockList        *lb;
  bool        first_time;
  unsigned      address;
  unsigned      high_address;

  if (!state.cod.enabled) {
    return;
  }

  ctx = state.src_list.last;

  /* Don't start until after the source is open. */
  if (ctx == NULL) {
    return;
  }

  /* Ignore the first few line numbers. */
/*  if (state.lst.line_number < COD_LST_FIRST_LINE) {*/
  if (state.lst.line_number < List_line) {
    return;
  }

  address      = gp_processor_insn_from_byte_c(state.device.pclass, state.lst.line.was_byte_addr);
  high_address = IMemBaseFromAddr(address);

  if ((dbi == NULL) || (high_address != _64k_base)) {
    _64k_base = high_address;
    dbi       = gp_cod_find_dir_block_by_high_addr(main_dir, _64k_base);
  }

  first_time = (gp_cod_block_get_last(&dbi->list) == NULL) ? true : false;

  lb = gp_cod_block_get_last_or_new(&dbi->list);

  if (dbi->list.offset >= (COD_MAX_LINE_SYM * COD_LINE_SYM_SIZE)) {
    lb = gp_cod_block_append(&dbi->list, gp_cod_block_new());
  }

  assert(ctx->fc);

  smod_flag = (uint8_t)(first_time
   ? COD_LS_SMOD_FLAG_ALL
   : state.cod.emitting
   ? COD_LS_SMOD_FLAG_C1
   : COD_LS_SMOD_FLAG_C1 | COD_LS_SMOD_FLAG_D);

  dbi->list.offset += gp_cod_put_line_number(&lb->block[dbi->list.offset], ctx->fc->id, ctx->line_number,
                                             address, smod_flag);
}

/*------------------------------------------------------------------------------------------------*/

/* cod_write_symbols - Write the symbol table to the .cod file.
 *
 * This routine will read the symbol table that gpasm has created and convert it into
 * a format suitable for .cod files. So far, only three variable types are supported:
 * address, register and constants
 *
 */

void
cod_write_symbols(const symbol_t **Symbol_list, size_t Num_symbols)
{
  size_t            i;
  unsigned      length;
  unsigned      type;
  const variable_t *var;
  const char       *name;
  BlockList        *sb;
  bool        truncated;

  if ((Symbol_list == NULL) || (Num_symbols == 0)) {
    return;
  }

  if (!state.cod.enabled) {
    return;
  }

  sb = NULL;
  for (i = 0; i < Num_symbols; i++) {
    name = gp_sym_get_symbol_name(Symbol_list[i]);
    var  = (const variable_t *)gp_sym_get_symbol_annotation(Symbol_list[i]);
    assert(var);

    if (FlagIsSet(var->flags, VATRR_HAS_NO_VALUE)) {
      msg_has_no_value("(.COD)", name);
    }

    length = gp_strlen_Plimit(name, COD_LSYMBOL_NAME_MAX_SIZE, &truncated);

    if (truncated && (state.strict_level > 0)) {
      /* This symbol name is too long. */
      gpmsg(GPW_STRING_TRUNCATE, "(.COD)", name, length);
    }

    /* If this symbol extends past the end of the cod block then write this block out. */

    if ((sb == NULL) || ((main_dir->lsym.offset + length + COD_LSYMBOL_EXTRA) >= COD_BLOCK_SIZE)) {
      sb = gp_cod_block_append(&main_dir->lsym, gp_cod_block_new());
    }

    switch (var->type) {
      case VAL_CBLOCK:
        type = COD_ST_C_SHORT;  /* Byte Craft's nomenclature for a memory byte. */
        break;

      case VAL_ADDRESS:
        type = COD_ST_ADDRESS;
        break;

      case VAL_CONSTANT:
      case VAL_VARIABLE:
      default:
        type = COD_ST_CONSTANT;
    }

    main_dir->lsym.offset += gp_cod_put_long_symbol(&sb->block[main_dir->lsym.offset], name, var->value, type);
  }
}

/*------------------------------------------------------------------------------------------------*/

void
cod_close_file(void)
{
  unsigned  length;
  bool    truncated;
  const char   *name;

  if (!state.cod.enabled) {
    return;
  }

  name = gp_processor_name(state.processor, 2);
  /* The processor is unknown if not defined in command line at cod_init() call
     so it should be set here. */
  length = gp_Pstr_from_str(&main_dir->dir[COD_DIR_PROCESSOR], COD_DIR_PROCESSOR_SIZE, name, &truncated);

  if (truncated && (state.strict_level > 0)) {
    gpmsg(GPW_STRING_TRUNCATE, "(.COD)", name, length);
  }

  _write_source_file_block();
  gp_cod_write_code(state.device.pclass, state.i_memory, main_dir);
  gp_cod_enumerate_directory(main_dir);
  gp_cod_write_directory(state.cod.f, main_dir);
  gp_cod_free_directory(main_dir);
  fclose(state.cod.f);

  main_dir  = NULL;
  dbi       = NULL;
  _64k_base = 0;
}
Vorgefundene Kodierung: UTF-80