1
0
mirror of https://github.com/ksherlock/x65.git synced 2025-01-16 23:30:02 +00:00

XREF support, starting cycle counting

- XREF directive now required for referencing XDEF symbols from other
files
- Created cycle timing table for 6502, displaying for each line in .lst
files
This commit is contained in:
Carl-Henrik Skårstedt 2015-10-30 22:30:16 -07:00
parent 8fdeb287e1
commit b1e9797160
2 changed files with 133 additions and 54 deletions

View File

@ -135,6 +135,7 @@ Directives are assembler commands that control the code generation but that does
* [**SECTION**](#section) Start a relative section * [**SECTION**](#section) Start a relative section
* [**LINK**](#link) Link a relative section at this address * [**LINK**](#link) Link a relative section at this address
* [**XDEF**](#xdef) Make a label available globally * [**XDEF**](#xdef) Make a label available globally
* [**XREF**](#xref) Reference a label declared globally in a different object file (.x65)
* [**INCOBJ**](#incobj) Include an object file (.x65) to this file * [**INCOBJ**](#incobj) Include an object file (.x65) to this file
* [**EXPORT**](#export) Save out additional binary files with argument appended to filename * [**EXPORT**](#export) Save out additional binary files with argument appended to filename
* [**ALIGN**](#align) Align the address to a multiple by filling with 0s * [**ALIGN**](#align) Align the address to a multiple by filling with 0s
@ -223,6 +224,10 @@ InitBobs:
rts rts
``` ```
<a name="xref">**XREF**
In order to reference a label that was globally declared in another object file using XDEF the label must be declared by using XREF.
<a name="incobj">**INCOBJ** <a name="incobj">**INCOBJ**
Include an object file for linking into this file. In order to include the object code into a binary the sections from the object file must be referenced using the *LINK* directive. Include an object file for linking into this file. In order to include the object code into a binary the sections from the object file must be referenced using the *LINK* directive.
@ -603,7 +608,7 @@ Change processor. The first instance of XC will switch from 6502 to 65C02, the s
**MX** **MX**
MX sets the immediate mode accumulator instruction size, it takes a number and uses the lowest two bits. Bit 0 applies to index registers (x, y) where 0 means 8 bits and 1 means 16 bits, bit 1 applies to the accumulator. Normally it is specified in binary using the '%' prefix. MX sets the immediate mode accumulator instruction size, it takes a number and uses the lowest two bits. Bit 0 applies to index registers (x, y) where 0 means 16 bits and 1 means 8 bits, bit 1 applies to the accumulator. Normally it is specified in binary using the '%' prefix.
``` ```
MX %11 MX %11
@ -647,11 +652,11 @@ DSK is similar to SAV
**ENT** **ENT**
ENT defines the label that preceeds it as external ENT defines the label that preceeds it as external, same as [**XDEF**](#xdef).
**EXT** **EXT**
EXT imports an external label, x65 doesn't need this. EXT imports an external label, same as [**XREF**](#xref).
**LNK** / **STR** **LNK** / **STR**
@ -806,9 +811,14 @@ FindFirstSpace
Fish food! Assembler has all important features and switching to make a 6502 project for more testing. Currently the assembler is in a limited release. Primarily tested with personal archive of sources written for Kick assmebler, DASM, TASM, XASM, etc. and passing most of Apple II Prince of Persia and Pinball Construction set. Fish food! Assembler has all important features and switching to make a 6502 project for more testing. Currently the assembler is in a limited release. Primarily tested with personal archive of sources written for Kick assmebler, DASM, TASM, XASM, etc. and passing most of Apple II Prince of Persia and Pinball Construction set.
**TODO** **TODO**
* OMF export for Apple II GS/OS executables
* Hierarchical cycle timing in list file
* irp (indefinite repeat) * irp (indefinite repeat)
**FIXED** **FIXED**
* First pass cycle timing in listing file for 6502 targets
* Enums can have comments
* XREF required to reference XDEF symbols in object files (.x65)
* Nested scopes and label pools broke recently and was fixed, section alignment wasn't working. * Nested scopes and label pools broke recently and was fixed, section alignment wasn't working.
* Link file issues fixed, added a dump tool to show the contents of object files for debugging. * Link file issues fixed, added a dump tool to show the contents of object files for debugging.
* Rastan for Apple II gs assembles and links. * Rastan for Apple II gs assembles and links.

171
x65.cpp
View File

@ -81,6 +81,7 @@ enum StatusCode {
STATUS_OK, // everything is fine STATUS_OK, // everything is fine
STATUS_RELATIVE_SECTION, // value is relative to a single section STATUS_RELATIVE_SECTION, // value is relative to a single section
STATUS_NOT_READY, // label could not be evaluated at this time STATUS_NOT_READY, // label could not be evaluated at this time
STATUS_XREF_DEPENDENT, // evaluated but relied on an XREF label to do so
STATUS_NOT_STRUCT, // return is not a struct. STATUS_NOT_STRUCT, // return is not a struct.
FIRST_ERROR, FIRST_ERROR,
ERROR_UNDEFINED_CODE = FIRST_ERROR, ERROR_UNDEFINED_CODE = FIRST_ERROR,
@ -142,6 +143,7 @@ const char *aStatusStrings[STATUSCODE_COUNT] = {
"ok", "ok",
"relative section", "relative section",
"not ready", "not ready",
"XREF dependent result",
"name is not a struct", "name is not a struct",
"Undefined code", "Undefined code",
"Unexpected character in expression", "Unexpected character in expression",
@ -203,7 +205,8 @@ enum AssemblerDirective {
AD_LOAD, // LOAD: If applicable, instruct to load at this address AD_LOAD, // LOAD: If applicable, instruct to load at this address
AD_SECTION, // SECTION: Enable code that will be assigned a start address during a link step AD_SECTION, // SECTION: Enable code that will be assigned a start address during a link step
AD_LINK, // LINK: Put sections with this name at this address (must be ORG / fixed address section) AD_LINK, // LINK: Put sections with this name at this address (must be ORG / fixed address section)
AD_XDEF, // XDEF: Externally declare a label AD_XDEF, // XDEF: Externally declare a symbol
AD_XREF, // XREF: Reference an external symbol
AD_INCOBJ, // INCOBJ: Read in an object file saved from a previous build AD_INCOBJ, // INCOBJ: Read in an object file saved from a previous build
AD_ALIGN, // ALIGN: Add to address to make it evenly divisible by this AD_ALIGN, // ALIGN: Add to address to make it evenly divisible by this
AD_MACRO, // MACRO: Create a macro AD_MACRO, // MACRO: Create a macro
@ -280,7 +283,8 @@ enum EvalOperator {
EVOP_SHR, // t, >> EVOP_SHR, // t, >>
EVOP_STP, // u, Unexpected input, should stop and evaluate what we have EVOP_STP, // u, Unexpected input, should stop and evaluate what we have
EVOP_NRY, // v, Not ready yet EVOP_NRY, // v, Not ready yet
EVOP_ERR, // w, Error EVOP_XRF, // w, value from XREF label
EVOP_ERR, // x, Error
}; };
// Opcode encoding // Opcode encoding
@ -515,6 +519,17 @@ const char* aliases_6502[] = {
nullptr, nullptr nullptr, nullptr
}; };
unsigned char timing_6502[] = {
0x0e, 0x0c, 0xff, 0xff, 0xff, 0x06, 0x0a, 0xff, 0x06, 0x04, 0x04, 0xff, 0xff, 0x08, 0x0c, 0xff, 0x05, 0x0b, 0xff, 0xff, 0xff, 0x08, 0x0c, 0xff, 0x04, 0x09, 0xff, 0xff, 0xff, 0x09, 0x0e, 0xff,
0x0c, 0x0c, 0xff, 0xff, 0x06, 0x06, 0x0a, 0xff, 0x08, 0x04, 0x04, 0xff, 0x08, 0x08, 0x0c, 0xff, 0x05, 0x0b, 0xff, 0xff, 0xff, 0x08, 0x0c, 0xff, 0x04, 0x09, 0xff, 0xff, 0xff, 0x09, 0x0e, 0xff,
0x0c, 0x0c, 0xff, 0xff, 0xff, 0x06, 0x0a, 0xff, 0x06, 0x04, 0x04, 0xff, 0x06, 0x08, 0x0c, 0xff, 0x05, 0x0b, 0xff, 0xff, 0xff, 0x08, 0x0c, 0xff, 0x04, 0x09, 0xff, 0xff, 0xff, 0x09, 0x0e, 0xff,
0x0c, 0x0c, 0xff, 0xff, 0xff, 0x06, 0x0a, 0xff, 0x08, 0x04, 0x04, 0xff, 0x0a, 0x08, 0x0c, 0xff, 0x05, 0x0b, 0xff, 0xff, 0xff, 0x08, 0x0c, 0xff, 0x04, 0x09, 0xff, 0xff, 0xff, 0x09, 0x0e, 0xff,
0xff, 0x0c, 0xff, 0xff, 0x06, 0x06, 0x06, 0xff, 0x04, 0xff, 0x04, 0xff, 0x08, 0x08, 0x08, 0xff, 0x05, 0x0c, 0xff, 0xff, 0x08, 0x08, 0x08, 0xff, 0x04, 0x0a, 0x04, 0xff, 0xff, 0x0a, 0xff, 0xff,
0x04, 0x0c, 0x04, 0xff, 0x06, 0x06, 0x06, 0xff, 0x04, 0x04, 0x04, 0xff, 0x08, 0x08, 0x08, 0xff, 0x05, 0x0b, 0xff, 0xff, 0x08, 0x08, 0x08, 0xff, 0x04, 0x09, 0x04, 0xff, 0x09, 0x09, 0x09, 0xff,
0x04, 0x0c, 0xff, 0xff, 0x06, 0x06, 0x0a, 0xff, 0x04, 0x04, 0x04, 0xff, 0x08, 0x08, 0x0c, 0xff, 0x05, 0x0b, 0xff, 0xff, 0xff, 0x08, 0x0c, 0xff, 0x04, 0x09, 0xff, 0xff, 0xff, 0x09, 0x0e, 0xff,
0x04, 0x0c, 0xff, 0xff, 0x06, 0x06, 0x0a, 0xff, 0x04, 0x04, 0x04, 0xff, 0x08, 0x08, 0x0c, 0xff, 0x05, 0x0b, 0xff, 0xff, 0xff, 0x08, 0x0c, 0xff, 0x04, 0x09, 0xff, 0xff, 0xff, 0x09, 0x0e, 0xff
};
static const int num_opcodes_6502 = sizeof(opcodes_6502) / sizeof(opcodes_6502[0]); static const int num_opcodes_6502 = sizeof(opcodes_6502) / sizeof(opcodes_6502[0]);
struct mnem opcodes_65C02[] = { struct mnem opcodes_65C02[] = {
@ -775,12 +790,13 @@ struct CPUDetails {
int num_opcodes; int num_opcodes;
const char* name; const char* name;
const char** aliases; const char** aliases;
const unsigned char *timing;
} aCPUs[] = { } aCPUs[] = {
{ opcodes_6502, num_opcodes_6502 - NUM_ILLEGAL_6502_OPS, "6502", aliases_6502 }, { opcodes_6502, num_opcodes_6502 - NUM_ILLEGAL_6502_OPS, "6502", aliases_6502, timing_6502 },
{ opcodes_6502, num_opcodes_6502, "6502ill", aliases_6502 }, { opcodes_6502, num_opcodes_6502, "6502ill", aliases_6502, timing_6502 },
{ opcodes_65C02, num_opcodes_65C02 - NUM_WDC_65C02_SPECIFIC_OPS, "65C02", aliases_65C02 }, { opcodes_65C02, num_opcodes_65C02 - NUM_WDC_65C02_SPECIFIC_OPS, "65C02", aliases_65C02, nullptr },
{ opcodes_65C02, num_opcodes_65C02, "65C02WDC", aliases_65C02 }, { opcodes_65C02, num_opcodes_65C02, "65C02WDC", aliases_65C02, nullptr },
{ opcodes_65816, num_opcodes_65816, "65816", aliases_65816 }, { opcodes_65816, num_opcodes_65816, "65816", aliases_65816, nullptr },
}; };
static const int nCPUs = sizeof(aCPUs) / sizeof(aCPUs[0]); static const int nCPUs = sizeof(aCPUs) / sizeof(aCPUs[0]);
@ -844,6 +860,7 @@ DirectiveName aDirectiveNames[] {
{ "SEG", AD_SECTION }, // DASM version of SECTION { "SEG", AD_SECTION }, // DASM version of SECTION
{ "LINK", AD_LINK }, { "LINK", AD_LINK },
{ "XDEF", AD_XDEF }, { "XDEF", AD_XDEF },
{ "XREF", AD_XREF },
{ "INCOBJ", AD_INCOBJ }, { "INCOBJ", AD_INCOBJ },
{ "ALIGN", AD_ALIGN }, { "ALIGN", AD_ALIGN },
{ "MACRO", AD_MACRO }, { "MACRO", AD_MACRO },
@ -1171,6 +1188,7 @@ public:
bool pc_relative; // this is an inline label describing a point in the code bool pc_relative; // this is an inline label describing a point in the code
bool constant; // the value of this label can not change bool constant; // the value of this label can not change
bool external; // this label is globally accessible bool external; // this label is globally accessible
bool reference; // this label is accessed from external and can't be used for evaluation locally
} Label; } Label;
// If an expression can't be evaluated immediately, this is required // If an expression can't be evaluated immediately, this is required
@ -1348,7 +1366,7 @@ public:
strref last_label; // most recently defined label for Merlin macro strref last_label; // most recently defined label for Merlin macro
bool accumulator_16bit; // 65816 specific software dependent immediate mode bool accumulator_16bit; // 65816 specific software dependent immediate mode
bool index_reg_16bit; // -"- bool index_reg_16bit; // -"-
bool errorEncountered; // if any error encountered, don't export binary bool error_encountered; // if any error encountered, don't export binary
bool list_assembly; // generate assembler listing bool list_assembly; // generate assembler listing
bool end_macro_directive; // whether to use { } or macro / endmacro for macro scope bool end_macro_directive; // whether to use { } or macro / endmacro for macro scope
bool link_all_section; // link all known relative sections to this section at end bool link_all_section; // link all known relative sections to this section at end
@ -1437,7 +1455,7 @@ public:
strref source_file, LateEval::Type type); strref source_file, LateEval::Type type);
void AddLateEval(strref label, int pc, int scope_pc, void AddLateEval(strref label, int pc, int scope_pc,
strref expression, LateEval::Type type); strref expression, LateEval::Type type);
StatusCode CheckLateEval(strref added_label = strref(), int scope_end = -1); StatusCode CheckLateEval(strref added_label = strref(), int scope_end = -1, bool missing_is_error = false);
// Assembler Directives // Assembler Directives
StatusCode ApplyDirective(AssemblerDirective dir, strref line, strref source_file); StatusCode ApplyDirective(AssemblerDirective dir, strref line, strref source_file);
@ -1514,7 +1532,7 @@ void Asm::Cleanup() {
conditional_depth = 0; conditional_depth = 0;
conditional_nesting[0] = 0; conditional_nesting[0] = 0;
conditional_consumed[0] = false; conditional_consumed[0] = false;
errorEncountered = false; error_encountered = false;
list_assembly = false; list_assembly = false;
end_macro_directive = false; end_macro_directive = false;
accumulator_16bit = false; // default 65816 8 bit immediate mode accumulator_16bit = false; // default 65816 8 bit immediate mode
@ -2361,9 +2379,10 @@ StatusCode Asm::BuildEnum(strref name, strref declaration)
line = line.before_or_full(','); line = line.before_or_full(',');
line.trim_whitespace(); line.trim_whitespace();
strref name = line.split_token_trim('='); strref name = line.split_token_trim('=');
line = line.before(';').before(c_comment).get_trimmed_ws();
if (line) { if (line) {
StatusCode error = EvalExpression(line, etx, value); StatusCode error = EvalExpression(line, etx, value);
if (error == STATUS_NOT_READY) if (error == STATUS_NOT_READY || error == STATUS_XREF_DEPENDENT)
return ERROR_ENUM_CANT_BE_ASSEMBLED; return ERROR_ENUM_CANT_BE_ASSEMBLED;
else if (error != STATUS_OK) else if (error != STATUS_OK)
return error; return error;
@ -2619,7 +2638,7 @@ EvalOperator Asm::RPNToken(strref &exp, const struct EvalContext &etx, EvalOpera
if (ret != STATUS_NOT_STRUCT) return EVOP_ERR; // partial struct if (ret != STATUS_NOT_STRUCT) return EVOP_ERR; // partial struct
} }
if (!pLabel || !pLabel->evaluated) return EVOP_NRY; // this label could not be found (yet) if (!pLabel || !pLabel->evaluated) return EVOP_NRY; // this label could not be found (yet)
value = pLabel->value; section = pLabel->section; return EVOP_VAL; value = pLabel->value; section = pLabel->section; return pLabel->reference ? EVOP_XRF : EVOP_VAL;
} }
return EVOP_ERR; return EVOP_ERR;
} }
@ -2652,6 +2671,7 @@ StatusCode Asm::EvalExpression(strref expression, const struct EvalContext &etx,
short section_ids[MAX_EVAL_SECTIONS]; // local index of each referenced section short section_ids[MAX_EVAL_SECTIONS]; // local index of each referenced section
short section_val[MAX_EVAL_VALUES] = { 0 }; // each value can be assigned to one section, or -1 if fixed short section_val[MAX_EVAL_VALUES] = { 0 }; // each value can be assigned to one section, or -1 if fixed
short num_sections = 0; // number of sections in section_ids (normally 0 or 1, can be up to MAX_EVAL_SECTIONS) short num_sections = 0; // number of sections in section_ids (normally 0 or 1, can be up to MAX_EVAL_SECTIONS)
bool xrefd = false;
values[0] = 0; // Initialize RPN if no expression values[0] = 0; // Initialize RPN if no expression
{ {
int sp = 0; int sp = 0;
@ -2670,6 +2690,10 @@ StatusCode Asm::EvalExpression(strref expression, const struct EvalContext &etx,
return ERROR_UNEXPECTED_CHARACTER_IN_EXPRESSION; return ERROR_UNEXPECTED_CHARACTER_IN_EXPRESSION;
else if (op == EVOP_NRY) else if (op == EVOP_NRY)
return STATUS_NOT_READY; return STATUS_NOT_READY;
else if (op == EVOP_XRF) {
xrefd = true;
op = EVOP_VAL;
}
if (section >= 0) { if (section >= 0) {
for (int s = 0; s<num_sections && index_section<0; s++) { for (int s = 0; s<num_sections && index_section<0; s++) {
if (section_ids[s] == section) index_section = s; if (section_ids[s] == section) index_section = s;
@ -2724,6 +2748,11 @@ StatusCode Asm::EvalExpression(strref expression, const struct EvalContext &etx,
ops[numOps++] = op_stack[sp]; ops[numOps++] = op_stack[sp];
} }
} }
// Check if dependent on XREF'd symbol
if (xrefd)
return STATUS_XREF_DEPENDENT;
// processing the result RPN will put the completed expression into values[0]. // processing the result RPN will put the completed expression into values[0].
// values is used as both the queue and the stack of values since reads/writes won't // values is used as both the queue and the stack of values since reads/writes won't
// exceed itself. // exceed itself.
@ -2891,7 +2920,7 @@ void Asm::AddLateEval(strref label, int pc, int scope_pc, strref expression, Lat
// When a label is defined or a scope ends check if there are // When a label is defined or a scope ends check if there are
// any related late label evaluators that can now be evaluated. // any related late label evaluators that can now be evaluated.
StatusCode Asm::CheckLateEval(strref added_label, int scope_end) StatusCode Asm::CheckLateEval(strref added_label, int scope_end, bool print_missing_reference_errors)
{ {
bool evaluated_label = true; bool evaluated_label = true;
strref new_labels[MAX_LABELS_EVAL_ALL]; strref new_labels[MAX_LABELS_EVAL_ALL];
@ -3031,8 +3060,13 @@ StatusCode Asm::CheckLateEval(strref added_label, int scope_end)
} }
if (resolved) if (resolved)
i = lateEval.erase(i); i = lateEval.erase(i);
} else } else {
if (print_missing_reference_errors && ret!=STATUS_XREF_DEPENDENT) {
PrintError(i->expression, ret);
error_encountered = true;
}
++i; ++i;
}
} else } else
++i; ++i;
} }
@ -3255,6 +3289,7 @@ StatusCode Asm::AssignPoolLabel(LabelPool &pool, strref label)
pLabel->pc_relative = true; pLabel->pc_relative = true;
pLabel->constant = true; pLabel->constant = true;
pLabel->external = false; pLabel->external = false;
pLabel->reference = false;
MarkLabelLocal(label, true); MarkLabelLocal(label, true);
return error; return error;
@ -3365,6 +3400,7 @@ StatusCode Asm::AssignLabel(strref label, strref line, bool make_constant)
pLabel->pc_relative = false; pLabel->pc_relative = false;
pLabel->constant = make_constant; pLabel->constant = make_constant;
pLabel->external = MatchXDEF(label); pLabel->external = MatchXDEF(label);
pLabel->reference = false;
bool local = label[0]=='.' || label[0]=='@' || label[0]=='!' || label[0]==':' || label.get_last()=='$'; bool local = label[0]=='.' || label[0]=='@' || label[0]=='!' || label[0]==':' || label.get_last()=='$';
if (!pLabel->evaluated) if (!pLabel->evaluated)
@ -3398,6 +3434,7 @@ StatusCode Asm::AddressLabel(strref label)
pLabel->evaluated = true; pLabel->evaluated = true;
pLabel->pc_relative = true; pLabel->pc_relative = true;
pLabel->external = MatchXDEF(label); pLabel->external = MatchXDEF(label);
pLabel->reference = false;
pLabel->constant = constLabel; pLabel->constant = constLabel;
last_label = label; last_label = label;
bool local = label[0]=='.' || label[0]=='@' || label[0]=='!' || label[0]==':' || label.get_last()=='$'; bool local = label[0]=='.' || label[0]=='@' || label[0]=='!' || label[0]==':' || label.get_last()=='$';
@ -3783,10 +3820,9 @@ StatusCode Asm::Directive_ORG(strref line)
struct EvalContext etx(CurrSection().GetPC(), scope_address[scope_depth], -1, -1); struct EvalContext etx(CurrSection().GetPC(), scope_address[scope_depth], -1, -1);
StatusCode error = EvalExpression(line, etx, addr); StatusCode error = EvalExpression(line, etx, addr);
if (error != STATUS_OK) { if (error != STATUS_OK)
error = error == STATUS_NOT_READY ? ERROR_TARGET_ADDRESS_MUST_EVALUATE_IMMEDIATELY : error; return (error == STATUS_NOT_READY || error == STATUS_XREF_DEPENDENT) ?
return error; ERROR_TARGET_ADDRESS_MUST_EVALUATE_IMMEDIATELY : error;
}
// Section immediately followed by ORG reassigns that section to be fixed // Section immediately followed by ORG reassigns that section to be fixed
if (CurrSection().size()==0 && !CurrSection().IsDummySection()) { if (CurrSection().size()==0 && !CurrSection().IsDummySection()) {
@ -3810,7 +3846,8 @@ StatusCode Asm::Directive_LOAD(strref line)
struct EvalContext etx(CurrSection().GetPC(), scope_address[scope_depth], -1, -1); struct EvalContext etx(CurrSection().GetPC(), scope_address[scope_depth], -1, -1);
StatusCode error = EvalExpression(line, etx, addr); StatusCode error = EvalExpression(line, etx, addr);
if (error != STATUS_OK) if (error != STATUS_OK)
return error == STATUS_NOT_READY ? ERROR_TARGET_ADDRESS_MUST_EVALUATE_IMMEDIATELY : error; return (error == STATUS_NOT_READY || error == STATUS_XREF_DEPENDENT) ?
ERROR_TARGET_ADDRESS_MUST_EVALUATE_IMMEDIATELY : error;
CurrSection().SetLoadAddress(addr); CurrSection().SetLoadAddress(addr);
return STATUS_OK; return STATUS_OK;
@ -3881,7 +3918,7 @@ StatusCode Asm::ApplyDirective(AssemblerDirective dir, strref line, strref sourc
case AD_LOAD: case AD_LOAD:
return Directive_LOAD(line); return Directive_LOAD(line);
case AD_SECTION: case AD_SECTION:
SetSection(line.get_trimmed_ws()); SetSection(line.get_trimmed_ws());
break; break;
@ -3903,6 +3940,23 @@ StatusCode Asm::ApplyDirective(AssemblerDirective dir, strref line, strref sourc
case AD_XDEF: case AD_XDEF:
return Directive_XDEF(line.get_trimmed_ws()); return Directive_XDEF(line.get_trimmed_ws());
case AD_XREF: {
strref label = line.split_range_trim(syntax==SYNTAX_MERLIN ? label_end_char_range_merlin : label_end_char_range);
if (Label *pXRefLabel = GetLabel(label))
break; // XREF already defined label => no action
Label *pLabelXREF = AddLabel(label.fnv1a());
pLabelXREF->label_name = label;
pLabelXREF->pool_name.clear();
pLabelXREF->section = -1; // address labels are based on section
pLabelXREF->value = 0;
pLabelXREF->evaluated = true;
pLabelXREF->pc_relative = true;
pLabelXREF->external = false;
pLabelXREF->constant = false;
pLabelXREF->reference = true;
break;
}
case AD_ENT: // MERLIN version of xdef, makes most recently defined label external case AD_ENT: // MERLIN version of xdef, makes most recently defined label external
if (Label *pLastLabel = GetLabel(last_label)) if (Label *pLastLabel = GetLabel(last_label))
pLastLabel->external = true; pLastLabel->external = true;
@ -3914,7 +3968,7 @@ StatusCode Asm::ApplyDirective(AssemblerDirective dir, strref line, strref sourc
line.next_word_ws(); line.next_word_ws();
int value; int value;
int status = EvalExpression(line, etx, value); int status = EvalExpression(line, etx, value);
if (status == STATUS_NOT_READY) if (status == STATUS_NOT_READY || error == STATUS_XREF_DEPENDENT)
error = ERROR_ALIGN_MUST_EVALUATE_IMMEDIATELY; error = ERROR_ALIGN_MUST_EVALUATE_IMMEDIATELY;
else if (status == STATUS_OK && value>0) { else if (status == STATUS_OK && value>0) {
if (CurrSection().address_assigned) { if (CurrSection().address_assigned) {
@ -3955,9 +4009,9 @@ StatusCode Asm::ApplyDirective(AssemblerDirective dir, strref line, strref sourc
if (syntax==SYNTAX_MERLIN && exp.get_first()=='#') // MERLIN allows for an immediate declaration on data if (syntax==SYNTAX_MERLIN && exp.get_first()=='#') // MERLIN allows for an immediate declaration on data
++exp; ++exp;
error = EvalExpression(exp, etx, value); error = EvalExpression(exp, etx, value);
if (error>STATUS_NOT_READY) if (error>STATUS_XREF_DEPENDENT)
break; break;
else if (error==STATUS_NOT_READY) else if (error==STATUS_NOT_READY || error == STATUS_XREF_DEPENDENT)
AddLateEval(CurrSection().DataOffset(), CurrSection().GetPC(), scope_address[scope_depth], exp, source_file, LateEval::LET_BYTE); AddLateEval(CurrSection().DataOffset(), CurrSection().GetPC(), scope_address[scope_depth], exp, source_file, LateEval::LET_BYTE);
else if (error == STATUS_RELATIVE_SECTION) else if (error == STATUS_RELATIVE_SECTION)
CurrSection().AddReloc(lastEvalValue, CurrSection().DataOffset(), lastEvalSection, CurrSection().AddReloc(lastEvalValue, CurrSection().DataOffset(), lastEvalSection,
@ -3972,9 +4026,9 @@ StatusCode Asm::ApplyDirective(AssemblerDirective dir, strref line, strref sourc
if (syntax==SYNTAX_MERLIN && exp_w.get_first()=='#') // MERLIN allows for an immediate declaration on data if (syntax==SYNTAX_MERLIN && exp_w.get_first()=='#') // MERLIN allows for an immediate declaration on data
++exp_w; ++exp_w;
error = EvalExpression(exp_w, etx, value); error = EvalExpression(exp_w, etx, value);
if (error>STATUS_NOT_READY) if (error>STATUS_XREF_DEPENDENT)
break; break;
else if (error==STATUS_NOT_READY) else if (error==STATUS_NOT_READY || error == STATUS_XREF_DEPENDENT)
AddLateEval(CurrSection().DataOffset(), CurrSection().DataOffset(), scope_address[scope_depth], exp_w, source_file, LateEval::LET_ABS_REF); AddLateEval(CurrSection().DataOffset(), CurrSection().DataOffset(), scope_address[scope_depth], exp_w, source_file, LateEval::LET_ABS_REF);
else if (error == STATUS_RELATIVE_SECTION) { else if (error == STATUS_RELATIVE_SECTION) {
CurrSection().AddReloc(lastEvalValue, CurrSection().DataOffset(), lastEvalSection, lastEvalPart); CurrSection().AddReloc(lastEvalValue, CurrSection().DataOffset(), lastEvalSection, lastEvalPart);
@ -3993,9 +4047,9 @@ StatusCode Asm::ApplyDirective(AssemblerDirective dir, strref line, strref sourc
if (syntax==SYNTAX_MERLIN && exp_w.get_first()=='#') // MERLIN allows for an immediate declaration on data if (syntax==SYNTAX_MERLIN && exp_w.get_first()=='#') // MERLIN allows for an immediate declaration on data
++exp_w; ++exp_w;
error = EvalExpression(exp_w, etx, value); error = EvalExpression(exp_w, etx, value);
if (error>STATUS_NOT_READY) if (error>STATUS_XREF_DEPENDENT)
break; break;
else if (error==STATUS_NOT_READY) else if (error==STATUS_NOT_READY || error == STATUS_XREF_DEPENDENT)
AddLateEval(CurrSection().DataOffset(), CurrSection().DataOffset(), scope_address[scope_depth], exp_w, source_file, dir==AD_ADR ? LateEval::LET_ABS_L_REF : LateEval::LET_ABS_4_REF); AddLateEval(CurrSection().DataOffset(), CurrSection().DataOffset(), scope_address[scope_depth], exp_w, source_file, dir==AD_ADR ? LateEval::LET_ABS_L_REF : LateEval::LET_ABS_4_REF);
else if (error == STATUS_RELATIVE_SECTION) { else if (error == STATUS_RELATIVE_SECTION) {
CurrSection().AddReloc(lastEvalValue, CurrSection().DataOffset(), lastEvalSection, lastEvalPart); CurrSection().AddReloc(lastEvalValue, CurrSection().DataOffset(), lastEvalSection, lastEvalPart);
@ -4028,9 +4082,9 @@ StatusCode Asm::ApplyDirective(AssemblerDirective dir, strref line, strref sourc
if (syntax==SYNTAX_MERLIN && exp_dc.get_first()=='#') // MERLIN allows for an immediate declaration on data if (syntax==SYNTAX_MERLIN && exp_dc.get_first()=='#') // MERLIN allows for an immediate declaration on data
++exp_dc; ++exp_dc;
error = EvalExpression(exp_dc, etx, value); error = EvalExpression(exp_dc, etx, value);
if (error > STATUS_NOT_READY) if (error > STATUS_XREF_DEPENDENT)
break; break;
else if (error == STATUS_NOT_READY) else if (error == STATUS_NOT_READY || error == STATUS_XREF_DEPENDENT)
AddLateEval(CurrSection().DataOffset(), CurrSection().GetPC(), scope_address[scope_depth], exp_dc, source_file, words ? LateEval::LET_ABS_REF : LateEval::LET_BYTE); AddLateEval(CurrSection().DataOffset(), CurrSection().GetPC(), scope_address[scope_depth], exp_dc, source_file, words ? LateEval::LET_ABS_REF : LateEval::LET_BYTE);
else if (error == STATUS_RELATIVE_SECTION) { else if (error == STATUS_RELATIVE_SECTION) {
value = 0; value = 0;
@ -4419,7 +4473,7 @@ StatusCode Asm::AddOpcode(strref line, int index, strref source_file)
struct EvalContext etx(CurrSection().GetPC(), scope_address[scope_depth], -1, struct EvalContext etx(CurrSection().GetPC(), scope_address[scope_depth], -1,
!!(validModes & AMM_BRANCH) ? SectionId() : -1); !!(validModes & AMM_BRANCH) ? SectionId() : -1);
error = EvalExpression(expression, etx, value); error = EvalExpression(expression, etx, value);
if (error == STATUS_NOT_READY) { if (error == STATUS_NOT_READY || error == STATUS_XREF_DEPENDENT) {
evalLater = true; evalLater = true;
error = STATUS_OK; error = STATUS_OK;
} else if (error == STATUS_RELATIVE_SECTION) { } else if (error == STATUS_RELATIVE_SECTION) {
@ -4588,7 +4642,7 @@ StatusCode Asm::AddOpcode(strref line, int index, strref source_file)
struct EvalContext etx(CurrSection().GetPC()-2, scope_address[scope_depth], -1, -1); struct EvalContext etx(CurrSection().GetPC()-2, scope_address[scope_depth], -1, -1);
line.split_token_trim(','); line.split_token_trim(',');
error = EvalExpression(line, etx, value); error = EvalExpression(line, etx, value);
if (error==STATUS_NOT_READY) if (error==STATUS_NOT_READY || error == STATUS_XREF_DEPENDENT)
AddLateEval(CurrSection().DataOffset(), CurrSection().GetPC(), scope_address[scope_depth], line, source_file, LateEval::LET_BYTE); AddLateEval(CurrSection().DataOffset(), CurrSection().GetPC(), scope_address[scope_depth], line, source_file, LateEval::LET_BYTE);
AddByte(value); AddByte(value);
break; break;
@ -4617,11 +4671,12 @@ StatusCode Asm::AddOpcode(strref line, int index, strref source_file)
AddByte(value); AddByte(value);
struct EvalContext etx(CurrSection().GetPC()-2, scope_address[scope_depth], -1, SectionId()); struct EvalContext etx(CurrSection().GetPC()-2, scope_address[scope_depth], -1, SectionId());
error = EvalExpression(line, etx, value); error = EvalExpression(line, etx, value);
if (error==STATUS_NOT_READY) if (error==STATUS_NOT_READY || error == STATUS_XREF_DEPENDENT)
AddLateEval(CurrSection().DataOffset(), CurrSection().GetPC(), scope_address[scope_depth], line, source_file, LateEval::LET_BRANCH); AddLateEval(CurrSection().DataOffset(), CurrSection().GetPC(), scope_address[scope_depth], line, source_file, LateEval::LET_BRANCH);
else if (((int)value - (int)CurrSection().GetPC() - 1) < -128 || ((int)value - (int)CurrSection().GetPC() - 1) > 127) else if (((int)value - (int)CurrSection().GetPC() - 1) < -128 || ((int)value - (int)CurrSection().GetPC() - 1) > 127)
error = ERROR_BRANCH_OUT_OF_RANGE; error = ERROR_BRANCH_OUT_OF_RANGE;
AddByte(error == STATUS_NOT_READY ? 0 : (unsigned char)((int)value - (int)CurrSection().GetPC()) - 1); AddByte((error == STATUS_NOT_READY || error == STATUS_XREF_DEPENDENT) ?
0 : (unsigned char)((int)value - (int)CurrSection().GetPC()) - 1);
break; break;
} }
case CA_NONE: case CA_NONE:
@ -4646,7 +4701,7 @@ void Asm::PrintError(strref line, StatusCode error)
errorText.append("\"\n"); errorText.append("\"\n");
errorText.c_str(); errorText.c_str();
fwrite(errorText.get(), errorText.get_len(), 1, stderr); fwrite(errorText.get(), errorText.get_len(), 1, stderr);
errorEncountered = true; error_encountered = true;
} }
// Build a line of code // Build a line of code
@ -4805,7 +4860,7 @@ StatusCode Asm::BuildLine(strref line)
if (line.same_str_case(line_start)) if (line.same_str_case(line_start))
error = ERROR_UNABLE_TO_PROCESS; error = ERROR_UNABLE_TO_PROCESS;
if (error > STATUS_NOT_READY) if (error > STATUS_XREF_DEPENDENT)
PrintError(line_start, error); PrintError(line_start, error);
// dealt with error, continue with next instruction unless too broken // dealt with error, continue with next instruction unless too broken
@ -4907,7 +4962,7 @@ bool Asm::List(strref filename)
if (line_fix[pos] == '\t') if (line_fix[pos] == '\t')
line_fix.exchange(pos, 1, pos & 1 ? strref(" ") : strref(" ")); line_fix.exchange(pos, 1, pos & 1 ? strref(" ") : strref(" "));
} }
out.append_to(' ', 30); out.append_to(' ', aCPUs[cpu].timing ? 36 : 33);
out.append(line_fix.get_strref()); out.append(line_fix.get_strref());
fprintf(f, STRREF_FMT "\n", STRREF_ARG(out)); fprintf(f, STRREF_FMT "\n", STRREF_ARG(out));
out.clear(); out.clear();
@ -4952,9 +5007,13 @@ bool Asm::List(strref filename)
out.sprintf_append("%s #$%04x", opcode_table[op].instr, buf[1] | (buf[2]<<8)); out.sprintf_append("%s #$%04x", opcode_table[op].instr, buf[1] | (buf[2]<<8));
else else
out.sprintf_append(fmt, opcode_table[op].instr, buf[1]); out.sprintf_append(fmt, opcode_table[op].instr, buf[1]);
if (aCPUs[cpu].timing) {
out.append_to(' ', 33);
out.sprintf_append("%x%s", aCPUs[cpu].timing[*buf] / 2, (aCPUs[cpu].timing[*buf] & 1) ? "+" : "");
}
} }
} }
out.append_to(' ', 33); out.append_to(' ', aCPUs[cpu].timing ? 36 : 33);
strref line = lst.code.get_skipped(lst.line_offs).get_line(); strref line = lst.code.get_skipped(lst.line_offs).get_line();
line.clip_trailing_whitespace(); line.clip_trailing_whitespace();
strown<128> line_fix(line); strown<128> line_fix(line);
@ -5043,12 +5102,13 @@ void Asm::Assemble(strref source, strref filename, bool obj_target)
LinkAllToSection(); LinkAllToSection();
if (error == STATUS_OK) { if (error == STATUS_OK) {
error = CheckLateEval(); error = CheckLateEval();
if (error > STATUS_NOT_READY) { if (error > STATUS_XREF_DEPENDENT) {
strown<512> errorText; strown<512> errorText;
errorText.copy("Error: "); errorText.copy("Error: ");
errorText.append(aStatusStrings[error]); errorText.append(aStatusStrings[error]);
fwrite(errorText.get(), errorText.get_len(), 1, stderr); fwrite(errorText.get(), errorText.get_len(), 1, stderr);
} } else
CheckLateEval(strref(), -1, true); // output any missing xref's
if (!obj_target) { if (!obj_target) {
for (std::vector<LateEval>::iterator i = lateEval.begin(); i!=lateEval.end(); ++i) { for (std::vector<LateEval>::iterator i = lateEval.begin(); i!=lateEval.end(); ++i) {
@ -5193,11 +5253,18 @@ StatusCode Asm::WriteObjectFile(strref filename)
hdr.relocs += short(s->pRelocs->size()); hdr.relocs += short(s->pRelocs->size());
hdr.bindata += (int)s->size(); hdr.bindata += (int)s->size();
} }
hdr.labels = labels.count();
hdr.late_evals = (short)lateEval.size(); hdr.late_evals = (short)lateEval.size();
hdr.map_symbols = (short)map.size(); hdr.map_symbols = (short)map.size();
hdr.stringdata = 0; hdr.stringdata = 0;
// labels don't include XREF labels
hdr.labels = 0;
for (unsigned int l = 0; l<labels.count(); l++) {
if (!labels.getValue(l).reference)
hdr.labels++;
}
// include space for external protected labels // include space for external protected labels
for (std::vector<ExtLabels>::iterator el = externals.begin(); el != externals.end(); ++el) for (std::vector<ExtLabels>::iterator el = externals.begin(); el != externals.end(); ++el)
hdr.labels += el->labels.count(); hdr.labels += el->labels.count();
@ -5244,16 +5311,18 @@ StatusCode Asm::WriteObjectFile(strref filename)
if (hdr.labels) { if (hdr.labels) {
for (unsigned int li = 0; li<labels.count(); li++) { for (unsigned int li = 0; li<labels.count(); li++) {
Label &lo = labels.getValue(li); Label &lo = labels.getValue(li);
struct ObjFileLabel &l = aLabels[labs++]; if (!lo.reference) {
l.name.offs = _AddStrPool(lo.label_name, &stringArray, &stringPool, hdr.stringdata, stringPoolCap); struct ObjFileLabel &l = aLabels[labs++];
l.value = lo.value; l.name.offs = _AddStrPool(lo.label_name, &stringArray, &stringPool, hdr.stringdata, stringPoolCap);
l.section = lo.section; l.value = lo.value;
l.mapIndex = lo.mapIndex; l.section = lo.section;
l.flags = l.mapIndex = lo.mapIndex;
(lo.constant ? ObjFileLabel::OFL_CNST : 0) | l.flags =
(lo.pc_relative ? ObjFileLabel::OFL_ADDR : 0) | (lo.constant ? ObjFileLabel::OFL_CNST : 0) |
(lo.evaluated ? ObjFileLabel::OFL_EVAL : 0) | (lo.pc_relative ? ObjFileLabel::OFL_ADDR : 0) |
(lo.external ? ObjFileLabel::OFL_XDEF : 0); (lo.evaluated ? ObjFileLabel::OFL_EVAL : 0) |
(lo.external ? ObjFileLabel::OFL_XDEF : 0);
}
} }
} }
@ -5609,7 +5678,7 @@ int main(int argc, char **argv)
assembler.Assemble(strref(buffer, strl_t(size)), srcname, obj_out_file != nullptr); assembler.Assemble(strref(buffer, strl_t(size)), srcname, obj_out_file != nullptr);
if (assembler.errorEncountered) if (assembler.error_encountered)
return_value = 1; return_value = 1;
else { else {
// export object file // export object file