fix merlin ddb

ddb generates a "double byte" which is actually a big-endian 16-bit number.
For relocation purposes, it has to be handled as 2 individual bytes with shifts to adjust it.
This commit is contained in:
Kelvin Sherlock 2020-10-18 13:24:08 -04:00
parent c2492ab348
commit 295129cd6c
2 changed files with 67 additions and 12 deletions

8
test/merlin_data.s Normal file
View File

@ -0,0 +1,8 @@
; merlin_data.s
db $12,$34,$56,$78
ddb $1234,$5678 ; double byte - big endian format.
dw $1234
da $1234
adr $123456
adrl $12345678

71
x65.cpp
View File

@ -322,6 +322,7 @@ enum AssemblerDirective {
AD_ENT, // ENT: MERLIN extern this address label AD_ENT, // ENT: MERLIN extern this address label
AD_EXT, // EXT: MERLIN reference this address label from a different file AD_EXT, // EXT: MERLIN reference this address label from a different file
AD_CYC, // CYC: MERLIN start / stop cycle timer AD_CYC, // CYC: MERLIN start / stop cycle timer
AD_DBL_BYTES, // DDB: MERLIN Store 2 bytes, big endian format.
AD_ERROR, AD_ERROR,
}; };
@ -1057,7 +1058,7 @@ DirectiveName aDirectiveNamesMerlin[] {
{ "DW", AD_WORDS }, // MERLIN { "DW", AD_WORDS }, // MERLIN
{ "ASC", AD_TEXT }, // MERLIN { "ASC", AD_TEXT }, // MERLIN
{ "PUT", AD_INCLUDE }, // MERLIN { "PUT", AD_INCLUDE }, // MERLIN
{ "DDB", AD_WORDS }, // MERLIN { "DDB", AD_DBL_BYTES }, // MERLIN
{ "DB", AD_BYTES }, // MERLIN { "DB", AD_BYTES }, // MERLIN
{ "DFB", AD_BYTES }, // MERLIN { "DFB", AD_BYTES }, // MERLIN
{ "HEX", AD_HEX }, // MERLIN { "HEX", AD_HEX }, // MERLIN
@ -1591,6 +1592,7 @@ typedef struct sLateEval {
LET_BRANCH, // calculate a branch offset and store at this address LET_BRANCH, // calculate a branch offset and store at this address
LET_BRANCH_16, // calculate a branch offset of 16 bits and store at this address LET_BRANCH_16, // calculate a branch offset of 16 bits and store at this address
LET_BYTE, // calculate a byte and store at this address LET_BYTE, // calculate a byte and store at this address
LET_DBL_BYTE, // calculate a 16-bit, big endian number.
}; };
int target; // offset into output buffer int target; // offset into output buffer
int address; // current pc int address; // current pc
@ -1948,7 +1950,7 @@ public:
StatusCode Directive_LNK(strref line); StatusCode Directive_LNK(strref line);
StatusCode Directive_XDEF(strref line); StatusCode Directive_XDEF(strref line);
StatusCode Directive_XREF(strref label); StatusCode Directive_XREF(strref label);
StatusCode Directive_DC(strref line, int width, strref source_file); StatusCode Directive_DC(strref line, int width, strref source_file, bool little_endian = true);
StatusCode Directive_DS(strref line); StatusCode Directive_DS(strref line);
StatusCode Directive_ALIGN(strref line); StatusCode Directive_ALIGN(strref line);
StatusCode Directive_EVAL(strref line); StatusCode Directive_EVAL(strref line);
@ -4257,6 +4259,23 @@ StatusCode Asm::CheckLateEval(strref added_label, int scope_end, bool print_miss
allSections[sec].SetByte(trg, value); allSections[sec].SetByte(trg, value);
break; break;
case LateEval::LET_DBL_BYTE:
if (ret==STATUS_RELATIVE_SECTION) {
if (i->section<0) {
resolved = false;
} else {
allSections[sec].AddReloc(lastEvalValue, trg, lastEvalSection, 1, lastEvalShift-8);
allSections[sec].AddReloc(lastEvalValue, trg+1, lastEvalSection, 1, lastEvalShift);
value = 0;
}
}
if ((trg+1)>=allSections[sec].size()) {
return ERROR_SECTION_TARGET_OFFSET_OUT_OF_RANGE;
}
allSections[sec].SetByte(trg, value>>8);
allSections[sec].SetByte(trg+1, value);
break;
case LateEval::LET_ABS_REF: case LateEval::LET_ABS_REF:
if (ret==STATUS_RELATIVE_SECTION) { if (ret==STATUS_RELATIVE_SECTION) {
if (i->section<0) { if (i->section<0) {
@ -5388,7 +5407,7 @@ StatusCode Asm::Directive_XREF(strref label)
} }
// dc.b, dc.w, dc.t, dc.l, ADR, ADRL, bytes, words, long // dc.b, dc.w, dc.t, dc.l, ADR, ADRL, bytes, words, long
StatusCode Asm::Directive_DC(strref line, int width, strref source_file) StatusCode Asm::Directive_DC(strref line, int width, strref source_file, bool little_endian)
{ {
struct EvalContext etx; struct EvalContext etx;
SetEvalCtxDefaults(etx); SetEvalCtxDefaults(etx);
@ -5401,18 +5420,43 @@ StatusCode Asm::Directive_DC(strref line, int width, strref source_file)
StatusCode error = EvalExpression(exp_dc, etx, value); StatusCode error = EvalExpression(exp_dc, etx, value);
if (error > STATUS_XREF_DEPENDENT) if (error > STATUS_XREF_DEPENDENT)
break; break;
else if (error == STATUS_NOT_READY || error == STATUS_XREF_DEPENDENT) else if (error == STATUS_NOT_READY || error == STATUS_XREF_DEPENDENT) {
AddLateEval(CurrSection().DataOffset(), CurrSection().GetPC(), scope_address[scope_depth], exp_dc, source_file, static LateEval::Type sizes[] = {
width == 1 ? LateEval::LET_BYTE : (width == 2 ? LateEval::LET_ABS_REF : (width == 3 ? LateEval::LET_ABS_L_REF : LateEval::LET_ABS_4_REF))); LateEval::LET_BYTE,
else if (error == STATUS_RELATIVE_SECTION) { LateEval::LET_ABS_REF,
LateEval::LET_ABS_L_REF,
LateEval::LET_ABS_4_REF
};
LateEval::Type type = sizes[width - 1];
if (!little_endian && width == 2) {
type = LateEval::LET_DBL_BYTE;
}
AddLateEval(CurrSection().DataOffset(), CurrSection().GetPC(), scope_address[scope_depth], exp_dc, source_file, type);
} else if (error == STATUS_RELATIVE_SECTION) {
value = 0; value = 0;
CurrSection().AddReloc(lastEvalValue, CurrSection().DataOffset(), lastEvalSection, (int8_t)width, (int8_t)lastEvalShift); if (little_endian || width == 1) {
CurrSection().AddReloc(lastEvalValue, CurrSection().DataOffset(), lastEvalSection, (int8_t)width, (int8_t)lastEvalShift);
} else {
// big endian needs 1 reloc for each byte
int shift = lastEvalShift + 8 - width * 8;
for (int i = 0; i < width; ++i, shift += 8) {
CurrSection().AddReloc(lastEvalValue, CurrSection().DataOffset() + i, lastEvalSection, 1, (int8_t)shift);
}
}
} }
} }
uint8_t bytes[4] = { if (little_endian) {
(uint8_t)value, (uint8_t)(value >> 8), uint8_t bytes[4] = {
(uint8_t)(value >> 16), (uint8_t)(value >> 24) }; (uint8_t)value, (uint8_t)(value >> 8),
AddBin(bytes, width); (uint8_t)(value >> 16), (uint8_t)(value >> 24) };
AddBin(bytes, width);
} else {
uint8_t bytes[4] = {
(uint8_t)(value >> 24), (uint8_t)(value >> 16),
(uint8_t)(value >> 8), (uint8_t)value };
AddBin(bytes + 4 - width, width);
}
} }
return STATUS_OK; return STATUS_OK;
} }
@ -5654,6 +5698,9 @@ StatusCode Asm::ApplyDirective(AssemblerDirective dir, strref line, strref sourc
case AD_WORDS: // words: add words (16 bit values) by comma separated values case AD_WORDS: // words: add words (16 bit values) by comma separated values
return Directive_DC(line, 2, source_file); return Directive_DC(line, 2, source_file);
case AD_DBL_BYTES: // DDB: Merlin store 2-byte word, big endian format.
return Directive_DC(line, 2, source_file, false);
case AD_ADR: // ADR: MERLIN store 3 byte word case AD_ADR: // ADR: MERLIN store 3 byte word
return Directive_DC(line, 3, source_file); return Directive_DC(line, 3, source_file);