Source file: /~heha/hs/gputils64-210929.zip/libgputils/gpcod.cpp

/* .cod file support
   Copyright 2003-2005	Craig Franklin
   Copyright 2012	Borut Ražem
   Copyright 2015-2016	Molnár Károly
*/

#include "stdhdr.h"
#include "libgputils.h"

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

static void _cod_time(uint8_t *Buffer, size_t Sizeof_buffer) {
  time_t        now;
  struct tm    *local;
  unsigned  value;

  time(&now);
  local = localtime(&now);
  value = (local->tm_hour * 100) + local->tm_min;
  gp_putl16(Buffer, value);
  /* No space for the seconds. */
}

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

static void _cod_Pdate(uint8_t* Pascal_str, size_t Pascal_max_size) {
  static const char m_day_names[] = 
    "Jan\0Feb\0Mar\0Apr\0May\0Jun\0Jul\0Aug\0Sep\0Oct\0Nov\0Dec";

  time_t     now;
  struct tm* t;
  char       temp[16];
  int        length;

  time(&now);
  t = localtime(&now);
  length = snprintf(temp, sizeof temp,
	"%02d%s%02d", t->tm_mday, m_day_names+(t->tm_mon<<2), t->tm_year % 100);
  assert(length < (int)Pascal_max_size);

  *Pascal_str++ = (uint8_t)length;
  memcpy(Pascal_str, temp, length);
}

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

void gp_cod_create(Block *B) {
  assert(B);
  B->block = new uint8_t[COD_BLOCK_SIZE];
  memset(B->block,0,COD_BLOCK_SIZE);
}

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

FUNC(DirBlockInfo*) gp_cod_new_dir_block() {
  /* initialize eveything to zero */
  DirBlockInfo*dir = new DirBlockInfo;
  memset(dir,0,sizeof*dir);
  gp_putl16(&dir->dir[COD_DIR_CODTYPE], 1);
  return dir;
}

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

FUNC(DirBlockInfo*) gp_cod_init_dir_block(const char *File_name, const char *Compiler) {
  DirBlockInfo*dir = gp_cod_new_dir_block();
  uint8_t*block = dir->dir;
  // Initialize the directory block with known data.
  // It will be written to the .cod file after everything else.
  gp_Pstr_from_str(&block[COD_DIR_SOURCE],   COD_DIR_SOURCE_SIZE,   File_name, NULL);
  _cod_Pdate      (&block[COD_DIR_DATE],     COD_DIR_DATE_SIZE);
  _cod_time       (&block[COD_DIR_TIME],     COD_DIR_TIME_SIZE);
  gp_Pstr_from_str(&block[COD_DIR_VERSION],  COD_DIR_VERSION_SIZE,  VERSION, NULL);
  gp_Pstr_from_str(&block[COD_DIR_COMPILER], COD_DIR_COMPILER_SIZE, Compiler, NULL);
  gp_Pstr_from_str(&block[COD_DIR_NOTICE],   COD_DIR_NOTICE_SIZE,   GPUTILS_COPYRIGHT_STRING, NULL);

  /* The address is always two shorts or 4 bytes long. */
  block[COD_DIR_ADDRSIZE] = 0;

  return dir;
}

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

FUNC(DirBlockInfo*) gp_cod_find_dir_block_by_high_addr(DirBlockInfo *Main, unsigned High_addr) {
  DirBlockInfo*dbi = Main;
  /* find the directory containing high_addr 64k segment */
  while (gp_getl16(&dbi->dir[COD_DIR_HIGHADDR]) != (int)High_addr) {
    /* If the next directory block (in the linked list of directory
       blocks) is NULL, then this is the first time to encounter this
       _64k segment. So we need to create a pnew segment. */
    if (!dbi->next) {
      dbi->next = gp_cod_new_dir_block();
      gp_putl16(&dbi->next->dir[COD_DIR_HIGHADDR], High_addr);
      dbi = dbi->next;
      break;
    }else dbi = dbi->next;
  }
  return dbi;
}

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

/* gp_cod_emit_opcode - write one opcode to a cod_image_block */

