Path: blob/master/libsnes/bsnes/snes/alt/ppu-compatibility/ppu.cpp
2 views
#include <snes/snes.hpp>12#define PPU_CPP3namespace SNES {45PPU ppu;67#include "memory/memory.cpp"8#include "mmio/mmio.cpp"9#include "render/render.cpp"10#include "serialization.cpp"1112void PPU::step(unsigned clocks) {13clock += clocks;14}1516void PPU::synchronize_cpu() {17if(CPU::Threaded == true) {18if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All)19co_switch(cpu.thread);20else if(clock >= 0 && scheduler.sync == Scheduler::SynchronizeMode::All)21interface()->message("PPU had to advance nondeterministically!");22} else {23while(clock >= 0) cpu.enter();24}25}2627void PPU::Enter() { ppu.enter(); }2829void PPU::enter() {30while(true) {31if(scheduler.sync == Scheduler::SynchronizeMode::CPU) {32synchronize_cpu(); // when in CPU sync mode, always switch back to CPU as soon as possible33}34if(scheduler.sync == Scheduler::SynchronizeMode::All) {35scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);36}3738switch(uindex)39{40case 0: enter1(); break;41case 1: enter2(); break;42case 2: enter3(); break;43case 3: enter4(); break;44}45uindex++;46uindex &= 3;47}48}4950void PPU::enter1() {51//H = 0 (initialize)52scanline();53add_clocks(10);54}5556void PPU::enter2() {57//H = 10 (cache mode7 registers + OAM address reset)58cache.m7_hofs = regs.m7_hofs;59cache.m7_vofs = regs.m7_vofs;60cache.m7a = regs.m7a;61cache.m7b = regs.m7b;62cache.m7c = regs.m7c;63cache.m7d = regs.m7d;64cache.m7x = regs.m7x;65cache.m7y = regs.m7y;66if(vcounter() == (!overscan() ? 225 : 240)) {67if(regs.display_disabled == false) {68regs.oam_addr = regs.oam_baseaddr << 1;69regs.oam_firstsprite = (regs.oam_priority == false) ? 0 : (regs.oam_addr >> 2) & 127;70}71}72add_clocks(502);73}7475void PPU::enter3() {76//H = 512 (render)77render_scanline();78add_clocks(640);79}8081void PPU::enter4() {82//H = 1152 (cache OBSEL)83if(cache.oam_basesize != regs.oam_basesize) {84cache.oam_basesize = regs.oam_basesize;85sprite_list_valid = false;86}87cache.oam_nameselect = regs.oam_nameselect;88cache.oam_tdaddr = regs.oam_tdaddr;89add_clocks(lineclocks() - 1152); //seek to start of next scanline90}9192void PPU::add_clocks(unsigned clocks) {93tick(clocks);94step(clocks);95synchronize_cpu();96}9798void PPU::scanline() {99line = vcounter();100101if(line == 0) {102frame();103104//RTO flag reset105regs.time_over = false;106regs.range_over = false;107}108109interface()->scanlineStart(line);110111if(line == 1) {112//mosaic reset113for(int bg = BG1; bg <= BG4; bg++) regs.bg_y[bg] = 1;114regs.mosaic_countdown = regs.mosaic_size + 1;115regs.mosaic_countdown--;116} else {117for(int bg = BG1; bg <= BG4; bg++) {118if(!regs.mosaic_enabled[bg] || !regs.mosaic_countdown) regs.bg_y[bg] = line;119}120if(!regs.mosaic_countdown) regs.mosaic_countdown = regs.mosaic_size + 1;121regs.mosaic_countdown--;122}123}124125void PPU::render_scanline() {126if(line >= 1 && line < (!overscan() ? 225 : 240)) {127if(framecounter) return;128render_line_oam_rto();129render_line();130}131}132133void PPU::frame() {134system.frame();135136if(field() == 0) {137display.interlace = regs.interlace;138regs.scanlines = (regs.overscan == false) ? 224 : 239;139}140141framecounter = (frameskip == 0 ? 0 : (framecounter + 1) % frameskip);142}143144void PPU::enable() {145function<uint8 (unsigned)> read = { &PPU::mmio_read, (PPU*)&ppu };146function<void (unsigned, uint8)> write = { &PPU::mmio_write, (PPU*)&ppu };147148bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2100, 0x213f, read, write);149bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2100, 0x213f, read, write);150}151152void PPU::power() {153ppu1_version = config.ppu1.version;154ppu2_version = config.ppu2.version;155156for(int i=0;i<128*1024;i++) vram[i] = 0;157for(int i=0;i<544;i++) oam[i] = 0;158for(int i=0;i<512;i++) cgram[i] = 0;159flush_tiledata_cache();160161region = (system.region() == System::Region::NTSC ? 0 : 1); //0 = NTSC, 1 = PAL162163regs.ioamaddr = 0x0000;164regs.icgramaddr = 0x01ff;165166//$2100167regs.display_disabled = true;168regs.display_brightness = 15;169170//$2101171regs.oam_basesize = 0;172regs.oam_nameselect = 0;173regs.oam_tdaddr = 0x0000;174175cache.oam_basesize = 0;176cache.oam_nameselect = 0;177cache.oam_tdaddr = 0x0000;178179//$2102-$2103180regs.oam_baseaddr = 0x0000;181regs.oam_addr = 0x0000;182regs.oam_priority = false;183regs.oam_firstsprite = 0;184185//$2104186regs.oam_latchdata = 0x00;187188//$2105189regs.bg_tilesize[BG1] = 0;190regs.bg_tilesize[BG2] = 0;191regs.bg_tilesize[BG3] = 0;192regs.bg_tilesize[BG4] = 0;193regs.bg3_priority = 0;194regs.bg_mode = 0;195196//$2106197regs.mosaic_size = 0;198regs.mosaic_enabled[BG1] = false;199regs.mosaic_enabled[BG2] = false;200regs.mosaic_enabled[BG3] = false;201regs.mosaic_enabled[BG4] = false;202regs.mosaic_countdown = 0;203204//$2107-$210a205regs.bg_scaddr[BG1] = 0x0000;206regs.bg_scaddr[BG2] = 0x0000;207regs.bg_scaddr[BG3] = 0x0000;208regs.bg_scaddr[BG4] = 0x0000;209regs.bg_scsize[BG1] = SC_32x32;210regs.bg_scsize[BG2] = SC_32x32;211regs.bg_scsize[BG3] = SC_32x32;212regs.bg_scsize[BG4] = SC_32x32;213214//$210b-$210c215regs.bg_tdaddr[BG1] = 0x0000;216regs.bg_tdaddr[BG2] = 0x0000;217regs.bg_tdaddr[BG3] = 0x0000;218regs.bg_tdaddr[BG4] = 0x0000;219220//$210d-$2114221regs.bg_ofslatch = 0x00;222regs.m7_hofs = regs.m7_vofs = 0x0000;223regs.bg_hofs[BG1] = regs.bg_vofs[BG1] = 0x0000;224regs.bg_hofs[BG2] = regs.bg_vofs[BG2] = 0x0000;225regs.bg_hofs[BG3] = regs.bg_vofs[BG3] = 0x0000;226regs.bg_hofs[BG4] = regs.bg_vofs[BG4] = 0x0000;227228//$2115229regs.vram_incmode = 1;230regs.vram_mapping = 0;231regs.vram_incsize = 1;232233//$2116-$2117234regs.vram_addr = 0x0000;235236//$211a237regs.mode7_repeat = 0;238regs.mode7_vflip = false;239regs.mode7_hflip = false;240241//$211b-$2120242regs.m7_latch = 0x00;243regs.m7a = 0x0000;244regs.m7b = 0x0000;245regs.m7c = 0x0000;246regs.m7d = 0x0000;247regs.m7x = 0x0000;248regs.m7y = 0x0000;249250//$2121251regs.cgram_addr = 0x0000;252253//$2122254regs.cgram_latchdata = 0x00;255256//$2123-$2125257regs.window1_enabled[BG1] = false;258regs.window1_enabled[BG2] = false;259regs.window1_enabled[BG3] = false;260regs.window1_enabled[BG4] = false;261regs.window1_enabled[OAM] = false;262regs.window1_enabled[COL] = false;263264regs.window1_invert [BG1] = false;265regs.window1_invert [BG2] = false;266regs.window1_invert [BG3] = false;267regs.window1_invert [BG4] = false;268regs.window1_invert [OAM] = false;269regs.window1_invert [COL] = false;270271regs.window2_enabled[BG1] = false;272regs.window2_enabled[BG2] = false;273regs.window2_enabled[BG3] = false;274regs.window2_enabled[BG4] = false;275regs.window2_enabled[OAM] = false;276regs.window2_enabled[COL] = false;277278regs.window2_invert [BG1] = false;279regs.window2_invert [BG2] = false;280regs.window2_invert [BG3] = false;281regs.window2_invert [BG4] = false;282regs.window2_invert [OAM] = false;283regs.window2_invert [COL] = false;284285//$2126-$2129286regs.window1_left = 0x00;287regs.window1_right = 0x00;288regs.window2_left = 0x00;289regs.window2_right = 0x00;290291//$212a-$212b292regs.window_mask[BG1] = 0;293regs.window_mask[BG2] = 0;294regs.window_mask[BG3] = 0;295regs.window_mask[BG4] = 0;296regs.window_mask[OAM] = 0;297regs.window_mask[COL] = 0;298299//$212c-$212d300regs.bg_enabled[BG1] = false;301regs.bg_enabled[BG2] = false;302regs.bg_enabled[BG3] = false;303regs.bg_enabled[BG4] = false;304regs.bg_enabled[OAM] = false;305regs.bgsub_enabled[BG1] = false;306regs.bgsub_enabled[BG2] = false;307regs.bgsub_enabled[BG3] = false;308regs.bgsub_enabled[BG4] = false;309regs.bgsub_enabled[OAM] = false;310311//$212e-$212f312regs.window_enabled[BG1] = false;313regs.window_enabled[BG2] = false;314regs.window_enabled[BG3] = false;315regs.window_enabled[BG4] = false;316regs.window_enabled[OAM] = false;317regs.sub_window_enabled[BG1] = false;318regs.sub_window_enabled[BG2] = false;319regs.sub_window_enabled[BG3] = false;320regs.sub_window_enabled[BG4] = false;321regs.sub_window_enabled[OAM] = false;322323//$2130324regs.color_mask = 0;325regs.colorsub_mask = 0;326regs.addsub_mode = false;327regs.direct_color = false;328329//$2131330regs.color_mode = 0;331regs.color_halve = false;332regs.color_enabled[BACK] = false;333regs.color_enabled[OAM] = false;334regs.color_enabled[BG4] = false;335regs.color_enabled[BG3] = false;336regs.color_enabled[BG2] = false;337regs.color_enabled[BG1] = false;338339//$2132340regs.color_r = 0x00;341regs.color_g = 0x00;342regs.color_b = 0x00;343regs.color_rgb = 0x0000;344345//$2133346regs.mode7_extbg = false;347regs.pseudo_hires = false;348regs.overscan = false;349regs.scanlines = 224;350regs.oam_interlace = false;351regs.interlace = false;352353//$2137354regs.hcounter = 0;355regs.vcounter = 0;356regs.latch_hcounter = 0;357regs.latch_vcounter = 0;358regs.counters_latched = false;359360//$2139-$213a361regs.vram_readbuffer = 0x0000;362363//$213e364regs.time_over = false;365regs.range_over = false;366367reset();368}369370void PPU::reset() {371create(Enter, system.cpu_frequency());372PPUcounter::reset();373memset(surface, 0, 512 * 512 * sizeof(uint32));374375uindex = 0;376377//zero 01-dec-2012 - gotta reset these sometime, somewhere378memset(oam_itemlist, 0, sizeof(oam_itemlist));379memset(oam_tilelist, 0, sizeof(oam_tilelist));380memset(oam_line_pal, 0, sizeof(oam_line_pal));381memset(oam_line_pri, 0, sizeof(oam_line_pri));382active_sprite = sprite_list_valid = 0;383memset(bg_info, 0, sizeof(bg_info));384memset(window, 0, sizeof(window));385memset(pixel_cache, 0, sizeof(pixel_cache));386regs.oam_tilecount = regs.oam_itemcount = 0;387388frame();389390//$2100391regs.display_disabled = true;392393display.interlace = false;394display.overscan = false;395regs.scanlines = 224;396397memset(sprite_list, 0, sizeof(sprite_list));398sprite_list_valid = false;399400//open bus support401regs.ppu1_mdr = 0xff;402regs.ppu2_mdr = 0xff;403404//bg line counters405regs.bg_y[0] = 0;406regs.bg_y[1] = 0;407regs.bg_y[2] = 0;408regs.bg_y[3] = 0;409}410411void PPU::layer_enable(unsigned layer, unsigned priority, bool enable) {412switch(layer * 4 + priority) {413case 0: layer_enabled[BG1][0] = enable; break;414case 1: layer_enabled[BG1][1] = enable; break;415case 4: layer_enabled[BG2][0] = enable; break;416case 5: layer_enabled[BG2][1] = enable; break;417case 8: layer_enabled[BG3][0] = enable; break;418case 9: layer_enabled[BG3][1] = enable; break;419case 12: layer_enabled[BG4][0] = enable; break;420case 13: layer_enabled[BG4][1] = enable; break;421case 16: layer_enabled[OAM][0] = enable; break;422case 17: layer_enabled[OAM][1] = enable; break;423case 18: layer_enabled[OAM][2] = enable; break;424case 19: layer_enabled[OAM][3] = enable; break;425}426}427428void PPU::set_frameskip(unsigned frameskip_) {429frameskip = frameskip_;430framecounter = 0;431}432433PPU::PPU()434: vram(nullptr)435, oam(nullptr)436, cgram(nullptr)437{438439}440441void PPU::initialize()442{443vram = (uint8*)interface()->allocSharedMemory("VRAM",128 * 1024);444oam = (uint8*)interface()->allocSharedMemory("OAM",544);445cgram = (uint8*)interface()->allocSharedMemory("CGRAM",512);446447surface = new uint32[512 * 512];448output = surface + 16 * 512;449450alloc_tiledata_cache();451452for(unsigned l = 0; l < 16; l++) {453for(unsigned i = 0; i < 4096; i++) {454mosaic_table[l][i] = (i / (l + 1)) * (l + 1);455}456}457458layer_enabled[BG1][0] = true;459layer_enabled[BG1][1] = true;460layer_enabled[BG2][0] = true;461layer_enabled[BG2][1] = true;462layer_enabled[BG3][0] = true;463layer_enabled[BG3][1] = true;464layer_enabled[BG4][0] = true;465layer_enabled[BG4][1] = true;466layer_enabled[OAM][0] = true;467layer_enabled[OAM][1] = true;468layer_enabled[OAM][2] = true;469layer_enabled[OAM][3] = true;470frameskip = 0;471framecounter = 0;472}473474PPU::~PPU() {475delete[] surface;476free_tiledata_cache();477interface()->freeSharedMemory(vram);478interface()->freeSharedMemory(oam);479interface()->freeSharedMemory(cgram);480}481482}483484485