mirror of
https://github.com/TomHarte/CLK.git
synced 2025-08-09 05:25:01 +00:00
Implement IMUL, improve test memory footprint.
This commit is contained in:
@@ -496,6 +496,41 @@ void mul(IntT &destination_high, IntT &destination_low, IntT source, Status &sta
|
|||||||
status.overflow = status.carry = destination_high;
|
status.overflow = status.carry = destination_high;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename IntT>
|
||||||
|
void imul(IntT &destination_high, IntT &destination_low, IntT source, Status &status) {
|
||||||
|
/*
|
||||||
|
(as modified by https://www.felixcloutier.com/x86/daa ...)
|
||||||
|
|
||||||
|
IF (OperandSize = 8)
|
||||||
|
THEN
|
||||||
|
AX ← AL ∗ SRC (* signed multiplication *)
|
||||||
|
IF (AX = SignExtend(AL))
|
||||||
|
THEN CF = 0; OF = 0;
|
||||||
|
ELSE CF = 1; OF = 1;
|
||||||
|
FI;
|
||||||
|
ELSE IF OperandSize = 16
|
||||||
|
THEN
|
||||||
|
DX:AX ← AX ∗ SRC (* signed multiplication *)
|
||||||
|
IF (DX:AX = SignExtend(AX))
|
||||||
|
THEN CF = 0; OF = 0;
|
||||||
|
ELSE CF = 1; OF = 1;
|
||||||
|
FI;
|
||||||
|
ELSE (* OperandSize = 32 *)
|
||||||
|
EDX:EAX ← EAX ∗ SRC (* signed multiplication *)
|
||||||
|
IF (EDX:EAX = SignExtend(EAX))
|
||||||
|
THEN CF = 0; OF = 0;
|
||||||
|
ELSE CF = 1; OF = 1;
|
||||||
|
FI;
|
||||||
|
FI;
|
||||||
|
*/
|
||||||
|
using sIntT = typename std::make_signed<IntT>::type;
|
||||||
|
destination_high = (sIntT(destination_low) * sIntT(source)) >> (8 * sizeof(IntT));
|
||||||
|
destination_low = IntT(sIntT(destination_low) * sIntT(source));
|
||||||
|
|
||||||
|
const auto sign_extension = (destination_low & top_bit<IntT>()) ? IntT(~0) : 0;
|
||||||
|
status.overflow = status.carry = destination_high != sign_extension;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename IntT>
|
template <typename IntT>
|
||||||
void and_(IntT &destination, IntT source, Status &status) {
|
void and_(IntT &destination, IntT source, Status &status) {
|
||||||
/*
|
/*
|
||||||
@@ -671,6 +706,15 @@ template <
|
|||||||
Primitive::mul(registers.edx(), registers.eax(), source(), status);
|
Primitive::mul(registers.edx(), registers.eax(), source(), status);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
case Operation::IMUL_1:
|
||||||
|
if constexpr (data_size == DataSize::Byte) {
|
||||||
|
Primitive::imul(registers.ah(), registers.al(), source(), status);
|
||||||
|
} else if constexpr (data_size == DataSize::Word) {
|
||||||
|
Primitive::imul(registers.dx(), registers.ax(), source(), status);
|
||||||
|
} else if constexpr (data_size == DataSize::DWord) {
|
||||||
|
Primitive::imul(registers.edx(), registers.eax(), source(), status);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
|
||||||
case Operation::AND: Primitive::and_(destination(), source(), status); break;
|
case Operation::AND: Primitive::and_(destination(), source(), status); break;
|
||||||
|
|
||||||
|
@@ -71,7 +71,7 @@ enum class Operation: uint8_t {
|
|||||||
SUB,
|
SUB,
|
||||||
/// Unsigned multiply; multiplies the source value by EAX, AX or AL, storing the result in EDX:EAX, DX:AX or AX.
|
/// Unsigned multiply; multiplies the source value by EAX, AX or AL, storing the result in EDX:EAX, DX:AX or AX.
|
||||||
MUL,
|
MUL,
|
||||||
/// Single operand signed multiply; multiplies the source value by AX or AL, storing the result in DX:AX or AX.
|
/// 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,
|
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 source value by AX or AL, storing the quotient in AL and the remainder in AH.
|
||||||
DIV,
|
DIV,
|
||||||
|
@@ -278,56 +278,59 @@ struct FailedExecution {
|
|||||||
- (NSArray<NSString *> *)testFiles {
|
- (NSArray<NSString *> *)testFiles {
|
||||||
NSString *path = [NSString stringWithUTF8String:TestSuiteHome];
|
NSString *path = [NSString stringWithUTF8String:TestSuiteHome];
|
||||||
NSSet *allowList = [NSSet setWithArray:@[
|
NSSet *allowList = [NSSet setWithArray:@[
|
||||||
// @"37.json.gz", // AAA
|
@"37.json.gz", // AAA
|
||||||
// @"3F.json.gz", // AAS
|
@"3F.json.gz", // AAS
|
||||||
// @"D4.json.gz", // AAM
|
@"D4.json.gz", // AAM
|
||||||
// @"D5.json.gz", // AAD
|
@"D5.json.gz", // AAD
|
||||||
// @"27.json.gz", // DAA
|
@"27.json.gz", // DAA
|
||||||
// @"2F.json.gz", // DAS
|
@"2F.json.gz", // DAS
|
||||||
//
|
|
||||||
// @"98.json.gz", // CBW
|
@"98.json.gz", // CBW
|
||||||
// @"99.json.gz", // CWD
|
@"99.json.gz", // CWD
|
||||||
//
|
|
||||||
// // ESC
|
// ESC
|
||||||
// @"D8.json.gz", @"D9.json.gz", @"DA.json.gz", @"DB.json.gz",
|
@"D8.json.gz", @"D9.json.gz", @"DA.json.gz", @"DB.json.gz",
|
||||||
// @"DC.json.gz", @"DD.json.gz", @"DE.json.gz", @"DE.json.gz",
|
@"DC.json.gz", @"DD.json.gz", @"DE.json.gz", @"DE.json.gz",
|
||||||
//
|
|
||||||
// // Untested: HLT, WAIT
|
// Untested: HLT, WAIT
|
||||||
////
|
|
||||||
// // ADC
|
// ADC
|
||||||
// @"10.json.gz", @"11.json.gz", @"12.json.gz", @"13.json.gz", @"14.json.gz", @"15.json.gz",
|
@"10.json.gz", @"11.json.gz", @"12.json.gz", @"13.json.gz", @"14.json.gz", @"15.json.gz",
|
||||||
// @"80.2.json.gz", @"81.2.json.gz", @"83.2.json.gz",
|
@"80.2.json.gz", @"81.2.json.gz", @"83.2.json.gz",
|
||||||
//
|
|
||||||
// // ADD
|
// ADD
|
||||||
// @"00.json.gz", @"01.json.gz", @"02.json.gz", @"03.json.gz", @"04.json.gz", @"05.json.gz",
|
@"00.json.gz", @"01.json.gz", @"02.json.gz", @"03.json.gz", @"04.json.gz", @"05.json.gz",
|
||||||
// @"80.0.json.gz", @"81.0.json.gz", @"83.0.json.gz",
|
@"80.0.json.gz", @"81.0.json.gz", @"83.0.json.gz",
|
||||||
//
|
|
||||||
// // SBB
|
// SBB
|
||||||
// @"18.json.gz", @"19.json.gz", @"1A.json.gz", @"1B.json.gz", @"1C.json.gz", @"1D.json.gz",
|
@"18.json.gz", @"19.json.gz", @"1A.json.gz", @"1B.json.gz", @"1C.json.gz", @"1D.json.gz",
|
||||||
// @"80.3.json.gz", @"81.3.json.gz", @"83.3.json.gz",
|
@"80.3.json.gz", @"81.3.json.gz", @"83.3.json.gz",
|
||||||
//
|
|
||||||
// // SUB
|
// SUB
|
||||||
// @"28.json.gz", @"29.json.gz", @"2A.json.gz", @"2B.json.gz", @"2C.json.gz", @"2D.json.gz",
|
@"28.json.gz", @"29.json.gz", @"2A.json.gz", @"2B.json.gz", @"2C.json.gz", @"2D.json.gz",
|
||||||
// @"80.5.json.gz", @"81.5.json.gz", @"83.5.json.gz",
|
@"80.5.json.gz", @"81.5.json.gz", @"83.5.json.gz",
|
||||||
|
|
||||||
// MUL
|
// MUL
|
||||||
@"F6.4.json.gz", @"F7.4.json.gz",
|
@"F6.4.json.gz", @"F7.4.json.gz",
|
||||||
|
|
||||||
// // NOP
|
// IMUL_1
|
||||||
// @"90.json.gz",
|
@"F6.5.json.gz", @"F7.5.json.gz",
|
||||||
|
|
||||||
|
// NOP
|
||||||
|
@"90.json.gz",
|
||||||
|
|
||||||
// AND
|
// AND
|
||||||
// @"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
|
// CALL
|
||||||
// @"E8.json.gz", @"FF.2.json.gz",
|
@"E8.json.gz", @"FF.2.json.gz",
|
||||||
// @"9A.json.gz", @"FF.3.json.gz",
|
@"9A.json.gz", @"FF.3.json.gz",
|
||||||
//
|
|
||||||
// @"F8.json.gz", // CLC
|
@"F8.json.gz", // CLC
|
||||||
// @"FC.json.gz", // CLD
|
@"FC.json.gz", // CLD
|
||||||
// @"FA.json.gz", // CLI
|
@"FA.json.gz", // CLI
|
||||||
// @"F5.json.gz", // CMC
|
@"F5.json.gz", // CMC
|
||||||
]];
|
]];
|
||||||
|
|
||||||
NSSet *ignoreList = nil;
|
NSSet *ignoreList = nil;
|
||||||
@@ -585,7 +588,7 @@ struct FailedExecution {
|
|||||||
|
|
||||||
- (void)testDecoding {
|
- (void)testDecoding {
|
||||||
NSMutableArray<NSString *> *failures = [[NSMutableArray alloc] init];
|
NSMutableArray<NSString *> *failures = [[NSMutableArray alloc] init];
|
||||||
for(NSString *file in [self testFiles]) {
|
for(NSString *file in [self testFiles]) @autoreleasepool {
|
||||||
for(NSDictionary *test in [self testsInFile:file]) {
|
for(NSDictionary *test in [self testsInFile:file]) {
|
||||||
// A single failure per instruction is fine.
|
// A single failure per instruction is fine.
|
||||||
if(![self applyDecodingTest:test file:file assert:YES]) {
|
if(![self applyDecodingTest:test file:file assert:YES]) {
|
||||||
@@ -604,7 +607,7 @@ struct FailedExecution {
|
|||||||
- (void)testExecution {
|
- (void)testExecution {
|
||||||
NSDictionary *metadata = [self metadata];
|
NSDictionary *metadata = [self metadata];
|
||||||
|
|
||||||
for(NSString *file in [self testFiles]) {
|
for(NSString *file in [self testFiles]) @autoreleasepool {
|
||||||
// Determine the metadata key.
|
// Determine the metadata key.
|
||||||
NSString *const name = [file lastPathComponent];
|
NSString *const name = [file lastPathComponent];
|
||||||
NSRange first_dot = [name rangeOfString:@"."];
|
NSRange first_dot = [name rangeOfString:@"."];
|
||||||
|
Reference in New Issue
Block a user