FUNC(void) gp_cod_emit_opcode(DirBlockInfo *Dbi, unsigned Address, unsigned Opcode) {

  /* The code image blocks are handled in a different manner than the
   * other cod blocks. In theory, it's possible to emit opcodes in a
   * non-sequential manner. Furthermore, it's possible that there may
   * be gaps in the program memory. These cases are handled by an array
   * of code blocks. The lower 8 bits of the opcode's address form an
   * index into the code block, while bits 9-15 are an index into the
   * array of code blocks. The code image blocks are not written until
   * all of the opcodes have been emitted.
   */

  unsigned block_index = (Address >> COD_BLOCK_BITS) & (COD_CODE_IMAGE_BLOCKS - 1);

  if (Dbi->cod_image_blocks[block_index].block == NULL) {
    gp_cod_create(&Dbi->cod_image_blocks[block_index]);
  }

  gp_putl16(&Dbi->cod_image_blocks[block_index].block[Address & (COD_BLOCK_SIZE - 1)], Opcode);
}

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

/* gp_cod_write_code - write all of the assembled pic code to the .cod file */

FUNC(void) gp_cod_write_code(proc_class_t Class, const MemBlock_t *Mem, DirBlockInfo *Main) {
  int               i;
  BlockList        *rb;
  uint16_t          insn;
  uint8_t          *record;

  int start_address = 0;
  bool used_flag    = false;
  DirBlockInfo*dbi  = 0;
  int _64k_base     = 0;
  const MemBlock_t*m= Mem;

  while (m) {
    int mem_base  = IMemAddrFromBase(m->base);
    int high_addr = IMemBaseFromAddr(mem_base);

    if (!dbi || high_addr != _64k_base) {
      _64k_base = high_addr;
      dbi       = gp_cod_find_dir_block_by_high_addr(Main, _64k_base);
    }

    for (i = mem_base; i - mem_base <= I_MEM_MAX; i += 2) {
      if (((i - mem_base) < I_MEM_MAX) &&
          (Class->i_memory_get(Mem, i, &insn, NULL, NULL))) {
        gp_cod_emit_opcode(dbi, i, insn);

        if (!used_flag) {
          /* Save the start address in a range of opcodes */
          start_address = i;
          used_flag     = true;
        }
      }else{
        /* No code at address i, but we need to check if this is the
           first empty address after a range of address. */
        if (used_flag) {
          rb = gp_cod_block_get_last_or_new(&dbi->range);

          if (!rb || dbi->range.offset + COD_MAPENTRY_SIZE >= COD_BLOCK_SIZE) {
            /* If there are a whole bunch of non-contiguous pieces of
               code then we'll get here. But most pic apps will only need
               one directory block (that will give you 64 ranges or non-
               contiguous chunks of pic code). */
            rb = gp_cod_block_append(&dbi->range, gp_cod_block_new());
          }
          /* We need to update dir map indicating a range of memory that is needed.
             This is done by writing the start and end address to the directory map. */
          record = &rb->block[dbi->range.offset];
// Murks: Beide Zahlen laufen über die 16-Bit-Grenze!
          gp_putl16(&record[COD_MAPTAB_START], (uint16_t)start_address);
          gp_putl16(&record[COD_MAPTAB_LAST], (uint16_t)(i-1));

          used_flag = false;

          dbi->range.offset += COD_MAPENTRY_SIZE;
        }
      }
    }
    m = m->next;
  }
}

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

FUNC(size_t) gp_cod_put_long_symbol(uint8_t *Record, const char *Name, gp_symvalue_t Value, unsigned Type) {
  size_t length;

  assert(Record);

  length = gp_Pstr_from_str(&Record[COD_LSYMBOL_NAME], COD_LSYMBOL_NAME_MAX_SIZE, Name, NULL);
  gp_putl16(&Record[length + COD_LSYMBOL_TYPE], Type);
  /* write 32 bits, big endian */
  gp_putb32(&Record[length + COD_LSYMBOL_VALUE], Value);
  return (length + COD_LSYMBOL_EXTRA);
}

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

FUNC(size_t) gp_cod_put_debug_symbol(uint8_t *Record, const char *String, gp_symvalue_t Value, char Command) {
  assert(Record);

  /* write 32 bits, big endian */
  gp_putb32(&Record[COD_DEBUG_ADDR], Value);
  Record[COD_DEBUG_CMD] = Command;
  return (gp_Pstr_from_str(&Record[COD_DEBUG_MSG], COD_DEBUG_MSG_MAX_SIZE, String, NULL) + COD_DEBUG_EXTRA);
}

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

