1
0
mirror of https://github.com/ksherlock/x65.git synced 2024-06-12 07:29:28 +00:00

Leftover fixes

- added -acc=16 and -xy=16 command line options for 65816 immediate mode
instruction size
- added conditional expressions (evaluates to 0 for false and 1 for
true)
- fixed macro substitution to be whole word only
This commit is contained in:
Carl-Henrik Skårstedt 2015-10-25 23:48:35 -07:00
parent c2c6aaef0f
commit 72b9842354
2 changed files with 240 additions and 156 deletions

View File

@ -49,6 +49,8 @@ x65 filename.s code.prg [options]
* -i(path): Add include path
* -D(label)[=(value)]: Define a label with an optional value (otherwise defined as 1)
* -cpu=6502/6502ill/65c02/65c02wdc/65816: assemble with opcodes for a different cpu
* -acc=8/16: start assembling with accumulator immediate mode instruction size 8 or 16 bits
* -xy=8/16: start assembling with index register immediate mode instruction size 8 or 16 bits
* -obj (file.x65): generate object file for later linking
* -bin: Raw binary
* -c64: Include load address (default)
@ -83,7 +85,7 @@ In order to manage more complex projects linking multiple assembled object files
Comments are currently line based and both ';' and '//' are accepted as delimiters.
### <a name="expressions">Expressions
### Expressions
Anywhere a number can be entered it can also be interpreted as a full expression, for example:
@ -336,20 +338,20 @@ incbin "wizfx.gfx"
Insert multiple types of data or code at the current address. Import takes an additional parameter to determine what to do with the file data, and can accept reading in a portion of binary data.
The options for import are:
* source: same as **INCLUDE**
* binary: same as **INCBIN**
* c64: same as **INCBIN** but skip first two bytes of file as if this was a c64 prg file
* text: include text data from another file, default is petscii otherwise add another directive from the **TEXT** directive
* object: same as **INCOBJ**
* symbols: same as **INCSYM**, specify list of desired symbols prior to filename.
After the filename for binary and c64 files follow comma separated values for skip data size and max load size. c64 mode will add the two extra bytes to the skip size.
```
import source "EQ.S"
import binary "GFX.BIN",0,256
import c64 "FONT.BIN",8,8*26
import text petscii_shifted "LICENSE.TXT"
* source: same as **INCLUDE**
* binary: same as **INCBIN**
* c64: same as **INCBIN** but skip first two bytes of file as if this was a c64 prg file
* text: include text data from another file, default is petscii otherwise add another directive from the **TEXT** directive
* object: same as **INCOBJ**
* symbols: same as **INCSYM**, specify list of desired symbols prior to filename.
After the filename for binary and c64 files follow comma separated values for skip data size and max load size. c64 mode will add the two extra bytes to the skip size.
```
import source "EQ.S"
import binary "GFX.BIN",0,256
import c64 "FONT.BIN",8,8*26
import text petscii_shifted "LICENSE.TXT"
import object "engine.x65"
import symbols InitEffect, UpdateEffect "effect.sym"
```
@ -648,6 +650,14 @@ Expressions contain values, such as labels or raw numbers and operators includin
* $: Precedes hexadecimal value
* %: If immediately followed by '0' or '1' this is a binary value and not scope closure address
**Conditional operators**
* ==: Double equal signs yields 1 if left value is the same as the right value
* <: If inbetween two values, less than will yield 1 if left value is less than right value
* >: If inbetween two values, greater than will yield 1 if left value is greater than right value
* <=: If inbetween two values, less than or equal will yield 1 if left value is less than or equal to right value
* >=: If inbetween two values, greater than or equal will yield 1 if left value is greater than or equal to right value
Example:
```
@ -655,6 +665,18 @@ lda #(((>SCREEN_MATRIX)&$3c)*4)+8
sta $d018
```
Avoid using parenthesis as the first character of the parameter of an opcode that can be relative addressed instead of an absolute address. This can be avoided by
```
jmp (a+b) ; generates a relative jump
jmp.a (a+b) ; generates an absolute jump
jmp +(a+b) ; generates an absolute jump
c = (a+b)
jmp c ; generates an absolute jump
jmp a+b ; generates an absolute jump
```
## <a name="macro">Macros
A macro can be defined by the using the directive macro and includes the line within the following scope:
@ -756,12 +778,12 @@ FindFirstSpace
Currently the assembler is in a limited release and while all features are in place and tested, more testing is needed to verify the completeness. 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**
* Set 65816 immediate op size on command line for files that make that assumption
* Macro parameters should replace only whole words instead of any substring
* irp (indefinite repeat)
* boolean operators (==, <, >, etc.) for better conditional expressions
**FIXED**
* Macro parameters should replace only whole words instead of any substring
* boolean operators (==, <, >, etc.) for better conditional expressions
* Set 65816 immediate op size on command line for files that make that assumption
* Merlin specific directives are not available in non-merlin syntax mode to avoid confusion
* Merlin macros use ]1, ]2, ]3 as arguments instead of the parameter list after [**MAC**](#merlin)
* -endm option also affects [**REPT**](#rept)

338
x65.cpp
View File

@ -255,23 +255,28 @@ enum OperationType {
enum EvalOperator {
EVOP_NONE,
EVOP_VAL = 'a', // a, value => read from value queue
EVOP_LPR, // b, left parenthesis
EVOP_RPR, // c, right parenthesis
EVOP_ADD, // d, +
EVOP_SUB, // e, -
EVOP_MUL, // f, * (note: if not preceded by value or right paren this is current PC)
EVOP_DIV, // g, /
EVOP_AND, // h, &
EVOP_OR, // i, |
EVOP_EOR, // j, ^
EVOP_SHL, // k, <<
EVOP_SHR, // l, >>
EVOP_LOB, // m, low byte of 16 bit value
EVOP_HIB, // n, high byte of 16 bit value
EVOP_BAB, // o, bank byte of 24 bit value
EVOP_STP, // p, Unexpected input, should stop and evaluate what we have
EVOP_NRY, // q, Not ready yet
EVOP_ERR, // r, Error
EVOP_EQU, // b, 1 if left equal to right otherwise 0
EVOP_LT, // c, 1 if left less than right otherwise 0
EVOP_GT, // d, 1 if left greater than right otherwise 0
EVOP_LTE, // e, 1 if left less than or equal to right otherwise 0
EVOP_GTE, // f, 1 if left greater than or equal to right otherwise 0
EVOP_LPR, // g, left parenthesis
EVOP_RPR, // h, right parenthesis
EVOP_ADD, // i, +
EVOP_SUB, // j, -
EVOP_MUL, // k, * (note: if not preceded by value or right paren this is current PC)
EVOP_DIV, // l, /
EVOP_AND, // m, &
EVOP_OR, // n, |
EVOP_EOR, // o, ^
EVOP_SHL, // p, <<
EVOP_SHR, // q, >>
EVOP_LOB, // r, low byte of 16 bit value
EVOP_HIB, // s, high byte of 16 bit value
EVOP_BAB, // t, bank byte of 24 bit value
EVOP_STP, // u, Unexpected input, should stop and evaluate what we have
EVOP_NRY, // v, Not ready yet
EVOP_ERR, // w, Error
};
// Opcode encoding
@ -1367,6 +1372,10 @@ public:
StatusCode WriteObjectFile(strref filename); // write x65 object file
StatusCode ReadObjectFile(strref filename); // read x65 object file
// Scope management
StatusCode EnterScope();
StatusCode ExitScope();
// Macro management
StatusCode AddMacro(strref macro, strref source_name, strref source_file, strref &left);
StatusCode BuildMacro(Macro &m, strref arg_list);
@ -1419,8 +1428,8 @@ public:
StatusCode Directive_Import(strref line);
// Assembler steps
StatusCode GetAddressMode(strref line, bool flipXY, AddrMode &addrMode,
int &len, strref &expression);
StatusCode GetAddressMode(strref line, bool flipXY, unsigned int validModes,
AddrMode &addrMode, int &len, strref &expression);
StatusCode AddOpcode(strref line, int index, strref source_file);
StatusCode BuildLine(strref line);
StatusCode BuildSegment();
@ -1554,10 +1563,6 @@ void Asm::SetCPU(CPUIndex CPU) {
opcode_count = aCPUs[CPU].num_opcodes;
num_instructions = BuildInstructionTable(aInstructions, MAX_OPCODES_DIRECTIVES, opcode_table,
opcode_count, aCPUs[CPU].aliases, syntax == SYNTAX_MERLIN);
if (CPU != CPU_65816) {
accumulator_16bit = false;
index_reg_16bit = false;
}
}
// Read in text data (main source, include, etc.)
@ -2044,6 +2049,33 @@ void Asm::CheckOutputCapacity(unsigned int addSize) {
}
//
//
// SCOPE MANAGEMENT
//
//
StatusCode Asm::EnterScope()
{
if (scope_depth >= (MAX_SCOPE_DEPTH - 1))
return ERROR_TOO_DEEP_SCOPE;
scope_address[++scope_depth] = CurrSection().GetPC();
return STATUS_OK;
}
StatusCode Asm::ExitScope()
{
CheckLateEval(strref(), CurrSection().GetPC());
FlushLocalLabels(scope_depth);
FlushLabelPools(scope_depth);
--scope_depth;
if (scope_depth<0)
return ERROR_UNBALANCED_SCOPE_CLOSURE;
return STATUS_OK;
}
//
//
@ -2154,9 +2186,17 @@ StatusCode Asm::AddMacro(strref macro, strref source_name, strref source_file, s
// Compile in a macro
StatusCode Asm::BuildMacro(Macro &m, strref arg_list)
{
strref macro_src = m.macro;
strref params = m.params_first_line ? macro_src.line() :
(macro_src[0] == '(' ? macro_src.scoped_block_skip() : strref());
strref macro_src = m.macro, params;
if (m.params_first_line) {
if (end_macro_directive)
params = macro_src.line();
else {
params = macro_src.before('{');
macro_src += params.get_len();
}
}
else
params = (macro_src[0] == '(' ? macro_src.scoped_block_skip() : strref());
params.trim_whitespace();
arg_list.trim_whitespace();
if (syntax == SYNTAX_MERLIN) {
@ -2165,7 +2205,7 @@ StatusCode Asm::BuildMacro(Macro &m, strref arg_list)
arg_list = (contextStack.curr().read_source +
strl_t(arg_list.get()-contextStack.curr().read_source.get())
).line();
arg_list = arg_list.before_or_full(c_comment);
arg_list = arg_list.before_or_full(c_comment).get_trimmed_ws();
strref arg = arg_list;
strown<16> tag;
int t_max = 16;
@ -2189,7 +2229,7 @@ StatusCode Asm::BuildMacro(Macro &m, strref arg_list)
for (int t=1; t<t_max; t++) {
tag.sprintf("]%d", t);
strref a = arg.split_token_trim(';');
macexp.replace(tag.get_strref(), a);
macexp.replace_bookend(tag.get_strref(), a, label_end_char_range_merlin);
}
contextStack.push(m.source_name, macexp.get_strref(), macexp.get_strref());
if (scope_depth>=(MAX_SCOPE_DEPTH-1))
@ -2222,7 +2262,7 @@ StatusCode Asm::BuildMacro(Macro &m, strref arg_list)
macexp.copy(macro_src);
while (strref param = params.split_token_trim(token_macro)) {
strref a = arg_list.split_token_trim(token);
macexp.replace(param, a);
macexp.replace_bookend(param, a, label_end_char_range);
}
contextStack.push(m.source_name, macexp.get_strref(), macexp.get_strref());
if (end_macro_directive) {
@ -2485,48 +2525,53 @@ EvalOperator Asm::RPNToken_Merlin(strref &expression, const struct EvalContext &
}
// Get a single token from most non-apple II assemblers
EvalOperator Asm::RPNToken(strref &expression, const struct EvalContext &etx, EvalOperator prev_op, short &section, int &value)
EvalOperator Asm::RPNToken(strref &exp, const struct EvalContext &etx, EvalOperator prev_op, short &section, int &value)
{
char c = expression.get_first();
char c = exp.get_first();
switch (c) {
case '$': ++expression; value = expression.ahextoui_skip(); return EVOP_VAL;
case '-': ++expression; return EVOP_SUB;
case '+': ++expression; return EVOP_ADD;
case '$': ++exp; value = exp.ahextoui_skip(); return EVOP_VAL;
case '-': ++exp; return EVOP_SUB;
case '+': ++exp; return EVOP_ADD;
case '*': // asterisk means both multiply and current PC, disambiguate!
++expression;
if (expression[0] == '*') return EVOP_STP; // double asterisks indicates comment
++exp;
if (exp[0] == '*') return EVOP_STP; // double asterisks indicates comment
else if (prev_op == EVOP_VAL || prev_op == EVOP_RPR) return EVOP_MUL;
value = etx.pc; section = CurrSection().IsRelativeSection() ? SectionId() : -1; return EVOP_VAL;
case '/': ++expression; return EVOP_DIV;
case '>': if (expression.get_len() >= 2 && expression[1] == '>') { expression += 2; return EVOP_SHR; }
++expression; return EVOP_HIB;
case '<': if (expression.get_len() >= 2 && expression[1] == '<') { expression += 2; return EVOP_SHL; }
++expression; return EVOP_LOB;
case '/': ++exp; return EVOP_DIV;
case '=': if (exp[1] == '=') { exp += 2; return EVOP_EQU; } return EVOP_STP;
case '>': if (exp.get_len() >= 2 && exp[1] == '>') { exp += 2; return EVOP_SHR; }
if (prev_op == EVOP_VAL || prev_op == EVOP_RPR) { ++exp;
if (exp[0] == '=') { ++exp; return EVOP_GTE; } return EVOP_GT; }
++exp; return EVOP_HIB;
case '<': if (exp.get_len() >= 2 && exp[1] == '<') { exp += 2; return EVOP_SHR; }
if (prev_op == EVOP_VAL || prev_op == EVOP_RPR) { ++exp;
if (exp[0] == '=') { ++exp; return EVOP_LTE; } return EVOP_LT; }
++exp; return EVOP_LOB;
case '%': // % means both binary and scope closure, disambiguate!
if (expression[1] == '0' || expression[1] == '1') { ++expression; value = expression.abinarytoui_skip(); return EVOP_VAL; }
if (exp[1] == '0' || exp[1] == '1') { ++exp; value = exp.abinarytoui_skip(); return EVOP_VAL; }
if (etx.scope_end_pc<0) return EVOP_NRY;
++expression; value = etx.scope_end_pc; section = CurrSection().IsRelativeSection() ? SectionId() : -1; return EVOP_VAL;
case '|': ++expression; return EVOP_OR;
case '^': if (prev_op == EVOP_VAL || prev_op == EVOP_RPR) { ++expression; return EVOP_EOR; }
++expression; return EVOP_BAB;
case '&': ++expression; return EVOP_AND;
case '(': if (prev_op != EVOP_VAL) { ++expression; return EVOP_LPR; } return EVOP_STP;
case ')': ++expression; return EVOP_RPR;
++exp; value = etx.scope_end_pc; section = CurrSection().IsRelativeSection() ? SectionId() : -1; return EVOP_VAL;
case '|': ++exp; return EVOP_OR;
case '^': if (prev_op == EVOP_VAL || prev_op == EVOP_RPR) { ++exp; return EVOP_EOR; }
++exp; return EVOP_BAB;
case '&': ++exp; return EVOP_AND;
case '(': if (prev_op != EVOP_VAL) { ++exp; return EVOP_LPR; } return EVOP_STP;
case ')': ++exp; return EVOP_RPR;
case ',':
case '?':
case '\'': return EVOP_STP;
default: { // ! by itself is current scope, !+label char is a local label
if (c == '!' && !(expression + 1).len_label()) {
if (c == '!' && !(exp + 1).len_label()) {
if (etx.scope_pc < 0) return EVOP_NRY;
++expression; value = etx.scope_pc; section = CurrSection().IsRelativeSection() ? SectionId() : -1; return EVOP_VAL;
++exp; value = etx.scope_pc; section = CurrSection().IsRelativeSection() ? SectionId() : -1; return EVOP_VAL;
} else if (strref::is_number(c)) {
if (prev_op == EVOP_VAL) return EVOP_STP; // value followed by value doesn't make sense, stop
value = expression.atoi_skip(); return EVOP_VAL;
value = exp.atoi_skip(); return EVOP_VAL;
} else if (c == '!' || c == ':' || c=='.' || c=='@' || strref::is_valid_label(c)) {
if (prev_op == EVOP_VAL) return EVOP_STP; // a value followed by a value does not make sense, probably start of a comment (ORCA/LISA?)
char e0 = expression[0];
char e0 = exp[0];
int start_pos = (e0 == ':' || e0 == '!' || e0 == '.') ? 1 : 0;
strref label = expression.split_range_trim(label_end_char_range, start_pos);
strref label = exp.split_range_trim(label_end_char_range, start_pos);
Label *pLabel = pLabel = GetLabel(label, etx.file_ref);
if (!pLabel) {
StatusCode ret = EvalStruct(label, value);
@ -2656,6 +2701,26 @@ StatusCode Asm::EvalExpression(strref expression, const struct EvalContext &etx,
for (int i = 0; i<num_sections; i++)
section_counts[i][ri] = i==section_val[ri] ? 1 : 0;
values[ri++] = values[valIdx++]; break;
case EVOP_EQU: // ==
ri--;
values[ri - 1] = values[ri - 1] == values[ri];
break;
case EVOP_GT: // >
ri--;
values[ri - 1] = values[ri - 1] > values[ri];
break;
case EVOP_LT: // <
ri--;
values[ri - 1] = values[ri - 1] < values[ri];
break;
case EVOP_GTE: // >=
ri--;
values[ri - 1] = values[ri - 1] >= values[ri];
break;
case EVOP_LTE: // >=
ri--;
values[ri - 1] = values[ri - 1] <= values[ri];
break;
case EVOP_ADD: // +
ri--;
for (int i = 0; i<num_sections; i++)
@ -4110,80 +4175,73 @@ StatusCode Asm::ApplyDirective(AssemblerDirective dir, strref line, strref sourc
}
// Make an educated guess at the intended address mode from an opcode argument
StatusCode Asm::GetAddressMode(strref line, bool flipXY, AddrMode &addrMode, int &len, strref &expression)
StatusCode Asm::GetAddressMode(strref line, bool flipXY, unsigned int validModes, AddrMode &addrMode, int &len, strref &expression)
{
bool force_zp = false;
bool force_24 = false;
bool force_abs = false;
bool need_more = true;
strref arg, deco;
len = 0;
while (need_more) {
bool long_rel = false;
need_more = false;
switch (line.get_first()) {
case 0: // empty line, empty addressing mode
addrMode = AMB_NON;
break;
case '[':
long_rel = true; // fall-through to '('
case '(': // relative (jmp (addr), (zp,x), (zp),y)
deco = line.scoped_block_skip();
line.skip_whitespace();
expression = deco.split_token_trim(',');
addrMode = long_rel ? (force_zp ? AMB_ZP_REL_L : AMB_REL_L) : (force_zp ? AMB_ZP_REL : AMB_REL);
if (strref::tolower(deco[0])=='x')
addrMode = long_rel ? AMB_ILL : AMB_ZP_REL_X;
else if (line[0]==',') {
++line;
line.skip_whitespace();
if (strref::tolower(line[0])=='y') {
if (strref::tolower(deco[0])=='s')
addrMode = AMB_STK_REL_Y;
else
addrMode = long_rel ? AMB_ZP_REL_Y_L : AMB_ZP_Y_REL;
++line;
}
}
break;
case '#': // immediate, determine if value is ok
unsigned char c = line.get_first();
if (!c)
addrMode = AMB_NON;
else if (!force_abs && (c == '[' || (c == '(' &&
(validModes&(AMM_REL | AMM_REL_X | AMM_ZP_REL_X | AMM_ZP_Y_REL))))) {
deco = line.scoped_block_skip();
line.skip_whitespace();
expression = deco.split_token_trim(',');
addrMode = c == '[' ? (force_zp ? AMB_ZP_REL_L : AMB_REL_L) : (force_zp ? AMB_ZP_REL : AMB_REL);
if (strref::tolower(deco[0]) == 'x')
addrMode = c == '[' ? AMB_ILL : AMB_ZP_REL_X;
else if (line[0] == ',') {
++line;
addrMode = AMB_IMM;
expression = line;
break;
default: { // accumulator or absolute
if (line) {
if (line[0]=='.' && strref::is_ws(line[2])) {
switch (strref::tolower(line[1])) {
case 'z': force_zp = true; line += 3; need_more = true; len = 1; break;
case 'b': line += 3; need_more = true; len = 1; break;
case 'w': line += 3; need_more = true; len = 2; break;
case 'l': force_24 = true; line += 3; need_more = true; len = 3; break;
}
}
if (!need_more) {
if (strref("A").is_prefix_word(line)) {
addrMode = AMB_ACC;
} else { // absolute (zp, offs x, offs y)
addrMode = force_24 ? AMB_ABS_L : (force_zp ? AMB_ZP : AMB_ABS);
expression = line.split_token_trim(',');
if (line && (line[0]=='s' || line[0]=='S'))
addrMode = AMB_STK;
else {
bool relX = line && (line[0]=='x' || line[0]=='X');
bool relY = line && (line[0]=='y' || line[0]=='Y');
if ((flipXY && relY) || (!flipXY && relX))
addrMode = force_24 ? AMB_ABS_L_X : (force_zp ? AMB_ZP_X : AMB_ABS_X);
else if ((flipXY && relX) || (!flipXY && relY)) {
if (force_zp)
return ERROR_INSTRUCTION_NOT_ZP;
addrMode = AMB_ABS_Y;
}
}
line.skip_whitespace();
if (strref::tolower(line[0]) == 'y') {
if (strref::tolower(deco[0]) == 's')
addrMode = AMB_STK_REL_Y;
else
addrMode = c == '[' ? AMB_ZP_REL_Y_L : AMB_ZP_Y_REL;
++line;
}
}
} else if (c == '#') {
++line;
addrMode = AMB_IMM;
expression = line;
} else if (line) {
if (line[0]=='.' && strref::is_ws(line[2])) {
switch (strref::tolower(line[1])) {
case 'z': force_zp = true; line += 3; need_more = true; len = 1; break;
case 'b': line += 3; need_more = true; len = 1; break;
case 'w': line += 3; need_more = true; len = 2; break;
case 'l': force_24 = true; line += 3; need_more = true; len = 3; break;
case 'a': force_abs = true; line += 3; need_more = true; break;
}
}
if (!need_more) {
if (strref("A").is_prefix_word(line)) {
addrMode = AMB_ACC;
} else { // absolute (zp, offs x, offs y)
addrMode = force_24 ? AMB_ABS_L : (force_zp ? AMB_ZP : AMB_ABS);
expression = line.split_token_trim(',');
if (line && (line[0]=='s' || line[0]=='S'))
addrMode = AMB_STK;
else {
bool relX = line && (line[0]=='x' || line[0]=='X');
bool relY = line && (line[0]=='y' || line[0]=='Y');
if ((flipXY && relY) || (!flipXY && relX))
addrMode = force_24 ? AMB_ABS_L_X : (force_zp ? AMB_ZP_X : AMB_ABS_X);
else if ((flipXY && relX) || (!flipXY && relY)) {
if (force_zp)
return ERROR_INSTRUCTION_NOT_ZP;
addrMode = AMB_ABS_Y;
}
}
}
break;
}
}
}
@ -4225,7 +4283,7 @@ StatusCode Asm::AddOpcode(strref line, int index, strref source_file)
expression = line.before_or_full(',');
break;
default:
error = GetAddressMode(line, !!(validModes & AMM_FLIPXY), addrMode, op_param, expression);
error = GetAddressMode(line, !!(validModes & AMM_FLIPXY), validModes, addrMode, op_param, expression);
break;
}
@ -4503,9 +4561,8 @@ StatusCode Asm::BuildLine(strref line)
// scope open / close
switch (line[0]) {
case '{':
if (scope_depth>=(MAX_SCOPE_DEPTH-1))
error = ERROR_TOO_DEEP_SCOPE;
else {
error = EnterScope();
if (error == STATUS_OK) {
scope_address[++scope_depth] = CurrSection().GetPC();
++line;
line.skip_whitespace();
@ -4513,14 +4570,11 @@ StatusCode Asm::BuildLine(strref line)
break;
case '}':
// check for late eval of anything with an end scope
CheckLateEval(strref(), CurrSection().GetPC());
FlushLocalLabels(scope_depth);
FlushLabelPools(scope_depth);
--scope_depth;
if (scope_depth<0)
error = ERROR_UNBALANCED_SCOPE_CLOSURE;
++line;
line.skip_whitespace();
error = ExitScope();
if (error == STATUS_OK) {
++line;
line.skip_whitespace();
}
break;
case '*':
// if first char is '*' this seems like a line comment on some assemblers
@ -4848,12 +4902,8 @@ void Asm::Assemble(strref source, strref filename, bool obj_target)
while (contextStack.has_work()) {
error = BuildSegment();
if (contextStack.curr().complete()) {
if (contextStack.curr().scoped_context && scope_depth) {
CheckLateEval(strref(), CurrSection().GetPC());
FlushLocalLabels(scope_depth);
FlushLabelPools(scope_depth);
--scope_depth;
}
if (contextStack.curr().scoped_context && scope_depth)
ExitScope();
contextStack.pop();
} else
contextStack.curr().restart();
@ -5305,6 +5355,8 @@ int main(int argc, char **argv)
const strref allinstr("opcodes");
const strref endmacro("endm");
const strref cpu("cpu");
const strref acc("acc");
const strref xy("xy");
int return_value = 0;
bool load_header = true;
bool size_header = false;
@ -5349,17 +5401,27 @@ int main(int argc, char **argv)
} else if (arg.has_prefix(allinstr) && (arg.get_len() == allinstr.get_len() || arg[allinstr.get_len()] == '=')) {
gen_allinstr = true;
allinstr_file = arg.after('=');
} else if (arg.has_prefix(acc) && arg[acc.get_len()] == '=') {
assembler.accumulator_16bit = arg.after('=').atoi() == 16;
} else if (arg.has_prefix(xy) && arg[xy.get_len()] == '=') {
assembler.index_reg_16bit = arg.after('=').atoi() == 16;
} else if (arg.has_prefix(cpu) && (arg.get_len() == cpu.get_len() || arg[cpu.get_len()] == '=')) {
arg.split_token_trim('=');
bool found = false;
for (int c = 0; c<nCPUs; c++) {
if (arg) {
if (arg.same_str(aCPUs[c].name)) {
assembler.SetCPU((CPUIndex)c);
found = true;
break;
}
} else
printf("%s\n", aCPUs[c].name);
}
if (!found && arg) {
printf("ERROR: UNKNOWN CPU " STRREF_FMT "\n", STRREF_ARG(arg));
return 1;
}
if (!arg)
return 0;
} else if (arg.same_str("sym") && (a + 1) < argc)
@ -5382,6 +5444,8 @@ int main(int argc, char **argv)
" * -i(path) : Add include path\n"
" * -D(label)[=<value>] : Define a label with an optional value(otherwise defined as 1)\n"
" * -cpu=6502/65c02/65c02wdc/65816: assemble with opcodes for a different cpu\n"
" * -acc=8/16: set the accumulator mode for 65816 at start, default is 8 bits"
" * -xy=8/16: set the iundex register mode for 65816 at start, default is 8 bits"
" * -obj(file.x65) : generate object file for later linking\n"
" * -bin : Raw binary\n"
" * -c64 : Include load address(default)\n"
@ -5486,9 +5550,8 @@ int main(int argc, char **argv)
break;
}
}
fprintf(f, "%s.label " STRREF_FMT " = $%04x",
wasLocal==i->local ? "\n" : (i->local ? " {\n" : "\n}\n"),
STRREF_ARG(i->name), value);
fprintf(f, "%s.label " STRREF_FMT " = $%04x", wasLocal==i->local ? "\n" :
(i->local ? " {\n" : "\n}\n"), STRREF_ARG(i->name), value);
wasLocal = i->local;
}
fputs(wasLocal ? "\n}\n" : "\n", f);
@ -5511,8 +5574,7 @@ int main(int argc, char **argv)
break;
}
}
fprintf(f, "al $%04x %s" STRREF_FMT "\n",
value, i->name[0]=='.' ? "" : ".",
fprintf(f, "al $%04x %s" STRREF_FMT "\n", value, i->name[0]=='.' ? "" : ".",
STRREF_ARG(i->name));
}
fclose(f);