mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-19 23:32:28 +00:00
Add DIV, faulty IDIV.
This commit is contained in:
parent
b420d4cbd7
commit
dbf7d07609
@ -256,7 +256,7 @@ inline void aam(CPU::RegisterPair16 &ax, uint8_t imm, Status &status, FlowContro
|
||||
If ... an immediate value of 0 is used, it will cause a #DE (divide error) exception.
|
||||
*/
|
||||
if(!imm) {
|
||||
flow_controller.interrupt(Interrupt::DivideByZero);
|
||||
flow_controller.interrupt(Interrupt::DivideError);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -531,6 +531,45 @@ void imul(IntT &destination_high, IntT &destination_low, IntT source, Status &st
|
||||
status.overflow = status.carry = destination_high != sign_extension;
|
||||
}
|
||||
|
||||
template <typename IntT, typename FlowControllerT>
|
||||
void div(IntT &destination_high, IntT &destination_low, IntT source, FlowControllerT &flow_controller) {
|
||||
if(!source) {
|
||||
flow_controller.interrupt(Interrupt::DivideError);
|
||||
return;
|
||||
}
|
||||
|
||||
// TEMPORARY HACK. Will not work with DWords.
|
||||
const uint32_t dividend = (destination_high << (8 * sizeof(IntT))) + destination_low;
|
||||
const auto result = dividend / source;
|
||||
if(IntT(result) != result) {
|
||||
flow_controller.interrupt(Interrupt::DivideError);
|
||||
return;
|
||||
}
|
||||
|
||||
destination_low = IntT(result);
|
||||
destination_high = dividend % source;
|
||||
}
|
||||
|
||||
template <typename IntT, typename FlowControllerT>
|
||||
void idiv(IntT &destination_high, IntT &destination_low, IntT source, FlowControllerT &flow_controller) {
|
||||
if(!source) {
|
||||
flow_controller.interrupt(Interrupt::DivideError);
|
||||
return;
|
||||
}
|
||||
|
||||
// TEMPORARY HACK. Will not work with DWords.
|
||||
using sIntT = typename std::make_signed<IntT>::type;
|
||||
const int32_t dividend = (sIntT(destination_high) << (8 * sizeof(IntT))) + destination_low;
|
||||
const auto result = dividend / sIntT(source);
|
||||
if(sIntT(result) != result) {
|
||||
flow_controller.interrupt(Interrupt::DivideError);
|
||||
return;
|
||||
}
|
||||
|
||||
destination_low = IntT(result);
|
||||
destination_high = dividend % sIntT(source);
|
||||
}
|
||||
|
||||
template <typename IntT>
|
||||
void and_(IntT &destination, IntT source, Status &status) {
|
||||
/*
|
||||
@ -718,6 +757,24 @@ template <
|
||||
Primitive::imul(registers.edx(), registers.eax(), source(), status);
|
||||
}
|
||||
return;
|
||||
case Operation::DIV:
|
||||
if constexpr (data_size == DataSize::Byte) {
|
||||
Primitive::div(registers.ah(), registers.al(), source(), flow_controller);
|
||||
} else if constexpr (data_size == DataSize::Word) {
|
||||
Primitive::div(registers.dx(), registers.ax(), source(), flow_controller);
|
||||
} else if constexpr (data_size == DataSize::DWord) {
|
||||
Primitive::div(registers.edx(), registers.eax(), source(), flow_controller);
|
||||
}
|
||||
return;
|
||||
case Operation::IDIV:
|
||||
if constexpr (data_size == DataSize::Byte) {
|
||||
Primitive::idiv(registers.ah(), registers.al(), source(), flow_controller);
|
||||
} else if constexpr (data_size == DataSize::Word) {
|
||||
Primitive::idiv(registers.dx(), registers.ax(), source(), flow_controller);
|
||||
} else if constexpr (data_size == DataSize::DWord) {
|
||||
Primitive::idiv(registers.edx(), registers.eax(), source(), flow_controller);
|
||||
}
|
||||
return;
|
||||
|
||||
case Operation::AND: Primitive::and_(destination(), source(), status); break;
|
||||
|
||||
|
@ -73,7 +73,7 @@ enum class Operation: uint8_t {
|
||||
MUL,
|
||||
/// Single operand signed multiply; multiplies the source value by EAX, AX or AL, storing the result in EDX:EAX, DX:AX or AX.
|
||||
IMUL_1,
|
||||
/// Unsigned divide; divide the source value by AX or AL, storing the quotient in AL and the remainder in AH.
|
||||
/// Unsigned divide; divide the AX, DX:AX or EDX:AX by the source(), storing the quotient in AL, AX or EAX and the remainder in AH, DX or EDX.
|
||||
DIV,
|
||||
/// Signed divide; divide the source value by AX or AL, storing the quotient in AL and the remainder in AH.
|
||||
IDIV,
|
||||
|
@ -12,7 +12,7 @@
|
||||
namespace InstructionSet::x86 {
|
||||
|
||||
enum Interrupt {
|
||||
DivideByZero = 0,
|
||||
DivideError = 0,
|
||||
SingleStep = 1,
|
||||
NMI = 2,
|
||||
OneByte = 3,
|
||||
|
@ -25,7 +25,7 @@ namespace {
|
||||
|
||||
// The tests themselves are not duplicated in this repository;
|
||||
// provide their real path here.
|
||||
constexpr char TestSuiteHome[] = "/Users/thomasharte/Projects/ProcessorTests/8088/v1";
|
||||
constexpr char TestSuiteHome[] = "/Users/tharte/Projects/ProcessorTests/8088/v1";
|
||||
|
||||
using Status = InstructionSet::x86::Status;
|
||||
struct Registers {
|
||||
@ -316,7 +316,12 @@ struct FailedExecution {
|
||||
// IMUL_1
|
||||
@"F6.5.json.gz", @"F7.5.json.gz",
|
||||
|
||||
// TODO: DIV, IDIV
|
||||
// DIV
|
||||
@"F6.6.json.gz", @"F7.6.json.gz",
|
||||
|
||||
// IDIV
|
||||
@"F6.7.json.gz", @"F7.7.json.gz",
|
||||
|
||||
// TODO: INC, DEC
|
||||
// TODO: IN, OUT
|
||||
// TODO: JO, JNO, JB, JNB, JZ, JNZ, JBE, JNBE, JS, JNS, JP, JNP, JL, JNL, JLE, JNLE,
|
||||
@ -363,6 +368,7 @@ struct FailedExecution {
|
||||
// TODO: CMP, TEST
|
||||
// TODO: XCHG, XLAT
|
||||
// TODO: SALC, SETMO, SETMOC
|
||||
|
||||
]];
|
||||
|
||||
NSSet *ignoreList = nil;
|
||||
@ -537,8 +543,10 @@ struct FailedExecution {
|
||||
for(NSArray<NSNumber *> *ram in final_state[@"ram"]) {
|
||||
execution_support.memory.touch([ram[0] intValue]);
|
||||
}
|
||||
[self populate:execution_support.registers status:initial_status value:initial_state[@"regs"]];
|
||||
Registers initial_registers;
|
||||
[self populate:initial_registers status:initial_status value:initial_state[@"regs"]];
|
||||
execution_support.status = initial_status;
|
||||
execution_support.registers = initial_registers;
|
||||
|
||||
// Execute instruction.
|
||||
execution_support.registers.ip_ += decoded.first;
|
||||
|
Loading…
Reference in New Issue
Block a user