m68kdecode
Version:
Port of deplinenoise/m68kdecode to Typescript
399 lines • 17.1 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const types_1 = require("./types");
const lib_1 = require("./lib");
class CodeStream {
constructor(bytes) {
this.bytes = bytes;
this.pos = 0;
}
hasWords(count) {
return this.pos + count * 2 <= this.bytes.length;
}
peekWord(offset) {
const p = this.pos + offset;
if (p + 2 > this.bytes.length) {
throw new Error("OutOfSpace");
}
return (this.bytes[p] << 8) | this.bytes[p + 1];
}
skipWords(count) {
this.pos += 2 * count;
}
pull16() {
const result = this.peekWord(0);
this.pos += 2;
return result;
}
pull32() {
const a = this.pull16();
const b = this.pull16();
return (a << 16) | b;
}
ea(srcReg, srcMod, size) {
switch (srcMod) {
case 0b000:
return (0, types_1.DR)(srcReg);
case 0b001:
return (0, types_1.AR)(srcReg);
case 0b010:
return (0, types_1.ARIND)(srcReg);
case 0b011:
return (0, types_1.ARINC)(srcReg);
case 0b100:
return (0, types_1.ARDEC)(srcReg);
case 0b101:
return (0, types_1.ARDISP)(srcReg, (0, lib_1.simpleDisp)((0, lib_1.i16)(this.pull16())));
case 0b110:
return this.decodeExtendedEa(srcReg);
case 0b111: {
switch (srcReg) {
case 0b000:
return (0, types_1.ABS16)((0, lib_1.i16)(this.pull16()));
case 0b001:
return (0, types_1.ABS32)(this.pull32());
case 0b010:
return (0, types_1.PCDISP)((0, lib_1.i8)(this.pos), (0, lib_1.simpleDisp)((0, lib_1.i16)(this.pull16())));
case 0b011:
return this.decodeExtendedEa(null);
case 0b100: {
switch (size) {
case 1:
return (0, types_1.IMM8)((0, lib_1.u8)(this.pull16()));
case 2:
return (0, types_1.IMM16)(this.pull16());
case 4:
return (0, types_1.IMM32)(this.pull32());
default: {
throw new Error("BadSize");
}
}
}
}
}
}
throw new Error("NotImplemented");
}
decodeExtendedEa(srcReg) {
const pcOff = (0, lib_1.u8)(this.pos);
const ext = this.pull16();
const scale = (0, lib_1.u8)((0, lib_1.getBits)(ext, 9, 2));
const idx = (0, lib_1.getBits)(ext, 12, 3);
const idxIsA = (0, lib_1.getBits)(ext, 15, 1) === 1;
if (0 !== (ext & (1 << 8))) {
// Handle full extension word.
const bd = (0, lib_1.getBits)(ext, 4, 2);
const od = (0, lib_1.getBits)(ext, 0, 2);
let baseDisplacement;
switch (bd) {
case 0:
throw new Error("Reserved");
case 1:
baseDisplacement = 0;
break;
case 2:
baseDisplacement = (0, lib_1.i16)(this.pull16());
break;
case 3:
baseDisplacement = this.pull32();
break;
default:
throw new Error("NotImplemented");
}
let outerDisplacement;
switch (od) {
case 0:
outerDisplacement = 0;
break;
case 1:
outerDisplacement = 0;
break;
case 2:
outerDisplacement = (0, lib_1.i16)(this.pull16());
break;
case 3:
outerDisplacement = this.pull32();
break;
default:
throw new Error("NotImplemented");
}
const suppressBase = (0, lib_1.getBits)(ext, 7, 1) === 1;
const suppressIndexer = (0, lib_1.getBits)(ext, 6, 1) === 1;
let indirection;
if (!suppressIndexer) {
switch ((0, lib_1.getBits)(ext, 0, 3)) {
case 0b000:
indirection = null;
break;
case 0b001:
indirection = "IndirectPreIndexed";
break;
case 0b010:
indirection = "IndirectPreIndexed";
break;
case 0b011:
indirection = "IndirectPreIndexed";
break;
case 0b100:
throw new Error("Reserved");
case 0b101:
indirection = "IndirectPostIndexed";
break;
case 0b110:
indirection = "IndirectPostIndexed";
break;
case 0b111:
indirection = "IndirectPostIndexed";
break;
default:
throw new Error("NotImplemented");
}
}
else {
switch ((0, lib_1.getBits)(ext, 0, 3)) {
case 0b000:
indirection = null;
break;
case 0b001:
indirection = "Indirect";
break;
case 0b010:
indirection = "Indirect";
break;
case 0b011:
indirection = "Indirect";
break;
default:
throw new Error("Reserved");
}
}
let indexer = null;
if (!suppressIndexer) {
indexer = idxIsA ? (0, types_1.ARIndexer)(idx, scale) : (0, types_1.DRIndexer)(idx, scale);
}
if (suppressBase) {
return (0, types_1.DISP)({
baseDisplacement,
outerDisplacement,
indexer,
indirection,
});
}
else {
return srcReg !== null
? (0, types_1.ARDISP)(srcReg, {
baseDisplacement,
outerDisplacement,
indexer,
indirection,
})
: (0, types_1.PCDISP)(pcOff, {
baseDisplacement,
outerDisplacement,
indexer,
indirection,
});
}
}
else {
// Handle brief extension word
const disp = (0, lib_1.i8)(ext & 0xff);
const indexer = idxIsA
? (0, types_1.ARIndexer)(idx, scale)
: (0, types_1.DRIndexer)(idx, scale);
const displacement = {
baseDisplacement: disp,
outerDisplacement: 0,
indexer,
indirection: null,
};
return srcReg !== null
? (0, types_1.ARDISP)(srcReg, displacement)
: (0, types_1.PCDISP)(pcOff, displacement);
}
}
imm8() {
return (0, types_1.IMM8)((0, lib_1.u8)(this.pull16()));
}
imm16() {
return (0, types_1.IMM16)(this.pull16());
}
imm32() {
return (0, types_1.IMM32)(this.pull32());
}
dar(dOrA, regno) {
return dOrA === 0 ? (0, types_1.DR)(regno) : (0, types_1.AR)(regno);
}
bitfield(dynOff, off, dynWidth, width) {
const bfOffset = dynOff === 0
? (0, types_1.STATIC)((off & 31) === 0 ? 32 : (0, lib_1.u8)(off & 31))
: (0, types_1.DYNAMIC)(off);
const bfWidth = dynWidth === 0
? (0, types_1.STATIC)((width & 31) === 0 ? 32 : (0, lib_1.u8)(width & 31))
: (0, types_1.DYNAMIC)(width);
return (0, types_1.Bitfield)(bfOffset, bfWidth);
}
cc(c) {
switch (c) {
case 0b0000:
return (0, types_1.Condition)(types_1.ConditionCode.CC_T); // Always True
case 0b0001:
return (0, types_1.Condition)(types_1.ConditionCode.CC_F); // Always False
case 0b0010:
return (0, types_1.Condition)(types_1.ConditionCode.CC_HI); // High
case 0b0011:
return (0, types_1.Condition)(types_1.ConditionCode.CC_LS); // Low or Same
case 0b0100:
return (0, types_1.Condition)(types_1.ConditionCode.CC_CC); // Carry Clear
case 0b0101:
return (0, types_1.Condition)(types_1.ConditionCode.CC_CS); // Carry Set
case 0b0110:
return (0, types_1.Condition)(types_1.ConditionCode.CC_NE); // Not Equal
case 0b0111:
return (0, types_1.Condition)(types_1.ConditionCode.CC_EQ); // Equal
case 0b1000:
return (0, types_1.Condition)(types_1.ConditionCode.CC_VC); // Overflow Clear
case 0b1001:
return (0, types_1.Condition)(types_1.ConditionCode.CC_VS); // Overflow Set
case 0b1010:
return (0, types_1.Condition)(types_1.ConditionCode.CC_PL); // Plus
case 0b1011:
return (0, types_1.Condition)(types_1.ConditionCode.CC_MI); // Negative
case 0b1100:
return (0, types_1.Condition)(types_1.ConditionCode.CC_GE); // Greater or Equal
case 0b1101:
return (0, types_1.Condition)(types_1.ConditionCode.CC_LT); // Less
case 0b1110:
return (0, types_1.Condition)(types_1.ConditionCode.CC_GT); // Greater
default:
return (0, types_1.Condition)(types_1.ConditionCode.CC_LE); // Less or Equal
}
}
quickConst(i) {
return (0, types_1.IMM8)(i === 0 ? 8 : (0, lib_1.u8)(i));
}
decodeFp(rg, md, m_r, s, d, k) {
if (m_r === 1) {
let sz;
let fpform;
switch (s) {
case 0b000:
sz = 4;
fpform = (0, types_1.FPF_LONG_INT)();
break;
case 0b001:
sz = 4;
fpform = (0, types_1.FPF_SINGLE)();
break;
case 0b010:
sz = 10;
fpform = (0, types_1.FPF_EXTENDED_REAL)();
break;
case 0b011:
sz = 12;
fpform = (0, types_1.FPF_PACKED_DECIMAL_REAL_STATIC)((0, lib_1.i8)(k << 1) >> 1);
break;
case 0b100:
sz = 2;
fpform = (0, types_1.FPF_WORD_INT)();
break;
case 0b101:
sz = 8;
fpform = (0, types_1.FPF_DOUBLE)();
break;
case 0b110:
sz = 1;
fpform = (0, types_1.FPF_BYTE_INT)();
break;
case 0b111:
sz = 12;
fpform = (0, types_1.FPF_PACKED_DECIMAL_REAL_DYNAMIC)(k >> 4);
break;
default:
throw new Error("Reserved");
}
return [sz, this.ea(rg, md, sz), (0, types_1.FR)(d), (0, types_1.FloatFormat)(fpform)];
}
else {
return [10, (0, types_1.FR)(s), (0, types_1.FR)(d), (0, types_1.FloatFormat)((0, types_1.FPF_EXTENDED_REAL)())];
}
}
fpcc(c) {
switch (c) {
case 0b000000:
return (0, types_1.FPCondition)(types_1.FPConditionCode.FPCC_F); // False
case 0b000001:
return (0, types_1.FPCondition)(types_1.FPConditionCode.FPCC_EQ); // Equal
case 0b000010:
return (0, types_1.FPCondition)(types_1.FPConditionCode.FPCC_OGT); // Ordered Greater Than
case 0b000011:
return (0, types_1.FPCondition)(types_1.FPConditionCode.FPCC_OGE); // Ordered Greater Than or Equal
case 0b000100:
return (0, types_1.FPCondition)(types_1.FPConditionCode.FPCC_OLT); // Ordered Less Than
case 0b000101:
return (0, types_1.FPCondition)(types_1.FPConditionCode.FPCC_OLE); // Ordered Less Than or Equal
case 0b000110:
return (0, types_1.FPCondition)(types_1.FPConditionCode.FPCC_OGL); // Ordered Greater Than or Less Than
case 0b000111:
return (0, types_1.FPCondition)(types_1.FPConditionCode.FPCC_OR); // Ordered
case 0b001000:
return (0, types_1.FPCondition)(types_1.FPConditionCode.FPCC_UN); // Unordered
case 0b001001:
return (0, types_1.FPCondition)(types_1.FPConditionCode.FPCC_UEQ); // Unordered or Equal
case 0b001010:
return (0, types_1.FPCondition)(types_1.FPConditionCode.FPCC_UGT); // Unordered or Greater Than
case 0b001011:
return (0, types_1.FPCondition)(types_1.FPConditionCode.FPCC_UGE); // Unordered or Greater Than or Equal
case 0b001100:
return (0, types_1.FPCondition)(types_1.FPConditionCode.FPCC_ULT); // Unordered or Less Than
case 0b001101:
return (0, types_1.FPCondition)(types_1.FPConditionCode.FPCC_ULE); // Unordered or Less Than or Equal
case 0b001110:
return (0, types_1.FPCondition)(types_1.FPConditionCode.FPCC_NE); // Not Equal
case 0b001111:
return (0, types_1.FPCondition)(types_1.FPConditionCode.FPCC_T); // True
case 0b010000:
return (0, types_1.FPCondition)(types_1.FPConditionCode.FPCC_SF); // Signaling False
case 0b010001:
return (0, types_1.FPCondition)(types_1.FPConditionCode.FPCC_SEQ); // Signaling Equal
case 0b010010:
return (0, types_1.FPCondition)(types_1.FPConditionCode.FPCC_GT); // Greater Than
case 0b010011:
return (0, types_1.FPCondition)(types_1.FPConditionCode.FPCC_GE); // Greater Than or Equal
case 0b010100:
return (0, types_1.FPCondition)(types_1.FPConditionCode.FPCC_LT); // Less Than
case 0b010101:
return (0, types_1.FPCondition)(types_1.FPConditionCode.FPCC_LE); // Less Than or Equal
case 0b010110:
return (0, types_1.FPCondition)(types_1.FPConditionCode.FPCC_GL); // Greater Than or Less Than
case 0b010111:
return (0, types_1.FPCondition)(types_1.FPConditionCode.FPCC_GLE); // Greater Than or Less Than or Equal
case 0b011000:
return (0, types_1.FPCondition)(types_1.FPConditionCode.FPCC_NGLE); // Not (Greater Than or Less Than or Equal)
case 0b011001:
return (0, types_1.FPCondition)(types_1.FPConditionCode.FPCC_NGL); // Not (Greater Than or Less Than)
case 0b011010:
return (0, types_1.FPCondition)(types_1.FPConditionCode.FPCC_NLE); // Not (Less Than or Equal)
case 0b011011:
return (0, types_1.FPCondition)(types_1.FPConditionCode.FPCC_NLT); // Not (Less Than)
case 0b011100:
return (0, types_1.FPCondition)(types_1.FPConditionCode.FPCC_NGE); // Not (Greater Than or Equal)
case 0b011101:
return (0, types_1.FPCondition)(types_1.FPConditionCode.FPCC_NGT); // Not (Greater Than)
case 0b011110:
return (0, types_1.FPCondition)(types_1.FPConditionCode.FPCC_SNE); // Signaling Not Equal
default:
return (0, types_1.FPCondition)(types_1.FPConditionCode.FPCC_ST); // Signaling True
}
}
decodeFpMovem(r, m, direction, mask, mode) {
const ea = this.ea(r, m, 10);
const regs = (mode & 1) === 0 ? (0, types_1.REGLIST)(mask) : (0, types_1.DR)(mask >> 4);
const extra = (0, types_1.FloatFormat)((0, types_1.FPF_EXTENDED_REAL)());
return direction === 0
? [10, ea, regs, extra] // move from memory to float registers
: [10, regs, ea, extra]; // move from registers to memory
}
}
exports.default = CodeStream;
//# sourceMappingURL=codestream.js.map