1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-06-25 18:30:07 +00:00

Add DIV, faulty IDIV.

This commit is contained in:
Thomas Harte 2023-10-10 10:34:18 -04:00
parent b420d4cbd7
commit dbf7d07609
4 changed files with 75 additions and 10 deletions

View File

@ -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;

View File

@ -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,

View File

@ -12,11 +12,11 @@
namespace InstructionSet::x86 {
enum Interrupt {
DivideByZero = 0,
SingleStep = 1,
NMI = 2,
OneByte = 3,
OnOverflow = 4,
DivideError = 0,
SingleStep = 1,
NMI = 2,
OneByte = 3,
OnOverflow = 4,
};
}

View File

@ -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;