📄 common.c
字号:
/*
* Disassembler common routines
* Copyright (C) 1995-2005 by Jeffery L. Post
* theposts <AT> pacbell <DOT> net
*
* common.c - Support routines
*
* Version 3.3.6 - 01/18/05
*
* This program 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 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <malloc.h>
#include "d52.h"
#include "common.h"
// Global variables
char src[FN_LEN], dst[FN_LEN]; // file name buffers
char baseFileName[FN_LEN]; // source file name without extension
char ctl[FN_LEN]; // control file name
char linebuffer[MAX_LINE]; // input line buffer
FILE *fp; // dos file struct
int hexflag; // append hex flag
int fileflag; // file type flag
int upperflag; // upper case output flag
int kcnt; // output char counter
int pc; // current program counter
int himark; // highest data adrs
int offset; // program counter offset
byte *pgmmem; // program data pointer
int *pgmflags; // pointer to program flags
#ifdef EXTENDED_MEM
byte *epgmmem[EXT_PGM_SEGS]; // extended program memory pointers
int *epgmflags[EXT_PGM_SEGS]; // extended program flags pointers
#endif
char string[ASCLIMIT]; // ascii data for defb
int asc_cnt; // count for string data
byte byte_data[BYTELIMIT]; // binary data for defb
int byte_cnt; // count for binary data
int word_data[WORDLIMIT]; // binary data for defw
int word_cnt; // count for word data
byte dump; // dump just done flag
byte ascii_flag; // use ascii string flag
char defbstr[8]; // string for defined bytes
char defwstr[8]; // string for defined words
char ascistr[8]; // string for defined ascii
char orgstr[] = ".or"; // org pseudo-op string
char equstr[] = ".eq"; // equ pseudo-op string
struct sym *sym_tab; // symbol table pointer
struct sym *lab_tab; // label table pointer
struct sym *name_tab; // operand names pointer
struct sym *sym_tab_last; // last symbol table pointer
struct sym *lab_tab_last; // lastlabel table pointer
struct sym *name_tab_last; // last name table pointer
int symbol_count; // number of symbols
int label_count; // number of labels
int name_count; // number of operand names
SYM_PTR *sym_val_index; // array of pointers
SYM_PTR *lab_val_index; // for binary search
SYM_PTR *name_val_index;
struct sym *tail_ptr, *head_ptr; // sort pointers
struct comment *comment_list; // header comment list
struct comment *icomment_list; // inline comment list
struct comment *patch_list; // patch list
int newline; // just output newline flag
struct tm *date_time; // disassembly time
//
// Code
//
bool init_memory(void)
{
int count;
#ifdef EXTENDED_MEM
for (count=0; count <EXT_PGM_SEGS; count++)
{
epgmmem[count] = NULL;
epgmflags[count] = NULL;
}
#endif
if ((pgmmem = (byte *) malloc(PMEMSIZE)) == NULL)
{
printf("INTERNAL ERROR! - Can't allocate program space!\n");
return FALSE;
}
if ((pgmflags = (int *) malloc(PMEMSIZE * sizeof(int))) == NULL)
{
printf("INTERNAL ERROR! - Can't allocate flag space!\n");
return FALSE;
}
printf("Initializing program spaces...");
for (count=WORD_MASK; count; count--) // fill code space with
{
pgmmem[count] = NO_DATA; // invalidate data
pgmflags[count] = PF_INIT; // invalidate flags
}
pgmmem[0] = NO_DATA; // include first location
pgmflags[0] = PF_INIT;
return TRUE;
}
#ifdef EXTENDED_MEM
// Get extended program or flag memory.
// Width = 1 for program memory or 2 for flag memory.
byte *get_extended_mem(int width)
{
byte *ptr;
ptr = (byte *) malloc(PMEMSIZE * width);
if (!ptr)
printf("\nCan't allocate extended memory!\n");
return ptr;
}
#endif
char * makeupper(char *str)
{
char *ret = str;
while (*str)
{
*str = toupper(*str);
str++;
}
return ret;
}
// Parse file name. Put file name without extension in
// baseFileName, and return:
// EITHERFILE if no extension provided
// BINFILE if extension is '.bin'
// HEXFILE if extension is '.hex'
// CPMFILE if extension is '.com'
int parseFileName(char *str, char *ext)
{
int i, type;
char *cptr;
type = EITHERFILE;
strcpy(baseFileName, str);
strcpy(src, str);
cptr = strrchr(str, '.');
if (!cptr) // if '.' not found, then use eitherfile
{
strcat(src, ".hex");
}
else
{
i = (int) (cptr - str); // get offset of '.' character
if (!strncasecmp(cptr, ".hex", 4))
{
baseFileName[i] = '\0';
type = HEXFILE;
}
else if (!strncasecmp(cptr, ".bin", 4))
{
baseFileName[i] = '\0';
type = BINFILE;
}
else if (!strncasecmp(cptr, ".com", 4) && !strcmp(ext, ".z80"))
{
baseFileName[i] = '\0';
offset = 0x100;
type = CPMFILE;
}
else
strcat(src, ".hex");
}
strcpy(dst, baseFileName);
strcat(dst, ext);
strcpy(ctl, baseFileName);
strcat(ctl, ".ctl");
return type;
}
//
// Read bin, hex, or com file into program memory.
//
int readfile(char *filename)
{
int i, j, rectype, page, line, readsize;
// open source file
switch (fileflag)
{
case EITHERFILE: // if no type specified...
fp = fopen(src, "r"); // search for hex file first
if (fp == NULL) // if not found, search for bin file
{
fileflag = BINFILE;
strcpy(src, baseFileName);
strcat(src, ".bin");
fp = fopen(src, "rb");
if (fp == NULL)
{
printf("\n* Can't open either '%s.hex' nor '%s.bin' *\n\n",
baseFileName, baseFileName);
exit(FILE_ERROR);
}
else
fileflag = BINFILE;
}
break;
case HEXFILE: // force hex file
fp = fopen(src, "r");
break;
case BINFILE: // force bin file
case CPMFILE: // CP/M .com file
fp = fopen(src, "rb");
break;
}
if (fp == NULL) // if file not found...
{
printf("\n* Can't open file '%s' *\n\n", src);
exit(FILE_ERROR);
}
// read input file and set up data array
himark = 0;
line = 0;
pc = offset;
printf("\nreading %s\n", src);
if (fileflag == BINFILE || fileflag == CPMFILE) // if binary file...
{
while (!feof(fp)) // until end of file...
{
if (pc >= PMEMSIZE) // exceeded 64K limit
{
printf("\nInput file too large!\n\n");
break;
}
if ((pc + MAX_LINE) >= PMEMSIZE) // if next read would exceed limit
readsize = PMEMSIZE - pc; // reduce read byte count
else
readsize = MAX_LINE;
i = fread(linebuffer, 1, readsize, fp); // read a block of data
for (j=0; j<i; j++)
{
pgmmem[pc] = linebuffer[j]; // copy to program space
pgmflags[pc] = PF_DATA;
pc++;
if ((pc & 0xff) == 0)
printf("\r%04x", pc); // show progress
}
if (pc & WORD_MASK)
himark = pc;
else
himark = WORD_MASK; // flag highest location
}
}
else // else hex file...
{
page = 0;
rectype = 0;
while (!feof(fp)) // until end of file...
{
*linebuffer = '\0'; // clear previous line
fgets(linebuffer, MAX_LINE - 1, fp);// read one line
line++;
if (sscanf(linebuffer, "%*c%2x%4x%2x", &i, &pc, &rectype) != EOF)
{ // get count and address
pc += offset; // add offset to address
pc += page; // add segment to address
if ((pc + i) >= PMEMSIZE)
{
printf("\nInput file too large!\n\n");
// exit(FILE_ERROR);
break;
}
if (rectype == 1)
break; // done if end of hex record
if (rectype == 2) // extended segment address record
{
sscanf((char *) &linebuffer[9], "%4x", &page);
page <<= 4;
}
else if (rectype == 0) // data record
{
if (i > 64) // oops! line too long
{
printf("invalid count (%d) in line %d:\n", i, line);
printf("%s", linebuffer);
exit(FILE_ERROR);
}
for (j=0; j<i ; j++) // now move data to program area
{
getcode(linebuffer + 9 + j * 2, &pgmmem[pc]); // code to program space
pgmflags[pc] = PF_DATA; // flag valid data
pc++;
if ((pc & 0xff) == 0) // show progress
printf("\r%04x", pc);
}
if (pc > himark)
himark = pc;
}
}
}
}
fclose(fp); // done reading input file
printf("\rHighest location = "); // show last location
if (himark == WORD_MASK)
printf("%04x\n", himark);
else
printf("%04x\n", himark - 1);
return 0;
}
//
// Put ascii hex data into binary array
//
void getcode(char *from, byte *loc)
{
byte c, i;
c = *from++ - 0x30;
c = (c > 10) ? c - 7 : c;
i = c << 4;
c = *from++ - 0x30;
c = (c > 10) ? c - 7 : c;
*loc = i | c;
}
//
// Get hexadecimal number from line in control file.
// Return updated character pointer.
//
char *get_adrs(char *text, int *val)
{
int result, start;
char c;
result = start = 0;
c = toupper(*text);
while (c)
{
if (c == ';') // beginning of comment, ignore all else
break;
if (c == '\n') // necessary because isspace() includes \n
break;
if (isspace(c)) // skip leading whitespace
{
text++;
if (start) // if result already begun...
break;
}
else if (!isxdigit(c)) // done if not hexadecimal character
break;
else
{
start = 1; // flag beginning of result conversion
c = (c > '9') ? c - 0x37 : c - 0x30;
result <<= 4;
result |= ((int) c & 0xf);
text++;
}
c = toupper(*text);
}
*val = result; // pass number back to caller
return(text); // and return updated text pointer
}
void error(char *str1, char *str2) // fatal error trap
{
printf("\n%s%s", str1, str2);
exit(FILE_ERROR);
}
// Sort label or symbol table
// First sort by name so that we can check for duplicates,
// then sort by value, check for duplicates, and set up
// pointer array for binary search.
//
struct sym *sort(struct sym *list, SYM_PTR *array, int count)
{
int i;
struct sym *sptr, *temp;
sptr = sort_by_name(list);
if (list == name_tab)
chk_dup_op_name(sptr, count);
else
chk_dup_name(sptr, count);
sptr = sort_by_value(sptr);
chk_dup_value(sptr, count);
temp = sptr;
for (i=0; i<count; i++) // set up array of pointers sorted by value
{
array[i] = temp;
temp = temp->next;
}
return(sptr);
}
//
// In-place non-recursive merge sort using label text as key
//
struct sym *sort_by_name(struct sym *list)
{
int i, n;
struct sym *a, *b, *todo, *t;
head_ptr = (struct sym *) malloc(sizeof(struct sym));
head_ptr->next = list;
a = tail_ptr;
for (n=1; a != head_ptr->next; n = n + n)
{
todo = head_ptr->next;
list = head_ptr;
while (todo != tail_ptr)
{
t = todo;
a = t;
for (i=1; i<n; i++)
t = t->next;
b = t->next;
t->next = tail_ptr;
t = b;
for (i=1; i<n; i++)
t = t->next;
todo = t->next;
t->next = tail_ptr;
list->next = merge_by_name(a, b);
for (i=1; i<=n+n; i++)
list = list->next;
}
}
return(head_ptr->next);
}
//
// In-place non-recursive merge sort using value as key
//
struct sym *sort_by_value(struct sym *list)
{
int i, n;
struct sym *a, *b, *todo, *t;
head_ptr = (struct sym *) malloc(sizeof(struct sym));
head_ptr->next = list;
a = tail_ptr;
for (n=1; a != head_ptr->next; n = n + n)
{
todo = head_ptr->next;
list = head_ptr;
while (todo != tail_ptr)
{
t = todo;
a = t;
for (i=1; i<n; i++)
t = t->next;
b = t->next;
t->next = tail_ptr;
t = b;
for (i=1; i<n; i++)
t = t->next;
todo = t->next;
t->next = tail_ptr;
list->next = merge_by_value(a, b);
for (i=1; i<=n+n; i++)
list = list->next;
}
}
return(head_ptr->next);
}
//
// Merge sub-lists by text field
//
struct sym *merge_by_name(struct sym *a, struct sym *b)
{
int i;
struct sym *c;
c = tail_ptr;
do
{
i = strcasecmp(a->name, b->name);
if (i <= 0)
{
c->next = a;
c = a;
a = a->next;
}
else
{
c->next = b;
c = b;
b = b->next;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -