mirror of https://github.com/bsnes-emu/bsnes.git
Update to v087r14 release.
byuu says: Fixed aforementioned issues. [From a previous post: - mul was using r(d) instead of r(n) for accumulate. - mull didn't remove c/v clear. - APU register mask was broken, so SOUNDBIAS was reading out wrong. - APU was only mapping 0x088 and not 0x089 as well. - Halfword reads in CPU+PPU+APU were all reading from the low address each time.] All CPU+PPU registers are now hooked up (not that they do anything.) SOUNDBIAS for APU was hooked up, got tired of working on it for the rest :P I recall from the GB APU that you can't just assign values for the APU MMIO regs. They do odd reload things as well. Also, was using MMIO read code like this: return ( (flaga << 0) || (flagb << 1) || (flagc << 2) ); Logical or doesn't work so well with building flags :P Bad habit from how I split multiple conditionals across several lines. So ... r14 is basically what r13 should have been yesterday, delaying my schedule by yet another day :(
This commit is contained in:
parent
f587cb0dcc
commit
c8bb4949b1
|
@ -1,7 +1,7 @@
|
|||
#ifndef BASE_HPP
|
||||
#define BASE_HPP
|
||||
|
||||
static const char Version[] = "087.13";
|
||||
static const char Version[] = "087.14";
|
||||
|
||||
#include <nall/platform.hpp>
|
||||
#include <nall/algorithm.hpp>
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace GBA {
|
||||
|
||||
#include "registers.cpp"
|
||||
#include "mmio.cpp"
|
||||
APU apu;
|
||||
|
||||
void APU::Enter() { apu.enter(); }
|
||||
|
@ -18,60 +20,12 @@ void APU::step(unsigned clocks) {
|
|||
if(clock >= 0) co_switch(cpu.thread);
|
||||
}
|
||||
|
||||
uint32 APU::read(uint32 addr, uint32 size) {
|
||||
if(size == Word) {
|
||||
addr &= ~3;
|
||||
uint32 word = 0;
|
||||
word |= read(addr + 0, Byte) << 0;
|
||||
word |= read(addr + 1, Byte) << 8;
|
||||
word |= read(addr + 2, Byte) << 16;
|
||||
word |= read(addr + 3, Byte) << 24;
|
||||
return word;
|
||||
}
|
||||
|
||||
if(size == Half) {
|
||||
addr &= ~1;
|
||||
uint32 half = 0;
|
||||
half |= read(addr + 0, Byte) << 0;
|
||||
half |= read(addr + 0, Byte) << 8;
|
||||
return half;
|
||||
}
|
||||
|
||||
switch(addr & 0x0f000000) {
|
||||
|
||||
//SOUNDBIAS
|
||||
case 0x04000088: return 0x00;
|
||||
case 0x04000089: return 0x02;
|
||||
|
||||
}
|
||||
|
||||
return 0u;
|
||||
}
|
||||
|
||||
void APU::write(uint32 addr, uint32 size, uint32 word) {
|
||||
if(size == Word) {
|
||||
addr &= ~3;
|
||||
write(addr + 0, Byte, word >> 0);
|
||||
write(addr + 1, Byte, word >> 8);
|
||||
write(addr + 2, Byte, word >> 16);
|
||||
write(addr + 3, Byte, word >> 24);
|
||||
return;
|
||||
}
|
||||
|
||||
if(size == Half) {
|
||||
addr &= ~1;
|
||||
write(addr + 0, Byte, word >> 0);
|
||||
write(addr + 1, Byte, word >> 8);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8 byte = word;
|
||||
}
|
||||
|
||||
void APU::power() {
|
||||
create(APU::Enter, 16777216);
|
||||
|
||||
bus.mmio[0x0088] = this;
|
||||
regs.bias = 0x0200;
|
||||
|
||||
for(unsigned n = 0x060; n <= 0x0a7; n++) bus.mmio[n] = this;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
struct APU : Thread, Memory {
|
||||
struct APU : Thread, MMIO {
|
||||
#include "registers.hpp"
|
||||
|
||||
static void Enter();
|
||||
void enter();
|
||||
void step(unsigned clocks);
|
||||
|
||||
uint32 read(uint32 addr, uint32 size);
|
||||
void write(uint32 addr, uint32 size, uint32 word);
|
||||
uint8 read(uint32 addr);
|
||||
void write(uint32 addr, uint8 byte);
|
||||
void power();
|
||||
};
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
namespace GBA {
|
||||
|
||||
#include "registers.cpp"
|
||||
#include "mmio.cpp"
|
||||
CPU cpu;
|
||||
|
||||
void CPU::Enter() { cpu.enter(); }
|
||||
|
@ -17,10 +18,10 @@ void CPU::enter() {
|
|||
while(true) step(frequency);
|
||||
}
|
||||
|
||||
processor.irqline = regs.ime && (regs.irq_enable & regs.irq_flag);
|
||||
processor.irqline = regs.ime && (regs.irq.enable & regs.irq.flag);
|
||||
|
||||
if(regs.mode == Registers::Mode::Halt) {
|
||||
if((regs.irq_enable & regs.irq_flag) == 0) {
|
||||
if((regs.irq.enable & regs.irq.flag) == 0) {
|
||||
step(1);
|
||||
continue;
|
||||
}
|
||||
|
@ -60,195 +61,23 @@ void CPU::power() {
|
|||
regs.dma[0].target = regs.dma[1].target = regs.dma[2].target = regs.dma[3].target = 0;
|
||||
regs.dma[0].length = regs.dma[1].length = regs.dma[2].length = regs.dma[3].length = 0;
|
||||
regs.dma[0].control = regs.dma[1].control = regs.dma[2].control = regs.dma[3].control = 0;
|
||||
|
||||
regs.timer[0].reload = regs.timer[1].reload = regs.timer[2].reload = regs.timer[3].reload = 0;
|
||||
regs.timer[0].control = regs.timer[1].control = regs.timer[2].control = regs.timer[3].control = 0;
|
||||
regs.keypad.control = 0;
|
||||
regs.ime = 0;
|
||||
regs.irq_enable = 0;
|
||||
regs.irq_flag = 0;
|
||||
regs.irq.enable = 0;
|
||||
regs.irq.flag = 0;
|
||||
regs.wait.control = 0;
|
||||
regs.postboot = 0;
|
||||
regs.mode = Registers::Mode::Normal;
|
||||
regs.memory.control = 0x0d000020;
|
||||
|
||||
for(unsigned n = 0x0b0; n <= 0x0df; n++) bus.mmio[n] = this;
|
||||
|
||||
bus.mmio[0x130] = bus.mmio[0x131] = this;
|
||||
bus.mmio[0x200] = bus.mmio[0x201] = this;
|
||||
bus.mmio[0x202] = bus.mmio[0x203] = this;
|
||||
bus.mmio[0x208] = bus.mmio[0x209] = this;
|
||||
bus.mmio[0x300] = bus.mmio[0x301] = this;
|
||||
}
|
||||
|
||||
uint32 CPU::read(uint32 addr, uint32 size) {
|
||||
if(size == Word) {
|
||||
addr &= ~3;
|
||||
uint32 word = 0;
|
||||
word |= read(addr + 0, Byte) << 0;
|
||||
word |= read(addr + 1, Byte) << 8;
|
||||
word |= read(addr + 2, Byte) << 16;
|
||||
word |= read(addr + 3, Byte) << 24;
|
||||
return word;
|
||||
}
|
||||
|
||||
if(size == Half) {
|
||||
addr &= ~1;
|
||||
uint32 half = 0;
|
||||
half |= read(addr + 0, Byte) << 0;
|
||||
half |= read(addr + 0, Byte) << 8;
|
||||
return half;
|
||||
}
|
||||
|
||||
uint8 result = 0;
|
||||
|
||||
switch(addr & 0x0fffffff) {
|
||||
|
||||
//KEYINPUT
|
||||
case 0x04000130:
|
||||
for(unsigned n = 0; n < 8; n++) result |= interface->inputPoll(n) << n;
|
||||
if((result & 0xc0) == 0xc0) result &= ~0xc0; //up+down cannot be pressed simultaneously
|
||||
if((result & 0x30) == 0x30) result &= ~0x30; //left+right cannot be pressed simultaneously
|
||||
return result ^ 0xff;
|
||||
case 0x40000131:
|
||||
result |= interface->inputPoll(8) << 0;
|
||||
result |= interface->inputPoll(9) << 1;
|
||||
return result ^ 0x03;
|
||||
|
||||
//IE
|
||||
case 0x04000200: return regs.irq_enable >> 0;
|
||||
case 0x04000201: return regs.irq_enable >> 8;
|
||||
|
||||
//IF
|
||||
case 0x04000202: return regs.irq_flag >> 0;
|
||||
case 0x04000203: return regs.irq_flag >> 8;
|
||||
|
||||
//IME
|
||||
case 0x04000208: return regs.ime;
|
||||
case 0x04000209: return 0u;
|
||||
|
||||
//POSTFLG + HALTCNT
|
||||
case 0x04000300: return regs.postboot;
|
||||
case 0x04000301: return 0u;
|
||||
|
||||
}
|
||||
|
||||
return 0u;
|
||||
}
|
||||
|
||||
void CPU::write(uint32 addr, uint32 size, uint32 word) {
|
||||
if(size == Word) {
|
||||
addr &= ~3;
|
||||
write(addr + 0, Byte, word >> 0);
|
||||
write(addr + 1, Byte, word >> 8);
|
||||
write(addr + 2, Byte, word >> 16);
|
||||
write(addr + 3, Byte, word >> 24);
|
||||
return;
|
||||
}
|
||||
|
||||
if(size == Half) {
|
||||
addr &= ~1;
|
||||
write(addr + 0, Byte, word >> 0);
|
||||
write(addr + 1, Byte, word >> 8);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8 byte = word;
|
||||
|
||||
switch(addr & 0x0fffffff) {
|
||||
|
||||
//DMA0SAD
|
||||
case 0x040000b0: regs.dma[0].source = (regs.dma[0].source & 0xffffff00) | (byte << 0); return;
|
||||
case 0x040000b1: regs.dma[0].source = (regs.dma[0].source & 0xffff00ff) | (byte << 8); return;
|
||||
case 0x040000b2: regs.dma[0].source = (regs.dma[0].source & 0xff00ffff) | (byte << 16); return;
|
||||
case 0x040000b3: regs.dma[0].source = (regs.dma[0].source & 0x00ffffff) | (byte << 24); return;
|
||||
|
||||
//DMA0DAD
|
||||
case 0x040000b4: regs.dma[0].target = (regs.dma[0].target & 0xffffff00) | (byte << 0); return;
|
||||
case 0x040000b5: regs.dma[0].target = (regs.dma[0].target & 0xffff00ff) | (byte << 8); return;
|
||||
case 0x040000b6: regs.dma[0].target = (regs.dma[0].target & 0xff00ffff) | (byte << 16); return;
|
||||
case 0x040000b7: regs.dma[0].target = (regs.dma[0].target & 0x00ffffff) | (byte << 24); return;
|
||||
|
||||
//DMA0CNT_L
|
||||
case 0x040000b8: regs.dma[0].length = (regs.dma[0].length & 0xff00) | (byte << 0); return;
|
||||
case 0x040000b9: regs.dma[0].length = (regs.dma[0].length & 0x00ff) | (byte << 8); return;
|
||||
|
||||
//DMA0CNT_H
|
||||
case 0x040000ba: regs.dma[0].control = (regs.dma[0].control & 0xff00) | (byte << 0); return;
|
||||
case 0x040000bb: regs.dma[0].control = (regs.dma[0].control & 0x00ff) | (byte << 8); return;
|
||||
|
||||
//DMA1SAD
|
||||
case 0x040000bc: regs.dma[1].source = (regs.dma[1].source & 0xffffff00) | (byte << 0); return;
|
||||
case 0x040000bd: regs.dma[1].source = (regs.dma[1].source & 0xffff00ff) | (byte << 8); return;
|
||||
case 0x040000be: regs.dma[1].source = (regs.dma[1].source & 0xff00ffff) | (byte << 16); return;
|
||||
case 0x040000bf: regs.dma[1].source = (regs.dma[1].source & 0x00ffffff) | (byte << 24); return;
|
||||
|
||||
//DMA1DAD
|
||||
case 0x040000c0: regs.dma[1].target = (regs.dma[1].target & 0xffffff00) | (byte << 0); return;
|
||||
case 0x040000c1: regs.dma[1].target = (regs.dma[1].target & 0xffff00ff) | (byte << 8); return;
|
||||
case 0x040000c2: regs.dma[1].target = (regs.dma[1].target & 0xff00ffff) | (byte << 16); return;
|
||||
case 0x040000c3: regs.dma[1].target = (regs.dma[1].target & 0x00ffffff) | (byte << 24); return;
|
||||
|
||||
//DMA1CNT_L
|
||||
case 0x040000c4: regs.dma[1].length = (regs.dma[1].length & 0xff00) | (byte << 0); return;
|
||||
case 0x040000c5: regs.dma[1].length = (regs.dma[1].length & 0x00ff) | (byte << 8); return;
|
||||
|
||||
//DMA1CNT_H
|
||||
case 0x040000c6: regs.dma[1].control = (regs.dma[1].control & 0xff00) | (byte << 0); return;
|
||||
case 0x040000c7: regs.dma[1].control = (regs.dma[1].control & 0x00ff) | (byte << 8); return;
|
||||
|
||||
//DMA2SAD
|
||||
case 0x040000c8: regs.dma[2].source = (regs.dma[2].source & 0xffffff00) | (byte << 0); return;
|
||||
case 0x040000c9: regs.dma[2].source = (regs.dma[2].source & 0xffff00ff) | (byte << 8); return;
|
||||
case 0x040000ca: regs.dma[2].source = (regs.dma[2].source & 0xff00ffff) | (byte << 16); return;
|
||||
case 0x040000cb: regs.dma[2].source = (regs.dma[2].source & 0x00ffffff) | (byte << 24); return;
|
||||
|
||||
//DMA2DAD
|
||||
case 0x040000cc: regs.dma[2].target = (regs.dma[2].target & 0xffffff00) | (byte << 0); return;
|
||||
case 0x040000cd: regs.dma[2].target = (regs.dma[2].target & 0xffff00ff) | (byte << 8); return;
|
||||
case 0x040000ce: regs.dma[2].target = (regs.dma[2].target & 0xff00ffff) | (byte << 16); return;
|
||||
case 0x040000cf: regs.dma[2].target = (regs.dma[2].target & 0x00ffffff) | (byte << 24); return;
|
||||
|
||||
//DMA2CNT_L
|
||||
case 0x040000d0: regs.dma[2].length = (regs.dma[2].length & 0xff00) | (byte << 0); return;
|
||||
case 0x040000d1: regs.dma[2].length = (regs.dma[2].length & 0x00ff) | (byte << 8); return;
|
||||
|
||||
//DMA2CNT_H
|
||||
case 0x040000d2: regs.dma[2].control = (regs.dma[2].control & 0xff00) | (byte << 0); return;
|
||||
case 0x040000d3: regs.dma[2].control = (regs.dma[2].control & 0x00ff) | (byte << 8); return;
|
||||
|
||||
//DMA3SAD
|
||||
case 0x040000d4: regs.dma[3].source = (regs.dma[3].source & 0xffffff00) | (byte << 0); return;
|
||||
case 0x040000d5: regs.dma[3].source = (regs.dma[3].source & 0xffff00ff) | (byte << 8); return;
|
||||
case 0x040000d6: regs.dma[3].source = (regs.dma[3].source & 0xff00ffff) | (byte << 16); return;
|
||||
case 0x040000d7: regs.dma[3].source = (regs.dma[3].source & 0x00ffffff) | (byte << 24); return;
|
||||
|
||||
//DMA3DAD
|
||||
case 0x040000d8: regs.dma[3].target = (regs.dma[3].target & 0xffffff00) | (byte << 0); return;
|
||||
case 0x040000d9: regs.dma[3].target = (regs.dma[3].target & 0xffff00ff) | (byte << 8); return;
|
||||
case 0x040000da: regs.dma[3].target = (regs.dma[3].target & 0xff00ffff) | (byte << 16); return;
|
||||
case 0x040000db: regs.dma[3].target = (regs.dma[3].target & 0x00ffffff) | (byte << 24); return;
|
||||
|
||||
//DMA3CNT_L
|
||||
case 0x040000dc: regs.dma[3].length = (regs.dma[3].length & 0xff00) | (byte << 0); return;
|
||||
case 0x040000dd: regs.dma[3].length = (regs.dma[3].length & 0x00ff) | (byte << 8); return;
|
||||
|
||||
//DMA3CNT_H
|
||||
case 0x040000de: regs.dma[3].control = (regs.dma[3].control & 0xff00) | (byte << 0); return;
|
||||
case 0x040000df: regs.dma[3].control = (regs.dma[3].control & 0x00ff) | (byte << 8); return;
|
||||
|
||||
//IE
|
||||
case 0x04000200: regs.irq_enable = (regs.irq_enable & 0xff00) | (byte << 0); return;
|
||||
case 0x04000201: regs.irq_enable = (regs.irq_enable & 0x00ff) | (byte << 8); return;
|
||||
|
||||
//IF
|
||||
case 0x04000202: regs.irq_flag = regs.irq_flag & ~(byte << 0); return;
|
||||
case 0x04000203: regs.irq_flag = regs.irq_flag & ~(byte << 8); return;
|
||||
|
||||
//IME
|
||||
case 0x04000208: regs.ime = byte & 1; return;
|
||||
case 0x04000209: return;
|
||||
|
||||
//POSTFLG + HALTCNT
|
||||
case 0x04000300: regs.postboot = byte & 1; return;
|
||||
case 0x04000301: regs.mode = byte & 0x80 ? Registers::Mode::Stop : Registers::Mode::Halt; return;
|
||||
|
||||
}
|
||||
for(unsigned n = 0x0b0; n <= 0x0df; n++) bus.mmio[n] = this; //DMA
|
||||
for(unsigned n = 0x100; n <= 0x10f; n++) bus.mmio[n] = this; //Timers
|
||||
for(unsigned n = 0x130; n <= 0x133; n++) bus.mmio[n] = this; //Keypad
|
||||
for(unsigned n = 0x200; n <= 0x209; n++) bus.mmio[n] = this; //System
|
||||
for(unsigned n = 0x300; n <= 0x301; n++) bus.mmio[n] = this; //System
|
||||
//0x080-0x083 mirrored via gba/memory/memory.cpp //System
|
||||
}
|
||||
|
||||
CPU::CPU() {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
struct CPU : Processor::ARM, Thread, Memory {
|
||||
struct CPU : Processor::ARM, Thread, MMIO {
|
||||
StaticMemory iwram;
|
||||
StaticMemory ewram;
|
||||
#include "registers.hpp"
|
||||
|
@ -11,8 +11,8 @@ struct CPU : Processor::ARM, Thread, Memory {
|
|||
|
||||
void power();
|
||||
|
||||
uint32 read(uint32 addr, uint32 size);
|
||||
void write(uint32 addr, uint32 size, uint32 word);
|
||||
uint8 read(uint32 addr);
|
||||
void write(uint32 addr, uint8 byte);
|
||||
|
||||
CPU();
|
||||
};
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
CPU::Registers::DMA::Control::operator uint16() const {
|
||||
return (
|
||||
(targetmode << 5)
|
||||
|| (sourcemode << 7)
|
||||
|| (repeat << 9)
|
||||
|| (size << 10)
|
||||
|| (drq << 11)
|
||||
|| (timing << 12)
|
||||
|| (irq << 14)
|
||||
|| (enable << 15)
|
||||
(targetmode << 5)
|
||||
| (sourcemode << 7)
|
||||
| (repeat << 9)
|
||||
| (size << 10)
|
||||
| (drq << 11)
|
||||
| (timing << 12)
|
||||
| (irq << 14)
|
||||
| (enable << 15)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -23,22 +23,72 @@ uint16 CPU::Registers::DMA::Control::operator=(uint16 source) {
|
|||
return operator uint16();
|
||||
}
|
||||
|
||||
CPU::Registers::TimerControl::operator uint16() const {
|
||||
return (
|
||||
(prescalar << 0)
|
||||
| (countup << 2)
|
||||
| (irq << 6)
|
||||
| (enable << 7)
|
||||
);
|
||||
}
|
||||
|
||||
uint16 CPU::Registers::TimerControl::operator=(uint16 source) {
|
||||
prescalar = (source >> 0) & 3;
|
||||
countup = (source >> 2) & 1;
|
||||
irq = (source >> 6) & 1;
|
||||
enable = (source >> 7) & 1;
|
||||
return operator uint16();
|
||||
}
|
||||
|
||||
CPU::Registers::KeypadControl::operator uint16() const {
|
||||
return (
|
||||
(a << 0)
|
||||
| (b << 1)
|
||||
| (select << 2)
|
||||
| (start << 3)
|
||||
| (right << 4)
|
||||
| (left << 5)
|
||||
| (up << 6)
|
||||
| (down << 7)
|
||||
| (r << 8)
|
||||
| (l << 9)
|
||||
| (enable << 14)
|
||||
| (condition << 15)
|
||||
);
|
||||
}
|
||||
|
||||
uint16 CPU::Registers::KeypadControl::operator=(uint16 source) {
|
||||
a = (source >> 0) & 1;
|
||||
b = (source >> 1) & 1;
|
||||
select = (source >> 2) & 1;
|
||||
start = (source >> 3) & 1;
|
||||
right = (source >> 4) & 1;
|
||||
left = (source >> 5) & 1;
|
||||
up = (source >> 6) & 1;
|
||||
down = (source >> 7) & 1;
|
||||
r = (source >> 8) & 1;
|
||||
l = (source >> 9) & 1;
|
||||
enable = (source >> 14) & 1;
|
||||
condition = (source >> 15) & 1;
|
||||
return operator uint16();
|
||||
}
|
||||
|
||||
CPU::Registers::Interrupt::operator uint16() const {
|
||||
return (
|
||||
(vblank << 0)
|
||||
|| (hblank << 1)
|
||||
|| (vcoincidence << 2)
|
||||
|| (timer0 << 3)
|
||||
|| (timer1 << 4)
|
||||
|| (timer2 << 5)
|
||||
|| (timer3 << 6)
|
||||
|| (serial << 7)
|
||||
|| (dma0 << 8)
|
||||
|| (dma1 << 9)
|
||||
|| (dma2 << 10)
|
||||
|| (dma3 << 11)
|
||||
|| (keypad << 12)
|
||||
|| (cartridge << 13)
|
||||
(vblank << 0)
|
||||
| (hblank << 1)
|
||||
| (vcoincidence << 2)
|
||||
| (timer0 << 3)
|
||||
| (timer1 << 4)
|
||||
| (timer2 << 5)
|
||||
| (timer3 << 6)
|
||||
| (serial << 7)
|
||||
| (dma0 << 8)
|
||||
| (dma1 << 9)
|
||||
| (dma2 << 10)
|
||||
| (dma3 << 11)
|
||||
| (keypad << 12)
|
||||
| (cartridge << 13)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -59,3 +109,51 @@ uint16 CPU::Registers::Interrupt::operator=(uint16 source) {
|
|||
cartridge = source & (1 << 13);
|
||||
return operator uint16();
|
||||
}
|
||||
|
||||
CPU::Registers::WaitControl::operator uint16() const {
|
||||
return (
|
||||
(sram << 0)
|
||||
| (wait0n << 2)
|
||||
| (wait0s << 4)
|
||||
| (wait1n << 5)
|
||||
| (wait1s << 7)
|
||||
| (wait2n << 8)
|
||||
| (wait2s << 10)
|
||||
| (phi << 11)
|
||||
| (prefetch << 14)
|
||||
| (gametype << 15)
|
||||
);
|
||||
}
|
||||
|
||||
uint16 CPU::Registers::WaitControl::operator=(uint16 source) {
|
||||
sram = (source >> 0) & 3;
|
||||
wait0n = (source >> 2) & 3;
|
||||
wait0s = (source >> 4) & 1;
|
||||
wait1n = (source >> 5) & 3;
|
||||
wait1s = (source >> 7) & 1;
|
||||
wait2n = (source >> 8) & 3;
|
||||
wait2s = (source >> 10) & 1;
|
||||
phi = (source >> 11) & 3;
|
||||
prefetch = (source >> 14) & 1;
|
||||
gametype = (source >> 15) & 1;
|
||||
return operator uint16();
|
||||
}
|
||||
|
||||
CPU::Registers::MemoryControl::operator uint32() const {
|
||||
return (
|
||||
(disable << 0)
|
||||
| (unknown1 << 1)
|
||||
| (ewram << 5)
|
||||
| (ewramwait << 24)
|
||||
| (unknown2 << 28)
|
||||
);
|
||||
}
|
||||
|
||||
uint32 CPU::Registers::MemoryControl::operator=(uint32 source) {
|
||||
disable = (source >> 0) & 1;
|
||||
unknown1 = (source >> 1) & 7;
|
||||
ewram = (source >> 5) & 1;
|
||||
ewramwait = (source >> 24) & 15;
|
||||
unknown2 = (source >> 28) & 15;
|
||||
return operator uint32();
|
||||
}
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
struct Registers {
|
||||
bool ime;
|
||||
|
||||
struct DMA {
|
||||
uint32 source;
|
||||
uint32 target;
|
||||
|
@ -21,6 +19,47 @@ struct Registers {
|
|||
} control;
|
||||
} dma[4];
|
||||
|
||||
struct TimerControl {
|
||||
uint2 prescalar;
|
||||
bool countup;
|
||||
bool irq;
|
||||
bool enable;
|
||||
|
||||
operator uint16() const;
|
||||
uint16 operator=(uint16 source);
|
||||
TimerControl& operator=(const TimerControl&) = delete;
|
||||
};
|
||||
|
||||
struct Timer {
|
||||
uint16 reload;
|
||||
TimerControl control;
|
||||
} timer[4];
|
||||
|
||||
struct KeypadControl {
|
||||
bool a;
|
||||
bool b;
|
||||
bool select;
|
||||
bool start;
|
||||
bool right;
|
||||
bool left;
|
||||
bool up;
|
||||
bool down;
|
||||
bool r;
|
||||
bool l;
|
||||
bool enable;
|
||||
bool condition;
|
||||
|
||||
operator uint16() const;
|
||||
uint16 operator=(uint16 source);
|
||||
KeypadControl& operator=(const KeypadControl&) = delete;
|
||||
};
|
||||
|
||||
struct Keypad {
|
||||
KeypadControl control;
|
||||
} keypad;
|
||||
|
||||
bool ime;
|
||||
|
||||
struct Interrupt {
|
||||
bool vblank;
|
||||
bool hblank;
|
||||
|
@ -40,7 +79,49 @@ struct Registers {
|
|||
operator uint16() const;
|
||||
uint16 operator=(uint16 source);
|
||||
Interrupt& operator=(const Interrupt&) = delete;
|
||||
} irq_enable, irq_flag;
|
||||
};
|
||||
|
||||
struct IRQ {
|
||||
Interrupt enable;
|
||||
Interrupt flag;
|
||||
} irq;
|
||||
|
||||
struct WaitControl {
|
||||
uint2 sram;
|
||||
uint2 wait0n;
|
||||
uint1 wait0s;
|
||||
uint2 wait1n;
|
||||
uint1 wait1s;
|
||||
uint2 wait2n;
|
||||
uint1 wait2s;
|
||||
uint2 phi;
|
||||
uint1 prefetch;
|
||||
uint1 gametype;
|
||||
|
||||
operator uint16() const;
|
||||
uint16 operator=(uint16 source);
|
||||
WaitControl& operator=(const WaitControl&) = delete;
|
||||
};
|
||||
|
||||
struct Wait {
|
||||
WaitControl control;
|
||||
} wait;
|
||||
|
||||
struct MemoryControl {
|
||||
bool disable;
|
||||
uint3 unknown1;
|
||||
bool ewram;
|
||||
uint4 ewramwait;
|
||||
uint4 unknown2;
|
||||
|
||||
operator uint32() const;
|
||||
uint32 operator=(uint32 source);
|
||||
MemoryControl& operator=(const MemoryControl&) = delete;
|
||||
};
|
||||
|
||||
struct Memory {
|
||||
MemoryControl control;
|
||||
} memory;
|
||||
|
||||
bool postboot;
|
||||
enum class Mode : unsigned { Normal, Halt, Stop } mode;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace GBA {
|
||||
|
||||
#include "mmio.cpp"
|
||||
Bus bus;
|
||||
|
||||
struct UnmappedMemory : Memory {
|
||||
|
@ -74,7 +75,10 @@ uint32 Bus::read(uint32 addr, uint32 size) {
|
|||
case 0x01000000: return system.bios.read(addr & 0x3fff, size);
|
||||
case 0x02000000: return cpu.ewram.read(addr & 0x3ffff, size);
|
||||
case 0x03000000: return cpu.iwram.read(addr & 0x7fff, size);
|
||||
case 0x04000000: return mmio[addr & 0x3ff]->read(addr, size);
|
||||
case 0x04000000:
|
||||
if((addr & 0xfffffc00) == 0x04000000) return mmio[addr & 0x3ff]->read(addr, size);
|
||||
if((addr & 0xff00ffff) == 0x04000800) return ((MMIO&)cpu).read(0x04000800 | (addr & 3), size);
|
||||
return 0u;
|
||||
case 0x05000000: return ppu.pram.read(addr & 0x3ff, size);
|
||||
case 0x06000000: return ppu.vram.read(addr & 0x10000 ? (0x10000 + (addr & 0x7fff)) : (addr & 0xffff), size);
|
||||
case 0x07000000: return ppu.oam.read(addr & 0x3ff, size);
|
||||
|
@ -95,7 +99,10 @@ void Bus::write(uint32 addr, uint32 size, uint32 word) {
|
|||
case 0x01000000: return;
|
||||
case 0x02000000: return cpu.ewram.write(addr & 0x3ffff, size, word);
|
||||
case 0x03000000: return cpu.iwram.write(addr & 0x7fff, size, word);
|
||||
case 0x04000000: return mmio[addr & 0x3ff]->write(addr, size, word);
|
||||
case 0x04000000:
|
||||
if((addr & 0xfffffc00) == 0x04000000) return mmio[addr & 0x3ff]->write(addr, size, word);
|
||||
if((addr & 0xff00ffff) == 0x04000800) return ((MMIO&)cpu).write(0x04000800 | (addr & 3), size, word);
|
||||
return;
|
||||
case 0x05000000: return ppu.pram.write(addr & 0x3ff, size, word);
|
||||
case 0x06000000: return ppu.vram.write(addr & 0x10000 ? (0x10000 + (addr & 0x7fff)) : (addr & 0xffff), size, word);
|
||||
case 0x07000000: return ppu.oam.write(addr & 0x3ff, size, word);
|
||||
|
|
|
@ -13,6 +13,13 @@ struct StaticMemory : Memory {
|
|||
~StaticMemory();
|
||||
};
|
||||
|
||||
struct MMIO : Memory {
|
||||
virtual uint8 read(uint32 addr) = 0;
|
||||
virtual void write(uint32 addr, uint8 data) = 0;
|
||||
uint32 read(uint32 addr, uint32 size);
|
||||
void write(uint32 addr, uint32 size, uint32 word);
|
||||
};
|
||||
|
||||
struct Bus : Memory {
|
||||
Memory *mmio[0x400];
|
||||
static uint32 mirror(uint32 addr, uint32 size);
|
||||
|
|
|
@ -1,23 +1,5 @@
|
|||
uint32 PPU::read(uint32 addr, uint32 size) {
|
||||
if(size == Word) {
|
||||
addr &= ~3;
|
||||
uint32 word = 0;
|
||||
word |= read(addr + 0, Byte) << 0;
|
||||
word |= read(addr + 1, Byte) << 8;
|
||||
word |= read(addr + 2, Byte) << 16;
|
||||
word |= read(addr + 3, Byte) << 24;
|
||||
return word;
|
||||
}
|
||||
|
||||
if(size == Half) {
|
||||
addr &= ~1;
|
||||
uint32 half = 0;
|
||||
half |= read(addr + 0, Byte) << 0;
|
||||
half |= read(addr + 0, Byte) << 8;
|
||||
return half;
|
||||
}
|
||||
|
||||
switch(addr & 0x0fffffff) {
|
||||
uint8 PPU::read(uint32 addr) {
|
||||
switch(addr) {
|
||||
|
||||
//DISPCNT
|
||||
case 0x04000000: return regs.control >> 0;
|
||||
|
@ -66,26 +48,8 @@ uint32 PPU::read(uint32 addr, uint32 size) {
|
|||
return 0u;
|
||||
}
|
||||
|
||||
void PPU::write(uint32 addr, uint32 size, uint32 word) {
|
||||
if(size == Word) {
|
||||
addr &= ~3;
|
||||
write(addr + 0, Byte, word >> 0);
|
||||
write(addr + 1, Byte, word >> 8);
|
||||
write(addr + 2, Byte, word >> 16);
|
||||
write(addr + 3, Byte, word >> 24);
|
||||
return;
|
||||
}
|
||||
|
||||
if(size == Half) {
|
||||
addr &= ~1;
|
||||
write(addr + 0, Byte, word >> 0);
|
||||
write(addr + 1, Byte, word >> 8);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8 byte = word;
|
||||
|
||||
switch(addr & 0x0fffffff) {
|
||||
void PPU::write(uint32 addr, uint8 byte) {
|
||||
switch(addr) {
|
||||
|
||||
//DISPCNT
|
||||
case 0x04000000: regs.control = (regs.control & 0xff00) | (byte << 0); return;
|
||||
|
|
|
@ -82,16 +82,16 @@ void PPU::scanline() {
|
|||
}
|
||||
|
||||
if(regs.vcounter == 160) {
|
||||
if(regs.status.irqvblank) cpu.regs.irq_flag.vblank = 1;
|
||||
if(regs.status.irqvblank) cpu.regs.irq.flag.vblank = 1;
|
||||
}
|
||||
|
||||
if(regs.status.irqvcoincidence) {
|
||||
if(regs.status.vcoincidence) cpu.regs.irq_flag.vcoincidence = 1;
|
||||
if(regs.status.vcoincidence) cpu.regs.irq.flag.vcoincidence = 1;
|
||||
}
|
||||
|
||||
step(256 * 4);
|
||||
regs.status.hblank = 1;
|
||||
if(regs.status.irqhblank) cpu.regs.irq_flag.hblank = 1;
|
||||
if(regs.status.irqhblank) cpu.regs.irq.flag.hblank = 1;
|
||||
|
||||
step( 52 * 4);
|
||||
regs.status.hblank = 0;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
struct PPU : Thread, Memory {
|
||||
struct PPU : Thread, MMIO {
|
||||
StaticMemory vram;
|
||||
StaticMemory oam;
|
||||
StaticMemory pram;
|
||||
|
@ -13,8 +13,8 @@ struct PPU : Thread, Memory {
|
|||
void scanline();
|
||||
void frame();
|
||||
|
||||
uint32 read(uint32 addr, uint32 size);
|
||||
void write(uint32 addr, uint32 size, uint32 word);
|
||||
uint8 read(uint32 addr);
|
||||
void write(uint32 addr, uint8 byte);
|
||||
|
||||
PPU();
|
||||
~PPU();
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
PPU::Registers::Control::operator uint16() const {
|
||||
return (
|
||||
(bgmode << 0)
|
||||
|| (cgbmode << 3)
|
||||
|| (frame << 4)
|
||||
|| (hblank << 5)
|
||||
|| (objmap << 6)
|
||||
|| (forceblank << 7)
|
||||
|| (enablebg[0] << 8)
|
||||
|| (enablebg[1] << 9)
|
||||
|| (enablebg[2] << 10)
|
||||
|| (enablebg[3] << 11)
|
||||
|| (enableobj << 12)
|
||||
|| (enablebgwindow0 << 13)
|
||||
|| (enablebgwindow1 << 14)
|
||||
|| (enableobjwindow << 15)
|
||||
(bgmode << 0)
|
||||
| (cgbmode << 3)
|
||||
| (frame << 4)
|
||||
| (hblank << 5)
|
||||
| (objmap << 6)
|
||||
| (forceblank << 7)
|
||||
| (enablebg[0] << 8)
|
||||
| (enablebg[1] << 9)
|
||||
| (enablebg[2] << 10)
|
||||
| (enablebg[3] << 11)
|
||||
| (enableobj << 12)
|
||||
| (enablebgwindow0 << 13)
|
||||
| (enablebgwindow1 << 14)
|
||||
| (enableobjwindow << 15)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -37,13 +37,13 @@ uint16 PPU::Registers::Control::operator=(uint16 source) {
|
|||
|
||||
PPU::Registers::Status::operator uint16() const {
|
||||
return (
|
||||
(vblank << 0)
|
||||
|| (hblank << 1)
|
||||
|| (vcoincidence << 2)
|
||||
|| (irqvblank << 3)
|
||||
|| (irqhblank << 4)
|
||||
|| (irqvcoincidence << 5)
|
||||
|| (vcompare << 8)
|
||||
(vblank << 0)
|
||||
| (hblank << 1)
|
||||
| (vcoincidence << 2)
|
||||
| (irqvblank << 3)
|
||||
| (irqhblank << 4)
|
||||
| (irqvcoincidence << 5)
|
||||
| (vcompare << 8)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -60,12 +60,12 @@ uint16 PPU::Registers::Status::operator=(uint16 source) {
|
|||
|
||||
PPU::Registers::BackgroundControl::operator uint16() const {
|
||||
return (
|
||||
(priority << 0)
|
||||
|| (characterbaseblock << 2)
|
||||
|| (mosaic << 6)
|
||||
|| (colormode << 7)
|
||||
|| (screenbaseblock << 8)
|
||||
|| (screensize << 14)
|
||||
(priority << 0)
|
||||
| (characterbaseblock << 2)
|
||||
| (mosaic << 6)
|
||||
| (colormode << 7)
|
||||
| (screenbaseblock << 8)
|
||||
| (screensize << 14)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -81,12 +81,12 @@ uint16 PPU::Registers::BackgroundControl::operator=(uint16 source) {
|
|||
|
||||
PPU::Registers::WindowFlags::operator uint8() const {
|
||||
return (
|
||||
(enablebg[0] << 0)
|
||||
|| (enablebg[1] << 1)
|
||||
|| (enablebg[2] << 2)
|
||||
|| (enablebg[3] << 3)
|
||||
|| (enableobj << 4)
|
||||
|| (enablesfx << 5)
|
||||
(enablebg[0] << 0)
|
||||
| (enablebg[1] << 1)
|
||||
| (enablebg[2] << 2)
|
||||
| (enablebg[3] << 3)
|
||||
| (enableobj << 4)
|
||||
| (enablesfx << 5)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -102,19 +102,19 @@ uint8 PPU::Registers::WindowFlags::operator=(uint8 source) {
|
|||
|
||||
PPU::Registers::BlendControl::operator uint16() const {
|
||||
return (
|
||||
(firstbg[0] << 0)
|
||||
|| (firstbg[1] << 1)
|
||||
|| (firstbg[2] << 2)
|
||||
|| (firstbg[3] << 3)
|
||||
|| (firstobj << 4)
|
||||
|| (firstbd << 5)
|
||||
|| (effect << 6)
|
||||
|| (secondbg[0] << 8)
|
||||
|| (secondbg[1] << 9)
|
||||
|| (secondbg[2] << 10)
|
||||
|| (secondbg[3] << 11)
|
||||
|| (secondobj << 12)
|
||||
|| (secondbd << 13)
|
||||
(firstbg[0] << 0)
|
||||
| (firstbg[1] << 1)
|
||||
| (firstbg[2] << 2)
|
||||
| (firstbg[3] << 3)
|
||||
| (firstobj << 4)
|
||||
| (firstbd << 5)
|
||||
| (effect << 6)
|
||||
| (secondbg[0] << 8)
|
||||
| (secondbg[1] << 9)
|
||||
| (secondbg[2] << 10)
|
||||
| (secondbg[3] << 11)
|
||||
| (secondobj << 12)
|
||||
| (secondbd << 13)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ void ARM::arm_step() {
|
|||
step(2);
|
||||
|
||||
instructions++;
|
||||
if(pipeline.execute.address == 0x08000000) print("Entry Point\n");
|
||||
if(trace) {
|
||||
print(disassemble_registers(), "\n");
|
||||
print(disassemble_arm_instruction(pipeline.execute.address), "\n");
|
||||
|
@ -135,7 +136,7 @@ void ARM::arm_op_multiply() {
|
|||
uint4 m = instruction();
|
||||
|
||||
step(1);
|
||||
r(d) = mul(accumulate ? r(d) : 0u, r(m), r(s));
|
||||
r(d) = mul(accumulate ? r(n) : 0u, r(m), r(s));
|
||||
}
|
||||
|
||||
//(u,s)mull{condition}{s} rdlo,rdhi,rm,rs
|
||||
|
@ -174,8 +175,8 @@ void ARM::arm_op_multiply_long() {
|
|||
if(save) {
|
||||
cpsr().n = r(dhi) >> 31;
|
||||
cpsr().z = r(dhi) == 0 && r(dlo) == 0;
|
||||
cpsr().c = 0;
|
||||
cpsr().v = 0;
|
||||
//cpsr().c = 0; //(undefined)
|
||||
//cpsr().v = 0; //(undefined)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue