2011-01-03 04:28:36 +00:00
|
|
|
#include <gameboy/gameboy.hpp>
|
2010-12-28 01:53:15 +00:00
|
|
|
|
|
|
|
#define CPU_CPP
|
|
|
|
namespace GameBoy {
|
|
|
|
|
2010-12-28 06:03:02 +00:00
|
|
|
#include "core/core.cpp"
|
2010-12-29 11:03:42 +00:00
|
|
|
#include "mmio/mmio.cpp"
|
2010-12-28 06:03:02 +00:00
|
|
|
#include "timing/timing.cpp"
|
2010-12-28 01:53:15 +00:00
|
|
|
CPU cpu;
|
|
|
|
|
2010-12-28 06:03:02 +00:00
|
|
|
void CPU::Main() {
|
|
|
|
cpu.main();
|
|
|
|
}
|
|
|
|
|
2010-12-28 01:53:15 +00:00
|
|
|
void CPU::main() {
|
|
|
|
while(true) {
|
2010-12-30 07:15:10 +00:00
|
|
|
//print(disassemble(r[PC]), "\n");
|
2010-12-30 07:18:47 +00:00
|
|
|
interrupt_test();
|
2010-12-28 06:03:02 +00:00
|
|
|
uint8 opcode = op_read(r[PC]++);
|
|
|
|
(this->*opcode_table[opcode])();
|
2010-12-28 01:53:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-02 04:46:54 +00:00
|
|
|
void CPU::interrupt_raise(CPU::Interrupt id) {
|
|
|
|
switch(id) {
|
|
|
|
case Interrupt::Vblank: status.interrupt_request_vblank = 1; break;
|
|
|
|
case Interrupt::Stat : status.interrupt_request_stat = 1; break;
|
|
|
|
case Interrupt::Timer : status.interrupt_request_timer = 1; break;
|
|
|
|
case Interrupt::Serial: status.interrupt_request_serial = 1; break;
|
|
|
|
case Interrupt::Joypad: status.interrupt_request_joypad = 1; break;
|
|
|
|
}
|
|
|
|
status.halt = false;
|
|
|
|
}
|
|
|
|
|
2010-12-30 07:18:47 +00:00
|
|
|
void CPU::interrupt_test() {
|
|
|
|
if(status.ime) {
|
|
|
|
if(status.interrupt_request_vblank && status.interrupt_enable_vblank) {
|
|
|
|
status.interrupt_request_vblank = 0;
|
|
|
|
return interrupt_exec(0x0040);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(status.interrupt_request_stat && status.interrupt_enable_stat) {
|
|
|
|
status.interrupt_request_stat = 0;
|
|
|
|
return interrupt_exec(0x0048);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(status.interrupt_request_timer && status.interrupt_enable_timer) {
|
|
|
|
status.interrupt_request_timer = 0;
|
|
|
|
return interrupt_exec(0x0050);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(status.interrupt_request_serial && status.interrupt_enable_serial) {
|
|
|
|
status.interrupt_request_serial = 0;
|
|
|
|
return interrupt_exec(0x0058);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(status.interrupt_request_joypad && status.interrupt_enable_joypad) {
|
|
|
|
status.interrupt_request_joypad = 0;
|
|
|
|
return interrupt_exec(0x0060);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CPU::interrupt_exec(uint16 pc) {
|
|
|
|
status.ime = 0;
|
|
|
|
op_write(--r[SP], r[PC] >> 8);
|
|
|
|
op_write(--r[SP], r[PC] >> 0);
|
|
|
|
r[PC] = pc;
|
|
|
|
op_io();
|
2011-01-03 04:28:36 +00:00
|
|
|
op_io();
|
|
|
|
op_io();
|
2010-12-30 07:18:47 +00:00
|
|
|
}
|
|
|
|
|
2010-12-28 01:53:15 +00:00
|
|
|
void CPU::power() {
|
2011-01-03 04:28:36 +00:00
|
|
|
create(Main, 4 * 1024 * 1024);
|
|
|
|
|
2010-12-29 11:03:42 +00:00
|
|
|
for(unsigned n = 0xc000; n <= 0xdfff; n++) bus.mmio[n] = this; //WRAM
|
|
|
|
for(unsigned n = 0xe000; n <= 0xfdff; n++) bus.mmio[n] = this; //WRAM (mirror)
|
2010-12-30 07:18:47 +00:00
|
|
|
for(unsigned n = 0xff00; n <= 0xff0f; n++) bus.mmio[n] = this; //MMIO
|
|
|
|
for(unsigned n = 0xff80; n <= 0xffff; n++) bus.mmio[n] = this; //HRAM+IE
|
|
|
|
|
|
|
|
for(unsigned n = 0; n < 8192; n++) wram[n] = 0x00;
|
|
|
|
for(unsigned n = 0; n < 128; n++) hram[n] = 0x00;
|
2010-12-29 11:03:42 +00:00
|
|
|
|
2010-12-28 06:03:02 +00:00
|
|
|
r[PC] = 0x0100;
|
|
|
|
r[SP] = 0xfffe;
|
2011-01-03 04:28:36 +00:00
|
|
|
r[AF] = 0x0100;
|
2010-12-28 06:03:02 +00:00
|
|
|
r[BC] = 0x0000;
|
|
|
|
r[DE] = 0x0000;
|
|
|
|
r[HL] = 0x0000;
|
|
|
|
|
2011-01-02 04:46:54 +00:00
|
|
|
status.halt = false;
|
|
|
|
status.stop = false;
|
|
|
|
|
2010-12-29 11:03:42 +00:00
|
|
|
status.ime = 0;
|
2010-12-30 07:18:47 +00:00
|
|
|
status.timer0 = 0;
|
|
|
|
status.timer1 = 0;
|
|
|
|
status.timer2 = 0;
|
|
|
|
status.timer3 = 0;
|
|
|
|
|
|
|
|
status.p15 = 0;
|
|
|
|
status.p14 = 0;
|
2010-12-31 05:43:47 +00:00
|
|
|
status.joyp = 0;
|
2010-12-30 07:18:47 +00:00
|
|
|
|
|
|
|
status.div = 0;
|
|
|
|
|
|
|
|
status.tima = 0;
|
|
|
|
|
|
|
|
status.tma = 0;
|
|
|
|
|
|
|
|
status.timer_enable = 0;
|
|
|
|
status.timer_clock = 0;
|
|
|
|
|
|
|
|
status.interrupt_request_joypad = 0;
|
|
|
|
status.interrupt_request_serial = 0;
|
|
|
|
status.interrupt_request_timer = 0;
|
|
|
|
status.interrupt_request_stat = 0;
|
|
|
|
status.interrupt_request_vblank = 0;
|
|
|
|
|
|
|
|
status.interrupt_enable_joypad = 0;
|
|
|
|
status.interrupt_enable_serial = 0;
|
|
|
|
status.interrupt_enable_timer = 0;
|
|
|
|
status.interrupt_enable_stat = 0;
|
|
|
|
status.interrupt_enable_vblank = 0;
|
2010-12-28 06:03:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CPU::CPU() {
|
|
|
|
initialize_opcode_table();
|
2010-12-28 01:53:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|