Skip to content

Commit 46e459a

Browse files
committed
[MC68000] Refactor relative branches
1 parent f6a13e6 commit 46e459a

7 files changed

+245
-326
lines changed

src/asm_mc68000.cpp

+46-36
Original file line numberDiff line numberDiff line change
@@ -214,61 +214,75 @@ void AsmMc68000::encodeDisplacement(
214214
}
215215

216216
void AsmMc68000::encodeRelativeAddr(AsmInsn &insn, AddrMode mode, const Operand &op) const {
217-
// FDxx has different base address
218-
const auto base = insn.address() + (insn.hasPostVal() ? 4 : 2);
217+
// FDBcc has different base address
218+
const auto FDBcc = insn.hasPostVal();
219+
const auto base = insn.address() + (FDBcc ? 4 : 2);
219220
const auto target = op.getError() ? base : op.val.getUnsigned();
220221
insn.setErrorIf(op, checkAddr(target, true));
221-
ErrorAt error;
222222
// the branchDelta() uses addressWidth(), which is 24 bit, to
223223
// check the range of |delta|. It is not suitable for
224224
// M_REL32. Record errors in |error| then copy it to |insn| if
225225
// any.
226-
const auto delta = branchDelta(base, target, error, op);
227-
const auto insnSize = insn.insnSize();
226+
const int32_t delta = target - base;
227+
ErrorAt error;
228+
if ((delta < 0 && target >= base) || (delta >= 0 && target < base))
229+
error.setErrorIf(op, OVERFLOW_RANGE);
230+
auto type = mode;
231+
const auto size = insn.insnSize();
228232
if (mode == M_REL8) {
229-
if (insnSize == ISZ_NONE) {
233+
if (size == ISZ_NONE) {
234+
if (overflowDelta(delta, 16))
235+
error.setErrorIf(op, OPERAND_TOO_FAR);
230236
if (overflowDelta(delta, 8))
231-
goto rel16;
232-
insn.embed(static_cast<uint8_t>(delta));
233-
} else if (insnSize == ISZ_BYTE || insnSize == ISZ_SNGL) {
237+
type = M_REL16;
238+
} else if (size == ISZ_BYTE || size == ISZ_SNGL) {
239+
// Mnemonics has suffix 'B' or 'S'
240+
type = M_REL8;
234241
if (overflowDelta(delta, 8))
235242
error.setErrorIf(op, OPERAND_TOO_FAR);
236-
insn.embed(static_cast<uint8_t>(delta));
237-
} else if (insnSize == ISZ_WORD || insnSize == ISZ_LONG) {
238-
goto rel16;
243+
} else if (size == ISZ_WORD || size == ISZ_LONG) {
244+
// Mnemonics has suffix 'W' or 'L'
245+
type = M_REL16;
239246
} else {
240-
error.setErrorIf(ILLEGAL_SIZE);
247+
type = M_NONE;
241248
}
242249
} else if (mode == M_REL16) {
243-
if (insnSize == ISZ_NONE || insnSize == ISZ_WORD || insnSize == ISZ_LONG) {
244-
rel16:
250+
if (size == ISZ_NONE || size == ISZ_WORD || size == ISZ_LONG) {
251+
// Mnemonics has suffix 'W' or 'L'
245252
if (overflowDelta(delta, 16))
246253
error.setErrorIf(op, OPERAND_TOO_FAR);
247254
} else {
248-
error.setErrorIf(ILLEGAL_SIZE);
255+
type = M_NONE;
249256
}
250-
insn.emitOperand16(delta);
251-
} else if (mode == M_REL32) {
252-
if (insnSize == ISZ_NONE) {
257+
} else { // mode == M_REL32
258+
if (size == ISZ_NONE) {
253259
if (!overflowDelta(delta, 16))
254-
goto rel32_16;
255-
goto rel32;
256-
} else if (insnSize == ISZ_WORD || insnSize == ISZ_LONG) {
260+
type = M_REL16;
261+
error.setOK(); // never overflow
262+
} else if (size == ISZ_WORD || size == ISZ_LONG) {
263+
// Mnemonics has suffix 'W' or 'L'
264+
type = M_REL16;
257265
if (overflowDelta(delta, 16))
258266
error.setErrorIf(op, OPERAND_TOO_FAR);
259-
rel32_16:
260-
insn.setOpCode(insn.opCode() & ~(1 << 6)); // M_REL16
261-
insn.emitOperand16(static_cast<uint16_t>(delta));
262-
} else if (insnSize == ISZ_LONG || insnSize == ISZ_XTND) {
263-
rel32:
264-
error.setOK(); // M_REL32 never overflow.
265-
insn.embed(1 << 6); // M_REL32
266-
insn.emitOperand32(target - base); // 32 bit delta
267+
} else if (size == ISZ_XTND) {
268+
// Mnemonics has suffix ''X'
267269
} else {
268-
error.setErrorIf(ILLEGAL_SIZE);
269-
goto rel32_16;
270+
type = M_NONE;
270271
}
271272
}
273+
if (type == M_NONE) {
274+
error.setErrorIf(op, ILLEGAL_SIZE);
275+
type = mode;
276+
}
277+
if (type == M_REL8) {
278+
insn.embed(static_cast<uint8_t>(delta));
279+
} else if (type == M_REL16) {
280+
insn.emitOperand16(delta);
281+
} else { // type == M_REL32
282+
insn.emitOperand32(delta);
283+
if (mode == M_REL32)
284+
insn.embed(1 << 6); // set SIZE bit
285+
}
272286
// Copy error if any
273287
insn.setErrorIf(error);
274288
}
@@ -499,10 +513,6 @@ Error AsmMc68000::encodeOperand(
499513
encodeImmediate(insn, op, size);
500514
break;
501515
case M_LABEL:
502-
if (size == SZ_BYTE && mode == M_REL16)
503-
insn.setErrorIf(op, ILLEGAL_SIZE);
504-
if (size == SZ_WORD && mode == M_REL8)
505-
mode = M_REL16;
506516
encodeRelativeAddr(insn, mode, op);
507517
break;
508518
case M_FPREG:

src/dis_mc68000.cpp

+44-36
Original file line numberDiff line numberDiff line change
@@ -288,45 +288,49 @@ void DisMc68000::decodeEffectiveAddr(
288288
}
289289

290290
void DisMc68000::decodeRelative(DisInsn &insn, StrBuffer &out, AddrMode mode) const {
291-
// FDxx has different base address
292-
const auto base = insn.address() + (insn.hasPostVal() ? 4 : 2);
293-
if (mode == M_REL32 && (insn.opCode() & (1 << 6)) == 0)
294-
mode = M_REL16;
291+
auto type = mode;
295292
if (mode == M_REL32) {
296-
const auto delta = static_cast<int32_t>(insn.readUint32());
297-
auto save{out};
298-
insn.nameBuffer().over(out);
299-
if (!overflowDelta(delta, 16)) {
300-
if (!_gnuAs)
301-
out.letter('.').letter('L');
302-
}
303-
if (_gnuAs)
304-
out.letter('L');
305-
out.over(insn.nameBuffer());
306-
save.over(out);
307-
const auto target = base + delta;
308-
insn.setErrorIf(out, checkAddr(target, true));
309-
outRelAddr(out, target, insn.address(), insn.isOK() ? addressWidth() : 32);
310-
return;
293+
// FBcc
294+
const auto size16 = (insn.opCode() & 0x40) == 0;
295+
if (size16)
296+
type = M_REL16;
311297
}
312-
const auto rel8 = (mode == M_REL8) ? static_cast<int8_t>(insn.opCode() & 0xFF) : 0;
313-
const auto delta = rel8 ? static_cast<int8_t>(rel8) : static_cast<int16_t>(insn.readUint16());
314298
if (mode == M_REL8) {
315-
auto save{out};
316-
insn.nameBuffer().over(out);
299+
const auto rel8 = insn.opCode() & 0xFF;
300+
if (rel8 == 0)
301+
type = M_REL16;
302+
}
303+
// FDBcc has different base address
304+
const auto FDBcc = insn.hasPostVal();
305+
const auto base = insn.address() + (FDBcc ? 4 : 2);
306+
auto bits = 8;
307+
Config::ptrdiff_t delta = 0;
308+
if (type == M_REL32) {
309+
bits = addressWidth();
310+
delta = static_cast<int32_t>(insn.readUint32());
317311
if (_gnuAs) {
318-
if (rel8)
319-
out.letter('S');
320-
} else {
321-
if (rel8 == 0 && !overflowDelta(delta, 8))
322-
out.letter('.').letter('W');
312+
insn.appendName(out, 'L');
313+
} else if (!overflowDelta(delta, 16)) {
314+
insn.appendName(out, '.');
315+
insn.appendName(out, 'L');
323316
}
324-
out.over(insn.nameBuffer());
325-
save.over(out);
317+
} else if (type == M_REL16) {
318+
bits = 16;
319+
delta = static_cast<int16_t>(insn.readUint16());
320+
if (!_gnuAs && mode == M_REL8 && !overflowDelta(delta, 8)) {
321+
insn.appendName(out, '.');
322+
insn.appendName(out, 'W');
323+
}
324+
} else { // type == M_REL8
325+
delta = static_cast<int8_t>(insn.opCode() & 0xFF);
326+
if (_gnuAs)
327+
insn.appendName(out, 'S');
326328
}
327329
const auto target = base + delta;
328330
insn.setErrorIf(out, checkAddr(target, true));
329-
outRelAddr(out, target, insn.address(), rel8 ? 8 : 16);
331+
if (insn.getError() == OVERFLOW_RANGE)
332+
bits = 32;
333+
outRelAddr(out, target, insn.address(), bits);
330334
}
331335

332336
namespace {
@@ -712,6 +716,13 @@ char decodeInsnSize(const DisInsn &insn, OprSize osize) {
712716
return sizeSuffix(size);
713717
}
714718

719+
void DisInsn::appendName(StrBuffer &out, char c) {
720+
auto save{out};
721+
nameBuffer().over(out);
722+
out.letter(c).over(nameBuffer());
723+
save.over(out);
724+
}
725+
715726
Error DisMc68000::decodeImpl(DisMemory &memory, Insn &_insn, StrBuffer &out) const {
716727
DisInsn insn(_insn, memory, out);
717728
const auto opc = insn.readUint16();
@@ -722,12 +733,9 @@ Error DisMc68000::decodeImpl(DisMemory &memory, Insn &_insn, StrBuffer &out) con
722733
const auto osize = decodeSize(insn);
723734
const auto suffix = decodeInsnSize(insn, osize);
724735
if (suffix) {
725-
auto save{out};
726-
insn.nameBuffer().over(out);
727736
if (!_gnuAs)
728-
out.letter('.');
729-
out.letter(suffix).over(insn.nameBuffer());
730-
save.over(out);
737+
insn.appendName(out, '.');
738+
insn.appendName(out, suffix);
731739
}
732740

733741
const auto dst = insn.dst();

src/entry_mc68000.h

+5-3
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,8 @@ enum AddrMode : uint8_t {
8686
M_JADDR = 27, // Jumpable Address: (An) /(*,An)/(Abs)/(*,PC)
8787
M_IADDR = 28, // Increment Address: (An)/(An)+ /(*,An)/(Abs)/(*,PC)
8888
M_DADDR = 29, // Decrement Address: (An)/ /-(An)/(*,An)/(Abs)
89-
M_REL16 = 30, // 16-bit Relative
90-
M_REL8 = 31, // 8/16-bit Relative
89+
M_REL8 = 30, // 8/16-bit Relative (Bcc)
90+
M_REL16 = 31, // 16-bit Relative (DBcc/FDBcc)
9191
M_IMBIT = 32, // Bit number: #0~#7/#15/#31
9292
M_IM3 = 33, // 3-bit Immediate: #1~#8
9393
M_IM8 = 34, // 8-bit Immediate
@@ -109,7 +109,7 @@ enum AddrMode : uint8_t {
109109
M_FPSR = 46, // FPSR register
110110
M_FPIAR = 47, // FPIAR register
111111
M_IMROM = 48, // MC68881 ROM constant
112-
M_REL32 = 49, // 32-bit Relative; 1111|ccc|01s|___|___: s=0 16bit, s=1 32bit
112+
M_REL32 = 49, // 32-bit Relative; 1111|ccc|01s|___|___: s=0 16bit, s=1 32bit (FBcc)
113113
M_IMFLT = 50, // Floating point immediate
114114
};
115115

@@ -173,6 +173,8 @@ struct Entry final : entry::Base<Config::opcode_t> {
173173
static Config::opcode_t insnMask(AddrMode mode) {
174174
if (mode == M_IM8 || mode == M_REL8)
175175
return 0xFF;
176+
if (mode == M_REL32)
177+
return 0x40;
176178
if (mode == M_IMVEC)
177179
return 0xF;
178180
if (mode == M_KFACT || mode == M_KDREG)

src/insn_mc68000.h

+1
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ struct DecimalString {
113113
struct DisInsn final : DisInsnImpl<Config>, EntryInsn {
114114
DisInsn(Insn &insn, DisMemory &memory, const StrBuffer &out) : DisInsnImpl(insn, memory, out) {}
115115
InsnSize insnSize() const { return flags().insnSize(); }
116+
void appendName(StrBuffer &out, char c);
116117

117118
void readPostfix() {
118119
if (!hasPostfix())

0 commit comments

Comments
 (0)