FUNC(size_t) gp_cod_put_line_number(uint8_t *Record, unsigned File_id, unsigned Line_number,
                       unsigned Address, unsigned Flag) {
  assert(Record);

  Record[COD_LS_SFILE] = File_id;
  Record[COD_LS_SMOD]  = Flag;

  /* Write the source file line number corresponding to the list file line number (only lower 16 bits). */
  gp_putl16(&Record[COD_LS_SLINE], (uint16_t)Line_number);

  /* Write the address of the opcode (only lower 16 bits). */
  gp_putl16(&Record[COD_LS_SLOC], (uint16_t)Address);
  return COD_LINE_SYM_SIZE;
}

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

FUNC(BlockList*) gp_cod_block_new(void) {
  BlockList*bl = new BlockList;
  memset(bl,0,sizeof*bl);
  return bl;
}

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

FUNC(BlockList*) gp_cod_block_append(Blocks *Bl, BlockList *B)
{
  if (Bl->first == NULL) {
    Bl->first = B;
    Bl->count = 1;
  }
  else {
    Bl->last->next = B;
    (Bl->count)++;
  }

  Bl->last   = B;
  Bl->offset = 0;
  return B;
}

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

FUNC(BlockList*) gp_cod_block_get_last(Blocks *Bl) {
  return Bl->last;
}

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

FUNC(BlockList*) gp_cod_block_get_last_or_new(Blocks *Bl) {
  if (Bl->first) {
    return gp_cod_block_get_last(Bl);
  }
  else {
    Bl->first  = gp_cod_block_new();
    Bl->last   = Bl->first;
    Bl->offset = 0;
    Bl->count  = 1;
    return Bl->first;
  }
}

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

FUNC(int) gp_cod_block_count(const Blocks *Bl) {
  return Bl->first ? Bl->count : 0;
}

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

FUNC(void) gp_cod_block_enumerate(DirBlockInfo *Dir, unsigned Offset, Blocks *Bl, unsigned *Block_num) {
  if (Bl->first) {
    /* enumerate block list */
    gp_putl16(&Dir->dir[Offset], ++(*Block_num));
    *Block_num += gp_cod_block_count(Bl) - 1;
    gp_putl16(&Dir->dir[Offset + 2], *Block_num);
  }
}

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

FUNC(void) gp_cod_enumerate_directory(DirBlockInfo *Main_dir) {
  DirBlockInfo *dbi;
  unsigned  block_num;
  unsigned  i;

  block_num = 0;

  /* enumerate directory blocks */
  for (dbi = Main_dir; dbi != NULL; dbi = dbi->next) {
    gp_putl16(&dbi->dir[COD_DIR_NEXTDIR], (dbi->next) ? ++block_num : 0);
  }

  /* enumerate code blocks */
  for (dbi = Main_dir; dbi != NULL; dbi = dbi->next) {
    for (i = 0; i < COD_CODE_IMAGE_BLOCKS; ++i) {
      if (dbi->cod_image_blocks[i].block) {
        gp_putl16(&dbi->dir[i * 2], ++block_num);
      }
    }
  }

  /* enumerate surce files blocks */
  for (dbi = Main_dir; dbi != NULL; dbi = dbi->next) {
    gp_cod_block_enumerate(dbi, COD_DIR_NAMTAB, &dbi->file, &block_num);
  }

  /* enumerate list lines blocks */
  for (dbi = Main_dir; dbi != NULL; dbi = dbi->next) {
    gp_cod_block_enumerate(dbi, COD_DIR_LSTTAB, &dbi->list, &block_num);
  }

  /* enumerate memory map blocks */
  for (dbi = Main_dir; dbi != NULL; dbi = dbi->next) {
    gp_cod_block_enumerate(dbi, COD_DIR_MEMMAP, &dbi->range, &block_num);
  }

  /* enumerate long symbol table blocks */
  for (dbi = Main_dir; dbi != NULL; dbi = dbi->next) {
    gp_cod_block_enumerate(dbi, COD_DIR_LSYMTAB, &dbi->lsym, &block_num);
  }

  /* enumerate debug messages table blocks */
  for (dbi = Main_dir; dbi != NULL; dbi = dbi->next) {
    gp_cod_block_enumerate(dbi, COD_DIR_MESSTAB, &dbi->debug, &block_num);
  }
}

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

