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