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:
Tim Allen 2012-04-01 11:41:15 +10:00
parent f587cb0dcc
commit c8bb4949b1
14 changed files with 310 additions and 367 deletions

View File

@ -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>

View File

@ -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;
}
}

View File

@ -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();
};

View File

@ -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() {

View File

@ -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();
};

View File

@ -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();
}

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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();

View File

@ -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)
);
}

View File

@ -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)
}
}