FUNC(void) gp_cod_block_write(FILE *F, const Blocks *Bl) {
  const BlockList *curr;

  curr = Bl->first;
  /* write block list */
  while (curr) {
    if (fwrite(curr->block, 1, COD_BLOCK_SIZE, F) != COD_BLOCK_SIZE) {
      fprintf(stderr, "%s() -- Could not write cod file.\n", "gp_cod_block_write");
      exit(1);
    }
    curr = curr->next;
  }
}

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

FUNC(void) gp_cod_write_directory(FILE *F, const DirBlockInfo *Main_dir) {
  const DirBlockInfo *dbi;
  unsigned        i;

  /* write directory blocks */
  for (dbi = Main_dir; dbi != NULL; dbi = dbi->next) {
    if (fwrite(dbi->dir, 1, COD_BLOCK_SIZE, F) != COD_BLOCK_SIZE) {
      fprintf(stderr, "%s() -- Could not write cod file.\n", "gp_cod_write_directory");
      exit(1);
    }
  }

  /* write code blocks */
  for (dbi = Main_dir; dbi != NULL; dbi = dbi->next) {
    for (i = 0; i < COD_CODE_IMAGE_BLOCKS; ++i) {
      if (dbi->cod_image_blocks[i].block) {
        if (fwrite(dbi->cod_image_blocks[i].block, 1, COD_BLOCK_SIZE, F) != COD_BLOCK_SIZE) {
          fprintf(stderr, "%s() -- Could not write cod file.\n", "gp_cod_write_directory");
          exit(1);
        }
      }
    }
  }

  /* write source files blocks */
  for (dbi = Main_dir; dbi != NULL; dbi = dbi->next) {
    gp_cod_block_write(F, &dbi->file);
  }

  /* write list lines blocks */
  for (dbi = Main_dir; dbi != NULL; dbi = dbi->next) {
    gp_cod_block_write(F, &dbi->list);
  }

  /* write memory map blocks */
  for (dbi = Main_dir; dbi != NULL; dbi = dbi->next) {
    gp_cod_block_write(F, &dbi->range);
  }

  /* write long symbol table blocks */
  for (dbi = Main_dir; dbi != NULL; dbi = dbi->next) {
    gp_cod_block_write(F, &dbi->lsym);
  }

  /* write debug messages table blocks */
  for (dbi = Main_dir; dbi != NULL; dbi = dbi->next) {
    gp_cod_block_write(F, &dbi->debug);
  }
}

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

FUNC(void) gp_cod_block_free(Blocks *Bl) {
  BlockList *curr;
  BlockList *next;

  curr = Bl->first;
  while (curr) {
    next = curr->next;
    free(curr);
    curr = next;
  }

  Bl->first  = NULL;
  Bl->last   = NULL;
  Bl->offset = 0;
  Bl->count  = 0;
}

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

FUNC(void) gp_cod_free_directory(DirBlockInfo *Main_dir) {
  DirBlockInfo *dbi;
  DirBlockInfo *next;
  unsigned  i;

  dbi = Main_dir;
  while (dbi) {
    /* free code blocks */
    for (i = 0; i < COD_CODE_IMAGE_BLOCKS; ++i) {
      if (dbi->cod_image_blocks[i].block) {
        free(dbi->cod_image_blocks[i].block);
      }
    }

    /* free surce files blocks */
    gp_cod_block_free(&dbi->file);

    /* free list lines blocks */
    gp_cod_block_free(&dbi->list);

    /* free memory map blocks */
    gp_cod_block_free(&dbi->range);

    /* free long symbol table blocks */
    gp_cod_block_free(&dbi->lsym);

    /* free debug messages table blocks */
    gp_cod_block_free(&dbi->debug);

    next = dbi->next;
    /* free directory blocks */
    free(dbi);
    dbi = next;
  }
}
Detected encoding: UTF-80