tests: complete exec tests (for now)
Signed-off-by: Amneesh Singh <natto@weirdnatto.in>
This commit is contained in:
5
.github/workflows/main.yml
vendored
5
.github/workflows/main.yml
vendored
@@ -14,6 +14,11 @@ jobs:
|
|||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
auto-optimise-store = true
|
auto-optimise-store = true
|
||||||
experimental-features = nix-command flakes
|
experimental-features = nix-command flakes
|
||||||
|
- uses: cachix/cachix-action@v12
|
||||||
|
with:
|
||||||
|
name: pain
|
||||||
|
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
|
||||||
|
|
||||||
|
|
||||||
- name: setup
|
- name: setup
|
||||||
run: nix develop -c meson setup $BUILDDIR
|
run: nix develop -c meson setup $BUILDDIR
|
||||||
|
@@ -90,7 +90,7 @@ main(int argc, const char* argv[]) {
|
|||||||
Cpu cpu(bus);
|
Cpu cpu(bus);
|
||||||
while (true) {
|
while (true) {
|
||||||
cpu.step();
|
cpu.step();
|
||||||
sleep(1);
|
sleep(2);
|
||||||
}
|
}
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
std::cerr << "Exception: " << e.what() << std::endl;
|
std::cerr << "Exception: " << e.what() << std::endl;
|
||||||
|
@@ -1 +0,0 @@
|
|||||||
/nix/store/6p64j7f5xl7rzf1i1avdn18nq9j0yisw-matar-dev
|
|
@@ -6,9 +6,10 @@ using namespace logger;
|
|||||||
|
|
||||||
void
|
void
|
||||||
CpuImpl::exec_arm(const arm::Instruction instruction) {
|
CpuImpl::exec_arm(const arm::Instruction instruction) {
|
||||||
auto cond = instruction.condition;
|
Condition cond = instruction.condition;
|
||||||
auto data = instruction.data;
|
arm::InstructionData data = instruction.data;
|
||||||
|
|
||||||
|
debug(cpsr.condition(cond));
|
||||||
if (!cpsr.condition(cond)) {
|
if (!cpsr.condition(cond)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -390,11 +391,6 @@ CpuImpl::exec_arm(const arm::Instruction instruction) {
|
|||||||
|
|
||||||
uint32_t result = 0;
|
uint32_t result = 0;
|
||||||
|
|
||||||
bool overflow = cpsr.v();
|
|
||||||
bool carry = cpsr.c();
|
|
||||||
bool negative = cpsr.n();
|
|
||||||
bool zero = cpsr.z();
|
|
||||||
|
|
||||||
if (const uint32_t* immediate =
|
if (const uint32_t* immediate =
|
||||||
std::get_if<uint32_t>(&data.operand)) {
|
std::get_if<uint32_t>(&data.operand)) {
|
||||||
op_2 = *immediate;
|
op_2 = *immediate;
|
||||||
@@ -419,144 +415,96 @@ CpuImpl::exec_arm(const arm::Instruction instruction) {
|
|||||||
op_1 += INSTRUCTION_SIZE;
|
op_1 += INSTRUCTION_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool overflow = cpsr.v();
|
||||||
|
bool carry = cpsr.c();
|
||||||
|
|
||||||
|
auto sub = [&carry, &overflow](uint32_t a, uint32_t b) -> uint32_t {
|
||||||
|
bool s1 = get_bit(a, 31);
|
||||||
|
bool s2 = get_bit(b, 31);
|
||||||
|
|
||||||
|
uint32_t result = a - b;
|
||||||
|
|
||||||
|
carry = b <= a;
|
||||||
|
overflow = s1 != s2 && s2 == get_bit(result, 31);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto add = [&carry, &overflow](
|
||||||
|
uint32_t a, uint32_t b, bool c = 0) -> uint32_t {
|
||||||
|
bool s1 = get_bit(a, 31);
|
||||||
|
bool s2 = get_bit(b, 31);
|
||||||
|
|
||||||
|
// 33 bits
|
||||||
|
uint64_t result_ = a + b + c;
|
||||||
|
uint32_t result = result_ & 0xFFFFFFFF;
|
||||||
|
|
||||||
|
carry = get_bit(result_, 32);
|
||||||
|
overflow = s1 == s2 && s2 != get_bit(result, 31);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto sbc = [&carry,
|
||||||
|
&overflow](uint32_t a, uint32_t b, bool c) -> uint32_t {
|
||||||
|
bool s1 = get_bit(a, 31);
|
||||||
|
bool s2 = get_bit(b, 31);
|
||||||
|
|
||||||
|
uint64_t result_ = a - b + c - 1;
|
||||||
|
uint32_t result = result_ & 0xFFFFFFFF;
|
||||||
|
|
||||||
|
carry = get_bit(result_, 32);
|
||||||
|
overflow = s1 != s2 && s2 == get_bit(result, 31);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
switch (data.opcode) {
|
switch (data.opcode) {
|
||||||
case OpCode::AND: {
|
case OpCode::AND:
|
||||||
|
case OpCode::TST:
|
||||||
result = op_1 & op_2;
|
result = op_1 & op_2;
|
||||||
|
|
||||||
negative = get_bit(result, 31);
|
|
||||||
} break;
|
|
||||||
case OpCode::EOR: {
|
|
||||||
result = op_1 ^ op_2;
|
|
||||||
|
|
||||||
negative = get_bit(result, 31);
|
|
||||||
} break;
|
|
||||||
case OpCode::SUB: {
|
|
||||||
bool s1 = get_bit(op_1, 31);
|
|
||||||
bool s2 = get_bit(op_2, 31);
|
|
||||||
result = op_1 - op_2;
|
|
||||||
negative = get_bit(result, 31);
|
|
||||||
carry = op_1 < op_2;
|
|
||||||
overflow = s1 != s2 && s2 == negative;
|
|
||||||
} break;
|
|
||||||
case OpCode::RSB: {
|
|
||||||
bool s1 = get_bit(op_1, 31);
|
|
||||||
bool s2 = get_bit(op_2, 31);
|
|
||||||
result = op_2 - op_1;
|
|
||||||
|
|
||||||
negative = get_bit(result, 31);
|
|
||||||
carry = op_2 < op_1;
|
|
||||||
overflow = s1 != s2 && s1 == negative;
|
|
||||||
} break;
|
|
||||||
case OpCode::ADD: {
|
|
||||||
bool s1 = get_bit(op_1, 31);
|
|
||||||
bool s2 = get_bit(op_2, 31);
|
|
||||||
|
|
||||||
// result_ is 33 bits
|
|
||||||
uint64_t result_ = op_2 + op_1;
|
|
||||||
result = result_ & 0xFFFFFFFF;
|
|
||||||
|
|
||||||
negative = get_bit(result, 31);
|
|
||||||
carry = get_bit(result_, 32);
|
|
||||||
overflow = s1 == s2 && s1 != negative;
|
|
||||||
} break;
|
|
||||||
case OpCode::ADC: {
|
|
||||||
bool s1 = get_bit(op_1, 31);
|
|
||||||
bool s2 = get_bit(op_2, 31);
|
|
||||||
|
|
||||||
uint64_t result_ = op_2 + op_1 + carry;
|
|
||||||
result = result_ & 0xFFFFFFFF;
|
|
||||||
|
|
||||||
negative = get_bit(result, 31);
|
|
||||||
carry = get_bit(result_, 32);
|
|
||||||
overflow = s1 == s2 && s1 != negative;
|
|
||||||
} break;
|
|
||||||
case OpCode::SBC: {
|
|
||||||
bool s1 = get_bit(op_1, 31);
|
|
||||||
bool s2 = get_bit(op_2, 31);
|
|
||||||
|
|
||||||
uint64_t result_ = op_1 - op_2 + carry - 1;
|
|
||||||
result = result_ & 0xFFFFFFFF;
|
|
||||||
|
|
||||||
negative = get_bit(result, 31);
|
|
||||||
carry = get_bit(result_, 32);
|
|
||||||
overflow = s1 != s2 && s2 == negative;
|
|
||||||
} break;
|
|
||||||
case OpCode::RSC: {
|
|
||||||
bool s1 = get_bit(op_1, 31);
|
|
||||||
bool s2 = get_bit(op_2, 31);
|
|
||||||
|
|
||||||
uint64_t result_ = op_1 - op_2 + carry - 1;
|
|
||||||
result = result_ & 0xFFFFFFFF;
|
|
||||||
|
|
||||||
negative = get_bit(result, 31);
|
|
||||||
carry = get_bit(result_, 32);
|
|
||||||
overflow = s1 != s2 && s1 == negative;
|
|
||||||
} break;
|
|
||||||
case OpCode::TST: {
|
|
||||||
result = op_1 & op_2;
|
result = op_1 & op_2;
|
||||||
|
break;
|
||||||
negative = get_bit(result, 31);
|
case OpCode::EOR:
|
||||||
} break;
|
case OpCode::TEQ:
|
||||||
case OpCode::TEQ: {
|
|
||||||
result = op_1 ^ op_2;
|
result = op_1 ^ op_2;
|
||||||
|
break;
|
||||||
negative = get_bit(result, 31);
|
case OpCode::SUB:
|
||||||
} break;
|
case OpCode::CMP:
|
||||||
case OpCode::CMP: {
|
result = sub(op_1, op_2);
|
||||||
bool s1 = get_bit(op_1, 31);
|
break;
|
||||||
bool s2 = get_bit(op_2, 31);
|
case OpCode::RSB:
|
||||||
|
result = sub(op_2, op_1);
|
||||||
result = op_1 - op_2;
|
break;
|
||||||
|
case OpCode::ADD:
|
||||||
negative = get_bit(result, 31);
|
case OpCode::CMN:
|
||||||
carry = op_1 < op_2;
|
result = add(op_1, op_2);
|
||||||
overflow = s1 != s2 && s2 == negative;
|
break;
|
||||||
} break;
|
case OpCode::ADC:
|
||||||
case OpCode::CMN: {
|
result = add(op_1, op_2, carry);
|
||||||
bool s1 = get_bit(op_1, 31);
|
break;
|
||||||
bool s2 = get_bit(op_2, 31);
|
case OpCode::SBC:
|
||||||
|
result = sbc(op_1, op_2, carry);
|
||||||
uint64_t result_ = op_2 + op_1;
|
break;
|
||||||
result = result_ & 0xFFFFFFFF;
|
case OpCode::RSC:
|
||||||
|
result = sbc(op_2, op_1, carry);
|
||||||
negative = get_bit(result, 31);
|
break;
|
||||||
carry = get_bit(result_, 32);
|
case OpCode::ORR:
|
||||||
overflow = s1 == s2 && s1 != negative;
|
|
||||||
} break;
|
|
||||||
case OpCode::ORR: {
|
|
||||||
result = op_1 | op_2;
|
result = op_1 | op_2;
|
||||||
|
break;
|
||||||
negative = get_bit(result, 31);
|
case OpCode::MOV:
|
||||||
} break;
|
|
||||||
case OpCode::MOV: {
|
|
||||||
result = op_2;
|
result = op_2;
|
||||||
|
break;
|
||||||
negative = get_bit(result, 31);
|
case OpCode::BIC:
|
||||||
} break;
|
|
||||||
case OpCode::BIC: {
|
|
||||||
result = op_1 & ~op_2;
|
result = op_1 & ~op_2;
|
||||||
|
break;
|
||||||
negative = get_bit(result, 31);
|
case OpCode::MVN:
|
||||||
} break;
|
|
||||||
case OpCode::MVN: {
|
|
||||||
result = ~op_2;
|
result = ~op_2;
|
||||||
|
break;
|
||||||
negative = get_bit(result, 31);
|
|
||||||
} break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
zero = result == 0;
|
auto set_conditions = [this, carry, overflow, result]() {
|
||||||
|
|
||||||
debug(carry);
|
|
||||||
debug(overflow);
|
|
||||||
debug(zero);
|
|
||||||
debug(negative);
|
|
||||||
|
|
||||||
auto set_conditions = [this, carry, overflow, negative, zero]() {
|
|
||||||
cpsr.set_c(carry);
|
cpsr.set_c(carry);
|
||||||
cpsr.set_v(overflow);
|
cpsr.set_v(overflow);
|
||||||
cpsr.set_n(negative);
|
cpsr.set_n(get_bit(result, 31));
|
||||||
cpsr.set_z(zero);
|
cpsr.set_z(result == 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (data.set) {
|
if (data.set) {
|
||||||
@@ -564,6 +512,7 @@ CpuImpl::exec_arm(const arm::Instruction instruction) {
|
|||||||
if (cpsr.mode() == Mode::User)
|
if (cpsr.mode() == Mode::User)
|
||||||
log_error("Running {} in User mode",
|
log_error("Running {} in User mode",
|
||||||
typeid(data).name());
|
typeid(data).name());
|
||||||
|
spsr = cpsr;
|
||||||
} else {
|
} else {
|
||||||
set_conditions();
|
set_conditions();
|
||||||
}
|
}
|
||||||
|
@@ -6,12 +6,12 @@ lib_sources = files(
|
|||||||
subdir('cpu')
|
subdir('cpu')
|
||||||
|
|
||||||
fmt = dependency('fmt', version : '>=10.1.0')
|
fmt = dependency('fmt', version : '>=10.1.0')
|
||||||
lib = library(
|
lib = static_library(
|
||||||
meson.project_name(),
|
meson.project_name(),
|
||||||
lib_sources,
|
lib_sources,
|
||||||
dependencies: [fmt],
|
dependencies: [fmt],
|
||||||
include_directories: inc,
|
include_directories: inc,
|
||||||
install: true
|
install: true,
|
||||||
)
|
)
|
||||||
|
|
||||||
import('pkgconfig').generate(lib)
|
import('pkgconfig').generate(lib)
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
#include "cpu/utility.hh"
|
#include "cpu/utility.hh"
|
||||||
#include "util/bits.hh"
|
#include "util/bits.hh"
|
||||||
#include <catch2/catch_test_macros.hpp>
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
#include <limits>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
|
||||||
class CpuFixture {
|
class CpuFixture {
|
||||||
@@ -21,6 +22,12 @@ class CpuFixture {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CpuImpl cpu;
|
CpuImpl cpu;
|
||||||
|
|
||||||
|
private:
|
||||||
|
class Null : public std::streambuf {
|
||||||
|
public:
|
||||||
|
int overflow(int c) override { return c; }
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
#define TAG "arm execution"
|
#define TAG "arm execution"
|
||||||
@@ -230,17 +237,18 @@ TEST_CASE_METHOD(CpuFixture, "Single Data Transfer", TAG) {
|
|||||||
.pre = true };
|
.pre = true };
|
||||||
SingleDataTransfer* data_transfer = std::get_if<SingleDataTransfer>(&data);
|
SingleDataTransfer* data_transfer = std::get_if<SingleDataTransfer>(&data);
|
||||||
|
|
||||||
cpu.gpr[3] = 1596;
|
cpu.gpr[3] = 1596;
|
||||||
cpu.gpr[12] = 3;
|
cpu.gpr[7] = 6;
|
||||||
cpu.gpr[7] = 6;
|
cpu.gpr[5] = -911111;
|
||||||
cpu.gpr[5] = -911111;
|
|
||||||
|
|
||||||
// shifted register (immediate)
|
// shifted register (immediate)
|
||||||
{
|
{
|
||||||
|
// 12768 + 6
|
||||||
cpu.bus->write_word(12774, 95995);
|
cpu.bus->write_word(12774, 95995);
|
||||||
exec(data);
|
exec(data);
|
||||||
|
|
||||||
CHECK(cpu.gpr[5] == 95995);
|
CHECK(cpu.gpr[5] == 95995);
|
||||||
|
cpu.gpr[5] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// shifted register (register)
|
// shifted register (register)
|
||||||
@@ -252,7 +260,9 @@ TEST_CASE_METHOD(CpuFixture, "Single Data Transfer", TAG) {
|
|||||||
.operand = 12,
|
.operand = 12,
|
||||||
} };
|
} };
|
||||||
|
|
||||||
cpu.bus->write_word(12774, 3948123487);
|
cpu.gpr[12] = 2;
|
||||||
|
// 6384 + 6
|
||||||
|
cpu.bus->write_word(6390, 3948123487);
|
||||||
exec(data);
|
exec(data);
|
||||||
|
|
||||||
CHECK(cpu.gpr[5] == 3948123487);
|
CHECK(cpu.gpr[5] == 3948123487);
|
||||||
@@ -733,4 +743,309 @@ TEST_CASE_METHOD(CpuFixture, "PSR Transfer", TAG) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(CpuFixture, "Data Processing", TAG) {
|
||||||
|
InstructionData data =
|
||||||
|
DataProcessing{ .operand = Shift{ .rm = 3,
|
||||||
|
.data =
|
||||||
|
ShiftData{
|
||||||
|
.type = ShiftType::ROR,
|
||||||
|
.immediate = true,
|
||||||
|
.operand = 29,
|
||||||
|
} },
|
||||||
|
.rd = 5,
|
||||||
|
.rn = 7,
|
||||||
|
.set = true,
|
||||||
|
.opcode = OpCode::AND };
|
||||||
|
DataProcessing* processing = std::get_if<DataProcessing>(&data);
|
||||||
|
|
||||||
|
// operand 1
|
||||||
|
cpu.gpr[7] = -28717;
|
||||||
|
|
||||||
|
// AND with shifted register (imediate)
|
||||||
|
{
|
||||||
|
// rm
|
||||||
|
cpu.gpr[3] = 1596;
|
||||||
|
exec(data);
|
||||||
|
// -28717 & 12768
|
||||||
|
CHECK(cpu.gpr[5] == 448);
|
||||||
|
}
|
||||||
|
|
||||||
|
// AND with shifted register (register)
|
||||||
|
{
|
||||||
|
processing->operand = Shift{ .rm = 3,
|
||||||
|
.data = ShiftData{
|
||||||
|
.type = ShiftType::LSL,
|
||||||
|
.immediate = false,
|
||||||
|
.operand = 12,
|
||||||
|
} };
|
||||||
|
// rm
|
||||||
|
cpu.gpr[3] = 1596;
|
||||||
|
// rs
|
||||||
|
cpu.gpr[12] = 2;
|
||||||
|
exec(data);
|
||||||
|
// -28717 & 6384
|
||||||
|
CHECK(cpu.gpr[5] == 2256);
|
||||||
|
}
|
||||||
|
|
||||||
|
// same as above but with rn (oprerand 1) = 15
|
||||||
|
{
|
||||||
|
processing->rn = 15;
|
||||||
|
cpu.gpr[15] = -2871;
|
||||||
|
exec(data);
|
||||||
|
|
||||||
|
// (-2871 + INSTRUCTION_SIZE) & 6384
|
||||||
|
CHECK(cpu.gpr[5] == ((-2871 + INSTRUCTION_SIZE) & 6384));
|
||||||
|
|
||||||
|
// cleanup
|
||||||
|
processing->rn = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto flags = [this](bool n, bool z, bool v, bool c) {
|
||||||
|
CHECK(cpu.cpsr.n() == n);
|
||||||
|
CHECK(cpu.cpsr.z() == z);
|
||||||
|
CHECK(cpu.cpsr.v() == v);
|
||||||
|
CHECK(cpu.cpsr.c() == c);
|
||||||
|
|
||||||
|
cpu.cpsr.set_n(false);
|
||||||
|
cpu.cpsr.set_z(false);
|
||||||
|
cpu.cpsr.set_v(false);
|
||||||
|
cpu.cpsr.set_c(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
// immediate operand
|
||||||
|
processing->operand = static_cast<uint32_t>(54924809);
|
||||||
|
// rs
|
||||||
|
cpu.gpr[12] = 2;
|
||||||
|
cpu.gpr[5] = 0;
|
||||||
|
|
||||||
|
SECTION("AND") {
|
||||||
|
processing->opcode = OpCode::AND;
|
||||||
|
exec(data);
|
||||||
|
|
||||||
|
// -28717 & 54924809
|
||||||
|
CHECK(cpu.gpr[5] == 54920705);
|
||||||
|
|
||||||
|
// check set flags
|
||||||
|
flags(false, false, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TST with immediate operand
|
||||||
|
SECTION("TST") {
|
||||||
|
processing->opcode = OpCode::TST;
|
||||||
|
|
||||||
|
exec(data);
|
||||||
|
|
||||||
|
// -28717 & 54924809
|
||||||
|
CHECK(cpu.gpr[5] == 0);
|
||||||
|
|
||||||
|
// check set flags
|
||||||
|
flags(false, false, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("EOR") {
|
||||||
|
processing->opcode = OpCode::EOR;
|
||||||
|
exec(data);
|
||||||
|
|
||||||
|
// -28717 ^ 54924809
|
||||||
|
CHECK(cpu.gpr[5] == 4240021978);
|
||||||
|
|
||||||
|
// check set flags
|
||||||
|
flags(true, false, false, false);
|
||||||
|
|
||||||
|
// check zero flag
|
||||||
|
processing->operand = static_cast<uint32_t>(-28717);
|
||||||
|
exec(data);
|
||||||
|
|
||||||
|
// -28717 ^ -28717
|
||||||
|
CHECK(cpu.gpr[5] == 0);
|
||||||
|
|
||||||
|
// check set flags
|
||||||
|
flags(false, true, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("TEQ") {
|
||||||
|
processing->opcode = OpCode::TEQ;
|
||||||
|
|
||||||
|
exec(data);
|
||||||
|
|
||||||
|
// -28717 ^ 54924809
|
||||||
|
CHECK(cpu.gpr[5] == 0);
|
||||||
|
|
||||||
|
// check set flags
|
||||||
|
flags(true, false, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("SUB") {
|
||||||
|
processing->opcode = OpCode::SUB;
|
||||||
|
exec(data);
|
||||||
|
|
||||||
|
// -28717 - 54924809
|
||||||
|
CHECK(cpu.gpr[5] == static_cast<uint32_t>(-54953526));
|
||||||
|
|
||||||
|
// check set flags
|
||||||
|
flags(true, false, false, true);
|
||||||
|
|
||||||
|
// check zero flag
|
||||||
|
processing->operand = static_cast<uint32_t>(-28717);
|
||||||
|
exec(data);
|
||||||
|
|
||||||
|
// -28717 - (-28717)
|
||||||
|
CHECK(cpu.gpr[5] == 0);
|
||||||
|
|
||||||
|
// check set flags
|
||||||
|
flags(false, true, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("CMP") {
|
||||||
|
processing->opcode = OpCode::CMP;
|
||||||
|
|
||||||
|
exec(data);
|
||||||
|
|
||||||
|
// -28717 - 54924809
|
||||||
|
CHECK(cpu.gpr[5] == 0);
|
||||||
|
|
||||||
|
// check set flags
|
||||||
|
flags(true, false, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("RSB") {
|
||||||
|
processing->opcode = OpCode::RSB;
|
||||||
|
exec(data);
|
||||||
|
|
||||||
|
// +28717 + 54924809
|
||||||
|
CHECK(cpu.gpr[5] == 54953526);
|
||||||
|
|
||||||
|
// check set flags
|
||||||
|
flags(false, false, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("ADD") {
|
||||||
|
processing->opcode = OpCode::ADD;
|
||||||
|
exec(data);
|
||||||
|
|
||||||
|
// -28717 + 54924809
|
||||||
|
CHECK(cpu.gpr[5] == 54896092);
|
||||||
|
|
||||||
|
// check set flags
|
||||||
|
flags(false, false, false, false);
|
||||||
|
|
||||||
|
// test zero flag
|
||||||
|
processing->operand = static_cast<uint32_t>(28717);
|
||||||
|
exec(data);
|
||||||
|
|
||||||
|
// -28717 + 28717
|
||||||
|
CHECK(cpu.gpr[5] == 0);
|
||||||
|
|
||||||
|
// check set flags
|
||||||
|
flags(false, true, false, false);
|
||||||
|
|
||||||
|
// test overflow flag
|
||||||
|
processing->operand = static_cast<uint32_t>((1u << 31) - 1);
|
||||||
|
cpu.gpr[7] = (1u << 31) - 1;
|
||||||
|
|
||||||
|
exec(data);
|
||||||
|
|
||||||
|
CHECK(cpu.gpr[5] == (1ull << 32) - 2);
|
||||||
|
|
||||||
|
// check set flags
|
||||||
|
flags(true, false, true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("CMN") {
|
||||||
|
processing->opcode = OpCode::CMN;
|
||||||
|
|
||||||
|
exec(data);
|
||||||
|
|
||||||
|
// -28717 + 54924809
|
||||||
|
CHECK(cpu.gpr[5] == 0);
|
||||||
|
|
||||||
|
// check set flags
|
||||||
|
flags(false, false, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("ADC") {
|
||||||
|
processing->opcode = OpCode::ADC;
|
||||||
|
cpu.cpsr.set_c(true);
|
||||||
|
exec(data);
|
||||||
|
|
||||||
|
// -28717 + 54924809 + carry
|
||||||
|
CHECK(cpu.gpr[5] == 54896093);
|
||||||
|
|
||||||
|
// check set flags
|
||||||
|
flags(false, false, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("SBC") {
|
||||||
|
processing->opcode = OpCode::SBC;
|
||||||
|
cpu.cpsr.set_c(false);
|
||||||
|
exec(data);
|
||||||
|
|
||||||
|
// -28717 - 54924809 + carry - 1
|
||||||
|
CHECK(cpu.gpr[5] == static_cast<uint32_t>(-54953527));
|
||||||
|
|
||||||
|
// check set flags
|
||||||
|
flags(true, false, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("RSC") {
|
||||||
|
processing->opcode = OpCode::RSC;
|
||||||
|
cpu.cpsr.set_c(false);
|
||||||
|
exec(data);
|
||||||
|
|
||||||
|
// +28717 +54924809 + carry - 1
|
||||||
|
CHECK(cpu.gpr[5] == 54953525);
|
||||||
|
|
||||||
|
// check set flags
|
||||||
|
flags(false, false, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("ORR") {
|
||||||
|
processing->opcode = OpCode::ORR;
|
||||||
|
exec(data);
|
||||||
|
|
||||||
|
// -28717 | 54924809
|
||||||
|
CHECK(cpu.gpr[5] == static_cast<uint32_t>(-24613));
|
||||||
|
|
||||||
|
// check set flags
|
||||||
|
flags(true, false, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("BIC") {
|
||||||
|
processing->opcode = OpCode::BIC;
|
||||||
|
exec(data);
|
||||||
|
|
||||||
|
// -28717 & ~54924809
|
||||||
|
CHECK(cpu.gpr[5] == static_cast<uint32_t>(-54949422));
|
||||||
|
|
||||||
|
// check set flags
|
||||||
|
flags(true, false, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("MVN") {
|
||||||
|
processing->opcode = OpCode::MVN;
|
||||||
|
exec(data);
|
||||||
|
|
||||||
|
// ~54924809
|
||||||
|
CHECK(cpu.gpr[5] == static_cast<uint32_t>(-54924810));
|
||||||
|
|
||||||
|
// check set flags
|
||||||
|
flags(true, false, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("R15 as destination") {
|
||||||
|
processing->opcode = OpCode::MVN;
|
||||||
|
processing->rd = 15;
|
||||||
|
cpu.gpr[15] = 0;
|
||||||
|
CHECK(cpu.spsr.raw() != cpu.cpsr.raw());
|
||||||
|
exec(data);
|
||||||
|
|
||||||
|
// ~54924809
|
||||||
|
CHECK(cpu.gpr[15] == static_cast<uint32_t>(-54924810));
|
||||||
|
|
||||||
|
// flags are not set
|
||||||
|
flags(false, false, false, false);
|
||||||
|
CHECK(cpu.spsr.raw() == cpu.cpsr.raw());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#undef TAG
|
#undef TAG
|
||||||
|
@@ -15,7 +15,7 @@ catch2_tests = executable(
|
|||||||
dependencies: catch2,
|
dependencies: catch2,
|
||||||
link_with: tests_deps,
|
link_with: tests_deps,
|
||||||
include_directories: [inc, src],
|
include_directories: [inc, src],
|
||||||
build_by_default: false
|
build_by_default: false,
|
||||||
)
|
)
|
||||||
|
|
||||||
test('catch2 tests', catch2_tests)
|
test('catch2 tests', catch2_tests)
|
||||||
|
Reference in New Issue
Block a user