mirror of https://github.com/bsnes-emu/bsnes.git
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:
parent
ea086fe33f
commit
f587cb0dcc
|
@ -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>
|
||||
|
|
|
@ -19,15 +19,53 @@ void APU::step(unsigned clocks) {
|
|||
}
|
||||
|
||||
uint32 APU::read(uint32 addr, uint32 size) {
|
||||
if(addr == 0x04000088) {
|
||||
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
|
||||
return 0x0200;
|
||||
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() {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
void PPU::render_bg() {
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -6,14 +6,14 @@ PPU::Registers::Control::operator uint16() const {
|
|||
|| (hblank << 5)
|
||||
|| (objmap << 6)
|
||||
|| (forceblank << 7)
|
||||
|| (displaybg0 << 8)
|
||||
|| (displaybg1 << 9)
|
||||
|| (displaybg2 << 10)
|
||||
|| (displaybg3 << 11)
|
||||
|| (displayobj << 12)
|
||||
|| (displaybgwindow0 << 13)
|
||||
|| (displaybgwindow1 << 14)
|
||||
|| (displayobjwindow << 15)
|
||||
|| (enablebg[0] << 8)
|
||||
|| (enablebg[1] << 9)
|
||||
|| (enablebg[2] << 10)
|
||||
|| (enablebg[3] << 11)
|
||||
|| (enableobj << 12)
|
||||
|| (enablebgwindow0 << 13)
|
||||
|| (enablebgwindow1 << 14)
|
||||
|| (enableobjwindow << 15)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -24,13 +24,113 @@ uint16 PPU::Registers::Control::operator=(uint16 source) {
|
|||
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;
|
||||
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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
void PPU::render_window() {
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue