diff --git a/f9dasm.c b/f9dasm.c index afe89ae..b0812c4 100644 --- a/f9dasm.c +++ b/f9dasm.c @@ -35,7 +35,7 @@ */ #ifndef RB_VARIANT - #define RB_VARIANT 0 + #define RB_VARIANT 1 #endif /* History, as far as I could retrace it: @@ -97,9 +97,24 @@ V1.75 2015-07-26 Only install system vector labels if they aren't defined in an info file INSERT, COMMENT, PREPCOMM without address range can be used to prepend text to the output, too PREPEND without address now works like normal PREPEND - it adds BEFORE the first line + V1.76 2015-07-31 (RB) declobbered CONST(ANT) + * CONST now works regardless of data type (formerly not possible with WORD data) + V1.77 2016-02-25 (RB) added support for banked code [in work] + * new directive: bdef[ine] name phys-addr size cpu-addr + * defines a new bank named "name" of size "size" at CPU-seen address "cpu-addr" that belongs to ROM/RAM physical address "phys-address" + * new directive: bass[ign] name from[-to] name_dst + * assigns address(-region) from(-to) to bank "name_dst" and gives it a descriptive name "name" used in disassembly + * label and data-type declaration get optinal parameter "bank name" so that declarations are added to the banked labels, not the master label + * code/data disassembly checks whether current ROM address is found in bdef_t list, then uses ORG/PHASE from there + * code/data disassembly checks whether current ROM address is found in bass_t, then uses operand label name from linked bdef_t->labels + * + * todo: + * 1) [x] data structures + * 2) label parser for bdef / bass + * 3) hook into disassembler */ -#define ID "1.75" +#define ID "1.77" #if RB_VARIANT #define VERSION ID "-RB" @@ -133,6 +148,19 @@ #define DATATYPE_DVEC 0x0100 #define DATATYPE_CVEC 0x0200 +/* RB: const needs to be unclobbered -- can be hex, bin, word, ...) */ +#define AREATYPE_CONST 0x0400 + +/* RB: banked code area requires own declaration */ +#define AREATYPE_BCODE 0x0800 + +/* RB: banked operands might appear, too, with banking independent of code bank */ +#define AREATYPE_BDATA 0x1000 + +/* RB: banked regions have a start and an end */ +#define AREATYPE_BSTART 0x2000 +#define AREATYPE_BEND 0x4000 + #define AREATYPE_CLABEL 0x01 #define AREATYPE_LABEL 0x02 #define AREATYPE_ULABEL 0x04 @@ -144,14 +172,17 @@ #define AREATYPE_DEC (AREATYPE_DATA | DATATYPE_DEC) #define AREATYPE_HEX (AREATYPE_DATA | DATATYPE_HEX) #define AREATYPE_CHAR (AREATYPE_DATA | DATATYPE_CHAR) -#define AREATYPE_CONST (AREATYPE_CODE | AREATYPE_DATA) + +/* RB: this used to be AREA_CONST, but in fact its CODA ... */ +#define AREATYPE_CODA (AREATYPE_CODE | AREATYPE_DATA) /* RB: new vector areatypes */ #define AREATYPE_DVEC (AREATYPE_WORD | DATATYPE_DVEC) #define AREATYPE_CVEC (AREATYPE_WORD | DATATYPE_CVEC) -#define IS_CODE(address) ((ATTRBYTE(address)&AREATYPE_CONST)==AREATYPE_CODE) -#define IS_DATA(address) ((ATTRBYTE(address)&AREATYPE_CONST)==AREATYPE_DATA) +/* RB: CODE/DATA now derived from CODA, not CONST anymore) */ +#define IS_CODE(address) ((ATTRBYTE(address)&AREATYPE_CODA)==AREATYPE_CODE) +#define IS_DATA(address) ((ATTRBYTE(address)&AREATYPE_CODA)==AREATYPE_DATA) #define IS_CONST(address) ((ATTRBYTE(address)&AREATYPE_CONST)==AREATYPE_CONST) #define SET_USED(address) used[(address) / 8] |= (1 << ((address) % 8)) @@ -176,6 +207,13 @@ #define IS_DVEC(address) (ATTRBYTE(address) & DATATYPE_DVEC) #define IS_CVEC(address) (ATTRBYTE(address) & DATATYPE_CVEC) +/* RB: bank check */ +#define IS_BCODE(address) ((ATTRBYTE(address) & AREATYPE_BCODE) == AREATYPE_BCODE) +#define IS_BDATA(address) ((ATTRBYTE(address) & AREATYPE_BDATA) == AREATYPE_BDATA) +#define IS_BSTART(address) ((ATTRBYTE(address) & AREATYPE_BSTART) == AREATYPE_BSTART) +#define IS_BEND(address) ((ATTRBYTE(address) & AREATYPE_BEND) == AREATYPE_BEND) +#define NUM_BANKS(address) (ATTRBYTE(address) & 0xff) + #ifndef TYPES #define TYPES typedef unsigned char byte; @@ -207,6 +245,38 @@ typedef struct _phasedef /* data for a phase */ unsigned short rel; } phasedef; +/* bank definition + * filled by: bdef[ine] name org_phy size org_cpu + * during INFO file parsing: *labels=calloc(sizeof(int)*size) + */ +typedef struct + { + char *name; /* bank name */ + int size; /* bank size */ + int org_cpu; /* CPU-seen base address of banked area */ + int org_phy; /* physical base address for currently disassembled ROM address */ + int *labels; /* dynamically malloc'ed labels for bank: labels = malloc(sizeof(int)*size)) */ + } bdef_t; + +/* banks container */ +typedef struct + { + int max; /* number of elements stored */ + bdef_t *def; /* pointer to definitions */ + } banks_t; + +/* bank/operand assignment definition + * filled by: bass[ign] bank_name addr_start[-addr_end] + * bank_name is resolved to corresponding bdef_t *bank during INFO file parsing + */ +typedef struct + { + int addr_start; /* start address */ + int addr_end; /* end address */ + bdef_t *bank; /* referenced bank */ + } bass_t; + + /*****************************************************************************/ /* Global Data */ /*****************************************************************************/ @@ -252,6 +322,7 @@ unsigned begin = 0xffff, end = 0, offset = 0; int load = -1; static char *loaded[200] = {0}; char *sLoadType = ""; + /* RB: get a divider after BRA/JMP/SWIx/RTS/RTI/PULx PC */ int optdelimbar = FALSE; @@ -265,6 +336,11 @@ int noLoadLabel = FALSE; char *vec_6801[] = {"IRQ_SCI","IRQ_T0F","IRQ_OCF","IRQ_ICF","IRQ_EXT","SWI","NMI","RST"}; char *vec_6809[] = {"DIV0","SWI3","SWI2","FIRQ","IRQ","SWI","NMI","RST"}; +/* RB: banking variables */ +banks_t banks={0,NULL}; /* container for all bank definitions */ +int *label_bcode = NULL; /* like *label, but holding address-to-bank assignment */ +int *label_bdata = NULL; /* like *label, but holding operand-to-bank assignment */ + enum /* available options */ { OPTION_BEGIN, @@ -1888,7 +1964,7 @@ if ((nDigits == 2) && /* if 2-digit value */ #if RB_VARIANT sprintf(s, "'%c'", W); #else - sprintf(s, "'%c", W); + sprintf(s, "'%c", W); /* RB: shouldn't this close somewhere? check! */ #endif else sprintf(s, "$%02x", W); @@ -1933,6 +2009,8 @@ return s; /* label_string : eventually converts a word to a string */ /*****************************************************************************/ +/* RB: should respect banking -- addr is PC at time of calling */ + char *label_string(word W, int bUseLabel, word addr) { static char szOut[256]; @@ -3072,6 +3150,8 @@ wfCur = ShowMemFlags(pc) & /* get flags for current byte */ for (end = pc + 1; ; end++) /* find end of block */ { + + /* RB: respect banking here */ if(IS_LABEL(end)) /* RB: don't overrun labels ... */ { /* HS: unless they're displacements! */ char *slabel = label_string((word)end, 1, (word)end); @@ -3196,7 +3276,6 @@ printf("\n" "\tdon't apply label name to constant but treat it as a number\n" "\t\t\t CONST from[-to]\n" "\tmark auto-generated label as used\n" - "\t\t\t USED[LABEL] addr\n" "\nCommenting\n" "\tcomment: COMM[ENT] addr[-addr] text\n" "\tsuppress comments: UNCOMM[ENT] addr[-addr] text\n" @@ -3244,6 +3323,9 @@ printf("\n" "UNREL[ATIVE] addr[-addr]\n" "REMAP addr[-addr] offset\n" "PHASE addr[-addr] phase\n" + "BDEF[ine] name phys_org size cpu_org\n" + "BCODE name addr[-addr]\n" + "BDATA name addr[-addr]\n" "END\n" #endif ); @@ -4149,10 +4231,15 @@ enum infoRelative, /* RELATIVE addr[-addr] rel */ infoUnRelative, /* UNRELATIVE addr[-addr] */ infoPrepLComment, /* PREPLCOMM addr[-addr] [.]lcomment */ - infoRemap, /* REMAP addr[-addr] offs */ infoFile, /* FILE filename */ + infoRemap, /* REMAP addr[-addr] offs */ infoPhase, /* PHASE addr[-addr] phase */ + /* RB: bank define / bank assign / operand assign directives */ + infoBdef, /* BDEF[INE] name phys-addr size cpu-addr */ + infoBcode, /* BCODE name from[-to] name_dst */ + infoBdata, /* BDATA name from[-to] name_dst */ + /* RB: new vector label types */ infoCVector, /* CVEC[TOR] addr[-addr] */ infoDVector, /* DVEC[TOR] addr[-addr] */ @@ -4213,6 +4300,12 @@ static struct /* structure to convert key to type */ { "FILE", infoFile }, { "PHASE", infoPhase }, + /* RB: bank define / bank assign */ + { "BDEF", infoBdef }, + { "BDEFINE", infoBdef }, + { "BCODE", infoBcode }, + { "BDATA", infoBdata }, + /* RB: new vector label types */ { "CVECTOR", infoCVector }, { "CVEC", infoCVector }, @@ -4900,6 +4993,136 @@ while (fgets(szBuf, sizeof(szBuf), fp)) loadfile(fname, &begin, &end, &load, nFrom, outfile); } break; + + case infoBdef: /* BDEF bank_name phys_addr bank_size cpu_addr */ + { + char *bname=p; + int pbase, psize, cbase; + int found=0; + + /* get/set name end */ + for (; (*p) && (*p != ' ' ) && (*p != '\t'); p++); + if(*p) *p++='\0'; + + /* get phys base addr of bank */ + q = p; + for (; (*p) && (*p != ' ' ) && (*p != '\t'); p++); + if(*p) *p++='\0'; + sscanf(q, "%x", &pbase); + + /* get bank size */ + q = p; + for (; (*p) && (*p != ' ' ) && (*p != '\t'); p++); + if(*p) *p++='\0'; + sscanf(q, "%x", &psize); + + /* get cpu base addr of bank */ + q = p; + for (; (*p) && (*p != ' ' ) && (*p != '\t'); p++); + if(*p) *p++='\0'; + sscanf(q, "%x", &cbase); + + /* check for redefinition */ + for(i=0; i nTo) || (nTo >= 0x10000)) + break; + + /* check for presence */ + for(i=0; i=0) + { + for(i=nFrom; i<=nTo; i++) + { + /* bcode: banked code -- address shift */ + if(nType==infoBcode) + { + label[i]=AREATYPE_BCODE; + label_bcode[i]=found; + } + + /* bdata: banked data -- operand address shift */ + else + { + label[i]=AREATYPE_BDATA; + label_bdata[i]=found; + } + + /* mark start/end of region for easier parsing in disassembler */ + if(i==nFrom) label[i]|=AREATYPE_BSTART; + else if(i==nTo) label[i]|=AREATYPE_BEND; + + } + } + else fprintf(stderr,"Unable to find definition of bank \"%s\", skipping bank assignment statement.\n",bname); + } + break; + case infoPhase : /* PHASE addr[-addr] phase */ { char *laddr = p; @@ -4991,21 +5214,27 @@ for (i = 1, n = 0; i < argc; ++i) memory = (byte *)malloc(0x10000); label = (int *)malloc(0x10000 * sizeof(int)); -used = (byte *)malloc(0x10000 / 8); lblnames = (char **)malloc(0x10000 * sizeof(char *)); +used = (byte *)malloc(0x10000 / 8); commentlines = (char **)malloc(0x10000 * sizeof(char *)); lcomments = (char **)malloc(0x10000 * sizeof(char *)); rels = (unsigned short *)malloc(0x10000 * sizeof(unsigned short)); dps = (short *)malloc(0x10000 * sizeof(short)); phases = (phasedef *)malloc(MAXPHASES * sizeof(phasedef)); remaps = (int *)malloc(0x10000 * sizeof(int)); -if ((!memory) || (!label) || (!used) || - (!lblnames) || (!commentlines) || (!lcomments) || - (!rels) || (!phases) || (!dps) || (!remaps)) +label_bcode = (int *)malloc(0x10000 * sizeof(int)); +label_bdata = (int *)malloc(0x10000 * sizeof(int)); +if ( + (!memory) || (!label) || (!used) || (!lblnames) || + (!commentlines) || (!lcomments) || (!rels) || (!phases) || + (!dps) || (!remaps) || (!label_bcode) || (!label_bdata) + ) { - printf("no mem buffer\n"); + printf("No mem buffer\n"); goto exit; } +memset(label_bcode, -1, 0x10000 * sizeof(int *)); /* RB: index to bdef, -1 means unused */ +memset(label_bdata, -1, 0x10000 * sizeof(int *)); /* RB: index to bdef, -1 means unused */ memset(memory, 0x01, 0x10000); memset(label, 0x00, 0x10000 * sizeof(int)); memset(used, 0x00, 0x10000 / 8); @@ -5021,7 +5250,7 @@ if (outname) out = fopen(outname,"w"); if (!out) { - printf("can't open %s \n",outname); + printf("Can't open %s \n",outname); return 1; } fprintf(out, @@ -5360,6 +5589,13 @@ do fprintf(out, " %-7s\n\n", "DEPHASE"); } } + + /* RB: does a banked code area start? */ + if( IS_BCODE(pc) && IS_BSTART(label[pc]) ) + { + fprintf(out, " %-7s $%02X\n\n", "ORG", banks.def[label_bcode[pc]].org_cpu); + fprintf(out, " %-7s $%02X\n\n", "PHASE", banks.def[label_bcode[pc]].org_phy); + } if (commentlines[pc]) { @@ -5373,6 +5609,11 @@ do } } + /* this needs to be reworked: + * 1) unbanked -> IS_LABEL(pc) + * 2) banked code -> IS_LABEL(banks.def[label_bcode[pc]].org_cpu + pc-banks.def[label_bcode[pc]].org_phys) to shift pc to actual cpu address + */ + if (IS_LABEL(pc)) /* if any label here */ { if ((strchr(slabel, '+')) || @@ -5398,6 +5639,11 @@ do else llen = fprintf(out, "%-*s ", 7, ""); + /* RB: ShowData() and Dasm() need to respect code/data banking * + * 1) unbanked -> IS_xxxx(pc) + * 2) banked code -> IS_xxxx(banks.def[label_bcode[pc]].org_cpu + pc-banks.def[label_bcode[pc]].org_phys) to shift pc to actual cpu address + * 3) ShowData / Dasm need to know proper reference + */ if (IS_CONST(pc) || IS_DATA(pc)) { add = ShowData(out, pc, (nComment || lcomments[pc])); @@ -5463,6 +5709,10 @@ do curphase != GetPhaseDef((word)pc)) fprintf(out, "\n %-*s\n\n", 7, "DEPHASE"); + /* RB: does a banked code area end? */ + if( IS_BCODE(pc) && IS_BEND(label[pc]) ) + fprintf(out, " %-7s\n\n", "DEPHASE"); + if ((pc < 0x10000) && /* only if still in range, */ (!IS_USED(pc - 1))) /* if we DID skip something set ORG */ fprintf(out, "\n %-*s $%04X \n\n", 7, "ORG", pc);