/* .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;
}
}
Vorgefundene Kodierung: UTF-8 | 0
|