mirror of
https://github.com/TomHarte/CLK.git
synced 2025-02-11 15:30:52 +00:00
Implement CALL
.
This commit is contained in:
parent
4f14210ee0
commit
5a77f0c93c
@ -885,7 +885,6 @@ std::pair<int, typename Decoder<model>::InstructionT> Decoder<model>::decode(con
|
|||||||
case 4: SetOperation(Operation::JMPabs); break;
|
case 4: SetOperation(Operation::JMPabs); break;
|
||||||
case 5: SetOperation(Operation::JMPfar); break;
|
case 5: SetOperation(Operation::JMPfar); break;
|
||||||
}
|
}
|
||||||
// TODO: CALLfar and JMPfar aren't correct above; find out what is.
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ModRegRMFormat::MemRegSingleOperand:
|
case ModRegRMFormat::MemRegSingleOperand:
|
||||||
|
@ -15,6 +15,144 @@
|
|||||||
|
|
||||||
namespace InstructionSet::x86 {
|
namespace InstructionSet::x86 {
|
||||||
|
|
||||||
|
template <Model model, typename IntT, typename InstructionT, typename RegistersT, typename MemoryT>
|
||||||
|
IntT *resolve(
|
||||||
|
InstructionT &instruction,
|
||||||
|
Source source,
|
||||||
|
DataPointer pointer,
|
||||||
|
RegistersT ®isters,
|
||||||
|
MemoryT &memory,
|
||||||
|
IntT *none = nullptr,
|
||||||
|
IntT *immediate = nullptr
|
||||||
|
);
|
||||||
|
|
||||||
|
template <Model model, Source source, typename IntT, typename InstructionT, typename RegistersT, typename MemoryT>
|
||||||
|
uint32_t address(
|
||||||
|
InstructionT &instruction,
|
||||||
|
DataPointer pointer,
|
||||||
|
RegistersT ®isters,
|
||||||
|
MemoryT &memory
|
||||||
|
) {
|
||||||
|
// TODO: non-word indexes and bases.
|
||||||
|
uint32_t address;
|
||||||
|
switch(source) {
|
||||||
|
default: return 0;
|
||||||
|
case Source::Indirect: {
|
||||||
|
uint16_t zero = 0;
|
||||||
|
address = *resolve<model, uint16_t>(instruction, pointer.index(), pointer, registers, memory, &zero);
|
||||||
|
if constexpr (is_32bit(model)) {
|
||||||
|
address <<= pointer.scale();
|
||||||
|
}
|
||||||
|
address += instruction.offset() + *resolve<model, uint16_t>(instruction, pointer.base(), pointer, registers, memory);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case Source::IndirectNoBase: {
|
||||||
|
uint16_t zero = 0;
|
||||||
|
address = *resolve<model, uint16_t>(instruction, pointer.index(), pointer, registers, memory, &zero);
|
||||||
|
if constexpr (is_32bit(model)) {
|
||||||
|
address <<= pointer.scale();
|
||||||
|
}
|
||||||
|
address += instruction.offset();
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case Source::DirectAddress: return instruction.offset();
|
||||||
|
}
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <Model model, typename IntT, typename InstructionT, typename RegistersT, typename MemoryT>
|
||||||
|
IntT *resolve(
|
||||||
|
InstructionT &instruction,
|
||||||
|
Source source,
|
||||||
|
DataPointer pointer,
|
||||||
|
RegistersT ®isters,
|
||||||
|
MemoryT &memory,
|
||||||
|
IntT *none,
|
||||||
|
IntT *immediate
|
||||||
|
) {
|
||||||
|
// Rules:
|
||||||
|
//
|
||||||
|
// * if this is a memory access, set target_address and break;
|
||||||
|
// * otherwise return the appropriate value.
|
||||||
|
uint32_t target_address;
|
||||||
|
switch(source) {
|
||||||
|
case Source::eAX:
|
||||||
|
// Slightly contorted if chain here and below:
|
||||||
|
//
|
||||||
|
// (i) does the `constexpr` version of a `switch`; and
|
||||||
|
// (i) ensures .eax() etc aren't called on @c registers for 16-bit processors, so they need not implement 32-bit storage.
|
||||||
|
if constexpr (is_32bit(model) && std::is_same_v<IntT, uint32_t>) { return ®isters.eax(); }
|
||||||
|
else if constexpr (std::is_same_v<IntT, uint16_t>) { return ®isters.ax(); }
|
||||||
|
else if constexpr (std::is_same_v<IntT, uint8_t>) { return ®isters.al(); }
|
||||||
|
else { return nullptr; }
|
||||||
|
case Source::eCX:
|
||||||
|
if constexpr (is_32bit(model) && std::is_same_v<IntT, uint32_t>) { return ®isters.ecx(); }
|
||||||
|
else if constexpr (std::is_same_v<IntT, uint16_t>) { return ®isters.cx(); }
|
||||||
|
else if constexpr (std::is_same_v<IntT, uint8_t>) { return ®isters.cl(); }
|
||||||
|
else { return nullptr; }
|
||||||
|
case Source::eDX:
|
||||||
|
if constexpr (is_32bit(model) && std::is_same_v<IntT, uint32_t>) { return ®isters.edx(); }
|
||||||
|
else if constexpr (std::is_same_v<IntT, uint16_t>) { return ®isters.dx(); }
|
||||||
|
else if constexpr (std::is_same_v<IntT, uint8_t>) { return ®isters.dl(); }
|
||||||
|
else if constexpr (std::is_same_v<IntT, uint32_t>) { return nullptr; }
|
||||||
|
case Source::eBX:
|
||||||
|
if constexpr (is_32bit(model) && std::is_same_v<IntT, uint32_t>) { return ®isters.ebx(); }
|
||||||
|
else if constexpr (std::is_same_v<IntT, uint16_t>) { return ®isters.bx(); }
|
||||||
|
else if constexpr (std::is_same_v<IntT, uint8_t>) { return ®isters.bl(); }
|
||||||
|
else if constexpr (std::is_same_v<IntT, uint32_t>) { return nullptr; }
|
||||||
|
case Source::eSPorAH:
|
||||||
|
if constexpr (is_32bit(model) && std::is_same_v<IntT, uint32_t>) { return ®isters.esp(); }
|
||||||
|
else if constexpr (std::is_same_v<IntT, uint16_t>) { return ®isters.sp(); }
|
||||||
|
else if constexpr (std::is_same_v<IntT, uint8_t>) { return ®isters.ah(); }
|
||||||
|
else { return nullptr; }
|
||||||
|
case Source::eBPorCH:
|
||||||
|
if constexpr (is_32bit(model) && std::is_same_v<IntT, uint32_t>) { return ®isters.ebp(); }
|
||||||
|
else if constexpr (std::is_same_v<IntT, uint16_t>) { return ®isters.bp(); }
|
||||||
|
else if constexpr (std::is_same_v<IntT, uint8_t>) { return ®isters.ch(); }
|
||||||
|
else { return nullptr; }
|
||||||
|
case Source::eSIorDH:
|
||||||
|
if constexpr (is_32bit(model) && std::is_same_v<IntT, uint32_t>) { return ®isters.esi(); }
|
||||||
|
else if constexpr (std::is_same_v<IntT, uint16_t>) { return ®isters.si(); }
|
||||||
|
else if constexpr (std::is_same_v<IntT, uint8_t>) { return ®isters.dh(); }
|
||||||
|
else { return nullptr; }
|
||||||
|
case Source::eDIorBH:
|
||||||
|
if constexpr (is_32bit(model) && std::is_same_v<IntT, uint32_t>) { return ®isters.edi(); }
|
||||||
|
else if constexpr (std::is_same_v<IntT, uint16_t>) { return ®isters.di(); }
|
||||||
|
else if constexpr (std::is_same_v<IntT, uint8_t>) { return ®isters.bh(); }
|
||||||
|
else { return nullptr; }
|
||||||
|
|
||||||
|
case Source::ES: if constexpr (std::is_same_v<IntT, uint16_t>) return ®isters.es(); else return nullptr;
|
||||||
|
case Source::CS: if constexpr (std::is_same_v<IntT, uint16_t>) return ®isters.cs(); else return nullptr;
|
||||||
|
case Source::SS: if constexpr (std::is_same_v<IntT, uint16_t>) return ®isters.ss(); else return nullptr;
|
||||||
|
case Source::DS: if constexpr (std::is_same_v<IntT, uint16_t>) return ®isters.ds(); else return nullptr;
|
||||||
|
|
||||||
|
// 16-bit models don't have FS and GS.
|
||||||
|
case Source::FS: if constexpr (is_32bit(model) && std::is_same_v<IntT, uint16_t>) return ®isters.fs(); else return nullptr;
|
||||||
|
case Source::GS: if constexpr (is_32bit(model) && std::is_same_v<IntT, uint16_t>) return ®isters.gs(); else return nullptr;
|
||||||
|
|
||||||
|
case Source::Immediate:
|
||||||
|
*immediate = instruction.operand();
|
||||||
|
return immediate;
|
||||||
|
|
||||||
|
case Source::None: return none;
|
||||||
|
|
||||||
|
case Source::Indirect:
|
||||||
|
target_address = address<model, Source::Indirect, IntT>(instruction, pointer, registers, memory);
|
||||||
|
break;
|
||||||
|
case Source::IndirectNoBase:
|
||||||
|
target_address = address<model, Source::IndirectNoBase, IntT>(instruction, pointer, registers, memory);
|
||||||
|
break;
|
||||||
|
case Source::DirectAddress:
|
||||||
|
target_address = address<model, Source::DirectAddress, IntT>(instruction, pointer, registers, memory);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If execution has reached here then a memory fetch is required.
|
||||||
|
// Do it and exit.
|
||||||
|
const Source segment = pointer.segment(instruction.segment_override());
|
||||||
|
return &memory.template access<IntT>(segment, target_address);
|
||||||
|
};
|
||||||
|
|
||||||
namespace Primitive {
|
namespace Primitive {
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -217,115 +355,49 @@ void and_(IntT &destination, IntT source, Status &status) {
|
|||||||
status.zero = status.parity = destination;
|
status.zero = status.parity = destination;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename IntT, typename RegistersT, typename FlowControllerT>
|
||||||
|
inline void call_relative(IntT offset, RegistersT ®isters, FlowControllerT &flow_controller) {
|
||||||
|
flow_controller.call(registers.ip() + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <Model model, DataSize data_size, typename InstructionT, typename RegistersT, typename MemoryT>
|
template <typename IntT, typename FlowControllerT>
|
||||||
typename DataSizeType<data_size>::type *
|
inline void call_absolute(IntT target, FlowControllerT &flow_controller) {
|
||||||
resolve(
|
flow_controller.call(target);
|
||||||
InstructionT &instruction,
|
}
|
||||||
Source source,
|
|
||||||
DataPointer pointer,
|
template <Model model, typename InstructionT, typename FlowControllerT, typename RegistersT, typename MemoryT>
|
||||||
|
inline void call_far(InstructionT &instruction,
|
||||||
|
FlowControllerT &flow_controller,
|
||||||
RegistersT ®isters,
|
RegistersT ®isters,
|
||||||
MemoryT &memory,
|
MemoryT &memory) {
|
||||||
typename DataSizeType<data_size>::type *none = nullptr,
|
|
||||||
typename DataSizeType<data_size>::type *immediate = nullptr
|
|
||||||
) {
|
|
||||||
// Rules:
|
|
||||||
//
|
|
||||||
// * if this is a memory access, set target_address and break;
|
|
||||||
// * otherwise return the appropriate value.
|
|
||||||
uint32_t address;
|
|
||||||
switch(source) {
|
|
||||||
case Source::eAX:
|
|
||||||
// Slightly contorted if chain here and below:
|
|
||||||
//
|
|
||||||
// (i) does the `constexpr` version of a `switch`; and
|
|
||||||
// (i) ensures .eax() etc aren't called on @c registers for 16-bit processors, so they need not implement 32-bit storage.
|
|
||||||
if constexpr (is_32bit(model) && data_size == DataSize::DWord) { return ®isters.eax(); }
|
|
||||||
else if constexpr (data_size == DataSize::Word) { return ®isters.ax(); }
|
|
||||||
else if constexpr (data_size == DataSize::Byte) { return ®isters.al(); }
|
|
||||||
else { return nullptr; }
|
|
||||||
case Source::eCX:
|
|
||||||
if constexpr (is_32bit(model) && data_size == DataSize::DWord) { return ®isters.ecx(); }
|
|
||||||
else if constexpr (data_size == DataSize::Word) { return ®isters.cx(); }
|
|
||||||
else if constexpr (data_size == DataSize::Byte) { return ®isters.cl(); }
|
|
||||||
else { return nullptr; }
|
|
||||||
case Source::eDX:
|
|
||||||
if constexpr (is_32bit(model) && data_size == DataSize::DWord) { return ®isters.edx(); }
|
|
||||||
else if constexpr (data_size == DataSize::Word) { return ®isters.dx(); }
|
|
||||||
else if constexpr (data_size == DataSize::Byte) { return ®isters.dl(); }
|
|
||||||
else if constexpr (data_size == DataSize::DWord) { return nullptr; }
|
|
||||||
case Source::eBX:
|
|
||||||
if constexpr (is_32bit(model) && data_size == DataSize::DWord) { return ®isters.ebx(); }
|
|
||||||
else if constexpr (data_size == DataSize::Word) { return ®isters.bx(); }
|
|
||||||
else if constexpr (data_size == DataSize::Byte) { return ®isters.bl(); }
|
|
||||||
else if constexpr (data_size == DataSize::DWord) { return nullptr; }
|
|
||||||
case Source::eSPorAH:
|
|
||||||
if constexpr (is_32bit(model) && data_size == DataSize::DWord) { return ®isters.esp(); }
|
|
||||||
else if constexpr (data_size == DataSize::Word) { return ®isters.sp(); }
|
|
||||||
else if constexpr (data_size == DataSize::Byte) { return ®isters.ah(); }
|
|
||||||
else { return nullptr; }
|
|
||||||
case Source::eBPorCH:
|
|
||||||
if constexpr (is_32bit(model) && data_size == DataSize::DWord) { return ®isters.ebp(); }
|
|
||||||
else if constexpr (data_size == DataSize::Word) { return ®isters.bp(); }
|
|
||||||
else if constexpr (data_size == DataSize::Byte) { return ®isters.ch(); }
|
|
||||||
else { return nullptr; }
|
|
||||||
case Source::eSIorDH:
|
|
||||||
if constexpr (is_32bit(model) && data_size == DataSize::DWord) { return ®isters.esi(); }
|
|
||||||
else if constexpr (data_size == DataSize::Word) { return ®isters.si(); }
|
|
||||||
else if constexpr (data_size == DataSize::Byte) { return ®isters.dh(); }
|
|
||||||
else { return nullptr; }
|
|
||||||
case Source::eDIorBH:
|
|
||||||
if constexpr (is_32bit(model) && data_size == DataSize::DWord) { return ®isters.edi(); }
|
|
||||||
else if constexpr (data_size == DataSize::Word) { return ®isters.di(); }
|
|
||||||
else if constexpr (data_size == DataSize::Byte) { return ®isters.bh(); }
|
|
||||||
else { return nullptr; }
|
|
||||||
|
|
||||||
case Source::ES: if constexpr (data_size == DataSize::Word) return ®isters.es(); else return nullptr;
|
// TODO: eliminate 16-bit assumption below.
|
||||||
case Source::CS: if constexpr (data_size == DataSize::Word) return ®isters.cs(); else return nullptr;
|
uint16_t source_address = 0;
|
||||||
case Source::SS: if constexpr (data_size == DataSize::Word) return ®isters.ss(); else return nullptr;
|
auto pointer = instruction.destination();
|
||||||
case Source::DS: if constexpr (data_size == DataSize::Word) return ®isters.ds(); else return nullptr;
|
switch(pointer.template source<false>()) {
|
||||||
|
default:
|
||||||
// 16-bit models don't have FS and GS.
|
case Source::Immediate: flow_controller.call(instruction.segment(), instruction.offset()); return;
|
||||||
case Source::FS: if constexpr (is_32bit(model) && data_size == DataSize::Word) return ®isters.fs(); else return nullptr;
|
|
||||||
case Source::GS: if constexpr (is_32bit(model) && data_size == DataSize::Word) return ®isters.gs(); else return nullptr;
|
|
||||||
|
|
||||||
case Source::Immediate:
|
|
||||||
*immediate = instruction.operand();
|
|
||||||
return immediate;
|
|
||||||
|
|
||||||
case Source::None: return none;
|
|
||||||
|
|
||||||
// TODO: non-word indexes and bases in the next two cases.
|
|
||||||
case Source::Indirect: {
|
|
||||||
uint16_t zero = 0;
|
|
||||||
address = *resolve<model, DataSize::Word>(instruction, pointer.index(), pointer, registers, memory, &zero);
|
|
||||||
if constexpr (is_32bit(model)) {
|
|
||||||
address <<= pointer.scale();
|
|
||||||
}
|
|
||||||
address += instruction.offset() + *resolve<model, DataSize::Word>(instruction, pointer.base(), pointer, registers, memory);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case Source::IndirectNoBase: {
|
|
||||||
uint16_t zero = 0;
|
|
||||||
address = *resolve<model, DataSize::Word>(instruction, pointer.index(), pointer, registers, memory, &zero);
|
|
||||||
if constexpr (is_32bit(model)) {
|
|
||||||
address <<= pointer.scale();
|
|
||||||
}
|
|
||||||
address += instruction.offset();
|
|
||||||
} break;
|
|
||||||
|
|
||||||
|
case Source::Indirect:
|
||||||
|
source_address = address<model, Source::Indirect, uint16_t>(instruction, pointer, registers, memory);
|
||||||
|
break;
|
||||||
|
case Source::IndirectNoBase:
|
||||||
|
source_address = address<model, Source::IndirectNoBase, uint16_t>(instruction, pointer, registers, memory);
|
||||||
|
break;
|
||||||
case Source::DirectAddress:
|
case Source::DirectAddress:
|
||||||
address = instruction.offset();
|
source_address = address<model, Source::DirectAddress, uint16_t>(instruction, pointer, registers, memory);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If execution has reached here then a memory fetch is required.
|
const Source source_segment = pointer.segment(instruction.segment_override());
|
||||||
// Do it and exit.
|
|
||||||
const Source segment = pointer.segment(instruction.segment_override());
|
const uint16_t offset = memory.template access<uint16_t>(source_segment, source_address);
|
||||||
using IntT = typename DataSizeType<data_size>::type;
|
source_address += 2;
|
||||||
return &memory.template access<IntT>(segment, address);
|
const uint16_t segment = memory.template access<uint16_t>(source_segment, source_address);
|
||||||
};
|
flow_controller.call(segment, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
template <
|
template <
|
||||||
Model model,
|
Model model,
|
||||||
@ -338,9 +410,9 @@ template <
|
|||||||
> void perform(
|
> void perform(
|
||||||
const InstructionT &instruction,
|
const InstructionT &instruction,
|
||||||
Status &status,
|
Status &status,
|
||||||
[[maybe_unused]] FlowControllerT &flow_controller,
|
FlowControllerT &flow_controller,
|
||||||
RegistersT ®isters,
|
RegistersT ®isters,
|
||||||
[[maybe_unused]] MemoryT &memory,
|
MemoryT &memory,
|
||||||
[[maybe_unused]] IOT &io
|
[[maybe_unused]] IOT &io
|
||||||
) {
|
) {
|
||||||
using IntT = typename DataSizeType<data_size>::type;
|
using IntT = typename DataSizeType<data_size>::type;
|
||||||
@ -349,7 +421,7 @@ template <
|
|||||||
// Establish source() and destination() shorthand to fetch data if necessary.
|
// Establish source() and destination() shorthand to fetch data if necessary.
|
||||||
IntT immediate;
|
IntT immediate;
|
||||||
auto source = [&]() -> IntT& {
|
auto source = [&]() -> IntT& {
|
||||||
return *resolve<model, data_size>(
|
return *resolve<model, IntT>(
|
||||||
instruction,
|
instruction,
|
||||||
instruction.source().template source<false>(),
|
instruction.source().template source<false>(),
|
||||||
instruction.source(),
|
instruction.source(),
|
||||||
@ -359,7 +431,7 @@ template <
|
|||||||
&immediate);
|
&immediate);
|
||||||
};
|
};
|
||||||
auto destination = [&]() -> IntT& {
|
auto destination = [&]() -> IntT& {
|
||||||
return *resolve<model, data_size>(
|
return *resolve<model, IntT>(
|
||||||
instruction,
|
instruction,
|
||||||
instruction.destination().template source<false>(),
|
instruction.destination().template source<false>(),
|
||||||
instruction.destination(),
|
instruction.destination(),
|
||||||
@ -375,8 +447,8 @@ template <
|
|||||||
// * return directly if there is definitely no possible write back to RAM;
|
// * return directly if there is definitely no possible write back to RAM;
|
||||||
// * otherwise use the source() and destination() lambdas, and break in order to allow a writeback if necessary.
|
// * otherwise use the source() and destination() lambdas, and break in order to allow a writeback if necessary.
|
||||||
switch(instruction.operation) {
|
switch(instruction.operation) {
|
||||||
default: return;
|
default:
|
||||||
//assert(false);
|
assert(false);
|
||||||
|
|
||||||
case Operation::AAA: Primitive::aaa(registers.axp(), status); return;
|
case Operation::AAA: Primitive::aaa(registers.axp(), status); return;
|
||||||
case Operation::AAD: Primitive::aad(registers.axp(), instruction.operand(), status); return;
|
case Operation::AAD: Primitive::aad(registers.axp(), instruction.operand(), status); return;
|
||||||
@ -387,6 +459,16 @@ template <
|
|||||||
case Operation::ADD: Primitive::add(destination(), source(), status); break;
|
case Operation::ADD: Primitive::add(destination(), source(), status); break;
|
||||||
|
|
||||||
case Operation::AND: Primitive::and_(destination(), source(), status); break;
|
case Operation::AND: Primitive::and_(destination(), source(), status); break;
|
||||||
|
|
||||||
|
case Operation::CALLrel:
|
||||||
|
Primitive::call_relative(instruction.displacement(), registers, flow_controller);
|
||||||
|
return;
|
||||||
|
case Operation::CALLabs:
|
||||||
|
Primitive::call_absolute(destination(), flow_controller);
|
||||||
|
return;
|
||||||
|
case Operation::CALLfar:
|
||||||
|
Primitive::call_far<model>(instruction, flow_controller, registers, memory);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write to memory if required to complete this operation.
|
// Write to memory if required to complete this operation.
|
||||||
|
@ -64,7 +64,9 @@ struct Registers {
|
|||||||
uint16_t &di() { return di_; }
|
uint16_t &di() { return di_; }
|
||||||
|
|
||||||
uint16_t es_, cs_, ds_, ss_;
|
uint16_t es_, cs_, ds_, ss_;
|
||||||
|
|
||||||
uint16_t ip_;
|
uint16_t ip_;
|
||||||
|
uint16_t ip() { return ip_; }
|
||||||
|
|
||||||
uint16_t &es() { return es_; }
|
uint16_t &es() { return es_; }
|
||||||
uint16_t &cs() { return cs_; }
|
uint16_t &cs() { return cs_; }
|
||||||
@ -206,6 +208,18 @@ class FlowController {
|
|||||||
registers_.ip_ = new_ip;
|
registers_.ip_ = new_ip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void call(uint16_t address) {
|
||||||
|
push(registers_.ip_);
|
||||||
|
registers_.ip_ = address;
|
||||||
|
}
|
||||||
|
|
||||||
|
void call(uint16_t segment, uint16_t offset) {
|
||||||
|
push(registers_.cs_);
|
||||||
|
push(registers_.ip_);
|
||||||
|
registers_.cs_ = segment;
|
||||||
|
registers_.ip_ = offset;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Memory &memory_;
|
Memory &memory_;
|
||||||
Registers ®isters_;
|
Registers ®isters_;
|
||||||
@ -273,6 +287,10 @@ struct FailedExecution {
|
|||||||
@"20.json.gz", @"21.json.gz", @"22.json.gz", @"23.json.gz", @"24.json.gz", @"25.json.gz",
|
@"20.json.gz", @"21.json.gz", @"22.json.gz", @"23.json.gz", @"24.json.gz", @"25.json.gz",
|
||||||
@"80.4.json.gz", @"81.4.json.gz", @"83.4.json.gz",
|
@"80.4.json.gz", @"81.4.json.gz", @"83.4.json.gz",
|
||||||
|
|
||||||
|
// CALL
|
||||||
|
@"E8.json.gz", @"FF.2.json.gz",
|
||||||
|
@"9A.json.gz", @"FF.3.json.gz",
|
||||||
|
|
||||||
@"37.json.gz", // AAA
|
@"37.json.gz", // AAA
|
||||||
@"3F.json.gz", // AAS
|
@"3F.json.gz", // AAS
|
||||||
@"D4.json.gz", // AAM
|
@"D4.json.gz", // AAM
|
||||||
|
Loading…
x
Reference in New Issue
Block a user