Update to v068r05 release.

byuu says:

Started over again on the new S-PPU, heh. Three hours wasted last night
I guess.
I wanted to make the new one more like the accurate core in its
structure: multiple class instances for each background. It makes the
code easier to read, results in less structure insanity
(regs.main_enabled[bg] -> main_enabled), and will probably make it a tad
easier to parallelize if we want to go that route eg for the ARM.

Still very incomplete.
このコミットが含まれているのは:
Tim Allen 2010-09-01 23:18:10 +10:00
コミット 2bafd18a5a
57個のファイルの変更592行の追加566行の削除

ファイルの表示

@ -1,6 +1,6 @@
include nall/Makefile
snes := snes
profile := accuracy
profile := performance
ui := qt
# compiler

ファイルの表示

@ -20,14 +20,14 @@ else ifeq ($(profile),compatibility)
flags += -DPROFILE_COMPATIBILITY
snescpu := $(snes)/cpu
snessmp := $(snes)/smp
snesdsp := $(snes)/alternative/dsp
snesppu := $(snes)/alternative/ppu
snesdsp := $(snes)/alt/dsp
snesppu := $(snes)/alt/ppu
else ifeq ($(profile),performance)
flags += -DPROFILE_PERFORMANCE
snescpu := $(snes)/alternative/cpu
snescpu := $(snes)/alt/cpu
snessmp := $(snes)/smp
snesdsp := $(snes)/alternative/dsp
snesppu := $(snes)/alternative/ppu-fast
snesdsp := $(snes)/alt/dsp
snesppu := $(snes)/alt/ppu-new
endif
obj/libco.o : libco/libco.c libco/*

313
bsnes/snes/alt/ppu-new/mmio/mmio.cpp 実行可能ファイル
ファイルの表示

@ -0,0 +1,313 @@
#ifdef PPU_CPP
void PPU::latch_counters() {}
bool PPU::interlace() const { return false; }
bool PPU::overscan() const { return false; }
bool PPU::hires() const { return false; }
uint16 PPU::get_vram_addr() {
uint16 addr = regs.vram_addr;
switch(regs.vram_mapping) {
case 0: break;
case 1: addr = (addr & 0xff00) | ((addr & 0x001f) << 3) | ((addr >> 5) & 7); break;
case 2: addr = (addr & 0xfe00) | ((addr & 0x003f) << 3) | ((addr >> 6) & 7); break;
case 3: addr = (addr & 0xfc00) | ((addr & 0x007f) << 3) | ((addr >> 7) & 7); break;
}
return (addr << 1);
}
uint8 PPU::vram_read(unsigned addr) {
if(regs.display_disable) return memory::vram[addr];
if(cpu.vcounter() >= display.height) return memory::vram[addr];
return 0x00;
}
void PPU::vram_write(unsigned addr, uint8 data) {
if(regs.display_disable) { memory::vram[addr] = data; return; }
if(cpu.vcounter() >= display.height) { memory::vram[addr] = data; return; }
}
uint8 PPU::oam_read(unsigned addr) {
if(addr & 0x0200) addr &= 0x021f;
if(regs.display_disable) return memory::oam[addr];
if(cpu.vcounter() >= display.height) return memory::oam[addr];
return memory::oam[0x0218];
}
void PPU::oam_write(unsigned addr, uint8 data) {
if(addr & 0x0200) addr &= 0x021f;
if(regs.display_disable) { memory::oam[addr] = data; return; }
if(cpu.vcounter() >= display.height) { memory::oam[addr] = data; return; }
memory::oam[0x0218] = data;
}
uint8 PPU::cgram_read(unsigned addr) {
return memory::cgram[addr];
}
void PPU::cgram_write(unsigned addr, uint8 data) {
memory::cgram[addr] = data;
}
uint8 PPU::mmio_read(unsigned addr) {
cpu.synchronize_ppu();
switch(addr & 0xffff) {
case 0x2104: case 0x2105: case 0x2106: case 0x2108: case 0x2109: case 0x210a:
case 0x2114: case 0x2115: case 0x2116: case 0x2118: case 0x2119: case 0x211a:
case 0x2124: case 0x2125: case 0x2126: case 0x2128: case 0x2129: case 0x212a: {
return regs.ppu1_mdr;
}
case 0x2134: { //MPYL
unsigned result = ((int16)regs.m7a * (int8)(regs.m7b >> 8));
regs.ppu1_mdr = result >> 0;
return regs.ppu1_mdr;
}
case 0x2135: { //MPYM
unsigned result = ((int16)regs.m7a * (int8)(regs.m7b >> 8));
regs.ppu1_mdr = result >> 8;
return regs.ppu1_mdr;
}
case 0x2136: { //MPYH
unsigned result = ((int16)regs.m7a * (int8)(regs.m7b >> 8));
regs.ppu1_mdr = result >> 16;
return regs.ppu1_mdr;
}
case 0x2137: { //SLHV
if(cpu.pio() & 0x80) latch_counters();
return cpu.regs.mdr;
}
case 0x2138: { //OAMDATAREAD
regs.ppu1_mdr = oam_read(regs.oam_addr);
regs.oam_addr = (regs.oam_addr + 1) & 0x03ff;
//TODO: handle OAM address reset here
return regs.ppu1_mdr;
}
case 0x2139: { //VMDATALREAD
regs.ppu1_mdr = regs.vram_readbuffer >> 0;
if(regs.vram_incmode == 0) {
uint16 addr = get_vram_addr();
regs.vram_readbuffer = vram_read(addr + 0) << 0;
regs.vram_readbuffer |= vram_read(addr + 1) << 8;
regs.vram_addr += regs.vram_incsize;
}
return regs.ppu1_mdr;
}
case 0x213a: { //VMDATAHREAD
regs.ppu1_mdr = regs.vram_readbuffer >> 8;
if(regs.vram_incmode == 1) {
uint16 addr = get_vram_addr();
regs.vram_readbuffer = vram_read(addr + 0) << 0;
regs.vram_readbuffer |= vram_read(addr + 1) << 8;
regs.vram_addr += regs.vram_incsize;
}
return regs.ppu1_mdr;
}
case 0x213b: { //CGDATAREAD
if((regs.cgram_addr & 1) == 0) {
regs.ppu2_mdr = cgram_read(regs.cgram_addr);
} else {
regs.ppu2_mdr = (regs.ppu2_mdr & 0x80) | (cgram_read(regs.cgram_addr) & 0x7f);
}
regs.cgram_addr = (regs.cgram_addr + 1) & 0x01ff;
return regs.ppu2_mdr;
}
}
return cpu.regs.mdr;
}
void PPU::mmio_write(unsigned addr, uint8 data) {
cpu.synchronize_ppu();
switch(addr & 0xffff) {
case 0x2100: { //INIDISP
//TODO: handle OAM address reset here
regs.display_disable = data & 0x80;
regs.display_brightness = data & 0x0f;
screen.light_table = screen.light_tables[regs.display_brightness];
return;
}
case 0x2102: { //OAMADDL
regs.oam_baseaddr = (regs.oam_baseaddr & 0x0100) | (data << 0);
//TODO: handle OAM address reset here
return;
}
case 0x2103: { //OAMADDH
regs.oam_priority = data & 0x80;
regs.oam_baseaddr = ((data & 1) << 8) | (regs.oam_baseaddr & 0x00ff);
//TODO: handle OAM address reset here
return;
}
case 0x2104: { //OAMDATA
if(regs.oam_addr & 0x0200) {
oam_write(regs.oam_addr, data);
} else if((regs.oam_addr & 1) == 0) {
regs.oam_latchdata = data;
} else {
oam_write((regs.oam_addr & ~1) + 0, regs.oam_latchdata);
oam_write((regs.oam_addr & ~1) + 1, data);
}
regs.oam_addr = (regs.oam_addr + 1) & 0x03ff;
//TODO: handle OAM address reset here
return;
}
case 0x2115: { //VMAIN
regs.vram_incmode = data & 0x80;
regs.vram_mapping = (data >> 2) & 3;
switch(data & 3) {
case 0: regs.vram_incsize = 1; break;
case 1: regs.vram_incsize = 32; break;
case 2: regs.vram_incsize = 128; break;
case 3: regs.vram_incsize = 128; break;
}
return;
}
case 0x2116: { //VMADDL
regs.vram_addr = (regs.vram_addr & 0xff00) | (data << 0);
uint16 addr = get_vram_addr();
regs.vram_readbuffer = vram_read(addr + 0) << 0;
regs.vram_readbuffer |= vram_read(addr + 1) << 8;
return;
}
case 0x2117: { //VMADDH
regs.vram_addr = (data << 8) | (regs.vram_addr & 0x00ff);
uint16 addr = get_vram_addr();
regs.vram_readbuffer = vram_read(addr + 0) << 0;
regs.vram_readbuffer |= vram_read(addr + 1) << 8;
return;
}
case 0x2118: { //VMDATAL
vram_write(get_vram_addr() + 0, data);
if(regs.vram_incmode == 0) regs.vram_addr += regs.vram_incsize;
return;
}
case 0x2119: { //VMDATAH
vram_write(get_vram_addr() + 1, data);
if(regs.vram_incmode == 1) regs.vram_addr += regs.vram_incsize;
return;
}
case 0x211a: { //M7SEL
regs.mode7_repeat = (data >> 6) & 3;
regs.mode7_vflip = data & 0x02;
regs.mode7_hflip = data & 0x01;
return;
}
case 0x211b: { //M7A
regs.m7a = (data << 8) | regs.mode7_latchdata;
regs.mode7_latchdata = data;
return;
}
case 0x211c: { //M7B
regs.m7b = (data << 8) | regs.mode7_latchdata;
regs.mode7_latchdata = data;
return;
}
case 0x211d: { //M7C
regs.m7c = (data << 8) | regs.mode7_latchdata;
regs.mode7_latchdata = data;
return;
}
case 0x211e: { //M7D
regs.m7d = (data << 8) | regs.mode7_latchdata;
regs.mode7_latchdata = data;
return;
}
case 0x211f: { //M7X
regs.m7x = (data << 8) | regs.mode7_latchdata;
regs.mode7_latchdata = data;
return;
}
case 0x2120: { //M7Y
regs.m7y = (data << 8) | regs.mode7_latchdata;
regs.mode7_latchdata = data;
return;
}
case 0x2121: { //CGADD
regs.cgram_addr = data << 1;
return;
}
case 0x2122: { //CGDATA
if((regs.cgram_addr & 1) == 0) {
regs.cgram_latchdata = data;
} else {
cgram_write((regs.cgram_addr & ~1) + 0, regs.cgram_latchdata);
cgram_write((regs.cgram_addr & ~1) + 1, data);
}
regs.cgram_addr = (regs.cgram_addr + 1) & 0x01ff;
return;
}
}
}
void PPU::mmio_reset() {
//internal
regs.ppu1_mdr = 0;
regs.ppu2_mdr = 0;
regs.vram_readbuffer = 0;
regs.oam_latchdata = 0;
regs.cgram_latchdata = 0;
regs.mode7_latchdata = 0;
//$2100
regs.display_disable = true;
regs.display_brightness = 0;
screen.light_table = screen.light_tables[regs.display_brightness];
//$2102-$2103
regs.oam_baseaddr = 0;
regs.oam_addr = 0;
regs.oam_priority = 0;
//$2115
regs.vram_incmode = 0;
regs.vram_mapping = 0;
regs.vram_incsize = 1;
//$2116-$2117
regs.vram_addr = 0;
//$211a
regs.mode7_repeat = 0;
regs.mode7_vflip = 0;
regs.mode7_hflip = 0;
//$211b-$2120
regs.m7a = 0;
regs.m7b = 0;
regs.m7c = 0;
regs.m7d = 0;
regs.m7x = 0;
regs.m7y = 0;
//$2121
regs.cgram_addr = 0;
}
#endif

57
bsnes/snes/alt/ppu-new/mmio/mmio.hpp 実行可能ファイル
ファイルの表示

@ -0,0 +1,57 @@
struct Regs {
//internal
uint8 ppu1_mdr;
uint8 ppu2_mdr;
uint16 vram_readbuffer;
uint8 oam_latchdata;
uint8 cgram_latchdata;
uint8 mode7_latchdata;
//$2100
bool display_disable;
unsigned display_brightness;
//$2102-$2103
uint16 oam_baseaddr;
uint16 oam_addr;
bool oam_priority;
//$2115
bool vram_incmode;
unsigned vram_mapping;
unsigned vram_incsize;
//$2116-$2117
uint16 vram_addr;
//$211a
unsigned mode7_repeat;
bool mode7_vflip;
bool mode7_hflip;
//$211b-$2120
uint16 m7a;
uint16 m7b;
uint16 m7c;
uint16 m7d;
uint16 m7x;
uint16 m7y;
//$2121
uint16 cgram_addr;
} regs;
uint16 get_vram_addr();
uint8 vram_read(unsigned addr);
void vram_write(unsigned addr, uint8 data);
uint8 oam_read(unsigned addr);
void oam_write(unsigned addr, uint8 data);
uint8 cgram_read(unsigned addr);
void cgram_write(unsigned addr, uint8 data);
uint8 mmio_read(unsigned addr);
void mmio_write(unsigned addr, uint8 data);
void mmio_reset();

89
bsnes/snes/alt/ppu-new/ppu.cpp 実行可能ファイル
ファイルの表示

@ -0,0 +1,89 @@
#include <snes.hpp>
#define PPU_CPP
namespace SNES {
PPU ppu;
#include "mmio/mmio.cpp"
#include "screen/screen.cpp"
#include "serialization.cpp"
void PPU::step(unsigned clocks) {
clock += clocks;
}
void PPU::synchronize_cpu() {
if(CPU::Threaded == true) {
if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread);
} else {
while(clock >= 0) cpu.enter();
}
}
void PPU::Enter() { ppu.enter(); }
void PPU::enter() {
while(true) {
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
}
scanline();
if(vcounter() < display.height) {
add_clocks(512);
render_scanline();
add_clocks(lineclocks() - 512);
} else {
add_clocks(lineclocks());
}
}
}
void PPU::add_clocks(unsigned clocks) {
tick(clocks);
step(clocks);
synchronize_cpu();
}
void PPU::render_scanline() {
if(regs.display_disable) return screen.render_black();
screen.render();
}
void PPU::scanline() {
if(vcounter() == 0) frame();
display.width = !hires() ? 256 : 512;
display.height = !overscan() ? 225 : 240;
}
void PPU::frame() {
system.frame();
}
void PPU::power() {
foreach(n, memory::vram) n = 0;
foreach(n, memory::oam) n = 0;
foreach(n, memory::cgram) n = 0;
reset();
}
void PPU::reset() {
create(Enter, system.cpu_frequency());
PPUcounter::reset();
memset(surface, 0, 512 * 512 * sizeof(uint16));
mmio_reset();
}
PPU::PPU() : screen(*this) {
surface = new uint16[512 * 512];
output = surface + 16 * 512;
}
PPU::~PPU() {
delete[] surface;
}
}

44
bsnes/snes/alt/ppu-new/ppu.hpp 実行可能ファイル
ファイルの表示

@ -0,0 +1,44 @@
class PPU : public Processor, public PPUcounter, public MMIO {
public:
enum : bool { Threaded = true };
alwaysinline void step(unsigned clocks);
alwaysinline void synchronize_cpu();
void latch_counters();
bool interlace() const;
bool overscan() const;
bool hires() const;
void enter();
void power();
void reset();
void scanline();
void frame();
void serialize(serializer&);
PPU();
~PPU();
private:
uint16 *surface;
uint16 *output;
#include "mmio/mmio.hpp"
#include "screen/screen.hpp"
Screen screen;
struct Display {
unsigned width;
unsigned height;
} display;
static void Enter();
void add_clocks(unsigned clocks);
void render_scanline();
friend class PPU::Screen;
friend class Video;
};
extern PPU ppu;

41
bsnes/snes/alt/ppu-new/screen/screen.cpp 実行可能ファイル
ファイルの表示

@ -0,0 +1,41 @@
#ifdef PPU_CPP
void PPU::Screen::render_black() {
uint16 *data = self.output + self.vcounter() * 1024;
memset(data, 0, self.display.width << 1);
}
void PPU::Screen::render() {
uint16 *data = self.output + self.vcounter() * 1024;
uint16 color = memory::cgram[0];
color |= memory::cgram[1] << 8;
color = light_table[color];
for(unsigned i = 0; i < 256; i++) {
data[i] = color;
}
}
PPU::Screen::Screen(PPU &self) : self(self) {
light_tables = new uint16*[16];
for(unsigned l = 0; l < 16; l++) {
light_tables[l] = new uint16[32768];
for(unsigned r = 0; r < 32; r++) {
for(unsigned g = 0; g < 32; g++) {
for(unsigned b = 0; b < 32; b++) {
double luma = (double)l / 15.0;
unsigned ar = (luma * r + 0.5);
unsigned ag = (luma * g + 0.5);
unsigned ab = (luma * b + 0.5);
light_tables[l][(r << 10) + (g << 5) + (b << 0)] = (ab << 10) + (ag << 5) + (ar << 0);
}
}
}
}
}
PPU::Screen::~Screen() {
for(unsigned l = 0; l < 16; l++) delete[] light_tables[l];
delete[] light_tables;
}
#endif

17
bsnes/snes/alt/ppu-new/screen/screen.hpp 実行可能ファイル
ファイルの表示

@ -0,0 +1,17 @@
class Screen {
public:
void render_black();
void render();
Screen(PPU &self);
~Screen();
private:
PPU &self;
uint16 **light_tables;
uint16 *light_table;
struct Regs {
} regs;
friend class PPU;
};

19
bsnes/snes/alt/ppu-new/serialization.cpp 実行可能ファイル
ファイルの表示

@ -0,0 +1,19 @@
#ifdef PPU_CPP
void PPUcounter::serialize(serializer &s) {
s.integer(status.interlace);
s.integer(status.field);
s.integer(status.vcounter);
s.integer(status.hcounter);
s.array(history.field);
s.array(history.vcounter);
s.array(history.hcounter);
s.integer(history.index);
}
void PPU::serialize(serializer &s) {
PPUcounter::serialize(s);
}
#endif

ファイルの表示

@ -1,3 +0,0 @@
#ifdef PPU_CPP
#endif

ファイルの表示

@ -1,7 +0,0 @@
#ifdef PPU_CPP
bool PPUDebugger::property(unsigned id, string &name, string &value) {
return false;
}
#endif

ファイルの表示

@ -1,10 +0,0 @@
class PPUDebugger : public PPU, public ChipDebugger {
public:
bool property(unsigned id, string &name, string &value);
bool bg1_enabled[2];
bool bg2_enabled[2];
bool bg3_enabled[2];
bool bg4_enabled[2];
bool oam_enabled[4];
};

ファイルの表示

@ -1,48 +0,0 @@
#ifdef PPU_CPP
void PPU::latch_counters() {
}
uint16 PPU::get_vram_addr() {
uint16 addr = regs.vram_addr;
switch(regs.vram_mapping) {
case 0: break;
case 1: addr = (addr & 0xff00) | ((addr & 0x001f) << 3) | ((addr >> 5) & 7); break;
case 2: addr = (addr & 0xfe00) | ((addr & 0x003f) << 3) | ((addr >> 6) & 7); break;
case 3: addr = (addr & 0xfc00) | ((addr & 0x007f) << 3) | ((addr >> 7) & 7); break;
}
return (addr << 1);
}
uint8 PPU::vram_read(unsigned addr) {
if(regs.display_disabled == true) return memory::vram[addr];
if(cpu.vcounter() >= regs.height) return memory::vram[addr];
return 0x00;
}
void PPU::vram_write(unsigned addr, uint8 data) {
if(regs.display_disabled == true) { memory::vram[addr] = data; return; }
if(cpu.vcounter() >= regs.height) { memory::vram[addr] = data; return; }
}
uint8 PPU::oam_read(unsigned addr) {
if(regs.display_disabled == true) return memory::oam[addr];
if(cpu.vcounter() >= regs.height) return memory::oam[addr];
return memory::oam[0x0218];
}
void PPU::oam_write(unsigned addr, uint8 data) {
if(regs.display_disabled == true) { memory::oam[addr] = data; return; }
if(cpu.vcounter() >= regs.height) { memory::oam[addr] = data; return; }
memory::oam[0x0218] = data;
}
uint8 PPU::cgram_read(unsigned addr) {
return memory::cgram[addr];
}
void PPU::cgram_write(unsigned addr, uint8 data) {
memory::cgram[addr] = data;
}
#endif

ファイルの表示

@ -1,227 +0,0 @@
#ifdef PPU_CPP
uint8 PPU::mmio_read(unsigned addr) {
switch(addr & 0xffff) {
}
return 0x00;
}
void PPU::mmio_write(unsigned addr, uint8 data) {
switch(addr & 0xffff) {
case 0x2100: {
regs.display_disabled = data & 0x80;
regs.display_brightness = data & 0x0f;
return;
}
case 0x2101: {
regs.oam_basesize = (data >> 5) & 7;
regs.oam_nameselect = (data >> 3) & 3;
regs.oam_tdaddr = (data & 3) << 14;
return;
}
case 0x2102: {
regs.oam_baseaddr = (regs.oam_baseaddr & 0xff00) | (data << 0);
regs.oam_baseaddr &= 0x01ff;
regs.oam_addr = regs.oam_baseaddr << 1;
regs.oam_firstsprite = (regs.oam_priority == false ? 0 : (regs.oam_addr >> 2) & 127);
return;
}
case 0x2103: {
regs.oam_priority = data & 0x80;
regs.oam_baseaddr = (data << 8) | (regs.oam_baseaddr & 0x00ff);
regs.oam_baseaddr &= 0x01ff;
regs.oam_addr = regs.oam_baseaddr << 1;
regs.oam_firstsprite = (regs.oam_priority == false ? 0 : (regs.oam_addr >> 2) & 127);
return;
}
case 0x2104: {
if(regs.oam_addr & 0x0200) {
oam_write(regs.oam_addr, data);
} else if((regs.oam_addr & 1) == 0) {
regs.oam_latchdata = data;
} else {
oam_write((regs.oam_addr & ~1) + 0, regs.oam_latchdata);
oam_write((regs.oam_addr & ~1) + 1, data);
}
regs.oam_addr = (regs.oam_addr + 1) & 0x03ff;
regs.oam_firstsprite = (regs.oam_priority == false ? 0 : (regs.oam_addr >> 2) & 127);
return;
}
case 0x2105: {
regs.bg_tilesize[BG4] = data & 0x80;
regs.bg_tilesize[BG3] = data & 0x40;
regs.bg_tilesize[BG2] = data & 0x20;
regs.bg_tilesize[BG1] = data & 0x10;
regs.bg3_priority = data & 0x08;
regs.bg_mode = data & 0x07;
return;
}
case 0x2106: {
regs.mosaic_size = (data >> 4) & 15;
regs.mosaic_enabled[BG4] = data & 0x08;
regs.mosaic_enabled[BG3] = data & 0x04;
regs.mosaic_enabled[BG2] = data & 0x02;
regs.mosaic_enabled[BG1] = data & 0x01;
return;
}
case 0x2107: {
regs.bg_scaddr[BG1] = (data & 0x7c) << 9;
regs.bg_scsize[BG1] = (data & 0x03);
return;
}
case 0x2108: {
regs.bg_scaddr[BG2] = (data & 0x7c) << 9;
regs.bg_scsize[BG2] = (data & 0x03);
return;
}
case 0x2109: {
regs.bg_scaddr[BG3] = (data & 0x7c) << 9;
regs.bg_scsize[BG3] = (data & 0x03);
return;
}
case 0x210a: {
regs.bg_scaddr[BG4] = (data & 0x7c) << 9;
regs.bg_scsize[BG4] = (data & 0x03);
return;
}
case 0x210b: {
regs.bg_tdaddr[BG1] = (data & 0x07) << 13;
regs.bg_tdaddr[BG2] = (data & 0x70) << 9;
return;
}
case 0x210c: {
regs.bg_tdaddr[BG3] = (data & 0x07) << 13;
regs.bg_tdaddr[BG4] = (data & 0x70) << 9;
return;
}
case 0x2115: {
regs.vram_incmode = data & 0x80;
regs.vram_mapping = (data >> 2) & 3;
switch(data & 3) {
case 0: regs.vram_incsize = 1; break;
case 1: regs.vram_incsize = 32; break;
case 2: regs.vram_incsize = 128; break;
case 3: regs.vram_incsize = 128; break;
}
return;
}
case 0x2116: {
regs.vram_addr = (regs.vram_addr & 0xff00) | (data << 0);
uint16 addr = get_vram_addr();
regs.vram_readbuffer = vram_read(addr + 0) << 0;
regs.vram_readbuffer |= vram_read(addr + 1) << 8;
return;
}
case 0x2117: {
regs.vram_addr = (data << 8) | (regs.vram_addr & 0x00ff);
uint16 addr = get_vram_addr();
regs.vram_readbuffer = vram_read(addr + 0) << 0;
regs.vram_readbuffer |= vram_read(addr + 1) << 8;
return;
}
case 0x2118: {
uint16 addr = get_vram_addr() + 0;
vram_write(addr, data);
if(regs.vram_incmode == 0) regs.vram_addr += regs.vram_incsize;
return;
}
case 0x2119: {
uint16 addr = get_vram_addr() + 1;
vram_write(addr, data);
if(regs.vram_incmode == 1) regs.vram_addr += regs.vram_incsize;
return;
}
case 0x2121: {
regs.cgram_addr = data << 1;
return;
}
case 0x2122: {
if((regs.cgram_addr & 1) == 0) {
regs.cgram_latchdata = data;
} else {
cgram_write((regs.cgram_addr & ~1) + 0, regs.cgram_latchdata);
cgram_write((regs.cgram_addr & ~1) + 1, data & 0x7f);
}
regs.cgram_addr = (regs.cgram_addr + 1) & 0x01ff;
return;
}
}
}
void PPU::mmio_reset() {
//internal
regs.width = 256;
regs.height = 225;
//$2100
regs.display_disabled = true;
regs.display_brightness = 0;
//$2101
regs.oam_basesize = 0;
regs.oam_nameselect = 0;
regs.oam_tdaddr = 0;
//$2102-$2103
regs.oam_baseaddr = 0;
regs.oam_addr = 0;
regs.oam_priority = 0;
regs.oam_firstsprite = 0;
//$2104
regs.oam_latchdata = 0;
//$2105
for(unsigned i = 0; i < 4; i++) regs.bg_tilesize[i] = 0;
regs.bg3_priority = 0;
regs.bg_mode = 0;
//$2106
regs.mosaic_size = 0;
for(unsigned i = 0; i < 4; i++) regs.mosaic_enabled[i] = 0;
//$2107-$210a
for(unsigned i = 0; i < 4; i++) regs.bg_scaddr[i] = 0;
for(unsigned i = 0; i < 4; i++) regs.bg_scsize[i] = 0;
//$210b-$210c
for(unsigned i = 0; i < 4; i++) regs.bg_tdaddr[i] = 0;
//$2115
regs.vram_incmode = 0;
regs.vram_mapping = 0;
regs.vram_incsize = 0;
//$2116-$2117
regs.vram_addr = 0;
//$2121
regs.cgram_addr = 0;
//$2122
regs.cgram_latchdata = 0;
//$2139-$213a
regs.vram_readbuffer = 0;
}
#endif

ファイルの表示

@ -1,124 +0,0 @@
#include <snes.hpp>
#define PPU_CPP
namespace SNES {
#if defined(DEBUGGER)
#include "debugger/debugger.cpp"
PPUDebugger ppu;
#else
PPU ppu;
#endif
#include "background.cpp"
#include "memory.cpp"
#include "mmio.cpp"
#include "screen.cpp"
void PPU::step(unsigned clocks) {
clock += clocks;
}
void PPU::synchronize_cpu() {
if(CPU::Threaded == true) {
if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread);
} else {
while(clock >= 0) cpu.enter();
}
}
void PPU::Enter() { ppu.enter(); }
void PPU::enter() {
while(true) {
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
}
scanline();
add_clocks(512);
if(vcounter() < regs.height) render_scanline();
add_clocks(lineclocks() - 512);
}
}
void PPU::add_clocks(unsigned clocks) {
tick(clocks);
step(clocks);
synchronize_cpu();
}
void PPU::scanline() {
if(vcounter() == 0) frame();
regs.width = !hires() ? 256 : 512;
regs.height = !overscan() ? 225 : 240;
}
void PPU::frame() {
system.frame();
}
void PPU::render_scanline() {
screen_render();
}
void PPU::power() {
for(unsigned i = 0; i < memory::vram.size(); i++) memory::vram[i] = 0x00;
for(unsigned i = 0; i < memory::oam.size(); i++) memory::oam[i] = 0x00;
for(unsigned i = 0; i < memory::cgram.size(); i++) memory::cgram[i] = 0x00;
reset();
}
void PPU::reset() {
create(Enter, system.cpu_frequency());
PPUcounter::reset();
memset(surface, 0, 512 * 512 * sizeof(uint16));
mmio_reset();
}
PPU::PPU() {
surface = new uint16[512 * 512];
output = surface + 16 * 512;
light_table = new uint16*[16];
for(unsigned l = 0; l < 16; l++) {
light_table[l] = new uint16[32768];
for(unsigned r = 0; r < 32; r++) {
for(unsigned g = 0; g < 32; g++) {
for(unsigned b = 0; b < 32; b++) {
double luma = (double)l / 15.0;
unsigned ar = (luma * r + 0.5);
unsigned ag = (luma * g + 0.5);
unsigned ab = (luma * b + 0.5);
light_table[l][(r << 10) + (g << 5) + (b << 0)] = (ab << 10) + (ag << 5) + (ar << 0);
}
}
}
}
}
PPU::~PPU() {
delete[] surface;
}
bool PPU::interlace() const { return false; }
bool PPU::overscan() const { return false; }
bool PPU::hires() const { return false; }
void PPUcounter::serialize(serializer &s) {
s.integer(status.interlace);
s.integer(status.field);
s.integer(status.vcounter);
s.integer(status.hcounter);
s.array(history.field);
s.array(history.vcounter);
s.array(history.hcounter);
s.integer(history.index);
}
void PPU::serialize(serializer &s) {
}
}

ファイルの表示

@ -1,118 +0,0 @@
class PPU : public Processor, public PPUcounter, public MMIO {
public:
enum : bool { Threaded = true };
alwaysinline void step(unsigned clocks);
alwaysinline void synchronize_cpu();
void latch_counters();
bool interlace() const;
bool overscan() const;
bool hires() const;
uint8 mmio_read(unsigned addr);
void mmio_write(unsigned addr, uint8 data);
void enter();
void power();
void reset();
void serialize(serializer&);
PPU();
~PPU();
private:
enum : unsigned { BG1 = 0, BG2 = 1, BG3 = 2, BG4 = 3, OAM = 4, COL = 5, BACK = 5 };
uint16 *surface;
uint16 *output;
//background.cpp
//memory.cpp
uint16 get_vram_addr();
uint8 vram_read(unsigned addr);
void vram_write(unsigned addr, uint8 data);
uint8 oam_read(unsigned addr);
void oam_write(unsigned addr, uint8 data);
uint8 cgram_read(unsigned addr);
void cgram_write(unsigned addr, uint8 data);
//mmio.cpp
struct Regs {
//internal
unsigned width;
unsigned height;
//$2100
bool display_disabled;
unsigned display_brightness;
//$2101
unsigned oam_basesize;
unsigned oam_nameselect;
uint16 oam_tdaddr;
//$2102-$2103
uint16 oam_baseaddr;
uint16 oam_addr;
bool oam_priority;
unsigned oam_firstsprite;
//$2104
uint8 oam_latchdata;
//$2105
bool bg_tilesize[4];
bool bg3_priority;
unsigned bg_mode;
//$2106
unsigned mosaic_size;
bool mosaic_enabled[4];
//$2107-$210a
uint16 bg_scaddr[4];
unsigned bg_scsize[4];
//$210b-$210c
uint16 bg_tdaddr[4];
//$2115
bool vram_incmode;
unsigned vram_mapping;
unsigned vram_incsize;
//$2116-$2117
uint16 vram_addr;
//$2121
uint16 cgram_addr;
//$2122
uint8 cgram_latchdata;
//$2139-$213a
uint16 vram_readbuffer;
} regs;
void mmio_reset();
//ppu.cpp
static void Enter();
void add_clocks(unsigned clocks);
void scanline();
void frame();
void render_scanline();
//screen.cpp
uint16 **light_table;
void screen_render();
friend class Video;
};
#if defined(DEBUGGER)
#include "debugger/debugger.hpp"
extern PPUDebugger ppu;
#else
extern PPU ppu;
#endif

ファイルの表示

@ -1,17 +0,0 @@
#ifdef PPU_CPP
void PPU::screen_render() {
uint16 *data = output + vcounter() * 1024;
if(regs.display_disabled) {
memset(data, 0x00, regs.width << 1);
return;
}
uint16 *table = light_table[regs.display_brightness];
uint16 color = memory::cgram[0];
color |= memory::cgram[1] << 8;
color = table[color];
for(unsigned i = 0; i < 256; i++) data[i] = color;
}
#endif

ファイルの表示

@ -4,5 +4,5 @@ namespace Info {
#include <cpu/cpu.hpp>
#include <smp/smp.hpp>
#include <alternative/dsp/dsp.hpp>
#include <alternative/ppu/ppu.hpp>
#include <alt/dsp/dsp.hpp>
#include <alt/ppu/ppu.hpp>

ファイルの表示

@ -2,7 +2,7 @@ namespace Info {
static const char Profile[] = "Performance";
}
#include <alternative/cpu/cpu.hpp>
#include <alt/cpu/cpu.hpp>
#include <smp/smp.hpp>
#include <alternative/dsp/dsp.hpp>
#include <alternative/ppu-fast/ppu.hpp>
#include <alt/dsp/dsp.hpp>
#include <alt/ppu-new/ppu.hpp>

ファイルの表示

@ -1,7 +1,7 @@
namespace SNES {
namespace Info {
static const char Name[] = "bsnes";
static const char Version[] = "068.04";
static const char Version[] = "068.05";
static const unsigned SerializerVersion = 13;
}
}