/* * Copyright (C) 2022 Riyyi * Copyright (C) 2022 Th3FrankXD * * SPDX-License-Identifier: MIT */ #include // int32_t, uint8_t, uint32_t #include "cpu.h" #include "emu.h" #include "ruc/format/print.h" #include "ruc/meta/assert.h" CPU::CPU(uint32_t frequency) : ProcessingUnit(frequency) // https://gbdev.io/pandocs/Power_Up_Sequence.html#cpu-registers // CGB registers , m_a(0x11) , m_b(0x0) , m_c(0x0) , m_d(0xff) , m_e(0x56) , m_h(0x0) , m_l(0x0d) // , m_pc(0x100) , m_pc(0x0) , m_sp(0xfffe) // Flags , m_zf(0x1) , m_nf(0x0) , m_hf(0x0) , m_cf(0x0) { m_shared_registers.emplace("a", &m_a); m_shared_registers.emplace("b", &m_b); m_shared_registers.emplace("c", &m_c); m_shared_registers.emplace("d", &m_d); m_shared_registers.emplace("e", &m_e); m_shared_registers.emplace("h", &m_h); m_shared_registers.emplace("l", &m_l); m_shared_registers.emplace("sp", &m_sp); m_shared_registers.emplace("pc", &m_pc); m_shared_registers.emplace("zf", &m_zf); m_shared_registers.emplace("nf", &m_nf); m_shared_registers.emplace("hf", &m_hf); m_shared_registers.emplace("cf", &m_cf); // Add opcode functions to lookup table m_opcode_lookup_table.emplace(0xc6, std::bind(&CPU::add, this)); m_opcode_lookup_table.emplace(0x01, std::bind(&CPU::ld16, this)); m_opcode_lookup_table.emplace(0x11, std::bind(&CPU::ld16, this)); m_opcode_lookup_table.emplace(0x21, std::bind(&CPU::ld16, this)); m_opcode_lookup_table.emplace(0x31, std::bind(&CPU::ld16, this)); } CPU::~CPU() { } // ----------------------------------------- void CPU::update() { m_wait_cycles--; if (m_wait_cycles <= 0) { // Read next opcode uint8_t opcode = peekBootrom(); m_opcode_lookup_table[opcode](); } // print("This is an update from the CPU\n"); } void CPU::add() { uint8_t opcode = consumeBootrom(); uint8_t immediate = consumeBootrom(); switch (opcode) { case 0xc6: // ADD A,d8 // Program counter +2 m_pc += 2; // Clock cycles +8 m_wait_cycles += 8; // Flags: Z0HC m_zf = m_a + immediate == 0; m_nf = 0; m_hf = m_a + immediate > 16; m_cf = m_a + immediate > 255; // A = A + r m_a += immediate; // Drop overflown bits, the 'A' register is 8-bit m_a &= 0xff; break; default: VERIFY_NOT_REACHED(); } } void CPU::ld16() { uint8_t opcode = consumeBootrom(); switch (opcode) { case 0x01: { m_wait_cycles += 12; setBc(immediate16()); break; } case 0x11: m_wait_cycles += 12; setDe(immediate16()); break; case 0x21: m_wait_cycles += 12; setHl(immediate16()); break; case 0x31: { m_wait_cycles += 12; m_sp = immediate16(); break; } default: VERIFY_NOT_REACHED(); } } // ----------------------------------------- uint8_t CPU::peekBootrom(int32_t offset) const { return Emu::the().bootrom()[m_pc + offset]; } uint8_t CPU::consumeBootrom() { return Emu::the().bootrom()[m_pc++]; } void CPU::setBc(uint32_t value) { m_b = value >> 8; m_c = value; } void CPU::setDe(uint32_t value) { m_d = value >> 8; m_e = value; } void CPU::setHl(uint32_t value) { m_h = value >> 8; m_l = value; }