1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-02-20 14:29:11 +00:00

Add logical right-shift tests.

This commit is contained in:
Thomas Harte 2024-03-01 18:06:54 -05:00
parent 7b28b3d634
commit e6f77a9b80
3 changed files with 82 additions and 33 deletions

View File

@ -28,6 +28,8 @@ template <> struct Carry<false> {
/// Apply a rotation of @c type to @c source of @c amount; @c carry should be either @c 1 or @c 0
/// at call to represent the current value of the carry flag. If @c set_carry is @c true then @c carry will
/// receive the new value of the carry flag following the rotation — @c 0 for no carry, @c non-0 for carry.
///
/// Shift amounts of 0 are given the meaning attributed to them for immediate shift counts.
template <ShiftType type, bool set_carry>
void shift(uint32_t &source, uint32_t amount, typename Carry<set_carry>::type carry) {
switch(type) {
@ -48,17 +50,14 @@ void shift(uint32_t &source, uint32_t amount, typename Carry<set_carry>::type ca
if(amount > 32) {
if constexpr (set_carry) carry = 0;
source = 0;
} else if(amount == 32) {
if constexpr (set_carry) carry = source & 0x8000'0000;
source = 0;
} else if(amount > 0) {
if constexpr (set_carry) carry = source & (1 << (amount - 1));
source >>= amount;
} else {
} else if(amount == 32 || !amount) {
// A logical shift right by '0' is treated as a shift by 32;
// assemblers are supposed to map LSR #0 to LSL #0.
if constexpr (set_carry) carry = source & 0x8000'0000;
source = 0;
} else {
if constexpr (set_carry) carry = source & (1 << (amount - 1));
source >>= amount;
}
break;

View File

@ -26,25 +26,6 @@ struct Executor {
template <bool allow_register, bool set_carry, typename FieldsT>
uint32_t decode_shift(FieldsT fields, uint32_t &rotate_carry, uint32_t pc_offset) {
uint32_t shift_amount;
if constexpr (allow_register) {
if(fields.shift_count_is_register()) {
// "When R15 appears in either of the Rn or Rs positions it will give the value
// of the PC alone, with the PSR bits replaced by zeroes. ...
//
// If a register is used to specify the shift amount, the
// PC will be 8 bytes ahead when used as Rs."
shift_amount =
fields.shift_register() == 15 ?
registers_.pc(8) :
registers_.active[fields.shift_register()];
} else {
shift_amount = fields.shift_amount();
}
} else {
shift_amount = fields.shift_amount();
}
// "When R15 appears in the Rm position it will give the value of the PC together
// with the PSR flags to the barrel shifter. ...
//
@ -57,8 +38,33 @@ struct Executor {
} else {
operand2 = registers_.active[fields.operand2()];
}
shift<set_carry>(fields.shift_type(), operand2, shift_amount, rotate_carry);
uint32_t shift_amount;
if constexpr (allow_register) {
if(fields.shift_count_is_register()) {
// "When R15 appears in either of the Rn or Rs positions it will give the value
// of the PC alone, with the PSR bits replaced by zeroes. ...
//
// If a register is used to specify the shift amount, the
// PC will be 8 bytes ahead when used as Rs."
shift_amount =
fields.shift_register() == 15 ?
registers_.pc(8) :
registers_.active[fields.shift_register()];
// A register shift amount of 0 has a different meaning than an in-instruction
// shift amount of 0.
if(!shift_amount) {
return operand2;
}
} else {
shift_amount = fields.shift_amount();
}
} else {
shift_amount = fields.shift_amount();
}
shift<set_carry>(fields.shift_type(), operand2, shift_amount, rotate_carry);
return operand2;
}

View File

@ -41,13 +41,57 @@ struct Memory {
@implementation ARMDecoderTests
- (void)testXYX {
Executor<Memory> scheduler;
//- (void)testXYX {
// Executor<Memory> scheduler;
//
// for(int c = 0; c < 65536; c++) {
// InstructionSet::ARM::dispatch(c << 16, scheduler);
// }
// InstructionSet::ARM::dispatch(0xEAE06900, scheduler);
//}
for(int c = 0; c < 65536; c++) {
InstructionSet::ARM::dispatch(c << 16, scheduler);
}
InstructionSet::ARM::dispatch(0xEAE06900, scheduler);
- (void)testBarrelShifterLogicalRight {
uint32_t value;
uint32_t carry;
// Test successive shifts by 4; one generating carry and one not.
value = 0x12345678;
shift<ShiftType::LogicalRight, true>(value, 4, carry);
XCTAssertEqual(value, 0x1234567);
XCTAssertNotEqual(carry, 0);
shift<ShiftType::LogicalRight, true>(value, 4, carry);
XCTAssertEqual(value, 0x123456);
XCTAssertEqual(carry, 0);
// Test shift by 1.
value = 0x8003001;
shift<ShiftType::LogicalRight, true>(value, 1, carry);
XCTAssertEqual(value, 0x4001800);
XCTAssertNotEqual(carry, 0);
// Test a shift by greater than 32.
value = 0xffff'ffff;
shift<ShiftType::LogicalRight, true>(value, 33, carry);
XCTAssertEqual(value, 0);
XCTAssertEqual(carry, 0);
// Test shifts by 32: result is always 0, carry is whatever was in bit 31.
value = 0xffff'ffff;
shift<ShiftType::LogicalRight, true>(value, 32, carry);
XCTAssertEqual(value, 0);
XCTAssertNotEqual(carry, 0);
value = 0x7fff'ffff;
shift<ShiftType::LogicalRight, true>(value, 32, carry);
XCTAssertEqual(value, 0);
XCTAssertEqual(carry, 0);
// Test that a logical right shift by 0 is the same as a shift by 32.
value = 0xffff'ffff;
shift<ShiftType::LogicalRight, true>(value, 0, carry);
XCTAssertEqual(value, 0);
XCTAssertNotEqual(carry, 0);
}
@end