/* -*- Mode: C++; c-file-style: "GNU"; comment-column: 40 -*- */
/*
Copyright (C) 1998,1999 T. Scott Dattalo
This file is part of gpsim.read_message_area
gpsim 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.
gpsim 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 gpsim; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
//
// cod.cc
//
// The file contains the code for reading Byte Craft's .cod
// formatted symbol files.
//
#include <stdio.h>
#include <iostream>
#include <string>
#include <string.h>
#include <assert.h>
#include <memory.h>
#ifdef _WIN32
#include <direct.h>
#endif
#include "exports.h"
#include "gpsim_def.h"
#include "sim_context.h"
#include "pic-processor.h"
#include "picdis.h"
#include "symbol.h"
#include "cod.h"
#include "interface.h"
#include "fopen-path.h"
#include "breakpoints.h"
/* experiment with assertions */
#include "cmd_manager.h"
/* end of assertion experiment */
PicCodProgramFileType::PicCodProgramFileType() {
codefile = 0;
temp_block = 0;
lstfilename = 0;
memset(&main_dir, 0, sizeof(main_dir));
// Define a flag that tells whether or not we should care about the
// case of text strings in the .cod file.
ignore_case_in_cod = 1;
gputils_recent = 0;
RegisterProgramFileType(this);
}
int PicCodProgramFileType::get_string(char *dest, char *src, size_t len)
{
size_t n = *src++;
if(n < len) {
n = min(n, len - 1);
strncpy(dest, src, n);
dest[n] = '\0';
return SUCCESS;
}
return ERR_BAD_FILE;
}
// Capitalize a string (there must be a library function that does this!
void strtoupper(char *s)
{
if(!s)
return;
while(*s)
{
*s = toupper(*s);
s++;
}
}
void strtolower(char *s)
{
if(!s)
return;
char *t = s;
if(verbose)
cout << "tolower " << s;
while(*s)
{
*s = tolower(*s);
s++;
}
if(verbose)
cout << "after " << t <<'\n';
}
unsigned short get_short_int( char * buff)
{
return ( (unsigned char)buff[0] + ((unsigned char)buff[1] << 8));
}
void PicCodProgramFileType::read_block(char * block, int block_number)
{
fseek(codefile, block_number * COD_BLOCK_SIZE, SEEK_SET);
fread(block, COD_BLOCK_SIZE, 1, codefile);
}
unsigned int get_be_int( char * buff)
{
return ( (unsigned char)buff[3] + ((unsigned char)buff[2] << 8) +
((unsigned char)buff[1] << 16) + ((unsigned char)buff[0] << 24));
}
//-----------------------------------------------------------
// cod_address_in_range - check to see if an address falls into
// one of the valid code areas. A code area is define by a start
// address and an end address. If the address is in a valid area
// then a '1' is returned.
//
int cod_address_in_range(char *range_block,int address)
{
int i =0;
int start,end;
do
{
// get the start and end addresses of this range
start = get_short_int(&range_block[i])/2;
i+=2;
end = get_short_int(&range_block[i])/2;
i+=2;
if((address>=start) && (address<=end))
return 1; // in range
// The end address can be zero on only the first
// start/end pair.
if((end == 0) && (i>4))
return 0;
}
while(i<COD_BLOCK_SIZE);
return 0;
}
//-----------------------------------------------------------
// read_hex_from_cod - this routine will get the opcodes from
// the .cod file and intialize the pic program memory with them.
//
void PicCodProgramFileType::read_hex_from_cod( Processor *cpu )
{
int _64k_base;
int safety = 0;
int i,j,index;
char range_block[COD_BLOCK_SIZE];
DirBlockInfo *dbi;
dbi = &main_dir;
do {
i = get_short_int(&dbi->dir.block[COD_DIR_MEMMAP]);
j = get_short_int(&dbi->dir.block[COD_DIR_MEMMAP+2]);
if( (i!=j) || (i==0))
{
cout << ".cod range error \n";
return;
}
_64k_base = get_short_int(&dbi->dir.block[COD_DIR_HIGHADDR]) << 15;
read_block(range_block, i);
// Loop through all of the .cod file blocks that (may) contain code
for(i=0; i<COD_CODE_IMAGE_BLOCKS; i++)
{
index = get_short_int(&dbi->dir.block[2*(COD_DIR_CODE + i)]);
if (index != 0) {
read_block(temp_block, index);
for(j=0; j<COD_BLOCK_SIZE/2; j++) {
int PCindex = i*COD_BLOCK_SIZE/2 + j;
if(cod_address_in_range(range_block, PCindex)) {
cpu->init_program_memory_at_index(PCindex+_64k_base, (int)get_short_int(&temp_block[j*2]));
}
}
}
}
dbi = dbi->next_dir_block_info;
} while(dbi && ++safety<10);
}
//-----------------------------------------------------------
FILE *PicCodProgramFileType::open_a_file(char **filename)
{
FILE *t;
if(verbose)
cout << "Trying to open a file: " << *filename << '\n';
if(0 != (t = fopen_path(*filename,"r")))
return t;
if(!ignore_case_in_cod)
return 0;
strtoupper(*filename);
if(0 != (t = fopen_path(*filename,"r")))
return t;
strtolower(*filename);
if(0 != (t = fopen_path(*filename,"r")))
return t;
// cout << "couldn't open " << *filename << " (or any upper/lower case variation)\n";
return 0;
}
//-----------------------------------------------------------
// Determing the .lst file name from the cod file file name.
// imo this is cheezy because the .cod file and .lst file have
// to have the same base file name. By convention, mpasm always
// made sure this happened. gpasm otoh, gives you an option to
// make the two different. Furthermore, gpasm includes the .lst
// file file name in the list of source files within the .cod
// file - unfortunately mpasm doesn't ... so gpsim has to assume
// the list file isn't present
int PicCodProgramFileType::cod_open_lst(const char *filename)
{
char *pc;
int i;
FILE *t;
lstfilename = strdup(filename);
pc = strrchr(lstfilename, '.');
if (pc == 0) {
if( (i = strlen(lstfilename)) < (256-4))
pc = lstfilename + i;
else
return ERR_FILE_NAME_TOO_LONG;
}
strcpy(pc, ".lst");
// Now, let's see if we can open the file
if(0 == (t = open_a_file(&lstfilename)))
return ERR_LST_FILE_NOT_FOUND;
fclose(t);
return SUCCESS;
}
//-----------------------------------------------------------
int PicCodProgramFileType::read_src_files_from_cod(Processor *cpu)
{
#define FILE_SIZE 64
#define FILES_PER_BLOCK (COD_BLOCK_SIZE/FILE_SIZE)
int iReturn = SUCCESS;
int i,j,start_block,end_block,offset,num_files;
char b[FILE_SIZE];
num_files = 0;
end_block = 0; // eliminates a (spurious) warning
//start_block = get_short_int(&directory_block_data[COD_DIR_NAMTAB]);
start_block = get_short_int(&main_dir.dir.block[COD_DIR_NAMTAB]);
// First, just count the number of source files
// These may be duplicates, but this is an upper bound
if(start_block) {
// end_block = get_short_int(&directory_block_data[COD_DIR_NAMTAB+2]);
end_block = get_short_int(&main_dir.dir.block[COD_DIR_NAMTAB+2]);
for(j=start_block; j<=end_block; j++) {
read_block(temp_block, j);
for(i=0; i<FILES_PER_BLOCK; i++) {
offset = i*FILE_SIZE;
if(temp_block[offset])
num_files++;
}
}
if(verbose)
printf ("Found up to %d source files in .cod file\n", num_files);
}
int found_lst_in_cod = 0;
if(num_files) {
cpu->files.list_id(num_files);
num_files = 0; // now use 'num_files' as a counter.
for(j=start_block; j<=end_block; j++) {
read_block(temp_block, j);
for(i=0; i<FILES_PER_BLOCK; i++) {
char *filenm;
offset = i*FILE_SIZE;
if((iReturn = get_string(b,&temp_block[offset],sizeof b)) != SUCCESS) {
goto _Cleanup;
}
filenm = b;
#ifdef _WIN32
// convert to DOS style file name
char *cp;
// convert Unix slash to DOS slash
for (cp = filenm; *cp; ++cp) { // convert Unix slash to DOS slash
if ('/' == *cp)
*cp = '\\';
}
#else
// convert to Unix style file name
if ((filenm[0] >= 'A') && (filenm[0] <= 'Z')
&& (':' == filenm[1]) && ('\\' == filenm[2])) {
char *cp;
filenm += 3; // strip C:\ from MPLAB files
// convert \ to / now???
for (cp = filenm; *cp; ++cp) { // convert DOS slash to Unix slash
if ('\\' == *cp) *cp = '/';
}
}
#endif
string s1 = string(filenm);
if(temp_block[offset] && (cpu->files.Find(s1) < 0)) {
//
// Add this file to the list
//
cpu->files.Add(filenm);
if((strncmp(lstfilename, filenm,256) == 0) &&
(cpu->files.list_id() >= cpu->files.nsrc_files()) ) {
if(verbose)
cout << "Found list file " << ((cpu->files)[num_files])->name() << endl;
cpu->files.list_id(num_files);
found_lst_in_cod = 1;
}
num_files++;
}
}
}
if(verbose)
cout << "Found " << num_files << " source files in .cod file\n";
if(num_files != cpu->files.nsrc_files())
cout << "warning, number of sources changed from " << num_files << " to "
<< cpu->files.nsrc_files() << " while reading code (gpsim bug)\n";
if(!found_lst_in_cod) {
cpu->files.Add(lstfilename);
cpu->files.list_id(num_files);
if(verbose)
printf("List file %s wasn't in .cod\n",lstfilename);
}
} else
printf("No source file info\n");
_Cleanup:
if(0){
// Debug code
int i;
cout << " new file stuff: " << cpu->files.nsrc_files() << " new files\n";
for(i=0; i<cpu->files.nsrc_files(); i++) {
cout << ((cpu->files)[i])->name() << endl;
}
cout << " end of new file stuff\n";
}
return iReturn;
}
//-----------------------------------------------------------
void PicCodProgramFileType::read_line_numbers_from_cod(Processor *cpu)
{
int j,start_block,end_block,offset;
int file_id, sline,smod;
unsigned int address;
start_block = get_short_int(&main_dir.dir.block[COD_DIR_LSTTAB]);
if(start_block) {
end_block = get_short_int(&main_dir.dir.block[COD_DIR_LSTTAB+2]);
// Loop through all of the .cod file blocks that contain line number info
for(j=start_block; j<=end_block; j++) {
read_block(temp_block,j);
// Get the line number info from within one .cod block
for(offset=0; offset<(COD_BLOCK_SIZE-COD_LS_SIZE); offset += COD_LS_SIZE) {
if((temp_block[offset+COD_LS_SMOD] & 4) == 0) {
file_id = temp_block[offset+COD_LS_SFILE];
address = get_short_int(&temp_block[offset+COD_LS_SLOC]);
//address = cpu->map_pm_address2index(address);
sline = get_short_int(&temp_block[offset+COD_LS_SLINE]);
smod = temp_block[offset+COD_LS_SMOD] & 0xff;
if( (file_id <= cpu->files.nsrc_files()) &&
(address <= cpu->program_memory_size()) &&
(smod == 0x80) )
cpu->attach_src_line(address,file_id,sline,0);
}
}
}
cpu->read_src_files();
}
}
//-----------------------------------------------------------
// read_message_area(Processor *cpu)
//
// The .cod file message area contains information like assertions
// and simulation scripts.
void PicCodProgramFileType::read_message_area(Processor *cpu)
{
#define MAX_STRING_LEN 255 /* Maximum length of a debug message */
char DebugType,DebugMessage[MAX_STRING_LEN];
unsigned short i, j, start_block, end_block;
unsigned short laddress;
// If the .cod file contains a simulation script, then we'll
// pass it to the command line interface. Note, we go through
// this indirect way of accessing the CLI since we don't wish
// for code in the src/ directory to depend directly on code
// in the cli/ (or any other) directory.
start_block = get_short_int(&main_dir.dir.block[COD_DIR_MESSTAB]);
if(start_block) {
end_block = get_short_int(&main_dir.dir.block[COD_DIR_MESSTAB+2]);
for(i=start_block; i<=end_block; i++) {
read_block(temp_block, i);
#if 0
{
// Debug code to display the contents of the message area.
int q,p;
printf ("Codefile block 0x%x\n",i);
for (q=0,p=0; q < COD_BLOCK_SIZE; q+=16) {
for (p=0; p<16; p++)
printf("%02X ",(unsigned char)temp_block[q+p]);
for (p=0; p<16; p++)
printf("%c", isascii(temp_block[q+p]) ? temp_block[q+p] : '.');
printf("\n");
}
#endif
j = 0;
// Each message has the form of
// AAAAAAAACCstring
// AAAAAAAA - 32bit address in PIC program memory
// CC - 8-bit command
// string - a 0-terminated string of characters.
while (j < COD_BLOCK_SIZE-8) {
/* read big endian */
laddress = get_be_int(&temp_block[j]);
j += 4; // 4 = size of big endian
DebugType = temp_block[j++];
if (DebugType == 0) {
break;
}
get_string(DebugMessage, &temp_block[j], sizeof DebugMessage);
j += strlen(DebugMessage)+1;
if(verbose)
printf("debug message: addr=%#x command=\"%c\" string=\"%s\"\n",
laddress,
DebugType,
DebugMessage);
// The lower case commands are user commands. The upper case are
// compiler or assembler generated. This code makes no distinction
// between them.
switch(DebugType) {
// The 'A' and 'E' options in gpasm specifies a list of gpsim commands
// that are to be executed after the .cod file has been loaded.
case 'a':
case 'A':
// assertion
{
string script("directive");
char buff[256];
snprintf(buff,sizeof(buff),"break e %d, %s\n",laddress,DebugMessage);
string cmd(buff);
cpu->add_command(script,cmd);
}
break;
case 'e':
case 'E':
// gpsim command
{
string script("directive");
string cmd(DebugMessage);
cmd = cmd + '\n';
cpu->add_command(script,cmd);
}
break;
case 'c':
case 'C':
// gpsim command
// The 'c'/'C' option in gpasm specifies a single gpsim command that is
// to be invoked whenever the address associated with this directive
// is being simulated.
{
bool bPost = DebugType == 'c';
CommandAssertion *pCA = new CommandAssertion(cpu,laddress,0,
DebugMessage,bPost);
get_bp().set_breakpoint(pCA);
}
case 'f':
case 'F':
// printf
break;
case 'l':
case 'L':
// log
break;
default:
cout << "Warning: unknown debug message \"" << DebugType << "\"\n";
}
}
}
}
}
//-----------------------------------------------------------
// open_cod_file
//
void PicCodProgramFileType::read_symbols( Processor *cpu )
{
int iReturn = SUCCESS;
char *s,length;
short type;
int i,j,start_block,end_block, value;
char b[256];
start_block = get_short_int(&main_dir.dir.block[COD_DIR_LSYMTAB]);
if(start_block) {
end_block = get_short_int(&main_dir.dir.block[COD_DIR_LSYMTAB+2]);
for(j=start_block; j<=end_block; j++) {
read_block(temp_block, j);
for(i=0; i<COD_BLOCK_SIZE;) {
s = &temp_block[i];
if(*s==0)
break;
length = *s;
type = get_short_int(&s[length+1]);
if(type>128)
type = COD_ST_CONSTANT;
value = get_be_int(&s[length+3]);
switch(type) {
case COD_ST_C_SHORT: {
// Change the register name to its symbolic name
iReturn = get_string(b, s, sizeof b);
cpu->registers[value]->new_name(b);
register_symbol *rs = new register_symbol((char*)0, cpu->registers[value]);
symbol_table.add(rs);
}
break;
case COD_ST_ADDRESS:
iReturn = get_string(b, s, sizeof b);
symbol_table.add_address(b, value);
break;
case COD_ST_CONSTANT: // Ignore as no useful purpose and may
// conflict with other symbols - RRR
break;
default:
iReturn = get_string(b,s,sizeof b);
symbol_table.add_constant(b,value);
break;
}
i += (length + 7);
}
}
}else
printf("No long symbol table info\n");
}
/*---------------------------------------------*/
void clear_block(Block *b)
{
if(b && b->block)
memset(b->block, 0, COD_BLOCK_SIZE);
else
assert(0);
}
/*---------------------------------------------*/
void create_block(Block *b)
{
assert(b != 0);
b->block = (char *)malloc(COD_BLOCK_SIZE);
clear_block(b);
}
void delete_block(Block *b)
{
if(b && b->block) {
free(b->block);
b->block = 0;
}
else
assert(0);
}
/*------------------------------------------------------------------
* read_directory - read the directory block(s) in the .cod file
*/
void PicCodProgramFileType::read_directory(void)
{
DirBlockInfo *dbi;
create_block(&main_dir.dir);
read_block(main_dir.dir.block, 0);
dbi = &main_dir;
do {
int next_dir_block = get_short_int(&dbi->dir.block[COD_DIR_NEXTDIR]);
if(next_dir_block) {
dbi->next_dir_block_info = (DirBlockInfo *)malloc(sizeof(DirBlockInfo));
dbi = dbi->next_dir_block_info;
create_block(&dbi->dir);
read_block(dbi->dir.block, next_dir_block);
} else {
dbi->next_dir_block_info = 0;
return;
}
} while(1);
}
void PicCodProgramFileType::delete_directory(void)
{
DirBlockInfo *dbi;
DirBlockInfo *next;
next = main_dir.next_dir_block_info;
while(next != 0) {
dbi = next;
next = dbi->next_dir_block_info;
delete_block(&dbi->dir);
free(dbi);
}
delete_block(&main_dir.dir);
}
int PicCodProgramFileType::check_for_gputils(char *block)
{
int iReturn = SUCCESS;
char buffer[256];
int have_gputils = 0;
if((iReturn = get_string(buffer,&block[COD_DIR_COMPILER - 1],12)) != SUCCESS) {
goto _Cleanup;
}
if ((strcmp("gpasm",buffer) == 0) || (strcmp("gplink",buffer) == 0)) {
if(verbose)
cout << "Have gputils\n";
have_gputils = 1;
if((iReturn = get_string(buffer,&block[COD_DIR_VERSION - 1],19)) != SUCCESS) {
goto _Cleanup;
}
int major=0, minor=0, micro=0;
if (isdigit(buffer[0])) {
// Extract version numbers in new gputils format
sscanf(&buffer[0],"%d.%d.%d",&major,&minor,µ);
if(verbose)
cout << "gputils version major "<< major << " minor " << minor << " micro " << micro << endl;
// if gputils version is greater than or equal to 0.13.0, then gputils
// is considered "recent"
if ((major >= 1) || ( minor >= 13))
gputils_recent = 1;
} else {
// version number in old gputils format, so it can't be recent
gputils_recent = 0;
}
}
if(have_gputils && gputils_recent) {
if(verbose)
cout << "good, you have a recent version of gputils\n";
} else {
cout << "Warning, you need to upgrade to gputils-0.13.0 or higher\n";
cout << "(Your assembler version is " << buffer << ")\n";
}
_Cleanup:
return iReturn;
}
//-----------------------------------------------------------
// Read .c line numbers from special .asm files.
void PicCodProgramFileType::read_hll_line_numbers_from_asm(Processor *cpu)
{
#if USE_OLD_FILE_CONTEXT == 1
int i;
struct file_context *gpsim_file;
char *file_name;
char filename[256];
char text_buffer[256];
int line_number;
char *srcptrbegin;
char *ptr;
FILE *file;
int line_nr;
int address;
int asmfile_id;
int asmsrc_line;
int found_line_numbers=0;
struct {
char filename[256];
struct file_context *file;
}hll_source_files[MAX_HLL_FILES];
int nr_of_hll_files=0;
int hll_files_index;
int file_index;
int filearray_index;
// Find the file context that contain the .asm file.
// This assumes 'there can be only one'.
for(i=0;i<cpu->number_of_source_files;i++) {
gpsim_file = &cpu->files[i];
file_name = gpsim_file->name;
if(!strcmp(file_name+strlen(file_name)-4,".asm")) {
// Make sure that the file is open
if(!gpsim_file->file_ptr) {
gpsim_file->file_ptr = fopen_path(file_name,"r");
if(!gpsim_file->file_ptr) {
printf("file \"%s\" not found!!!\n",file_name);
return;
}
}
break;
}
}
if(i==cpu->number_of_source_files)
{
puts("Could not find .asm file!");
return;
}
// Reset hll_file_id and hll_src_line throughout cpu memory
for(address=0;cpu->program_memory_size()>address;address++)
{
cpu->program_memory[address]->hll_file_id=0;
cpu->program_memory[address]->hll_src_line=0;
}
// asmfile_id is index into file context array.
asmfile_id=i;
for(i=0;cpu->files[i].file_ptr!=0;i++)
;
filearray_index=i;
rewind(gpsim_file->file_ptr);
asmsrc_line=0;
// Loop through the whole .asm file and look for any ";#CSRC" markers
while(fgets(text_buffer,sizeof(text_buffer),gpsim_file->file_ptr)!=0)
{
char *ptr2;
asmsrc_line++;
if(0!=strncmp(text_buffer,";#CSRC",6))
continue;
// Found a line marker
ptr=text_buffer+7;
for(;*ptr!='\0';ptr++)
if(*ptr==' '||*ptr=='\t')
break;
if(*ptr=='\0')
continue; // Syntax error
// file name
for(ptr2=text_buffer+7;ptr2<ptr;ptr2++)
filename[ptr2-(text_buffer+7)]=*ptr2;
filename[ptr2-(text_buffer+7)]=0;
ptr++;
for(;*ptr!='\0';ptr++)
if(isdigit(*ptr) || isspace(*ptr))
break;
if(!isdigit(*ptr))
continue; // Syntax error
found_line_numbers=1; // The .asm file contains line numbers.
line_number=atoi(ptr);
// Locate filename in hll_source_files[]
for(hll_files_index=0;hll_files_index<nr_of_hll_files;hll_files_index++)
{
if(!strcmp(filename,hll_source_files[hll_files_index].filename))
{
// Found it!
file_index=hll_files_index+cpu->number_of_source_files;
break;
}
}
if(nr_of_hll_files==MAX_HLL_FILES)
{
printf("Too many hll files, increase MAX_HLL_FILES\n");
}
else if(hll_files_index==nr_of_hll_files)
{
// Add new file
int maxline;
file_index=hll_files_index+cpu->number_of_source_files;
strcpy(hll_source_files[hll_files_index].filename,filename);
hll_source_files[hll_files_index].file=0;
nr_of_hll_files++;
cpu->files[file_index].name=strdup(filename);
file=fopen(cpu->files[file_index].name,"r");
if(file==0)
{
puts("file is not found\n");
assert(0);
}
cpu->files[file_index].file_ptr=file;
rewind(cpu->files[file_index].file_ptr);
maxline=0;
while(fgets(text_buffer,sizeof(text_buffer),cpu->files[file_index].file_ptr)!=0)
maxline++;
// Make a new file context
cpu->files[file_index].line_seek=0;//new int[maxline+1];
cpu->files[file_index].max_line=maxline;
cpu->files[file_index+1].file_ptr=0; // End of list
line_nr=0;
// cpu->files[file_index].line_seek[line_nr++]=0;
}
address=cpu->pma->find_closest_address_to_line(asmfile_id, asmsrc_line);
if(address >= 0) {
cpu->program_memory[address]->hll_src_line=line_number;
cpu->program_memory[address]->hll_file_id=file_index;
}
}
if(found_line_numbers)
{
cpu->number_of_source_files+=nr_of_hll_files;
}
else
{
cpu->files[i].file_ptr=0;
}
// Find first valid line number.
for(address=cpu->program_memory_size()-1;address>=0;address--)
{
if(cpu->program_memory[address]->hll_src_line)
{
line_number=cpu->program_memory[address]->hll_src_line;
file_index=cpu->program_memory[address]->hll_file_id;
}
}
// Fill the addresses in the gaps.
for(address=0;cpu->program_memory_size()>address;address++)
{
if(cpu->program_memory[address]->hll_src_line)
{
line_number=cpu->program_memory[address]->hll_src_line;
file_index=cpu->program_memory[address]->hll_file_id;
}
if(cpu->program_memory[address]->isa()!=instruction::INVALID_INSTRUCTION)
{
cpu->program_memory[address]->hll_file_id=file_index;
cpu->program_memory[address]->hll_src_line=line_number;
}
}
#else
cout << "FIXME: HLL files are not supported at the moment" << endl;
#endif
}
//-----------------------------------------------------------
// open_cod_file
//
// The purpose of this function is to process a .cod symbol file.
// If a cpu hasn't been declared prior to calling this function, then this
// function will attempt to determine the cpu from the .cod file.
//
/*
int open_cod_file(Processor **pcpu, const char *filename)
{
char directory[256];
const char *dir_path_end;
dir_path_end = get_dir_delim(filename);
if(dir_path_end!=0)
{
strncpy(directory,filename,dir_path_end-filename);
directory[dir_path_end-filename]=0;
printf("directory is \"%s\"\n",directory);
chdir(directory);
filename=dir_path_end+1;
printf("filename is \"%s\"\n",filename);
}
return load_cod_file(pcpu, filename, fopen(filename,"rb"));
}
*/
int PicCodProgramFileType::LoadProgramFile(Processor **pcpu,
const char *filename,
FILE *pFile,
const char *pProcessorName)
{
int error_code= SUCCESS;
Processor *ccpu = 0;
codefile = pFile;
if(codefile == 0) {
printf("Unable to open %s\n",filename);
return ERR_FILE_NOT_FOUND;
}
error_code= cod_open_lst(filename);
if(error_code != SUCCESS) {
display_symbol_file_error(error_code);
return error_code;
}
temp_block = new char[COD_BLOCK_SIZE];
/* Start off by reading the directory block */
read_directory();
// Perform a series of integrity checks
if((error_code = check_for_gputils(main_dir.dir.block)) != SUCCESS) {
goto _Cleanup;
}
// If we get here, then the .cod file is good.
if(*pcpu == 0) {
char processor_type[16];
processor_type[0] = 'p'; // Hack to get around processors whose name begin with a digit.
if(verbose)
cout << "ascertaining cpu from the .cod file\n";
if(SUCCESS == get_string(&processor_type[1],
&main_dir.dir.block[COD_DIR_PROCESSOR - 1],
sizeof (processor_type)-1)) {
char *pProcessorTypeOffset = isdigit(processor_type[1]) ?
&processor_type[0] : &processor_type[1];
if (!pProcessorName)
pProcessorName = pProcessorTypeOffset;
if(verbose)
cout << "found a " << processor_type << " in the .cod file\n";
*pcpu = (Processor *)CSimulationContext::GetContext()->add_processor(processor_type,
pProcessorName);
if(*pcpu == 0) {
if(!ignore_case_in_cod)
return(ERR_UNRECOGNIZED_PROCESSOR);
// Could be that there's a case sensitivity issue:
strtolower(processor_type);
*pcpu = (Processor *)CSimulationContext::GetContext()->
add_processor(processor_type,pProcessorName);
if(*pcpu == 0)
return(ERR_UNRECOGNIZED_PROCESSOR);
}
}
else {
return(ERR_UNRECOGNIZED_PROCESSOR);
}
}
else
cout << "cpu is non NULL\n";
ccpu = *pcpu;
read_hex_from_cod(ccpu);
ccpu->files.SetSourcePath(filename);
read_src_files_from_cod(ccpu);
// Associate the .lst and .asm files' line numbers with
// the assembly instructions' addresses.
read_line_numbers_from_cod(ccpu);
read_symbols(ccpu);
// If the .asm file contains special HLL source line comment, then
// read these and put the HLL line numbers into each instruction.
read_hll_line_numbers_from_asm(ccpu);
// Read all the debug messages
read_message_area(ccpu);
_Cleanup:
//delete directory_block_data;
delete_directory();
delete [] temp_block;
if(*pcpu != NULL) {
(*pcpu)->reset(POR_RESET);
bp.clear_global();
string script("directive");
(*pcpu)->run_script(script);
}
return error_code;
}
void PicCodProgramFileType::display_symbol_file_error(int err)
{
switch(err) {
case ERR_FILE_NOT_FOUND:
cout << "unable to find the symbol file\n";
break;
case ERR_UNRECOGNIZED_PROCESSOR:
cout << "unrecognized processor in the symbol file\n";
break;
case ERR_BAD_FILE:
cout << "bad file format\n";
break;
}
}
syntax highlighted by Code2HTML, v. 0.9.1