diff --git a/bsnes/base/base.hpp b/bsnes/base/base.hpp index a6ce8b05..2280f3f2 100755 --- a/bsnes/base/base.hpp +++ b/bsnes/base/base.hpp @@ -1,7 +1,7 @@ #ifndef BASE_HPP #define BASE_HPP -static const char Version[] = "087.12"; +static const char Version[] = "087.13"; #include #include diff --git a/bsnes/gba/apu/apu.cpp b/bsnes/gba/apu/apu.cpp index 2a4ce3f3..12e77a2b 100755 --- a/bsnes/gba/apu/apu.cpp +++ b/bsnes/gba/apu/apu.cpp @@ -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() { diff --git a/bsnes/gba/cpu/cpu.cpp b/bsnes/gba/cpu/cpu.cpp index c1ab471b..7b38bcef 100755 --- a/bsnes/gba/cpu/cpu.cpp +++ b/bsnes/gba/cpu/cpu.cpp @@ -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; diff --git a/bsnes/gba/ppu/bg.cpp b/bsnes/gba/ppu/bg.cpp deleted file mode 100755 index 982cc80e..00000000 --- a/bsnes/gba/ppu/bg.cpp +++ /dev/null @@ -1,2 +0,0 @@ -void PPU::render_bg() { -} diff --git a/bsnes/gba/ppu/mmio.cpp b/bsnes/gba/ppu/mmio.cpp index 74338f92..35bf47e4 100755 --- a/bsnes/gba/ppu/mmio.cpp +++ b/bsnes/gba/ppu/mmio.cpp @@ -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; + } } diff --git a/bsnes/gba/ppu/obj.cpp b/bsnes/gba/ppu/obj.cpp deleted file mode 100755 index 868b0ba7..00000000 --- a/bsnes/gba/ppu/obj.cpp +++ /dev/null @@ -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() { -} diff --git a/bsnes/gba/ppu/ppu.cpp b/bsnes/gba/ppu/ppu.cpp index 52288ee2..8012c4e7 100755 --- a/bsnes/gba/ppu/ppu.cpp +++ b/bsnes/gba/ppu/ppu.cpp @@ -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; } } diff --git a/bsnes/gba/ppu/ppu.hpp b/bsnes/gba/ppu/ppu.hpp index b1ff840c..885437e3 100755 --- a/bsnes/gba/ppu/ppu.hpp +++ b/bsnes/gba/ppu/ppu.hpp @@ -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; diff --git a/bsnes/gba/ppu/registers.cpp b/bsnes/gba/ppu/registers.cpp index 7dff719b..71f95021 100755 --- a/bsnes/gba/ppu/registers.cpp +++ b/bsnes/gba/ppu/registers.cpp @@ -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(); } diff --git a/bsnes/gba/ppu/registers.hpp b/bsnes/gba/ppu/registers.hpp index 6297da3f..568862a7 100755 --- a/bsnes/gba/ppu/registers.hpp +++ b/bsnes/gba/ppu/registers.hpp @@ -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; diff --git a/bsnes/gba/ppu/window.cpp b/bsnes/gba/ppu/window.cpp deleted file mode 100755 index f97ae99c..00000000 --- a/bsnes/gba/ppu/window.cpp +++ /dev/null @@ -1,2 +0,0 @@ -void PPU::render_window() { -} diff --git a/bsnes/processor/arm/algorithms.cpp b/bsnes/processor/arm/algorithms.cpp index 34d562cf..42b5c1ae 100755 --- a/bsnes/processor/arm/algorithms.cpp +++ b/bsnes/processor/arm/algorithms.cpp @@ -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); } diff --git a/bsnes/processor/arm/instructions-arm.cpp b/bsnes/processor/arm/instructions-arm.cpp index ed0e3b3e..c7064a96 100755 --- a/bsnes/processor/arm/instructions-arm.cpp +++ b/bsnes/processor/arm/instructions-arm.cpp @@ -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); } diff --git a/bsnes/processor/arm/instructions-thumb.cpp b/bsnes/processor/arm/instructions-thumb.cpp index b713c4d7..c7320a4a 100755 --- a/bsnes/processor/arm/instructions-thumb.cpp +++ b/bsnes/processor/arm/instructions-thumb.cpp @@ -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; } } diff --git a/bsnes/ruby/video/direct3d.cpp b/bsnes/ruby/video/direct3d.cpp index 9719309f..3d0e29f6 100755 --- a/bsnes/ruby/video/direct3d.cpp +++ b/bsnes/ruby/video/direct3d.cpp @@ -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() { diff --git a/bsnes/target-ui/main.cpp b/bsnes/target-ui/main.cpp index f3a4b49d..2c2d7c2c 100755 --- a/bsnes/target-ui/main.cpp +++ b/bsnes/target-ui/main.cpp @@ -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();