Update to v087r13 release.

byuu says:

Contains all of Cydrak's fixes, sans PPU.
On the PPU front, I've hooked up 100% of read and write registers.
All three DISPSTAT IRQs (Vblank, Hblank, Vcoincidence) are connected now
as well.
Super Mario Advance now runs without *appearing* to crash, although it's
hard to tell since I have no video or sound :P
ARM Wrestler is known to run, as is the BIOS.
This commit is contained in:
Tim Allen 2012-03-31 19:17:36 +11:00
parent ea086fe33f
commit f587cb0dcc
16 changed files with 560 additions and 146 deletions

View File

@ -1,7 +1,7 @@
#ifndef BASE_HPP
#define BASE_HPP
static const char Version[] = "087.12";
static const char Version[] = "087.13";
#include <nall/platform.hpp>
#include <nall/algorithm.hpp>

View File

@ -19,15 +19,53 @@ void APU::step(unsigned clocks) {
}
uint32 APU::read(uint32 addr, uint32 size) {
if(addr == 0x04000088) {
//SOUNDBIAS
return 0x0200;
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() {

View File

@ -17,7 +17,7 @@ void CPU::enter() {
while(true) step(frequency);
}
processor.irqline = regs.ime && 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) {
@ -88,7 +88,7 @@ uint32 CPU::read(uint32 addr, uint32 size) {
}
if(size == Half) {
addr &= ~3;
addr &= ~1;
uint32 half = 0;
half |= read(addr + 0, Byte) << 0;
half |= read(addr + 0, Byte) << 8;
@ -101,14 +101,14 @@ uint32 CPU::read(uint32 addr, uint32 size) {
//KEYINPUT
case 0x04000130:
for(unsigned n = 0; n < 8; n++) result |= (interface->inputPoll(n) == false) << n;
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;
return result ^ 0xff;
case 0x40000131:
result |= (interface->inputPoll(8) == false) << 0;
result |= (interface->inputPoll(9) == false) << 1;
return result;
result |= interface->inputPoll(8) << 0;
result |= interface->inputPoll(9) << 1;
return result ^ 0x03;
//IE
case 0x04000200: return regs.irq_enable >> 0;

View File

@ -1,2 +0,0 @@
void PPU::render_bg() {
}

View File

@ -10,7 +10,7 @@ uint32 PPU::read(uint32 addr, uint32 size) {
}
if(size == Half) {
addr &= ~3;
addr &= ~1;
uint32 half = 0;
half |= read(addr + 0, Byte) << 0;
half |= read(addr + 0, Byte) << 8;
@ -19,9 +19,47 @@ uint32 PPU::read(uint32 addr, uint32 size) {
switch(addr & 0x0fffffff) {
//DISPCNT
case 0x04000000: return regs.control >> 0;
case 0x04000001: return regs.control >> 8;
//GRSWP
case 0x04000002: return regs.greenswap;
case 0x04000003: return 0u;
//DISPSTAT
case 0x04000004: return regs.status >> 0;
case 0x04000005: return regs.status >> 8;
//VCOUNT
case 0x04000006: return regs.scanline >> 0;
case 0x04000007: return regs.scanline >> 8;
case 0x04000006: return regs.vcounter >> 0;
case 0x04000007: return regs.vcounter >> 8;
//BG0CNT
case 0x04000008: return regs.bg[0].control >> 0;
case 0x04000009: return regs.bg[0].control >> 8;
//BG1CNT
case 0x0400000a: return regs.bg[1].control >> 0;
case 0x0400000b: return regs.bg[1].control >> 8;
//BG2CNT
case 0x0400000c: return regs.bg[2].control >> 0;
case 0x0400000d: return regs.bg[2].control >> 8;
//BG3CNT
case 0x0400000e: return regs.bg[3].control >> 0;
case 0x0400000f: return regs.bg[3].control >> 8;
//WININ
case 0x04000048: return regs.window[0].in;
case 0x04000049: return regs.window[1].in;
case 0x0400004a: return regs.window[0].out;
case 0x0400004b: return regs.windowobj.in;
//BLTCNT
case 0x04000050: return regs.blend.control >> 0;
case 0x04000051: return regs.blend.control >> 8;
}
@ -53,5 +91,177 @@ void PPU::write(uint32 addr, uint32 size, uint32 word) {
case 0x04000000: regs.control = (regs.control & 0xff00) | (byte << 0); return;
case 0x04000001: regs.control = (regs.control & 0x00ff) | (byte << 8); return;
//GRSWP
case 0x04000002: regs.greenswap = byte & 0x01; return;
case 0x04000003: return;
//DISPSTAT
case 0x04000004:
regs.status.irqvblank = byte & (1 << 3);
regs.status.irqhblank = byte & (1 << 4);
regs.status.irqvcoincidence = byte & (1 << 5);
return;
case 0x04000005:
regs.status.vcoincidence = byte;
return;
//BG0CNT
case 0x04000008: regs.bg[0].control = (regs.bg[0].control & 0xff00) | (byte << 0); return;
case 0x04000009: regs.bg[0].control = (regs.bg[0].control & 0x00ff) | (byte << 8); return;
//BG1CNT
case 0x0400000a: regs.bg[1].control = (regs.bg[1].control & 0xff00) | (byte << 0); return;
case 0x0400000b: regs.bg[1].control = (regs.bg[1].control & 0x00ff) | (byte << 8); return;
//BG2CNT
case 0x0400000c: regs.bg[2].control = (regs.bg[2].control & 0xff00) | (byte << 0); return;
case 0x0400000d: regs.bg[2].control = (regs.bg[2].control & 0x00ff) | (byte << 8); return;
//BG3CNT
case 0x0400000e: regs.bg[3].control = (regs.bg[3].control & 0xff00) | (byte << 0); return;
case 0x0400000f: regs.bg[3].control = (regs.bg[3].control & 0x00ff) | (byte << 8); return;
//BG0HOFS
case 0x04000010: regs.bg[0].hoffset = (regs.bg[0].hoffset & 0xff00) | (byte << 0); return;
case 0x04000011: regs.bg[0].hoffset = (regs.bg[0].hoffset & 0x00ff) | (byte << 8); return;
//BG0VOFS
case 0x04000012: regs.bg[0].voffset = (regs.bg[0].voffset & 0xff00) | (byte << 0); return;
case 0x04000013: regs.bg[0].voffset = (regs.bg[0].voffset & 0x00ff) | (byte << 8); return;
//BG1HOFS
case 0x04000014: regs.bg[1].hoffset = (regs.bg[1].hoffset & 0xff00) | (byte << 0); return;
case 0x04000015: regs.bg[1].hoffset = (regs.bg[1].hoffset & 0x00ff) | (byte << 8); return;
//BG1VOFS
case 0x04000016: regs.bg[1].voffset = (regs.bg[1].voffset & 0xff00) | (byte << 0); return;
case 0x04000017: regs.bg[1].voffset = (regs.bg[1].voffset & 0x00ff) | (byte << 8); return;
//BG2HOFS
case 0x04000018: regs.bg[2].hoffset = (regs.bg[2].hoffset & 0xff00) | (byte << 0); return;
case 0x04000019: regs.bg[2].hoffset = (regs.bg[2].hoffset & 0x00ff) | (byte << 8); return;
//BG2VOFS
case 0x0400001a: regs.bg[2].voffset = (regs.bg[2].voffset & 0xff00) | (byte << 0); return;
case 0x0400001b: regs.bg[2].voffset = (regs.bg[2].voffset & 0x00ff) | (byte << 8); return;
//BG3HOFS
case 0x0400001c: regs.bg[3].hoffset = (regs.bg[3].hoffset & 0xff00) | (byte << 0); return;
case 0x0400001d: regs.bg[3].hoffset = (regs.bg[3].hoffset & 0x00ff) | (byte << 8); return;
//BG3VOFS
case 0x0400001e: regs.bg[3].voffset = (regs.bg[3].voffset & 0xff00) | (byte << 0); return;
case 0x0400001f: regs.bg[3].voffset = (regs.bg[3].voffset & 0x00ff) | (byte << 8); return;
//BG2PA
case 0x04000020: regs.bg[2].pa = (regs.bg[2].pa & 0xff00) | (byte << 0); return;
case 0x04000021: regs.bg[2].pa = (regs.bg[2].pa & 0x00ff) | (byte << 8); return;
//BG2PB
case 0x04000022: regs.bg[2].pb = (regs.bg[2].pb & 0xff00) | (byte << 0); return;
case 0x04000023: regs.bg[2].pb = (regs.bg[2].pb & 0x00ff) | (byte << 8); return;
//BG2PC
case 0x04000024: regs.bg[2].pc = (regs.bg[2].pc & 0xff00) | (byte << 0); return;
case 0x04000025: regs.bg[2].pc = (regs.bg[2].pc & 0x00ff) | (byte << 0); return;
//BG2PD
case 0x04000026: regs.bg[2].pd = (regs.bg[2].pd & 0xff00) | (byte << 0); return;
case 0x04000027: regs.bg[2].pd = (regs.bg[2].pd & 0x00ff) | (byte << 8); return;
//BG2X_L
case 0x04000028: regs.bg[2].x = (regs.bg[2].x & 0xffffff00) | (byte << 0); return;
case 0x04000029: regs.bg[2].x = (regs.bg[2].x & 0xffff00ff) | (byte << 8); return;
//BG2X_H
case 0x0400002a: regs.bg[2].x = (regs.bg[2].x & 0xff00ffff) | (byte << 16); return;
case 0x0400002b: regs.bg[2].x = (regs.bg[2].x & 0x00ffffff) | (byte << 24); return;
//BG2Y_L
case 0x0400002c: regs.bg[2].y = (regs.bg[2].y & 0xffffff00) | (byte << 0); return;
case 0x0400002d: regs.bg[2].y = (regs.bg[2].y & 0xffff00ff) | (byte << 8); return;
//BG2Y_H
case 0x0400002e: regs.bg[2].y = (regs.bg[2].y & 0xff00ffff) | (byte << 16); return;
case 0x0400002f: regs.bg[2].y = (regs.bg[2].y & 0x00ffffff) | (byte << 24); return;
//BG3PA
case 0x04000030: regs.bg[3].pa = (regs.bg[3].pa & 0xff00) | (byte << 0); return;
case 0x04000031: regs.bg[3].pa = (regs.bg[3].pa & 0x00ff) | (byte << 8); return;
//BG3PB
case 0x04000032: regs.bg[3].pb = (regs.bg[3].pb & 0xff00) | (byte << 0); return;
case 0x04000033: regs.bg[3].pb = (regs.bg[3].pb & 0x00ff) | (byte << 8); return;
//BG3PC
case 0x04000034: regs.bg[3].pc = (regs.bg[3].pc & 0xff00) | (byte << 0); return;
case 0x04000035: regs.bg[3].pc = (regs.bg[3].pc & 0x00ff) | (byte << 8); return;
//BG3PD
case 0x04000036: regs.bg[3].pd = (regs.bg[3].pd & 0xff00) | (byte << 0); return;
case 0x04000037: regs.bg[3].pd = (regs.bg[3].pd & 0x00ff) | (byte << 8); return;
//BG3X_L
case 0x04000038: regs.bg[3].x = (regs.bg[3].x & 0xffffff00) | (byte << 0); return;
case 0x04000039: regs.bg[3].x = (regs.bg[3].x & 0xffff00ff) | (byte << 8); return;
//BG3X_H
case 0x0400003a: regs.bg[3].x = (regs.bg[3].x & 0xff00ffff) | (byte << 16); return;
case 0x0400003b: regs.bg[3].x = (regs.bg[3].x & 0x00ffffff) | (byte << 24); return;
//BG3Y_L
case 0x0400003c: regs.bg[3].y = (regs.bg[3].y & 0xffffff00) | (byte << 0); return;
case 0x0400003d: regs.bg[3].y = (regs.bg[3].y & 0xffff00ff) | (byte << 8); return;
//BG3Y_H
case 0x0400003e: regs.bg[3].y = (regs.bg[3].y & 0xff00ffff) | (byte << 16); return;
case 0x0400003f: regs.bg[3].y = (regs.bg[3].y & 0x00ffffff) | (byte << 24); return;
//WIN0H
case 0x04000040: regs.window[0].x2 = byte; return;
case 0x04000041: regs.window[0].x1 = byte; return;
//WIN1H
case 0x04000042: regs.window[1].x2 = byte; return;
case 0x04000043: regs.window[1].x1 = byte; return;
//WIN0V
case 0x04000044: regs.window[0].y2 = byte; return;
case 0x04000045: regs.window[0].y1 = byte; return;
//WIN1V
case 0x04000046: regs.window[1].y2 = byte; return;
case 0x04000047: regs.window[1].y1 = byte; return;
//WININ
case 0x04000048: regs.window[0].in = byte; return;
case 0x04000049: regs.window[1].in = byte; return;
//WINOUT
case 0x0400004a: regs.window[0].out = regs.window[1].out = byte; return;
case 0x0400004b: regs.windowobj.in = byte; return;
//MOSAIC
case 0x0400004c:
regs.mosaic.bghsize = byte >> 0;
regs.mosaic.bgvsize = byte >> 4;
return;
case 0x0400004d:
regs.mosaic.objhsize = byte >> 0;
regs.mosaic.objvsize = byte >> 4;
return;
//BLDCNT
case 0x04000050: regs.blend.control = (regs.blend.control & 0xff00) | (byte << 0); return;
case 0x04000051: regs.blend.control = (regs.blend.control & 0x00ff) | (byte << 8); return;
//BLDALPHA
case 0x04000052: regs.blend.eva = std::min(16, byte & 0x1f); return;
case 0x04000053: regs.blend.evb = std::min(16, byte & 0x1f); return;
//BLDY
case 0x04000054: regs.blend.evy = std::min(16, byte & 0x1f); return;
case 0x04000055: return;
}
}

View File

@ -1,25 +0,0 @@
//BG modes 0,1,2 = 0x10000-0x17fff
//BG modes 3,4,5 = 0x14000-0x17fff
//OAM = 1024 bytes (128 entries x 64-bits)
// 0- 7 = y
// 8 = scale
// 9 = scaleflag (0 = single-fold, 1 = double-angle)
//10-11 = mode (0 = normal, 1 = semi-transparent, 2 = obj window, 3 = prohibited)
// 12 = mosaic
// 13 = colormode (0 = 16 colors x 16 palettes, 1 = 256 colors x 1 palette)
//14-15 = shape (0 = square, 1 = horizontal, 2 = vertical, 3 = prohibited)
//00-08 = x
//09-11 = rotation/scaling parameter
// 12 = hflip
// 13 = vflip
//14-15 = size
//00-09 = character
//10-11 = priority
//12-15 = palette (16-color mode)
void PPU::render_obj() {
}

View File

@ -14,16 +14,12 @@ namespace GBA {
#include "registers.cpp"
#include "mmio.cpp"
#include "bg.cpp"
#include "obj.cpp"
#include "window.cpp"
PPU ppu;
void PPU::Enter() { ppu.enter(); }
void PPU::enter() {
while(true) {
step(1232);
scanline();
}
}
@ -39,48 +35,71 @@ void PPU::power() {
for(unsigned n = 0; n < vram.size; n++) vram.data[n] = 0;
for(unsigned n = 0; n < oam.size; n++) oam.data[n] = 0;
for(unsigned n = 0; n < pram.size; n++) pram.data[n] = 0;
for(unsigned n = 0; n < 240 * 160; n++) output[n] = 0;
regs.control = 0;
regs.scanline = 0;
regs.greenswap = 0;
regs.status = 0;
regs.vcounter = 0;
for(auto &bg : regs.bg) {
bg.control = 0;
bg.hoffset = 0;
bg.voffset = 0;
bg.pa = 0;
bg.pb = 0;
bg.pc = 0;
bg.pd = 0;
bg.x = 0;
bg.y = 0;
}
for(auto &w : regs.window) {
w.x1 = 0;
w.x2 = 0;
w.y1 = 0;
w.y2 = 0;
w.in = 0;
w.out = 0;
}
regs.windowobj.in = 0;
regs.mosaic.bghsize = 0;
regs.mosaic.bgvsize = 0;
regs.mosaic.objhsize = 0;
regs.mosaic.objvsize = 0;
regs.blend.control = 0;
regs.blend.eva = 0;
regs.blend.evb = 0;
regs.blend.evy = 0;
for(unsigned n = 0x000; n <= 0x055; n++) bus.mmio[n] = this;
}
void PPU::scanline() {
regs.scanline++;
regs.status.vblank = regs.vcounter >= 160 && regs.vcounter <= 226;
regs.status.vcoincidence = regs.vcounter == regs.status.vcompare;
if(regs.scanline == 160) {
if(cpu.regs.ime && cpu.regs.irq_enable.vblank) {
cpu.regs.irq_flag.vblank = 1;
}
}
if(regs.scanline == 228) {
regs.scanline = 0;
if(regs.vcounter == 0) {
frame();
}
if(regs.scanline >= 160) return;
render_bg();
render_obj();
if(regs.vcounter == 160) {
if(regs.status.irqvblank) cpu.regs.irq_flag.vblank = 1;
}
if(regs.status.irqvcoincidence) {
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;
step( 52 * 4);
regs.status.hblank = 0;
if(++regs.vcounter == 228) regs.vcounter = 0;
}
void PPU::frame() {
static uint16_t output[240 * 160];
static bool once = true;
if(once) {
once = false;
for(signed y = 0; y < 160; y++) {
uint16_t *dp = output + y * 240;
for(signed x = 0; x < 240; x++) {
uint16_t color = sin((x - 60) * 6.283 / 240) * 16 + cos((y - 80) * 6.283 / 160) * 16;
if(color >= 16) color = 31 - color;
*dp++ = color;
}
}
}
interface->videoRefresh(output);
scheduler.exit(Scheduler::ExitReason::FrameEvent);
}
@ -89,6 +108,11 @@ PPU::PPU() {
vram.data = new uint8[vram.size = 96 * 1024];
oam.data = new uint8[oam.size = 1024];
pram.data = new uint8[pram.size = 1024];
output = new uint16[240 * 160];
}
PPU::~PPU() {
delete[] output;
}
}

View File

@ -3,6 +3,7 @@ struct PPU : Thread, Memory {
StaticMemory oam;
StaticMemory pram;
#include "registers.hpp"
uint16 *output;
static void Enter();
void enter();
@ -15,11 +16,8 @@ struct PPU : Thread, Memory {
uint32 read(uint32 addr, uint32 size);
void write(uint32 addr, uint32 size, uint32 word);
void render_bg();
void render_obj();
void render_window();
PPU();
~PPU();
};
extern PPU ppu;

View File

@ -1,36 +1,136 @@
PPU::Registers::Control::operator uint16() const {
return (
(bgmode << 0)
|| (cgbmode << 3)
|| (frame << 4)
|| (hblank << 5)
|| (objmap << 6)
|| (forceblank << 7)
|| (displaybg0 << 8)
|| (displaybg1 << 9)
|| (displaybg2 << 10)
|| (displaybg3 << 11)
|| (displayobj << 12)
|| (displaybgwindow0 << 13)
|| (displaybgwindow1 << 14)
|| (displayobjwindow << 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)
);
}
uint16 PPU::Registers::Control::operator=(uint16 source) {
bgmode = source & 0x0007;
cgbmode = source & 0x0008;
frame = source & 0x0010;
hblank = source & 0x0020;
objmap = source & 0x0040;
forceblank = source & 0x0080;
displaybg0 = source & 0x0100;
displaybg1 = source & 0x0200;
displaybg2 = source & 0x0400;
displaybg3 = source & 0x0800;
displayobj = source & 0x1000;
displaybgwindow0 = source & 0x2000;
displaybgwindow1 = source & 0x4000;
displayobjwindow = source & 0x8000;
bgmode = source & 0x0007;
cgbmode = source & 0x0008;
frame = source & 0x0010;
hblank = source & 0x0020;
objmap = source & 0x0040;
forceblank = source & 0x0080;
enablebg[0] = source & 0x0100;
enablebg[1] = source & 0x0200;
enablebg[2] = source & 0x0400;
enablebg[3] = source & 0x0800;
enableobj = source & 0x1000;
enablebgwindow0 = source & 0x2000;
enablebgwindow1 = source & 0x4000;
enableobjwindow = source & 0x8000;
return operator uint16();
}
PPU::Registers::Status::operator uint16() const {
return (
(vblank << 0)
|| (hblank << 1)
|| (vcoincidence << 2)
|| (irqvblank << 3)
|| (irqhblank << 4)
|| (irqvcoincidence << 5)
|| (vcompare << 8)
);
}
uint16 PPU::Registers::Status::operator=(uint16 source) {
vblank = source & 0x0001;
hblank = source & 0x0002;
vcoincidence = source & 0x0004;
irqvblank = source & 0x0008;
irqhblank = source & 0x0010;
irqvcoincidence = source & 0x0020;
vcompare = source >> 8;
return operator uint16();
}
PPU::Registers::BackgroundControl::operator uint16() const {
return (
(priority << 0)
|| (characterbaseblock << 2)
|| (mosaic << 6)
|| (colormode << 7)
|| (screenbaseblock << 8)
|| (screensize << 14)
);
}
uint16 PPU::Registers::BackgroundControl::operator=(uint16 source) {
priority = source >> 0;
characterbaseblock = source >> 2;
mosaic = source >> 6;
colormode = source >> 7;
screenbaseblock = source >> 8;
screensize = source >> 14;
return operator uint16();
}
PPU::Registers::WindowFlags::operator uint8() const {
return (
(enablebg[0] << 0)
|| (enablebg[1] << 1)
|| (enablebg[2] << 2)
|| (enablebg[3] << 3)
|| (enableobj << 4)
|| (enablesfx << 5)
);
}
uint8 PPU::Registers::WindowFlags::operator=(uint8 source) {
enablebg[0] = source & 0x01;
enablebg[1] = source & 0x02;
enablebg[2] = source & 0x04;
enablebg[3] = source & 0x08;
enableobj = source & 0x10;
enablesfx = source & 0x20;
return operator uint8();
}
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)
);
}
uint16 PPU::Registers::BlendControl::operator=(uint16 source) {
firstbg[0] = source & (1 << 0);
firstbg[1] = source & (1 << 1);
firstbg[2] = source & (1 << 2);
firstbg[3] = source & (1 << 3);
firstobj = source & (1 << 4);
firstbd = source & (1 << 5);
effect = source >> 6;
secondbg[0] = source & (1 << 8);
secondbg[1] = source & (1 << 9);
secondbg[2] = source & (1 << 10);
secondbg[3] = source & (1 << 11);
secondobj = source & (1 << 12);
secondbd = source & (1 << 13);
return operator uint16();
}

View File

@ -6,19 +6,103 @@ struct Registers {
bool hblank;
bool objmap;
bool forceblank;
bool displaybg0;
bool displaybg1;
bool displaybg2;
bool displaybg3;
bool displayobj;
bool displaybgwindow0;
bool displaybgwindow1;
bool displayobjwindow;
bool enablebg[4];
bool enableobj;
bool enablebgwindow0;
bool enablebgwindow1;
bool enableobjwindow;
operator uint16() const;
uint16 operator=(uint16 source);
Control& operator=(const Control&) = delete;
} control;
uint16 scanline;
bool greenswap;
struct Status {
bool vblank;
bool hblank;
bool vcoincidence;
bool irqvblank;
bool irqhblank;
bool irqvcoincidence;
uint8 vcompare;
operator uint16() const;
uint16 operator=(uint16 source);
Status& operator=(const Status&) = delete;
} status;
uint16 vcounter;
struct BackgroundControl {
uint2 priority;
uint2 characterbaseblock;
uint1 mosaic;
uint1 colormode;
uint5 screenbaseblock;
uint2 screensize;
operator uint16() const;
uint16 operator=(uint16 source);
BackgroundControl& operator=(const BackgroundControl&) = delete;
};
struct Background {
BackgroundControl control;
uint9 hoffset;
uint9 voffset;
//BG2,3 only
uint16 pa, pb, pc, pd;
uint28 x, y;
} bg[4];
struct WindowFlags {
bool enablebg[4];
bool enableobj;
bool enablesfx;
operator uint8() const;
uint8 operator=(uint8 source);
WindowFlags& operator=(const WindowFlags&) = delete;
};
struct Window {
uint8 x1, x2;
uint8 y1, y2;
WindowFlags in, out;
} window[2];
struct ObjectWindow {
WindowFlags in;
} windowobj;
struct Mosaic {
uint4 bghsize;
uint4 bgvsize;
uint4 objhsize;
uint4 objvsize;
} mosaic;
struct BlendControl {
bool firstbg[4];
bool firstobj;
bool firstbd;
uint2 effect;
bool secondbg[4];
bool secondobj;
bool secondbd;
operator uint16() const;
uint16 operator=(uint16 source);
BlendControl& operator=(const BlendControl&) = delete;
};
struct Blend {
BlendControl control;
uint5 eva;
uint5 evb;
uint5 evy;
} blend;
} regs;

View File

@ -1,2 +0,0 @@
void PPU::render_window() {
}

View File

@ -45,28 +45,11 @@ uint32 ARM::sub(uint32 source, uint32 modify, bool carry) {
}
uint32 ARM::mul(uint32 product, uint32 multiplicand, uint32 multiplier) {
//Modified Booth Encoding
bool carry = 0;
unsigned place = 0;
do {
step(1);
signed factor = (int2)multiplier + carry;
if(factor == -2) product -= multiplicand << (place + 1);
if(factor == -1) product -= multiplicand << (place + 0);
if(factor == +1) product += multiplicand << (place + 0);
if(factor == +2) product += multiplicand << (place + 1);
carry = multiplier & 2;
place += 2;
multiplier >>= 2;
} while(multiplier + carry && place < 32);
product += multiplicand * multiplier;
if(cpsr().t || instruction() & (1 << 20)) {
cpsr().n = product >> 31;
cpsr().z = product == 0;
cpsr().c = carry;
}
return product;
@ -134,5 +117,5 @@ uint32 ARM::ror(uint32 source, uint32 shift) {
uint32 ARM::rrx(uint32 source) {
carryout() = source & 1;
source = (cpsr().c << 31) | (source >> 1);
return (cpsr().c << 31) | (source >> 1);
}

View File

@ -134,9 +134,8 @@ void ARM::arm_op_multiply() {
uint4 s = instruction() >> 8;
uint4 m = instruction();
r(d) = accumulate ? r(n) : 0u;
step(1);
r(d) = mul(r(d), r(m), r(s));
r(d) = mul(accumulate ? r(d) : 0u, r(m), r(s));
}
//(u,s)mull{condition}{s} rdlo,rdhi,rm,rs
@ -159,8 +158,12 @@ void ARM::arm_op_multiply_long() {
uint4 s = instruction() >> 8;
uint4 m = instruction();
uint64 rm = signextend ? r(m) : (int32)r(m);
uint64 rs = signextend ? r(s) : (int32)r(s);
uint64 rm = r(m);
uint64 rs = r(s);
if(signextend) {
rm = (int32)rm;
rs = (int32)rs;
}
uint64 rd = rm * rs;
if(accumulate) rd += ((uint64)r(dhi) << 32) + ((uint64)r(dlo) << 0);
@ -399,6 +402,7 @@ void ARM::arm_op_data_immediate_shift() {
uint32 rs = shift;
uint32 rm = r(m);
carryout() = cpsr().c;
if(mode == 0) rm = lsl(rm, rs);
if(mode == 1) rm = lsr(rm, rs ? rs : 32);
@ -428,6 +432,7 @@ void ARM::arm_op_data_register_shift() {
uint8 rs = r(s);
uint32 rm = r(m);
carryout() = cpsr().c;
if(mode == 0 ) rm = lsl(rm, rs < 33 ? rs : 33);
if(mode == 1 ) rm = lsr(rm, rs < 33 ? rs : 33);
@ -453,9 +458,10 @@ void ARM::arm_op_data_immediate() {
uint4 shift = instruction() >> 8;
uint8 immediate = instruction();
uint32 rs = shift << 1;
uint32 rm = (immediate >> rs) | (immediate << (32 - rs));
if(rs) carryout() = immediate >> 31;
uint32 rm = immediate;
carryout() = cpsr().c;
if(shift) rm = ror(immediate, 2 * shift);
arm_opcode(rm);
}

View File

@ -125,8 +125,8 @@ void ARM::thumb_op_shift_immediate() {
switch(opcode) {
case 0: r(d) = lsl(r(m), immediate); break;
case 1: r(d) = lsr(r(m), immediate); break;
case 2: r(d) = asr(r(m), immediate); break;
case 1: r(d) = lsr(r(m), immediate == 0 ? 32u : (unsigned)immediate); break;
case 2: r(d) = asr(r(m), immediate == 0 ? 32u : (unsigned)immediate); break;
}
}

View File

@ -228,6 +228,7 @@ public:
if(surface) {
device->ColorFill(surface, 0, D3DCOLOR_XRGB(0x00, 0x00, 0x00));
surface->Release();
surface = nullptr;
}
//clear primary display and all backbuffers
@ -255,6 +256,7 @@ public:
void unlock() {
surface->UnlockRect();
surface->Release();
surface = nullptr;
}
void refresh() {

View File

@ -123,8 +123,6 @@ Application::Application(int argc, char **argv) {
Application::run();
}
if(GBA::cartridge.loaded()) print(GBA::cpu.disassemble_registers(), "\n");
interface->unloadCartridge();
windowManager->saveGeometry();
windowManager->hideAll();