mirror of https://github.com/bsnes-emu/bsnes.git
Update to bsnes v013 release.
- Greatly improved HDMA timing and accuracy with help from anomie and DMV27 -- fixes bugs in Energy Breaker and Street Fighter Alpha 2 - Fixed a problem with color add/sub code -- fixes opening battle in Tales of Phantasia and clouds in Energy Breaker - Temporarily added DMV27's bugfix for the DSP KON register -- fixes sound in Der Langrisser, but this is not a hardware-accurate fix - Disabled VRAM writes outside of vblank -- fixes Hook, but breaks many PD ROMs and fan translations (Roto's BS Zelda hack, Gideon Zhi's Ys 4 translation, etc). I might add an option in the future to toggle this behavior, but for now these games will no longer work. Please keep in mind these games will not run properly on real SNES hardware, either. - Improved frameskipping code thanks to a suggestion from Richard Bannister - Misc. other code cleanups and improvements (notably in the color table generation code) - bsnes is now endian-safe and runs on Mac OS X - Added caching support for window clipping tables resulting in a slight speedup. Please let me know if you spot any errors as a result of this change.
This commit is contained in:
parent
397b9c4505
commit
c6c5f4669c
50
bsnes.cfg
50
bsnes.cfg
|
@ -35,7 +35,7 @@ video.vblank = false
|
|||
|
||||
# Show framerate in window title
|
||||
# (default = true)
|
||||
gui.show_fps = false
|
||||
gui.show_fps = true
|
||||
|
||||
# Joypad1 up
|
||||
# (default = 0x26)
|
||||
|
@ -85,3 +85,51 @@ input.joypad1.select = 0x10
|
|||
# (default = 0xd)
|
||||
input.joypad1.start = 0xd
|
||||
|
||||
# Joypad2 up
|
||||
# (default = 0x54)
|
||||
input.joypad2.up = 0x54
|
||||
|
||||
# Joypad2 down
|
||||
# (default = 0x47)
|
||||
input.joypad2.down = 0x47
|
||||
|
||||
# Joypad2 left
|
||||
# (default = 0x46)
|
||||
input.joypad2.left = 0x46
|
||||
|
||||
# Joypad2 right
|
||||
# (default = 0x48)
|
||||
input.joypad2.right = 0x48
|
||||
|
||||
# Joypad2 A
|
||||
# (default = 0x4b)
|
||||
input.joypad2.a = 0x4b
|
||||
|
||||
# Joypad2 B
|
||||
# (default = 0x4a)
|
||||
input.joypad2.b = 0x4a
|
||||
|
||||
# Joypad2 X
|
||||
# (default = 0x49)
|
||||
input.joypad2.x = 0x49
|
||||
|
||||
# Joypad2 Y
|
||||
# (default = 0x55)
|
||||
input.joypad2.y = 0x55
|
||||
|
||||
# Joypad2 L
|
||||
# (default = 0x4f)
|
||||
input.joypad2.l = 0x4f
|
||||
|
||||
# Joypad2 R
|
||||
# (default = 0x4c)
|
||||
input.joypad2.r = 0x4c
|
||||
|
||||
# Joypad2 select
|
||||
# (default = 0x5b)
|
||||
input.joypad2.select = 0x5b
|
||||
|
||||
# Joypad2 start
|
||||
# (default = 0x5d)
|
||||
input.joypad2.start = 0x5d
|
||||
|
||||
|
|
|
@ -19,3 +19,8 @@ http://www.libsdl.org/
|
|||
|
||||
This library is distributed under the terms of the GNU LGPL:
|
||||
http://www.gnu.org/copyleft/lesser.html
|
||||
|
||||
Licensing Exemptions:
|
||||
---------------------
|
||||
Richard Bannister has asked for and received my permission to distribute
|
||||
a binary-only port of bsnes on the Mac OS X platform.
|
||||
|
|
|
@ -13,7 +13,7 @@ private:
|
|||
inline bool operator ^= (bool i) { if(i)_b ^= B; return (_b & B); }
|
||||
};
|
||||
public:
|
||||
union {
|
||||
union {
|
||||
uint8 _b;
|
||||
bit<0x80> n;
|
||||
bit<0x40> v;
|
||||
|
@ -23,7 +23,7 @@ public:
|
|||
bit<0x04> i;
|
||||
bit<0x02> z;
|
||||
bit<0x01> c;
|
||||
};
|
||||
};
|
||||
|
||||
APURegFlags() { _b = 0; }
|
||||
inline operator uint8() { return _b; }
|
||||
|
@ -38,10 +38,11 @@ public:
|
|||
uint16 pc;
|
||||
union {
|
||||
uint16 ya;
|
||||
//not endian-safe
|
||||
struct {
|
||||
uint8 a, y;
|
||||
};
|
||||
#ifdef ARCH_LSB
|
||||
struct { uint8 a, y; };
|
||||
#else
|
||||
struct { uint8 y, a; };
|
||||
#endif
|
||||
};
|
||||
uint8 x, sp;
|
||||
APURegFlags p;
|
||||
|
|
|
@ -510,7 +510,7 @@ void bAPU::op_cbne_dp() {
|
|||
rd = op_read();
|
||||
break;
|
||||
case 3:
|
||||
sp = op_read(OPMODE_DP, dp + 0);
|
||||
sp = op_read(OPMODE_DP, dp);
|
||||
break;
|
||||
case 4:
|
||||
if(regs.a == sp)status.cycle_pos = 0;
|
||||
|
@ -533,14 +533,16 @@ void bAPU::op_cbne_dpx() {
|
|||
rd = op_read();
|
||||
break;
|
||||
case 3:
|
||||
sp = op_read(OPMODE_DP, dp + regs.x);
|
||||
break;
|
||||
case 4:
|
||||
if(regs.a == sp)status.cycle_pos = 0;
|
||||
sp = op_read(OPMODE_DP, dp + regs.x);
|
||||
break;
|
||||
case 5:
|
||||
if(regs.a == sp)status.cycle_pos = 0;
|
||||
break;
|
||||
case 6:
|
||||
break;
|
||||
case 7:
|
||||
regs.pc += (int8)rd;
|
||||
status.cycle_pos = 0;
|
||||
break;
|
||||
|
|
|
@ -37,16 +37,25 @@ bbc7(0xf3, 0x80, ==) {
|
|||
6:regs.pc += (int8)rd;
|
||||
}
|
||||
|
||||
cbne_dp(0x2e, 0),
|
||||
cbne_dpx(0xde, regs.x) {
|
||||
cbne_dp(0x2e) {
|
||||
1:dp = op_read();
|
||||
2:rd = op_read();
|
||||
3:sp = op_read(OPMODE_DP, dp + $1);
|
||||
3:sp = op_read(OPMODE_DP, dp);
|
||||
4:if(regs.a == sp)end;
|
||||
5:
|
||||
6:regs.pc += (int8)rd;
|
||||
}
|
||||
|
||||
cbne_dpx(0xde) {
|
||||
1:dp = op_read();
|
||||
2:rd = op_read();
|
||||
3:
|
||||
4:sp = op_read(OPMODE_DP, dp + regs.x);
|
||||
5:if(regs.a == sp)end;
|
||||
6:
|
||||
7:regs.pc += (int8)rd;
|
||||
}
|
||||
|
||||
dbnz_dp(0x6e) {
|
||||
1:dp = op_read();
|
||||
2:rd = op_read();
|
||||
|
|
18
src/base.h
18
src/base.h
|
@ -1,9 +1,27 @@
|
|||
//this should be declared in the port-specific makefiles
|
||||
//#define ARCH_LSB
|
||||
//#define ARCH_MSB
|
||||
|
||||
#ifndef ARCH_LSB
|
||||
#ifndef ARCH_MSB
|
||||
#define ARCH_LSB
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <time.h>
|
||||
#include "lib/libbase.h"
|
||||
#include "lib/libvector.h"
|
||||
#include "lib/libstring.h"
|
||||
#include "lib/libconfig.h"
|
||||
|
||||
inline uint16 read16(uint8 *addr, uint pos) {
|
||||
#ifdef ARCH_LSB
|
||||
return *((uint16*)(addr + pos));
|
||||
#else
|
||||
return (addr[pos]) | (addr[pos + 1] << 8);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define _WIN32_
|
||||
#undef _UNIX_
|
||||
|
|
|
@ -18,54 +18,72 @@
|
|||
uint8 bCPU::pio_status() { return status.pio; }
|
||||
|
||||
void bCPU::run() {
|
||||
switch(status.cpu_state) {
|
||||
case CPUSTATE_DMA:
|
||||
dma_run();
|
||||
break;
|
||||
case CPUSTATE_WAI:
|
||||
case CPUSTATE_RUN:
|
||||
if(status.cycle_pos == 0) {
|
||||
//interrupts only trigger on opcode edges
|
||||
if(time.nmi_pending == true) {
|
||||
time.nmi_pending = false;
|
||||
irq(0xffea);
|
||||
break;
|
||||
}
|
||||
if(time.irq_pending == true) {
|
||||
time.irq_pending = false;
|
||||
irq(0xffee);
|
||||
break;
|
||||
}
|
||||
}
|
||||
//fallthrough
|
||||
case CPUSTATE_STP:
|
||||
exec_cycle();
|
||||
break;
|
||||
if(run_state.hdma) {
|
||||
exec_hdma();
|
||||
return;
|
||||
}
|
||||
|
||||
cycle_edge();
|
||||
if(run_state.dma) {
|
||||
exec_dma();
|
||||
return;
|
||||
}
|
||||
|
||||
if(run_state.irq) {
|
||||
irq_run();
|
||||
return;
|
||||
}
|
||||
|
||||
if(run_state.stp) {
|
||||
exec_cycle();
|
||||
return;
|
||||
}
|
||||
|
||||
if(status.cycle_pos == 0) {
|
||||
//interrupts only trigger on opcode edges
|
||||
if(time.nmi_pending == true) {
|
||||
time.nmi_pending = false;
|
||||
aa.w = 0xffea;
|
||||
run_state.irq = true;
|
||||
return;
|
||||
}
|
||||
if(time.irq_pending == true) {
|
||||
time.irq_pending = false;
|
||||
aa.w = 0xffee;
|
||||
run_state.irq = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
exec_cycle();
|
||||
}
|
||||
|
||||
void bCPU::scanline() {
|
||||
status.hdma_triggered = false;
|
||||
time.hdma_triggered = false;
|
||||
|
||||
if(vcounter() == 225 && status.auto_joypad_poll == true) {
|
||||
snes->poll_input();
|
||||
snes->poll_input(SNES::DEV_JOYPAD1);
|
||||
snes->poll_input(SNES::DEV_JOYPAD2);
|
||||
//When the SNES auto-polls the joypads, it writes 1, then 0 to
|
||||
//$4016, then reads from each 16 times to get the joypad state
|
||||
//information. As a result, the joypad read positions are set
|
||||
//to 16 after such a poll. Position 16 is the controller
|
||||
//connected status bit.
|
||||
status.joypad1_read_pos = 16;
|
||||
status.joypad2_read_pos = 16;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::frame() {
|
||||
hdma_initialize();
|
||||
|
||||
time.nmi_read = 1;
|
||||
time.nmi_line = 1;
|
||||
time.nmi_transition = 0;
|
||||
|
||||
if(cpu_version == 2) {
|
||||
time.hdmainit_trigger_pos = 12 + dma_counter();
|
||||
} else {
|
||||
time.hdmainit_trigger_pos = 12 + 8 - dma_counter();
|
||||
}
|
||||
time.hdmainit_triggered = false;
|
||||
}
|
||||
|
||||
void bCPU::power() {
|
||||
|
@ -94,21 +112,27 @@ void bCPU::reset() {
|
|||
mmio_reset();
|
||||
dma_reset();
|
||||
|
||||
status.cpu_state = CPUSTATE_RUN;
|
||||
status.dma_state = DMASTATE_STOP;
|
||||
run_state.hdma = false;
|
||||
run_state.dma = false;
|
||||
run_state.irq = false;
|
||||
run_state.wai = false;
|
||||
run_state.stp = false;
|
||||
|
||||
status.cycle_pos = 0;
|
||||
status.cycle_count = 0;
|
||||
status.cycles_executed = 0;
|
||||
|
||||
status.hdma_triggered = false;
|
||||
|
||||
apu_port[0] = 0x00;
|
||||
apu_port[1] = 0x00;
|
||||
apu_port[2] = 0x00;
|
||||
apu_port[3] = 0x00;
|
||||
|
||||
frame();
|
||||
|
||||
//initial latch values for $213c/$213d
|
||||
//[x]0035 : [y]0000 (53.0 -> 212) [lda $2137]
|
||||
//[x]0038 : [y]0000 (56.5 -> 226) [nop : lda $2137]
|
||||
add_cycles(186);
|
||||
}
|
||||
|
||||
uint8 bCPU::port_read(uint8 port) {
|
||||
|
@ -141,20 +165,18 @@ void bCPU::cpu_c6(uint16 addr) {
|
|||
* cpu_io is an I/O cycle, and always 6 clock cycles long.
|
||||
* mem_read / mem_write indicate memory access bus cycle,
|
||||
* they are either 6, 8, or 12 bus cycles long, depending
|
||||
* both on location and the $420d.1 FastROM enable bit.
|
||||
* both on location and the $420d.d0 FastROM enable bit.
|
||||
*/
|
||||
|
||||
void bCPU::cpu_io() {
|
||||
if(status.is_last_cycle)last_cycle_exec();
|
||||
|
||||
status.cycle_count = 6;
|
||||
pre_exec_cycle();
|
||||
add_cycles(6);
|
||||
}
|
||||
|
||||
uint8 bCPU::mem_read(uint32 addr) {
|
||||
if(status.is_last_cycle)last_cycle_exec();
|
||||
|
||||
status.cycle_count = mem_bus->speed(addr);
|
||||
pre_exec_cycle();
|
||||
add_cycles(status.cycle_count - 4);
|
||||
regs.mdr = mem_bus->read(addr);
|
||||
add_cycles(4);
|
||||
|
@ -162,9 +184,8 @@ uint8 bCPU::mem_read(uint32 addr) {
|
|||
}
|
||||
|
||||
void bCPU::mem_write(uint32 addr, uint8 value) {
|
||||
if(status.is_last_cycle)last_cycle_exec();
|
||||
|
||||
status.cycle_count = mem_bus->speed(addr);
|
||||
pre_exec_cycle();
|
||||
add_cycles(status.cycle_count);
|
||||
mem_bus->write(addr, value);
|
||||
}
|
||||
|
|
|
@ -32,32 +32,39 @@ CPUReg24 aa, rd;
|
|||
uint8 dp, sp;
|
||||
|
||||
enum {
|
||||
CPUSTATE_RUN = 0,
|
||||
CPUSTATE_WAI,
|
||||
CPUSTATE_STP,
|
||||
CPUSTATE_DMA
|
||||
};
|
||||
|
||||
enum {
|
||||
DMASTATE_STOP = 0,
|
||||
DMASTATE_DMASYNC,
|
||||
DMASTATE_DMASYNC2,
|
||||
DMASTATE_DMASYNC3,
|
||||
DMASTATE_RUN,
|
||||
DMASTATE_CPUSYNC,
|
||||
DMASTATE_CPUSYNC2
|
||||
|
||||
HDMASTATE_IDMASYNC,
|
||||
HDMASTATE_IDMASYNC2,
|
||||
HDMASTATE_IDMASYNC3,
|
||||
HDMASTATE_ICPUSYNC,
|
||||
|
||||
HDMASTATE_DMASYNC,
|
||||
HDMASTATE_DMASYNC2,
|
||||
HDMASTATE_DMASYNC3,
|
||||
HDMASTATE_RUN,
|
||||
HDMASTATE_CPUSYNC
|
||||
};
|
||||
|
||||
struct {
|
||||
uint8 cpu_state, cycle_pos, cycle_count;
|
||||
bool hdma;
|
||||
bool dma;
|
||||
bool irq;
|
||||
bool stp;
|
||||
bool wai;
|
||||
} run_state;
|
||||
|
||||
struct {
|
||||
uint8 cycle_pos, cycle_count;
|
||||
uint8 opcode;
|
||||
uint32 cycles_executed;
|
||||
|
||||
//set by last_cycle(), cleared by last_cycle_exec()
|
||||
bool is_last_cycle;
|
||||
|
||||
uint8 dma_state;
|
||||
uint32 dma_cycle_count;
|
||||
bool hdma_triggered;
|
||||
uint8 dma_state, hdma_state;
|
||||
uint32 dma_cycle_count, hdma_cycle_count;
|
||||
|
||||
//$4207-$420a
|
||||
uint16 virq_trigger, hirq_trigger;
|
||||
|
@ -65,9 +72,9 @@ struct {
|
|||
//$2181-$2183
|
||||
uint32 wram_addr;
|
||||
|
||||
//$4016
|
||||
uint8 joypad1_strobe_value;
|
||||
uint8 joypad1_read_pos;
|
||||
//$4016-$4017
|
||||
uint8 joypad1_strobe_value, joypad2_strobe_value;
|
||||
uint8 joypad1_read_pos, joypad2_read_pos;
|
||||
|
||||
//$4200
|
||||
bool nmi_enabled;
|
||||
|
@ -92,6 +99,12 @@ struct {
|
|||
uint16 r4216;
|
||||
} status;
|
||||
|
||||
//$43x0.d7
|
||||
enum {
|
||||
DMA_CPUTOMMIO = 0,
|
||||
DMA_MMIOTOCPU = 1
|
||||
};
|
||||
|
||||
struct {
|
||||
uint32 read_index; //set to 0 at beginning of DMA/HDMA
|
||||
|
||||
|
@ -113,7 +126,10 @@ struct {
|
|||
//$43x4
|
||||
uint8 srcbank;
|
||||
//$43x5-$43x6
|
||||
uint16 xfersize;
|
||||
union {
|
||||
uint16 xfersize;
|
||||
uint16 hdma_iaddr;
|
||||
};
|
||||
//$43x7
|
||||
uint8 hdma_ibank;
|
||||
//$43x8-$43x9
|
||||
|
@ -124,15 +140,11 @@ struct {
|
|||
uint8 hdma_unknown;
|
||||
|
||||
//hdma-specific
|
||||
bool hdma_first_line;
|
||||
bool hdma_repeat;
|
||||
uint16 hdma_iaddr;
|
||||
bool hdma_active;
|
||||
bool hdma_do_transfer;
|
||||
} channel[8];
|
||||
|
||||
inline bool hdma_test();
|
||||
|
||||
inline void irq(uint16 addr);
|
||||
inline bool nmi_test();
|
||||
inline bool irq_test();
|
||||
|
||||
|
@ -144,17 +156,27 @@ struct {
|
|||
inline void power();
|
||||
inline void reset();
|
||||
|
||||
inline void irq_run();
|
||||
|
||||
//dma commands
|
||||
inline void dma_add_cycles(uint32 cycles);
|
||||
inline void hdma_add_cycles(uint32 cycles);
|
||||
inline void dma_run();
|
||||
inline void hdma_run();
|
||||
inline void hdma_initialize();
|
||||
inline void hdma_update(uint8 i);
|
||||
inline uint8 hdma_enabled_channels();
|
||||
inline uint8 hdma_active_channels();
|
||||
inline void hdmainit_activate();
|
||||
inline void hdma_activate();
|
||||
inline void dma_cputommio(uint8 i, uint8 index);
|
||||
inline void dma_mmiotocpu(uint8 i, uint8 index);
|
||||
inline void dma_write(uint8 i, uint8 index);
|
||||
inline uint32 dma_addr(uint8 i);
|
||||
inline uint32 hdma_addr(uint8 i);
|
||||
inline uint32 hdma_iaddr(uint8 i);
|
||||
inline void hdma_write(uint8 i, uint8 l, uint8 x);
|
||||
inline uint16 hdma_mmio(uint8 i);
|
||||
inline uint8 hdma_read(uint8 i);
|
||||
inline void hdma_write(uint8 i, uint8 x);
|
||||
inline void dma_reset();
|
||||
|
||||
//mmio commands
|
||||
|
@ -172,6 +194,8 @@ struct {
|
|||
uint8 mmio_r4217();
|
||||
uint8 mmio_r4218();
|
||||
uint8 mmio_r4219();
|
||||
uint8 mmio_r421a();
|
||||
uint8 mmio_r421b();
|
||||
uint8 mmio_r43x0(uint8 i);
|
||||
uint8 mmio_r43x1(uint8 i);
|
||||
uint8 mmio_r43x2(uint8 i);
|
||||
|
@ -189,6 +213,7 @@ struct {
|
|||
void mmio_w2182(uint8 value);
|
||||
void mmio_w2183(uint8 value);
|
||||
void mmio_w4016(uint8 value);
|
||||
void mmio_w4017(uint8 value);
|
||||
void mmio_w4200(uint8 value);
|
||||
void mmio_w4201(uint8 value);
|
||||
void mmio_w4202(uint8 value);
|
||||
|
@ -217,10 +242,11 @@ struct {
|
|||
void mmio_w43xb(uint8 value, uint8 i);
|
||||
|
||||
enum { CYCLE_OPREAD = 0, CYCLE_READ, CYCLE_WRITE, CYCLE_IO };
|
||||
inline void pre_exec_cycle();
|
||||
inline void exec_hdma();
|
||||
inline void exec_dma();
|
||||
inline void exec_cycle();
|
||||
inline void last_cycle();
|
||||
inline void last_cycle_exec();
|
||||
inline void cycle_edge();
|
||||
inline bool in_opcode();
|
||||
|
||||
//cpu extra-cycle conditions
|
||||
|
|
|
@ -1,7 +1,22 @@
|
|||
void bCPU::dma_add_cycles(uint32 cycles) {
|
||||
status.dma_cycle_count += cycles;
|
||||
}
|
||||
|
||||
void bCPU::hdma_add_cycles(uint32 cycles) {
|
||||
if(run_state.dma) {
|
||||
status.dma_cycle_count += cycles;
|
||||
}
|
||||
status.hdma_cycle_count += cycles;
|
||||
}
|
||||
|
||||
uint32 bCPU::dma_addr(uint8 i) {
|
||||
uint32 r;
|
||||
r = channel[i].srcaddr;
|
||||
r |= (channel[i].srcbank << 16);
|
||||
r = (channel[i].srcbank << 16) | (channel[i].srcaddr);
|
||||
|
||||
if(channel[i].fixedxfer == false) {
|
||||
channel[i].srcaddr += channel[i].incmode;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -15,10 +30,6 @@ uint8 x;
|
|||
|
||||
mem_bus->write(0x2100 | ((channel[i].destaddr + index) & 0xff), x);
|
||||
|
||||
if(channel[i].fixedxfer == false) {
|
||||
channel[i].srcaddr += channel[i].incmode;
|
||||
}
|
||||
|
||||
add_cycles(8);
|
||||
channel[i].xfersize--;
|
||||
}
|
||||
|
@ -28,10 +39,6 @@ uint8 x;
|
|||
x = mem_bus->read(0x2100 | ((channel[i].destaddr + index) & 0xff));
|
||||
mem_bus->write(dma_addr(i), x);
|
||||
|
||||
if(channel[i].fixedxfer == false) {
|
||||
channel[i].srcaddr += channel[i].incmode;
|
||||
}
|
||||
|
||||
add_cycles(8);
|
||||
channel[i].xfersize--;
|
||||
}
|
||||
|
@ -51,7 +58,8 @@ int i;
|
|||
|
||||
//first byte transferred?
|
||||
if(channel[i].read_index == 0) {
|
||||
sdd1->dma_begin(i, dma_addr(i), channel[i].xfersize);
|
||||
sdd1->dma_begin(i, (channel[i].srcbank << 16) | (channel[i].srcaddr),
|
||||
channel[i].xfersize);
|
||||
}
|
||||
|
||||
switch(channel[i].xfermode) {
|
||||
|
@ -66,6 +74,7 @@ int i;
|
|||
}
|
||||
|
||||
channel[i].read_index++;
|
||||
dma_add_cycles(8);
|
||||
|
||||
if(channel[i].xfersize == 0) {
|
||||
channel[i].active = false;
|
||||
|
@ -78,22 +87,15 @@ int i;
|
|||
}
|
||||
|
||||
uint32 bCPU::hdma_addr(uint8 i) {
|
||||
uint32 r;
|
||||
r = channel[i].hdma_addr;
|
||||
r |= (channel[i].srcbank << 16);
|
||||
channel[i].hdma_addr++;
|
||||
return r;
|
||||
return (channel[i].srcbank << 16) | (channel[i].hdma_addr++);
|
||||
}
|
||||
|
||||
uint32 bCPU::hdma_iaddr(uint8 i) {
|
||||
uint32 r;
|
||||
r = channel[i].hdma_iaddr;
|
||||
r |= (channel[i].hdma_ibank << 16);
|
||||
channel[i].hdma_iaddr++;
|
||||
return r;
|
||||
return (channel[i].hdma_ibank << 16) | (channel[i].hdma_iaddr++);
|
||||
}
|
||||
|
||||
void bCPU::hdma_write(uint8 i, uint8 l, uint8 x) {
|
||||
uint16 bCPU::hdma_mmio(uint8 i) {
|
||||
uint8 l = channel[i].read_index;
|
||||
uint16 index;
|
||||
switch(channel[i].xfermode) {
|
||||
case 0:index = 0; break; //0
|
||||
|
@ -106,90 +108,118 @@ uint16 index;
|
|||
case 7:index = (l >> 1) & 1;break; //0,0,1,1 [3]
|
||||
}
|
||||
|
||||
index = 0x2100 | ((channel[i].destaddr + index) & 0xff);
|
||||
mem_bus->write(index, x);
|
||||
return (0x2100 | ((channel[i].destaddr + index) & 0xff));
|
||||
}
|
||||
|
||||
uint8 bCPU::hdma_read(uint8 i) {
|
||||
if(channel[i].direction == DMA_MMIOTOCPU) {
|
||||
return mem_bus->read(hdma_mmio(i));
|
||||
} else if(!channel[i].hdma_indirect) {
|
||||
return mem_bus->read(hdma_addr(i));
|
||||
} else {
|
||||
return mem_bus->read(hdma_iaddr(i));
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::hdma_write(uint8 i, uint8 x) {
|
||||
if(channel[i].direction == DMA_CPUTOMMIO) {
|
||||
mem_bus->write(hdma_mmio(i), x);
|
||||
} else if(!channel[i].hdma_indirect) {
|
||||
mem_bus->write(hdma_addr(i), x);
|
||||
} else {
|
||||
mem_bus->write(hdma_iaddr(i), x);
|
||||
}
|
||||
|
||||
add_cycles(8);
|
||||
hdma_add_cycles(8);
|
||||
}
|
||||
|
||||
void bCPU::hdma_update(uint8 i) {
|
||||
channel[i].hdma_line_counter = mem_bus->read(hdma_addr(i));
|
||||
add_cycles(8);
|
||||
hdma_add_cycles(8);
|
||||
|
||||
if(channel[i].hdma_indirect) {
|
||||
channel[i].hdma_iaddr = mem_bus->read(hdma_addr(i)) << 8;
|
||||
add_cycles(8);
|
||||
hdma_add_cycles(8);
|
||||
}
|
||||
|
||||
if(channel[i].hdma_line_counter == 0) {
|
||||
channel[i].hdma_active = false;
|
||||
channel[i].hdma_do_transfer = false;
|
||||
return;
|
||||
}
|
||||
|
||||
channel[i].hdma_do_transfer = true;
|
||||
|
||||
if(channel[i].hdma_indirect) {
|
||||
channel[i].hdma_iaddr >>= 8;
|
||||
channel[i].hdma_iaddr |= mem_bus->read(hdma_addr(i)) << 8;
|
||||
add_cycles(8);
|
||||
hdma_add_cycles(8);
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::hdma_run() {
|
||||
int l, xferlen;
|
||||
uint8 x, active_channels = 0;
|
||||
static uint8 hdma_xferlen[8] = { 1, 2, 2, 4, 4, 4, 2, 4 };
|
||||
for(int i=0;i<8;i++) {
|
||||
if(channel[i].hdma_active == false)continue;
|
||||
if(!channel[i].hdma_enabled || !channel[i].hdma_active)continue;
|
||||
|
||||
add_cycles(8);
|
||||
active_channels++;
|
||||
|
||||
if(channel[i].hdma_line_counter == 0) {
|
||||
channel[i].hdma_line_counter = mem_bus->read(hdma_addr(i));
|
||||
|
||||
if(channel[i].hdma_line_counter == 0) {
|
||||
channel[i].hdma_active = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(channel[i].hdma_line_counter > 0x80) {
|
||||
channel[i].hdma_repeat = true;
|
||||
channel[i].hdma_line_counter -= 0x80;
|
||||
} else {
|
||||
channel[i].hdma_repeat = false;
|
||||
}
|
||||
|
||||
channel[i].hdma_first_line = true;
|
||||
|
||||
if(channel[i].hdma_indirect == true) {
|
||||
channel[i].hdma_iaddr = mem_bus->read(hdma_addr(i));
|
||||
channel[i].hdma_iaddr |= mem_bus->read(hdma_addr(i)) << 8;
|
||||
add_cycles(16);
|
||||
if(channel[i].hdma_do_transfer) {
|
||||
int xferlen = hdma_xferlen[channel[i].xfermode];
|
||||
for(channel[i].read_index=0;channel[i].read_index<xferlen;channel[i].read_index++) {
|
||||
hdma_write(i, hdma_read(i));
|
||||
}
|
||||
}
|
||||
|
||||
channel[i].hdma_line_counter--;
|
||||
if(channel[i].hdma_first_line == false && channel[i].hdma_repeat == false)continue;
|
||||
channel[i].hdma_first_line = false;
|
||||
|
||||
xferlen = hdma_xferlen[channel[i].xfermode];
|
||||
for(l=0;l<xferlen;l++) {
|
||||
if(channel[i].hdma_indirect == false) {
|
||||
x = mem_bus->read(hdma_addr(i));
|
||||
} else {
|
||||
x = mem_bus->read(hdma_iaddr(i));
|
||||
}
|
||||
|
||||
hdma_write(i, l, x);
|
||||
add_cycles(8);
|
||||
channel[i].hdma_do_transfer = !!(channel[i].hdma_line_counter & 0x80);
|
||||
if((channel[i].hdma_line_counter & 0x7f) == 0) {
|
||||
hdma_update(i);
|
||||
}
|
||||
}
|
||||
|
||||
if(active_channels != 0) {
|
||||
add_cycles(18);
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::hdma_initialize() {
|
||||
uint8 active_channels = 0;
|
||||
uint8 bCPU::hdma_enabled_channels() {
|
||||
int r = 0;
|
||||
for(int i=0;i<8;i++) {
|
||||
//does this happen when $420c channel bit is clear?
|
||||
channel[i].hdma_addr = channel[i].srcaddr;
|
||||
channel[i].hdma_line_counter = 0x00;
|
||||
if(channel[i].hdma_enabled)r++;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
if(channel[i].hdma_enabled == false) {
|
||||
channel[i].hdma_active = false;
|
||||
continue;
|
||||
}
|
||||
uint8 bCPU::hdma_active_channels() {
|
||||
int r = 0;
|
||||
for(int i=0;i<8;i++) {
|
||||
if(channel[i].hdma_enabled && channel[i].hdma_active)r++;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
channel[i].hdma_active = true;
|
||||
active_channels++;
|
||||
/* hdmainit_activate()
|
||||
* hdma_activate()
|
||||
*
|
||||
* Functions are called by CPU timing routine
|
||||
* when an HDMA event (init or run) occurs.
|
||||
*/
|
||||
|
||||
if(channel[i].hdma_indirect == false) {
|
||||
add_cycles(8);
|
||||
} else {
|
||||
add_cycles(24);
|
||||
}
|
||||
void bCPU::hdmainit_activate() {
|
||||
for(int i=0;i<8;i++) {
|
||||
channel[i].hdma_active = false;
|
||||
channel[i].hdma_do_transfer = false;
|
||||
}
|
||||
|
||||
if(active_channels != 0) {
|
||||
add_cycles(18);
|
||||
if(hdma_enabled_channels() != 0) {
|
||||
status.hdma_state = HDMASTATE_IDMASYNC;
|
||||
run_state.hdma = true;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::hdma_activate() {
|
||||
if(hdma_active_channels() != 0) {
|
||||
status.hdma_state = HDMASTATE_DMASYNC;
|
||||
run_state.hdma = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -206,15 +236,15 @@ void bCPU::dma_reset() {
|
|||
channel[i].xfermode = 0;
|
||||
channel[i].destaddr = 0;
|
||||
channel[i].srcaddr = 0;
|
||||
channel[i].xfersize = 0;
|
||||
channel[i].xfersize = 0x0000;
|
||||
//xfersize and hdma_iaddr are of union { uint16 };
|
||||
//channel[i].hdma_iaddr = 0x0000;
|
||||
channel[i].hdma_ibank = 0;
|
||||
channel[i].hdma_addr = 0x0000;
|
||||
channel[i].hdma_line_counter = 0x00;
|
||||
channel[i].hdma_unknown = 0x00;
|
||||
|
||||
channel[i].hdma_active = false;
|
||||
channel[i].hdma_first_line = false;
|
||||
channel[i].hdma_repeat = false;
|
||||
channel[i].hdma_iaddr = 0x0000;
|
||||
channel[i].hdma_do_transfer = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,51 +1,145 @@
|
|||
void bCPU::last_cycle() {
|
||||
status.is_last_cycle = true;
|
||||
}
|
||||
|
||||
void bCPU::last_cycle_exec() {
|
||||
status.is_last_cycle = false;
|
||||
|
||||
time.nmi_pending = nmi_test();
|
||||
time.irq_pending = irq_test();
|
||||
}
|
||||
|
||||
void bCPU::cycle_edge() {
|
||||
int c, n, z;
|
||||
if(status.dma_state != DMASTATE_STOP) {
|
||||
void bCPU::pre_exec_cycle() {
|
||||
if(!run_state.dma && !run_state.hdma)return;
|
||||
|
||||
int c, z;
|
||||
if(run_state.hdma) {
|
||||
switch(status.hdma_state) {
|
||||
case HDMASTATE_ICPUSYNC:
|
||||
case HDMASTATE_CPUSYNC:
|
||||
c = status.cycle_count;
|
||||
z = c - (status.hdma_cycle_count % c);
|
||||
if(!z)z = c;
|
||||
add_cycles(z);
|
||||
run_state.hdma = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(run_state.dma) {
|
||||
switch(status.dma_state) {
|
||||
case DMASTATE_DMASYNC:
|
||||
status.dma_state = DMASTATE_DMASYNC2;
|
||||
break;
|
||||
case DMASTATE_DMASYNC2:
|
||||
n = 8 - dma_counter() + 8;
|
||||
add_cycles(n);
|
||||
status.dma_cycle_count = n;
|
||||
for(z=0;z<8;z++) {
|
||||
if(channel[z].active == false)continue;
|
||||
add_cycles(8);
|
||||
status.dma_cycle_count += 8;
|
||||
}
|
||||
status.cpu_state = CPUSTATE_DMA;
|
||||
status.dma_state = DMASTATE_RUN;
|
||||
break;
|
||||
case DMASTATE_RUN:
|
||||
status.dma_cycle_count += 8;
|
||||
break;
|
||||
case DMASTATE_CPUSYNC:
|
||||
status.cpu_state = CPUSTATE_RUN;
|
||||
status.dma_state = DMASTATE_CPUSYNC2;
|
||||
break;
|
||||
case DMASTATE_CPUSYNC2:
|
||||
c = status.cycle_count;
|
||||
z = c - (status.dma_cycle_count % c);
|
||||
if(!z)z = c;
|
||||
add_cycles(z);
|
||||
status.dma_state = DMASTATE_STOP;
|
||||
run_state.dma = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::exec_hdma() {
|
||||
int n;
|
||||
static int z;
|
||||
switch(status.hdma_state) {
|
||||
case HDMASTATE_IDMASYNC:
|
||||
status.hdma_cycle_count = 0;
|
||||
z = 0;
|
||||
if(!run_state.dma) {
|
||||
exec_cycle();
|
||||
status.hdma_state = HDMASTATE_IDMASYNC2;
|
||||
} else {
|
||||
status.hdma_state = HDMASTATE_IDMASYNC3;
|
||||
}
|
||||
break;
|
||||
case HDMASTATE_IDMASYNC2:
|
||||
n = 8 - dma_counter() + 8;
|
||||
add_cycles(n);
|
||||
status.hdma_cycle_count += n;
|
||||
status.hdma_state = HDMASTATE_IDMASYNC3;
|
||||
break;
|
||||
case HDMASTATE_IDMASYNC3:
|
||||
channel[z].hdma_active = channel[z].hdma_enabled;
|
||||
if(channel[z].hdma_enabled) {
|
||||
channel[z].hdma_addr = channel[z].srcaddr;
|
||||
hdma_update(z); //updates status.hdma_cycle_count
|
||||
}
|
||||
if(++z < 8)break;
|
||||
if(!run_state.dma) {
|
||||
status.hdma_state = HDMASTATE_ICPUSYNC;
|
||||
} else {
|
||||
run_state.hdma = false;
|
||||
}
|
||||
break;
|
||||
case HDMASTATE_ICPUSYNC:
|
||||
exec_cycle();
|
||||
break;
|
||||
|
||||
case HDMASTATE_DMASYNC:
|
||||
status.hdma_cycle_count = 0;
|
||||
z = 0;
|
||||
if(!run_state.dma) {
|
||||
exec_cycle();
|
||||
status.hdma_state = HDMASTATE_DMASYNC2;
|
||||
} else {
|
||||
status.hdma_state = HDMASTATE_DMASYNC3;
|
||||
}
|
||||
break;
|
||||
case HDMASTATE_DMASYNC2:
|
||||
n = 8 - dma_counter() + 8;
|
||||
add_cycles(n);
|
||||
status.hdma_cycle_count += n;
|
||||
status.hdma_state = HDMASTATE_DMASYNC3;
|
||||
break;
|
||||
case HDMASTATE_DMASYNC3:
|
||||
if(channel[z].hdma_active) {
|
||||
add_cycles(8);
|
||||
status.hdma_cycle_count += 8;
|
||||
}
|
||||
if(++z < 8)break;
|
||||
status.hdma_state = HDMASTATE_RUN;
|
||||
break;
|
||||
case HDMASTATE_RUN:
|
||||
hdma_run(); //updates status.hdma_cycle_count
|
||||
if(!run_state.dma) {
|
||||
status.hdma_state = HDMASTATE_CPUSYNC;
|
||||
} else {
|
||||
run_state.hdma = false;
|
||||
}
|
||||
break;
|
||||
case HDMASTATE_CPUSYNC:
|
||||
exec_cycle();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::exec_dma() {
|
||||
int n;
|
||||
static int z;
|
||||
switch(status.dma_state) {
|
||||
case DMASTATE_DMASYNC:
|
||||
exec_cycle();
|
||||
status.dma_state = DMASTATE_DMASYNC2;
|
||||
break;
|
||||
case DMASTATE_DMASYNC2:
|
||||
n = 8 - dma_counter() + 8;
|
||||
add_cycles(n);
|
||||
status.dma_cycle_count = n;
|
||||
z = 0;
|
||||
status.dma_state = DMASTATE_DMASYNC3;
|
||||
break;
|
||||
case DMASTATE_DMASYNC3:
|
||||
if(channel[z].active == true) {
|
||||
add_cycles(8);
|
||||
status.dma_cycle_count += 8;
|
||||
}
|
||||
if(++z < 8)break;
|
||||
status.dma_state = DMASTATE_RUN;
|
||||
break;
|
||||
case DMASTATE_RUN:
|
||||
dma_run(); //updates status.dma_cycle_count
|
||||
break;
|
||||
case DMASTATE_CPUSYNC:
|
||||
exec_cycle();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bCPU::exec_cycle() {
|
||||
//on first cycle?
|
||||
if(status.cycle_pos == 0) {
|
||||
|
|
|
@ -1,43 +1,43 @@
|
|||
/*
|
||||
[IRQ cycles]
|
||||
[1] pbr,pc ; opcode
|
||||
[2] pbr,pc ; io
|
||||
[3] 0,s ; pbr
|
||||
[4] 0,s-1 ; pch
|
||||
[5] 0,s-2 ; pcl
|
||||
[6] 0,s-3 ; p
|
||||
[7] 0,va ; aavl
|
||||
[8] 0,va+1 ; aavh
|
||||
[0] pbr,pc ; opcode
|
||||
[1] pbr,pc ; io
|
||||
[2] 0,s ; pbr
|
||||
[3] 0,s-1 ; pch
|
||||
[4] 0,s-2 ; pcl
|
||||
[5] 0,s-3 ; p
|
||||
[6] 0,va ; aavl
|
||||
[7] 0,va+1 ; aavh
|
||||
*/
|
||||
void bCPU::irq(uint16 addr) {
|
||||
void bCPU::irq_run() {
|
||||
//WDC documentation is incorrect, first cycle
|
||||
//is a memory read fetch from PBR:PC
|
||||
add_cycles(mem_bus->speed(regs.pc.d));
|
||||
add_cycles(6);
|
||||
stack_write(regs.pc.b);
|
||||
stack_write(regs.pc.h);
|
||||
stack_write(regs.pc.l);
|
||||
stack_write(regs.p);
|
||||
rd.l = op_read(OPMODE_ADDR, addr);
|
||||
rd.h = op_read(OPMODE_ADDR, addr + 1);
|
||||
|
||||
regs.pc.b = 0x00;
|
||||
regs.pc.w = rd.w;
|
||||
regs.p.i = 1;
|
||||
regs.p.d = 0;
|
||||
|
||||
//let debugger know the new IRQ opcode address
|
||||
snes->notify(SNES::CPU_EXEC_OPCODE_END);
|
||||
switch(status.cycle_pos++) {
|
||||
case 0: add_cycles(mem_bus->speed(regs.pc.d)); break;
|
||||
case 1: add_cycles(6); break;
|
||||
case 2: stack_write(regs.pc.b); break;
|
||||
case 3: stack_write(regs.pc.h); break;
|
||||
case 4: stack_write(regs.pc.l); break;
|
||||
case 5: stack_write(regs.p); break;
|
||||
case 6: rd.l = op_read(OPMODE_ADDR, aa.w); break;
|
||||
case 7: rd.h = op_read(OPMODE_ADDR, aa.w + 1);
|
||||
regs.pc.b = 0x00;
|
||||
regs.pc.w = rd.w;
|
||||
regs.p.i = 1;
|
||||
regs.p.d = 0;
|
||||
//let debugger know the new IRQ opcode address
|
||||
snes->notify(SNES::CPU_EXEC_OPCODE_END);
|
||||
status.cycle_pos = 0;
|
||||
run_state.irq = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool bCPU::nmi_test() {
|
||||
if(time.nmi_transition == 0)return false;
|
||||
time.nmi_transition = 0;
|
||||
|
||||
if(status.cpu_state == CPUSTATE_WAI) {
|
||||
status.cpu_state = CPUSTATE_RUN;
|
||||
}
|
||||
|
||||
run_state.wai = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -61,10 +61,7 @@ bool bCPU::irq_test() {
|
|||
_true:
|
||||
time.irq_transition = 0;
|
||||
|
||||
if(status.cpu_state == CPUSTATE_WAI) {
|
||||
status.cpu_state = CPUSTATE_RUN;
|
||||
}
|
||||
|
||||
run_state.wai = false;
|
||||
if(regs.p.i)return false;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -2,9 +2,11 @@ void bCPU::mmio_reset() {
|
|||
//$2181-$2183
|
||||
status.wram_addr = 0x000000;
|
||||
|
||||
//$4016
|
||||
//$4016-$4017
|
||||
status.joypad1_strobe_value = 0x00;
|
||||
status.joypad2_strobe_value = 0x00;
|
||||
status.joypad1_read_pos = 0;
|
||||
status.joypad2_read_pos = 0;
|
||||
|
||||
//$4200
|
||||
status.nmi_enabled = false;
|
||||
|
@ -91,6 +93,28 @@ uint8 r;
|
|||
r = regs.mdr & 0xe0;
|
||||
r |= 0x1c;
|
||||
|
||||
if(status.joypad2_strobe_value == 1) {
|
||||
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_B);
|
||||
} else {
|
||||
switch(status.joypad2_read_pos) {
|
||||
case 0:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_B); break;
|
||||
case 1:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_Y); break;
|
||||
case 2:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_SELECT);break;
|
||||
case 3:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_START); break;
|
||||
case 4:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_UP); break;
|
||||
case 5:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_DOWN); break;
|
||||
case 6:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_LEFT); break;
|
||||
case 7:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_RIGHT); break;
|
||||
case 8:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_A); break;
|
||||
case 9:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_X); break;
|
||||
case 10:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_L); break;
|
||||
case 11:r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_R); break;
|
||||
case 16:r |= 1;break; //joypad connected bit
|
||||
default:r |= 1;break; //after 16th read, all subsequent reads return 1
|
||||
}
|
||||
if(++status.joypad2_read_pos > 17)status.joypad2_read_pos = 17;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -206,6 +230,36 @@ uint16 v = vcounter();
|
|||
return r;
|
||||
}
|
||||
|
||||
//JOY2L
|
||||
uint8 bCPU::mmio_r421a() {
|
||||
uint8 r = 0x00;
|
||||
uint16 v = vcounter();
|
||||
if(status.auto_joypad_poll == false)return 0x00; //can't read joypad if auto polling not enabled
|
||||
//if(v >= 225 && v <= 227)return 0x00; //can't read joypad while SNES is polling input
|
||||
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_A) << 7;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_X) << 6;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_L) << 5;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_R) << 4;
|
||||
return r;
|
||||
}
|
||||
|
||||
//JOY2H
|
||||
uint8 bCPU::mmio_r421b() {
|
||||
uint8 r = 0x00;
|
||||
uint16 v = vcounter();
|
||||
if(status.auto_joypad_poll == false)return 0x00; //can't read joypad if auto polling not enabled
|
||||
//if(v >= 225 && v <= 227)return 0x00; //can't read joypad while SNES is polling input
|
||||
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_B) << 7;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_Y) << 6;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_SELECT) << 5;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_START) << 4;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_UP) << 3;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_DOWN) << 2;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_LEFT) << 1;
|
||||
r |= (uint8)snes->get_input_status(SNES::DEV_JOYPAD2, SNES::JOYPAD_RIGHT);
|
||||
return r;
|
||||
}
|
||||
|
||||
//DMAPx
|
||||
uint8 bCPU::mmio_r43x0(uint8 i) {
|
||||
return channel[i].dmap;
|
||||
|
@ -310,9 +364,9 @@ uint i;
|
|||
case 0x4217:return cpu->mmio_r4217(); //RDMPYH
|
||||
case 0x4218:return cpu->mmio_r4218(); //JOY1L
|
||||
case 0x4219:return cpu->mmio_r4219(); //JOY1H
|
||||
case 0x421a:case 0x421b:case 0x421c:case 0x421d:case 0x421e:case 0x421f:return 0x00;
|
||||
case 0x4000:dprintf("* 4000 read at %3d,%4d <%d>", cpu->time.v, cpu->time.hc, cpu->status.cycle_count);break;
|
||||
case 0x4200:dprintf("* 4200 read at %3d,%4d", cpu->time.v, cpu->time.hc);break;
|
||||
case 0x421a:return cpu->mmio_r421a(); //JOY2L
|
||||
case 0x421b:return cpu->mmio_r421b(); //JOY2H
|
||||
case 0x421c:case 0x421d:case 0x421e:case 0x421f:return 0x00;
|
||||
}
|
||||
|
||||
return cpu->regs.mdr;
|
||||
|
@ -345,13 +399,22 @@ void bCPU::mmio_w2183(uint8 value) {
|
|||
|
||||
//JOYSER0
|
||||
void bCPU::mmio_w4016(uint8 value) {
|
||||
status.joypad1_strobe_value = (value & 1);
|
||||
status.joypad1_strobe_value = !!(value & 1);
|
||||
if(value == 1) {
|
||||
snes->poll_input();
|
||||
snes->poll_input(SNES::DEV_JOYPAD1);
|
||||
status.joypad1_read_pos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//JOYSER1
|
||||
void bCPU::mmio_w4017(uint8 value) {
|
||||
status.joypad2_strobe_value = !!(value & 1);
|
||||
if(value == 1) {
|
||||
snes->poll_input(SNES::DEV_JOYPAD2);
|
||||
status.joypad2_read_pos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//NMITIMEN
|
||||
void bCPU::mmio_w4200(uint8 value) {
|
||||
status.nmi_enabled = !!(value & 0x80);
|
||||
|
@ -438,6 +501,7 @@ void bCPU::mmio_w420a(uint8 value) {
|
|||
void bCPU::mmio_w420b(uint8 value) {
|
||||
int len;
|
||||
if(value != 0x00) {
|
||||
run_state.dma = true;
|
||||
status.dma_state = DMASTATE_DMASYNC;
|
||||
}
|
||||
|
||||
|
@ -566,6 +630,7 @@ uint8 i;
|
|||
case 0x2182:cpu->mmio_w2182(value);return; //WMADDM
|
||||
case 0x2183:cpu->mmio_w2183(value);return; //WMADDH
|
||||
case 0x4016:cpu->mmio_w4016(value);return; //JOYSER0
|
||||
case 0x4017:cpu->mmio_w4017(value);return; //JOYSER1
|
||||
case 0x4200:cpu->mmio_w4200(value);return; //NMITIMEN
|
||||
case 0x4201:cpu->mmio_w4201(value);return; //WRIO
|
||||
case 0x4202:cpu->mmio_w4202(value);return; //WRMPYA
|
||||
|
@ -580,7 +645,6 @@ uint8 i;
|
|||
case 0x420b:cpu->mmio_w420b(value);return; //DMAEN
|
||||
case 0x420c:cpu->mmio_w420c(value);return; //HDMAEN
|
||||
case 0x420d:cpu->mmio_w420d(value);return; //MEMSEL
|
||||
case 0x4000:dprintf("* 4000 write at %3d,%4d", cpu->time.v, cpu->time.hc);break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -164,7 +164,7 @@ void bCPU::op_stp() {
|
|||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
cpu_io();
|
||||
status.cpu_state = CPUSTATE_STP;
|
||||
run_state.stp = true;
|
||||
break;
|
||||
case 2:
|
||||
last_cycle();
|
||||
|
@ -179,12 +179,13 @@ void bCPU::op_wai() {
|
|||
switch(status.cycle_pos++) {
|
||||
case 1:
|
||||
cpu_io();
|
||||
status.cpu_state = CPUSTATE_WAI;
|
||||
run_state.wai = true;
|
||||
break;
|
||||
case 2:
|
||||
last_cycle();
|
||||
cpu_io();
|
||||
if(status.cpu_state == CPUSTATE_WAI) {
|
||||
if(run_state.wai) {
|
||||
//this can be cleared within last_cycle()
|
||||
regs.pc.w--;
|
||||
}
|
||||
status.cycle_pos = 0;
|
||||
|
|
|
@ -207,7 +207,7 @@ void bCPU::inc_vcounter() {
|
|||
}
|
||||
}
|
||||
|
||||
time.dma_counter = time.line_cycles & 6;
|
||||
time.dma_counter += time.line_cycles;
|
||||
if(time.v == 240 && time.interlace == false && time.interlace_field == 1) {
|
||||
time.line_cycles = 1360;
|
||||
} else {
|
||||
|
@ -259,21 +259,14 @@ void bCPU::add_cycles(int cycles) {
|
|||
|
||||
scanline();
|
||||
ppu->scanline();
|
||||
// ppu->render_scanline();
|
||||
snes->scanline();
|
||||
time.line_rendered = false;
|
||||
}
|
||||
|
||||
if(time.line_rendered == false) {
|
||||
//rendering should start at H=22, but due to inaccurate
|
||||
//timing, and due to using a scanline-based renderer, use
|
||||
//a higher value to allow more games to run properly...
|
||||
//H=48 fixes off-by-one HDMA effects with FF6's battles
|
||||
if(time.hc + cycles >= (48 * 4)) {
|
||||
cycles = (time.hc + cycles) - (48 * 4);
|
||||
time.hc = (48 * 4);
|
||||
time.line_rendered = true;
|
||||
ppu->render_scanline();
|
||||
if(time.hdmainit_triggered == false) {
|
||||
if(time.hc + cycles >= time.hdmainit_trigger_pos || time.v) {
|
||||
time.hdmainit_triggered = true;
|
||||
hdmainit_activate();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -296,14 +289,22 @@ void bCPU::add_cycles(int cycles) {
|
|||
}
|
||||
}
|
||||
|
||||
if(status.hdma_triggered == false) {
|
||||
//vcounter range verified on hardware
|
||||
if(time.line_rendered == false) {
|
||||
//rendering should start at H=18 (+256=274), but since the
|
||||
//current PPU emulation renders the entire scanline at once,
|
||||
//PPU register changes mid-scanline do not show up.
|
||||
//therefore, wait a few dots before rendering the scanline
|
||||
if(time.hc + cycles >= (48 * 4)) {
|
||||
time.line_rendered = true;
|
||||
ppu->render_scanline();
|
||||
}
|
||||
}
|
||||
|
||||
if(time.hdma_triggered == false) {
|
||||
if(time.v <= (overscan() ? 239 : 224)) {
|
||||
if(time.hc + cycles >= 1112) { //278 * 4 = 1112
|
||||
cycles = (time.hc + cycles) - 1112;
|
||||
time.hc = 1112;
|
||||
status.hdma_triggered = true;
|
||||
hdma_run();
|
||||
if(time.hc + cycles >= 1106) {
|
||||
time.hdma_triggered = true;
|
||||
hdma_activate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -312,11 +313,8 @@ void bCPU::add_cycles(int cycles) {
|
|||
}
|
||||
|
||||
void bCPU::time_reset() {
|
||||
//initial latch values for $213c/$213d
|
||||
//[x]0035 : [y]0000 (53.0 -> 212) [lda $2137]
|
||||
//[x]0038 : [y]0000 (56.5 -> 226) [nop : lda $2137]
|
||||
time.v = 0;
|
||||
time.hc = 186;
|
||||
time.hc = 0;
|
||||
|
||||
//upon SNES reset, start at scanline 0 non-interlace
|
||||
time.interlace = false;
|
||||
|
@ -329,6 +327,12 @@ void bCPU::time_reset() {
|
|||
|
||||
time.dma_counter = 0;
|
||||
|
||||
//set at V=0,H=0
|
||||
time.hdmainit_trigger_pos = 0;
|
||||
time.hdmainit_triggered = true;
|
||||
|
||||
time.hdma_triggered = false;
|
||||
|
||||
time.nmi_pending = false;
|
||||
time.irq_pending = false;
|
||||
time.nmi_line = time.nmi_read = 1;
|
||||
|
|
|
@ -11,6 +11,11 @@ struct {
|
|||
|
||||
uint8 dma_counter;
|
||||
|
||||
uint16 hdmainit_trigger_pos;
|
||||
bool hdmainit_triggered;
|
||||
|
||||
bool hdma_triggered;
|
||||
|
||||
uint16 region_scanlines;
|
||||
|
||||
//nmi_pending, irq_pending are used by last_cycle()
|
||||
|
|
|
@ -53,7 +53,7 @@ cop(0x02, 0xfff4, 0xfff5, 0xffe4, 0xffe5) {
|
|||
|
||||
stp(0xdb) {
|
||||
1:cpu_io();
|
||||
status.cpu_state = CPUSTATE_STP;
|
||||
run_state.stp = true;
|
||||
2:last_cycle();
|
||||
cpu_io();
|
||||
regs.pc.w--;
|
||||
|
@ -61,10 +61,11 @@ stp(0xdb) {
|
|||
|
||||
wai(0xcb) {
|
||||
1:cpu_io();
|
||||
status.cpu_state = CPUSTATE_WAI;
|
||||
run_state.wai = true;
|
||||
2:last_cycle();
|
||||
cpu_io();
|
||||
if(status.cpu_state == CPUSTATE_WAI) {
|
||||
if(run_state.wai) {
|
||||
//this can be cleared within last_cycle()
|
||||
regs.pc.w--;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,6 @@
|
|||
#include "dcpu.cpp"
|
||||
|
||||
CPU::CPU() {
|
||||
cpu_version = 2;
|
||||
cpu_version = 1;
|
||||
mmio = &mmio_unmapped;
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ uint8 cpu_version;
|
|||
virtual bool interlace() = 0;
|
||||
virtual bool interlace_field() = 0;
|
||||
virtual bool overscan() = 0;
|
||||
virtual uint16 region_scanlines() = 0;
|
||||
virtual void set_interlace(bool r) = 0;
|
||||
virtual void set_overscan (bool r) = 0;
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ private:
|
|||
inline bool operator ^= (bool i) { if(i)_b ^= B; return (_b & B); }
|
||||
};
|
||||
public:
|
||||
union {
|
||||
union {
|
||||
uint8 _b;
|
||||
bit<0x80> n;
|
||||
bit<0x40> v;
|
||||
|
@ -23,7 +23,7 @@ public:
|
|||
bit<0x04> i;
|
||||
bit<0x02> z;
|
||||
bit<0x01> c;
|
||||
};
|
||||
};
|
||||
|
||||
CPURegFlags() { _b = 0; }
|
||||
inline operator uint8() { return _b; }
|
||||
|
@ -35,10 +35,14 @@ public:
|
|||
|
||||
class CPUReg16 {
|
||||
public:
|
||||
union {
|
||||
union {
|
||||
uint16 w;
|
||||
#ifdef ARCH_LSB
|
||||
struct { uint8 l, h; };
|
||||
};
|
||||
#else
|
||||
struct { uint8 h, l; };
|
||||
#endif;
|
||||
};
|
||||
|
||||
CPUReg16() { w = 0; }
|
||||
inline operator uint16() { return w; }
|
||||
|
@ -56,11 +60,16 @@ public:
|
|||
|
||||
class CPUReg24 {
|
||||
public:
|
||||
union {
|
||||
uint16 w;
|
||||
union {
|
||||
uint32 d;
|
||||
struct { uint8 l, h, b; };
|
||||
};
|
||||
#ifdef ARCH_LSB
|
||||
struct { uint16 w, null_w; };
|
||||
struct { uint8 l, h, b, null_b; };
|
||||
#else
|
||||
struct { uint16 null_w, w; };
|
||||
struct { uint8 null_b, b, h, l; };
|
||||
#endif
|
||||
};
|
||||
|
||||
CPUReg24() { d = 0; }
|
||||
inline operator uint32() { return (d & 0xffffff); }
|
||||
|
|
|
@ -145,7 +145,7 @@ int i, v, n;
|
|||
|
||||
case 0x4c:
|
||||
status.KON = data;
|
||||
status.kon = data;
|
||||
// status.kon = data;
|
||||
status.key_flag = true;
|
||||
break;
|
||||
|
||||
|
@ -221,7 +221,7 @@ int v;
|
|||
status.KOFF = 0x00;
|
||||
status.FLG |= 0xe0;
|
||||
|
||||
status.kon = 0x00;
|
||||
//status.kon = 0x00;
|
||||
status.key_flag = false;
|
||||
|
||||
status.noise_ctr = 0;
|
||||
|
@ -290,17 +290,20 @@ int32 fir_samplel, fir_sampler;
|
|||
|
||||
if(!(dsp_counter++ & 1) && status.key_flag) {
|
||||
for(v=0;v<8;v++) {
|
||||
uint8 mask = 1 << v;
|
||||
if(status.soft_reset()) {
|
||||
if(voice[v].env_state != SILENCE) {
|
||||
voice[v].env_state = SILENCE;
|
||||
voice[v].AdjustEnvelope();
|
||||
}
|
||||
} else if(status.KOFF & (1 << v)) {
|
||||
} else if(status.KOFF & mask) {
|
||||
if(voice[v].env_state != SILENCE && voice[v].env_state != RELEASE) {
|
||||
voice[v].env_state = RELEASE;
|
||||
voice[v].AdjustEnvelope();
|
||||
}
|
||||
} else if(status.kon & (1 << v)) {
|
||||
} else if(status.KON & mask) { //status.kon
|
||||
status.KON &= ~mask; //new code
|
||||
status.ENDX &= ~mask; //new code
|
||||
voice[v].brr_ptr = read_16((status.DIR << 8) + (voice[v].SRCN << 2));
|
||||
voice[v].brr_index = -9;
|
||||
voice[v].brr_looped = false;
|
||||
|
@ -313,8 +316,8 @@ int32 fir_samplel, fir_sampler;
|
|||
voice[v].AdjustEnvelope();
|
||||
}
|
||||
}
|
||||
status.ENDX &= ~status.kon;
|
||||
status.kon = 0;
|
||||
// status.ENDX &= ~status.kon;
|
||||
// status.kon = 0;
|
||||
status.key_flag = false;
|
||||
}
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@ struct Status {
|
|||
int8 FIR[8];
|
||||
|
||||
//internal variables
|
||||
uint8 kon;
|
||||
//uint8 kon;
|
||||
bool key_flag;
|
||||
|
||||
int16 noise_ctr, noise_rate;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#define BSNES_VERSION "0.012"
|
||||
#define BSNES_VERSION "0.013"
|
||||
#define BSNES_TITLE "bsnes v" BSNES_VERSION
|
||||
|
||||
#include "reader/reader.h"
|
||||
|
|
|
@ -32,35 +32,18 @@ void bPPU::scanline() {
|
|||
}
|
||||
|
||||
void bPPU::render_scanline() {
|
||||
//only allow frameskip setting to ignore actual rendering; not RTO, etc.
|
||||
if(settings.frameskip_pos != 0)return;
|
||||
if(status.render_output == false)return;
|
||||
|
||||
if(_y > 0 && _y < (cpu->overscan() ? 239 : 224)) {
|
||||
render_line();
|
||||
}
|
||||
}
|
||||
|
||||
bool bPPU::render_frame() { return (settings.frameskip_pos == 0); }
|
||||
|
||||
void bPPU::frame() {
|
||||
if(settings.frameskip_changed == true) {
|
||||
settings.frameskip_changed = false;
|
||||
settings.frameskip_pos = 0;
|
||||
} else {
|
||||
settings.frameskip_pos++;
|
||||
settings.frameskip_pos %= (settings.frameskip + 1);
|
||||
}
|
||||
|
||||
if(settings.frameskip_pos != 0)return;
|
||||
|
||||
PPU::frame();
|
||||
snes->notify(SNES::RENDER_FRAME);
|
||||
}
|
||||
|
||||
void bPPU::set_frameskip(int fs) {
|
||||
settings.frameskip = fs;
|
||||
settings.frameskip_changed = true;
|
||||
}
|
||||
|
||||
void bPPU::power() {
|
||||
memset(vram, 0, 65536);
|
||||
memset(oam, 0, 544);
|
||||
|
@ -162,30 +145,33 @@ void bPPU::reset() {
|
|||
regs.cgram_addr = 0x0000;
|
||||
|
||||
//$2123-$2125
|
||||
regs.bg_window1_enabled[BG1] = false;
|
||||
regs.bg_window1_enabled[BG2] = false;
|
||||
regs.bg_window1_enabled[BG3] = false;
|
||||
regs.bg_window1_enabled[BG4] = false;
|
||||
regs.bg_window1_enabled[OAM] = false;
|
||||
regs.bg_window1_invert [BG1] = false;
|
||||
regs.bg_window1_invert [BG2] = false;
|
||||
regs.bg_window1_invert [BG3] = false;
|
||||
regs.bg_window1_invert [BG4] = false;
|
||||
regs.bg_window1_invert [OAM] = false;
|
||||
regs.bg_window2_enabled[BG1] = false;
|
||||
regs.bg_window2_enabled[BG2] = false;
|
||||
regs.bg_window2_enabled[BG3] = false;
|
||||
regs.bg_window2_enabled[BG4] = false;
|
||||
regs.bg_window2_enabled[OAM] = false;
|
||||
regs.bg_window2_invert [BG1] = false;
|
||||
regs.bg_window2_invert [BG2] = false;
|
||||
regs.bg_window2_invert [BG3] = false;
|
||||
regs.bg_window2_invert [BG4] = false;
|
||||
regs.bg_window2_invert [OAM] = false;
|
||||
regs.color_window1_enabled = false;
|
||||
regs.color_window1_invert = false;
|
||||
regs.color_window2_enabled = false;
|
||||
regs.color_window2_invert = false;
|
||||
regs.window1_enabled[BG1] = false;
|
||||
regs.window1_enabled[BG2] = false;
|
||||
regs.window1_enabled[BG3] = false;
|
||||
regs.window1_enabled[BG4] = false;
|
||||
regs.window1_enabled[OAM] = false;
|
||||
regs.window1_enabled[COL] = false;
|
||||
|
||||
regs.window1_invert [BG1] = false;
|
||||
regs.window1_invert [BG2] = false;
|
||||
regs.window1_invert [BG3] = false;
|
||||
regs.window1_invert [BG4] = false;
|
||||
regs.window1_invert [OAM] = false;
|
||||
regs.window1_invert [COL] = false;
|
||||
|
||||
regs.window2_enabled[BG1] = false;
|
||||
regs.window2_enabled[BG2] = false;
|
||||
regs.window2_enabled[BG3] = false;
|
||||
regs.window2_enabled[BG4] = false;
|
||||
regs.window2_enabled[OAM] = false;
|
||||
regs.window2_enabled[COL] = false;
|
||||
|
||||
regs.window2_invert [BG1] = false;
|
||||
regs.window2_invert [BG2] = false;
|
||||
regs.window2_invert [BG3] = false;
|
||||
regs.window2_invert [BG4] = false;
|
||||
regs.window2_invert [OAM] = false;
|
||||
regs.window2_invert [COL] = false;
|
||||
|
||||
//$2126-$2129
|
||||
regs.window1_left = 0;
|
||||
|
@ -194,12 +180,12 @@ void bPPU::reset() {
|
|||
regs.window2_right = 0;
|
||||
|
||||
//$212a-$212b
|
||||
regs.bg_window_mask[BG1] = 0;
|
||||
regs.bg_window_mask[BG2] = 0;
|
||||
regs.bg_window_mask[BG3] = 0;
|
||||
regs.bg_window_mask[BG4] = 0;
|
||||
regs.bg_window_mask[OAM] = 0;
|
||||
regs.color_window_mask = 0;
|
||||
regs.window_mask[BG1] = 0;
|
||||
regs.window_mask[BG2] = 0;
|
||||
regs.window_mask[BG3] = 0;
|
||||
regs.window_mask[BG4] = 0;
|
||||
regs.window_mask[OAM] = 0;
|
||||
regs.window_mask[COL] = 0;
|
||||
|
||||
//$212c-$212d
|
||||
regs.bg_enabled[BG1] = false;
|
||||
|
@ -214,16 +200,16 @@ void bPPU::reset() {
|
|||
regs.bgsub_enabled[OAM] = false;
|
||||
|
||||
//$212e-$212f
|
||||
regs.bg_window_enabled[BG1] = false;
|
||||
regs.bg_window_enabled[BG2] = false;
|
||||
regs.bg_window_enabled[BG3] = false;
|
||||
regs.bg_window_enabled[BG4] = false;
|
||||
regs.bg_window_enabled[OAM] = false;
|
||||
regs.bgsub_window_enabled[BG1] = false;
|
||||
regs.bgsub_window_enabled[BG2] = false;
|
||||
regs.bgsub_window_enabled[BG3] = false;
|
||||
regs.bgsub_window_enabled[BG4] = false;
|
||||
regs.bgsub_window_enabled[OAM] = false;
|
||||
regs.window_enabled[BG1] = false;
|
||||
regs.window_enabled[BG2] = false;
|
||||
regs.window_enabled[BG3] = false;
|
||||
regs.window_enabled[BG4] = false;
|
||||
regs.window_enabled[OAM] = false;
|
||||
regs.sub_window_enabled[BG1] = false;
|
||||
regs.sub_window_enabled[BG2] = false;
|
||||
regs.sub_window_enabled[BG3] = false;
|
||||
regs.sub_window_enabled[BG4] = false;
|
||||
regs.sub_window_enabled[OAM] = false;
|
||||
|
||||
//$2130
|
||||
regs.color_mask = 0;
|
||||
|
@ -231,14 +217,14 @@ void bPPU::reset() {
|
|||
regs.addsub_mode = 0;
|
||||
|
||||
//$2131
|
||||
regs.color_mode = 0;
|
||||
regs.color_halve = false;
|
||||
regs.bg_color_enabled[BACK] = false;
|
||||
regs.bg_color_enabled[OAM] = false;
|
||||
regs.bg_color_enabled[BG4] = false;
|
||||
regs.bg_color_enabled[BG3] = false;
|
||||
regs.bg_color_enabled[BG2] = false;
|
||||
regs.bg_color_enabled[BG1] = false;
|
||||
regs.color_mode = 0;
|
||||
regs.color_halve = false;
|
||||
regs.color_enabled[BACK] = false;
|
||||
regs.color_enabled[OAM] = false;
|
||||
regs.color_enabled[BG4] = false;
|
||||
regs.color_enabled[BG3] = false;
|
||||
regs.color_enabled[BG2] = false;
|
||||
regs.color_enabled[BG1] = false;
|
||||
|
||||
//$2132
|
||||
regs.color_r = 0x00;
|
||||
|
@ -266,8 +252,10 @@ void bPPU::reset() {
|
|||
regs.time_over = false;
|
||||
regs.range_over = false;
|
||||
|
||||
_screen_width = 256; //needed for clear_window_cache()
|
||||
update_sprite_list_sizes();
|
||||
clear_tiledata_cache();
|
||||
clear_window_cache();
|
||||
}
|
||||
|
||||
uint8 bPPU::vram_read(uint16 addr) {
|
||||
|
@ -318,10 +306,6 @@ void bPPU::cgram_write(uint16 addr, uint8 value) {
|
|||
}
|
||||
|
||||
bPPU::bPPU() {
|
||||
settings.frameskip = 0;
|
||||
settings.frameskip_pos = 0;
|
||||
settings.frameskip_changed = false;
|
||||
|
||||
mmio = new bPPUMMIO(this);
|
||||
|
||||
vram = (uint8*)malloc(65536);
|
||||
|
|
|
@ -14,7 +14,7 @@ uint8 *vram, *oam, *cgram;
|
|||
uint8 region;
|
||||
|
||||
enum { NTSC = 0, PAL = 1 };
|
||||
enum { BG1 = 0, BG2 = 1, BG3 = 2, BG4 = 3, OAM = 4, BACK = 5 };
|
||||
enum { BG1 = 0, BG2 = 1, BG3 = 2, BG4 = 3, OAM = 4, BACK = 5, COL = 5 };
|
||||
enum { SC_32x32 = 0, SC_32x64 = 1, SC_64x32 = 2, SC_64x64 = 3 };
|
||||
|
||||
struct sprite_item {
|
||||
|
@ -27,11 +27,6 @@ struct sprite_item {
|
|||
uint8 priority;
|
||||
} sprite_list[128];
|
||||
|
||||
struct {
|
||||
int32 frameskip, frameskip_pos;
|
||||
bool frameskip_changed;
|
||||
} settings;
|
||||
|
||||
struct {
|
||||
//open bus support
|
||||
uint8 ppu1_mdr, ppu2_mdr;
|
||||
|
@ -95,26 +90,23 @@ struct {
|
|||
uint16 cgram_addr;
|
||||
|
||||
//$2123-$2125
|
||||
bool bg_window1_enabled[5];
|
||||
bool bg_window1_invert [5];
|
||||
bool bg_window2_enabled[5];
|
||||
bool bg_window2_invert [5];
|
||||
bool color_window1_enabled, color_window1_invert;
|
||||
bool color_window2_enabled, color_window2_invert;
|
||||
bool window1_enabled[6];
|
||||
bool window1_invert [6];
|
||||
bool window2_enabled[6];
|
||||
bool window2_invert [6];
|
||||
|
||||
//$2126-$2129
|
||||
uint8 window1_left, window1_right;
|
||||
uint8 window2_left, window2_right;
|
||||
|
||||
//$212a-$212b
|
||||
uint8 bg_window_mask[5];
|
||||
uint8 color_window_mask;
|
||||
uint8 window_mask[6];
|
||||
|
||||
//$212c-$212d
|
||||
bool bg_enabled[5], bgsub_enabled[5];
|
||||
|
||||
//$212e-$212f
|
||||
bool bg_window_enabled[5], bgsub_window_enabled[5];
|
||||
bool window_enabled[5], sub_window_enabled[5];
|
||||
|
||||
//$2130
|
||||
uint8 color_mask, colorsub_mask;
|
||||
|
@ -123,7 +115,7 @@ struct {
|
|||
|
||||
//$2131
|
||||
bool color_mode, color_halve;
|
||||
bool bg_color_enabled[6];
|
||||
bool color_enabled[6];
|
||||
|
||||
//$2132
|
||||
uint8 color_r, color_g, color_b;
|
||||
|
@ -158,6 +150,8 @@ struct {
|
|||
void update_sprite_list(uint16 addr);
|
||||
void update_sprite_list_sizes();
|
||||
uint16 get_vram_address();
|
||||
bool vram_can_read();
|
||||
bool vram_can_write(uint8 &value);
|
||||
|
||||
void mmio_w2100(uint8 value); //INIDISP
|
||||
void mmio_w2101(uint8 value); //OBSEL
|
||||
|
@ -242,8 +236,6 @@ uint16 *mosaic_table[16];
|
|||
void frame();
|
||||
void power();
|
||||
void reset();
|
||||
void set_frameskip(int fs);
|
||||
bool render_frame();
|
||||
|
||||
bool scanline_is_hires() { return (regs.bg_mode == 5 || regs.bg_mode == 6); }
|
||||
|
||||
|
|
|
@ -16,6 +16,55 @@ uint16 addr;
|
|||
return (addr << 1);
|
||||
}
|
||||
|
||||
bool bPPU::vram_can_read() {
|
||||
if(regs.display_disabled == true) {
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16 v = cpu->vcounter();
|
||||
uint16 hc = cpu->hcycles();
|
||||
uint16 ls;
|
||||
if(cpu->interlace() && !cpu->interlace_field()) {
|
||||
ls = cpu->region_scanlines();
|
||||
} else {
|
||||
ls = cpu->region_scanlines() - 1;
|
||||
}
|
||||
|
||||
if(v == ls && hc == 1362)return false;
|
||||
|
||||
if(v < (cpu->overscan() ? 239 : 224))return false;
|
||||
|
||||
if(v == (cpu->overscan() ? 239 : 224)) {
|
||||
if(hc == 1362)return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bPPU::vram_can_write(uint8 &value) {
|
||||
if(regs.display_disabled == true) {
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16 v = cpu->vcounter();
|
||||
uint16 hc = cpu->hcycles();
|
||||
if(v == 0) {
|
||||
if(hc <= 4)return true;
|
||||
if(hc == 6) { value = cpu->regs.mdr; return true; }
|
||||
return false;
|
||||
}
|
||||
|
||||
if(v < (cpu->overscan() ? 240 : 225))return false;
|
||||
|
||||
if(v == (cpu->overscan() ? 240 : 225)) {
|
||||
if(hc <= 4)return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//INIDISP
|
||||
void bPPU::mmio_w2100(uint8 value) {
|
||||
regs.display_disabled = !!(value & 0x80);
|
||||
|
@ -68,6 +117,13 @@ void bPPU::mmio_w2105(uint8 value) {
|
|||
regs.bg_tilesize[BG1] = !!(value & 0x10);
|
||||
regs.bg3_priority = !!(value & 0x08);
|
||||
regs.bg_mode = (value & 7);
|
||||
|
||||
window_cache[BG1].main_dirty = window_cache[BG1].sub_dirty = true;
|
||||
window_cache[BG2].main_dirty = window_cache[BG2].sub_dirty = true;
|
||||
window_cache[BG3].main_dirty = window_cache[BG3].sub_dirty = true;
|
||||
window_cache[BG4].main_dirty = window_cache[BG4].sub_dirty = true;
|
||||
window_cache[OAM].main_dirty = window_cache[OAM].sub_dirty = true;
|
||||
window_cache[COL].main_dirty = window_cache[COL].sub_dirty = true;
|
||||
}
|
||||
|
||||
//MOSAIC
|
||||
|
@ -185,40 +241,54 @@ void bPPU::mmio_w2115(uint8 value) {
|
|||
void bPPU::mmio_w2116(uint8 value) {
|
||||
regs.vram_addr = (regs.vram_addr & 0xff00) | value;
|
||||
uint16 addr = get_vram_address();
|
||||
regs.vram_readbuffer = vram_read(addr);
|
||||
regs.vram_readbuffer |= vram_read(addr + 1) << 8;
|
||||
if(vram_can_read()) {
|
||||
regs.vram_readbuffer = vram_read(addr);
|
||||
regs.vram_readbuffer |= vram_read(addr + 1) << 8;
|
||||
} else {
|
||||
regs.vram_readbuffer = 0x0000;
|
||||
}
|
||||
}
|
||||
|
||||
//VMADDH
|
||||
void bPPU::mmio_w2117(uint8 value) {
|
||||
regs.vram_addr = (value << 8) | (regs.vram_addr & 0x00ff);
|
||||
uint16 addr = get_vram_address();
|
||||
regs.vram_readbuffer = vram_read(addr);
|
||||
regs.vram_readbuffer |= vram_read(addr + 1) << 8;
|
||||
if(vram_can_read()) {
|
||||
regs.vram_readbuffer = vram_read(addr);
|
||||
regs.vram_readbuffer |= vram_read(addr + 1) << 8;
|
||||
} else {
|
||||
regs.vram_readbuffer = 0x0000;
|
||||
}
|
||||
}
|
||||
|
||||
//VMDATAL
|
||||
void bPPU::mmio_w2118(uint8 value) {
|
||||
uint16 addr = get_vram_address();
|
||||
vram_write(addr, value);
|
||||
if(vram_can_write(value)) {
|
||||
vram_write(addr, value);
|
||||
bg_tiledata_state[TILE_2BIT][(addr >> 4)] = 1;
|
||||
bg_tiledata_state[TILE_4BIT][(addr >> 5)] = 1;
|
||||
bg_tiledata_state[TILE_8BIT][(addr >> 6)] = 1;
|
||||
}
|
||||
|
||||
if(regs.vram_incmode == 0) {
|
||||
regs.vram_addr += regs.vram_incsize;
|
||||
}
|
||||
bg_tiledata_state[TILE_2BIT][(addr >> 4)] = 1;
|
||||
bg_tiledata_state[TILE_4BIT][(addr >> 5)] = 1;
|
||||
bg_tiledata_state[TILE_8BIT][(addr >> 6)] = 1;
|
||||
}
|
||||
|
||||
//VMDATAH
|
||||
void bPPU::mmio_w2119(uint8 value) {
|
||||
uint16 addr = get_vram_address() + 1;
|
||||
vram_write(addr, value);
|
||||
if(vram_can_write(value)) {
|
||||
vram_write(addr, value);
|
||||
bg_tiledata_state[TILE_2BIT][(addr >> 4)] = 1;
|
||||
bg_tiledata_state[TILE_4BIT][(addr >> 5)] = 1;
|
||||
bg_tiledata_state[TILE_8BIT][(addr >> 6)] = 1;
|
||||
}
|
||||
|
||||
if(regs.vram_incmode == 1) {
|
||||
regs.vram_addr += regs.vram_incsize;
|
||||
}
|
||||
bg_tiledata_state[TILE_2BIT][(addr >> 4)] = 1;
|
||||
bg_tiledata_state[TILE_4BIT][(addr >> 5)] = 1;
|
||||
bg_tiledata_state[TILE_8BIT][(addr >> 6)] = 1;
|
||||
}
|
||||
|
||||
//M7SEL
|
||||
|
@ -284,72 +354,117 @@ void bPPU::mmio_w2122(uint8 value) {
|
|||
|
||||
//W12SEL
|
||||
void bPPU::mmio_w2123(uint8 value) {
|
||||
regs.bg_window2_enabled[BG2] = !!(value & 0x80);
|
||||
regs.bg_window2_invert [BG2] = !!(value & 0x40);
|
||||
regs.bg_window1_enabled[BG2] = !!(value & 0x20);
|
||||
regs.bg_window1_invert [BG2] = !!(value & 0x10);
|
||||
regs.bg_window2_enabled[BG1] = !!(value & 0x08);
|
||||
regs.bg_window2_invert [BG1] = !!(value & 0x04);
|
||||
regs.bg_window1_enabled[BG1] = !!(value & 0x02);
|
||||
regs.bg_window1_invert [BG1] = !!(value & 0x01);
|
||||
regs.window2_enabled[BG2] = !!(value & 0x80);
|
||||
regs.window2_invert [BG2] = !!(value & 0x40);
|
||||
regs.window1_enabled[BG2] = !!(value & 0x20);
|
||||
regs.window1_invert [BG2] = !!(value & 0x10);
|
||||
regs.window2_enabled[BG1] = !!(value & 0x08);
|
||||
regs.window2_invert [BG1] = !!(value & 0x04);
|
||||
regs.window1_enabled[BG1] = !!(value & 0x02);
|
||||
regs.window1_invert [BG1] = !!(value & 0x01);
|
||||
|
||||
window_cache[BG1].main_dirty = window_cache[BG1].sub_dirty = true;
|
||||
window_cache[BG2].main_dirty = window_cache[BG2].sub_dirty = true;
|
||||
}
|
||||
|
||||
//W34SEL
|
||||
void bPPU::mmio_w2124(uint8 value) {
|
||||
regs.bg_window2_enabled[BG4] = !!(value & 0x80);
|
||||
regs.bg_window2_invert [BG4] = !!(value & 0x40);
|
||||
regs.bg_window1_enabled[BG4] = !!(value & 0x20);
|
||||
regs.bg_window1_invert [BG4] = !!(value & 0x10);
|
||||
regs.bg_window2_enabled[BG3] = !!(value & 0x08);
|
||||
regs.bg_window2_invert [BG3] = !!(value & 0x04);
|
||||
regs.bg_window1_enabled[BG3] = !!(value & 0x02);
|
||||
regs.bg_window1_invert [BG3] = !!(value & 0x01);
|
||||
regs.window2_enabled[BG4] = !!(value & 0x80);
|
||||
regs.window2_invert [BG4] = !!(value & 0x40);
|
||||
regs.window1_enabled[BG4] = !!(value & 0x20);
|
||||
regs.window1_invert [BG4] = !!(value & 0x10);
|
||||
regs.window2_enabled[BG3] = !!(value & 0x08);
|
||||
regs.window2_invert [BG3] = !!(value & 0x04);
|
||||
regs.window1_enabled[BG3] = !!(value & 0x02);
|
||||
regs.window1_invert [BG3] = !!(value & 0x01);
|
||||
|
||||
window_cache[BG3].main_dirty = window_cache[BG3].sub_dirty = true;
|
||||
window_cache[BG4].main_dirty = window_cache[BG4].sub_dirty = true;
|
||||
}
|
||||
|
||||
//WOBJSEL
|
||||
void bPPU::mmio_w2125(uint8 value) {
|
||||
regs.color_window2_enabled = !!(value & 0x80);
|
||||
regs.color_window2_invert = !!(value & 0x40);
|
||||
regs.color_window1_enabled = !!(value & 0x20);
|
||||
regs.color_window1_invert = !!(value & 0x10);
|
||||
regs.bg_window2_enabled[OAM] = !!(value & 0x08);
|
||||
regs.bg_window2_invert [OAM] = !!(value & 0x04);
|
||||
regs.bg_window1_enabled[OAM] = !!(value & 0x02);
|
||||
regs.bg_window1_invert [OAM] = !!(value & 0x01);
|
||||
regs.window2_enabled[COL] = !!(value & 0x80);
|
||||
regs.window2_invert [COL] = !!(value & 0x40);
|
||||
regs.window1_enabled[COL] = !!(value & 0x20);
|
||||
regs.window1_invert [COL] = !!(value & 0x10);
|
||||
regs.window2_enabled[OAM] = !!(value & 0x08);
|
||||
regs.window2_invert [OAM] = !!(value & 0x04);
|
||||
regs.window1_enabled[OAM] = !!(value & 0x02);
|
||||
regs.window1_invert [OAM] = !!(value & 0x01);
|
||||
|
||||
window_cache[OAM].main_dirty = window_cache[OAM].sub_dirty = true;
|
||||
window_cache[COL].main_dirty = window_cache[COL].sub_dirty = true;
|
||||
}
|
||||
|
||||
//WH0
|
||||
void bPPU::mmio_w2126(uint8 value) {
|
||||
regs.window1_left = value;
|
||||
|
||||
window_cache[BG1].main_dirty = window_cache[BG1].sub_dirty = true;
|
||||
window_cache[BG2].main_dirty = window_cache[BG2].sub_dirty = true;
|
||||
window_cache[BG3].main_dirty = window_cache[BG3].sub_dirty = true;
|
||||
window_cache[BG4].main_dirty = window_cache[BG4].sub_dirty = true;
|
||||
window_cache[OAM].main_dirty = window_cache[OAM].sub_dirty = true;
|
||||
window_cache[COL].main_dirty = window_cache[COL].sub_dirty = true;
|
||||
}
|
||||
|
||||
//WH1
|
||||
void bPPU::mmio_w2127(uint8 value) {
|
||||
regs.window1_right = value;
|
||||
|
||||
window_cache[BG1].main_dirty = window_cache[BG1].sub_dirty = true;
|
||||
window_cache[BG2].main_dirty = window_cache[BG2].sub_dirty = true;
|
||||
window_cache[BG3].main_dirty = window_cache[BG3].sub_dirty = true;
|
||||
window_cache[BG4].main_dirty = window_cache[BG4].sub_dirty = true;
|
||||
window_cache[OAM].main_dirty = window_cache[OAM].sub_dirty = true;
|
||||
window_cache[COL].main_dirty = window_cache[COL].sub_dirty = true;
|
||||
}
|
||||
|
||||
//WH2
|
||||
void bPPU::mmio_w2128(uint8 value) {
|
||||
regs.window2_left = value;
|
||||
|
||||
window_cache[BG1].main_dirty = window_cache[BG1].sub_dirty = true;
|
||||
window_cache[BG2].main_dirty = window_cache[BG2].sub_dirty = true;
|
||||
window_cache[BG3].main_dirty = window_cache[BG3].sub_dirty = true;
|
||||
window_cache[BG4].main_dirty = window_cache[BG4].sub_dirty = true;
|
||||
window_cache[OAM].main_dirty = window_cache[OAM].sub_dirty = true;
|
||||
window_cache[COL].main_dirty = window_cache[COL].sub_dirty = true;
|
||||
}
|
||||
|
||||
//WH3
|
||||
void bPPU::mmio_w2129(uint8 value) {
|
||||
regs.window2_right = value;
|
||||
|
||||
window_cache[BG1].main_dirty = window_cache[BG1].sub_dirty = true;
|
||||
window_cache[BG2].main_dirty = window_cache[BG2].sub_dirty = true;
|
||||
window_cache[BG3].main_dirty = window_cache[BG3].sub_dirty = true;
|
||||
window_cache[BG4].main_dirty = window_cache[BG4].sub_dirty = true;
|
||||
window_cache[OAM].main_dirty = window_cache[OAM].sub_dirty = true;
|
||||
window_cache[COL].main_dirty = window_cache[COL].sub_dirty = true;
|
||||
}
|
||||
|
||||
//WBGLOG
|
||||
void bPPU::mmio_w212a(uint8 value) {
|
||||
regs.bg_window_mask[BG4] = (value >> 6) & 3;
|
||||
regs.bg_window_mask[BG3] = (value >> 4) & 3;
|
||||
regs.bg_window_mask[BG2] = (value >> 2) & 3;
|
||||
regs.bg_window_mask[BG1] = (value ) & 3;
|
||||
regs.window_mask[BG4] = (value >> 6) & 3;
|
||||
regs.window_mask[BG3] = (value >> 4) & 3;
|
||||
regs.window_mask[BG2] = (value >> 2) & 3;
|
||||
regs.window_mask[BG1] = (value ) & 3;
|
||||
|
||||
window_cache[BG1].main_dirty = window_cache[BG1].sub_dirty = true;
|
||||
window_cache[BG2].main_dirty = window_cache[BG2].sub_dirty = true;
|
||||
window_cache[BG3].main_dirty = window_cache[BG3].sub_dirty = true;
|
||||
window_cache[BG4].main_dirty = window_cache[BG4].sub_dirty = true;
|
||||
}
|
||||
|
||||
//WOBJLOG
|
||||
void bPPU::mmio_w212b(uint8 value) {
|
||||
regs.color_window_mask = (value >> 2) & 3;
|
||||
regs.bg_window_mask[OAM] = (value ) & 3;
|
||||
regs.window_mask[COL] = (value >> 2) & 3;
|
||||
regs.window_mask[OAM] = (value ) & 3;
|
||||
|
||||
window_cache[OAM].main_dirty = window_cache[OAM].sub_dirty = true;
|
||||
window_cache[COL].main_dirty = window_cache[COL].sub_dirty = true;
|
||||
}
|
||||
|
||||
//TM
|
||||
|
@ -372,20 +487,32 @@ void bPPU::mmio_w212d(uint8 value) {
|
|||
|
||||
//TMW
|
||||
void bPPU::mmio_w212e(uint8 value) {
|
||||
regs.bg_window_enabled[OAM] = !!(value & 0x10);
|
||||
regs.bg_window_enabled[BG4] = !!(value & 0x08);
|
||||
regs.bg_window_enabled[BG3] = !!(value & 0x04);
|
||||
regs.bg_window_enabled[BG2] = !!(value & 0x02);
|
||||
regs.bg_window_enabled[BG1] = !!(value & 0x01);
|
||||
regs.window_enabled[OAM] = !!(value & 0x10);
|
||||
regs.window_enabled[BG4] = !!(value & 0x08);
|
||||
regs.window_enabled[BG3] = !!(value & 0x04);
|
||||
regs.window_enabled[BG2] = !!(value & 0x02);
|
||||
regs.window_enabled[BG1] = !!(value & 0x01);
|
||||
|
||||
window_cache[BG1].main_dirty = window_cache[BG1].sub_dirty = true;
|
||||
window_cache[BG2].main_dirty = window_cache[BG2].sub_dirty = true;
|
||||
window_cache[BG3].main_dirty = window_cache[BG3].sub_dirty = true;
|
||||
window_cache[BG4].main_dirty = window_cache[BG4].sub_dirty = true;
|
||||
window_cache[OAM].main_dirty = window_cache[OAM].sub_dirty = true;
|
||||
}
|
||||
|
||||
//TSW
|
||||
void bPPU::mmio_w212f(uint8 value) {
|
||||
regs.bgsub_window_enabled[OAM] = !!(value & 0x10);
|
||||
regs.bgsub_window_enabled[BG4] = !!(value & 0x08);
|
||||
regs.bgsub_window_enabled[BG3] = !!(value & 0x04);
|
||||
regs.bgsub_window_enabled[BG2] = !!(value & 0x02);
|
||||
regs.bgsub_window_enabled[BG1] = !!(value & 0x01);
|
||||
regs.sub_window_enabled[OAM] = !!(value & 0x10);
|
||||
regs.sub_window_enabled[BG4] = !!(value & 0x08);
|
||||
regs.sub_window_enabled[BG3] = !!(value & 0x04);
|
||||
regs.sub_window_enabled[BG2] = !!(value & 0x02);
|
||||
regs.sub_window_enabled[BG1] = !!(value & 0x01);
|
||||
|
||||
window_cache[BG1].main_dirty = window_cache[BG1].sub_dirty = true;
|
||||
window_cache[BG2].main_dirty = window_cache[BG2].sub_dirty = true;
|
||||
window_cache[BG3].main_dirty = window_cache[BG3].sub_dirty = true;
|
||||
window_cache[BG4].main_dirty = window_cache[BG4].sub_dirty = true;
|
||||
window_cache[OAM].main_dirty = window_cache[OAM].sub_dirty = true;
|
||||
}
|
||||
|
||||
//CGWSEL
|
||||
|
@ -394,18 +521,20 @@ void bPPU::mmio_w2130(uint8 value) {
|
|||
regs.colorsub_mask = (value >> 4) & 3;
|
||||
regs.addsub_mode = !!(value & 0x02);
|
||||
regs.direct_color = !!(value & 0x01);
|
||||
|
||||
window_cache[COL].main_dirty = window_cache[COL].sub_dirty = true;
|
||||
}
|
||||
|
||||
//CGADDSUB
|
||||
void bPPU::mmio_w2131(uint8 value) {
|
||||
regs.color_mode = !!(value & 0x80);
|
||||
regs.color_halve = !!(value & 0x40);
|
||||
regs.bg_color_enabled[BACK] = !!(value & 0x20);
|
||||
regs.bg_color_enabled[OAM] = !!(value & 0x10);
|
||||
regs.bg_color_enabled[BG4] = !!(value & 0x08);
|
||||
regs.bg_color_enabled[BG3] = !!(value & 0x04);
|
||||
regs.bg_color_enabled[BG2] = !!(value & 0x02);
|
||||
regs.bg_color_enabled[BG1] = !!(value & 0x01);
|
||||
regs.color_mode = !!(value & 0x80);
|
||||
regs.color_halve = !!(value & 0x40);
|
||||
regs.color_enabled[BACK] = !!(value & 0x20);
|
||||
regs.color_enabled[OAM] = !!(value & 0x10);
|
||||
regs.color_enabled[BG4] = !!(value & 0x08);
|
||||
regs.color_enabled[BG3] = !!(value & 0x04);
|
||||
regs.color_enabled[BG2] = !!(value & 0x02);
|
||||
regs.color_enabled[BG1] = !!(value & 0x01);
|
||||
}
|
||||
|
||||
//COLDATA
|
||||
|
@ -476,8 +605,12 @@ uint16 addr = get_vram_address();
|
|||
regs.ppu1_mdr = regs.vram_readbuffer;
|
||||
if(regs.vram_incmode == 0) {
|
||||
addr &= 0xfffe;
|
||||
regs.vram_readbuffer = vram_read(addr);
|
||||
regs.vram_readbuffer |= vram_read(addr + 1) << 8;
|
||||
if(vram_can_read()) {
|
||||
regs.vram_readbuffer = vram_read(addr);
|
||||
regs.vram_readbuffer |= vram_read(addr + 1) << 8;
|
||||
} else {
|
||||
regs.vram_readbuffer = 0x0000;
|
||||
}
|
||||
regs.vram_addr += regs.vram_incsize;
|
||||
}
|
||||
return regs.ppu1_mdr;
|
||||
|
@ -489,8 +622,12 @@ uint16 addr = get_vram_address() + 1;
|
|||
regs.ppu1_mdr = regs.vram_readbuffer >> 8;
|
||||
if(regs.vram_incmode == 1) {
|
||||
addr &= 0xfffe;
|
||||
regs.vram_readbuffer = vram_read(addr);
|
||||
regs.vram_readbuffer |= vram_read(addr + 1) << 8;
|
||||
if(vram_can_read()) {
|
||||
regs.vram_readbuffer = vram_read(addr);
|
||||
regs.vram_readbuffer |= vram_read(addr + 1) << 8;
|
||||
} else {
|
||||
regs.vram_readbuffer = 0x0000;
|
||||
}
|
||||
regs.vram_addr += regs.vram_incsize;
|
||||
}
|
||||
return regs.ppu1_mdr;
|
||||
|
|
|
@ -126,7 +126,7 @@ void bPPU::render_line() {
|
|||
}
|
||||
|
||||
clear_pixel_cache();
|
||||
build_color_window_tables();
|
||||
build_window_tables(COL);
|
||||
|
||||
switch(regs.bg_mode) {
|
||||
case 0:render_line_mode0();break;
|
||||
|
|
|
@ -35,17 +35,18 @@ uint8 *bg_tiledata_state[3];
|
|||
|
||||
void render_bg_tile(uint8 color_depth, uint16 tile_num);
|
||||
inline void clear_pixel_cache();
|
||||
void init_tiledata_cache();
|
||||
void clear_tiledata_cache();
|
||||
inline void init_tiledata_cache();
|
||||
inline void clear_tiledata_cache();
|
||||
|
||||
//bppu_render_windows.cpp
|
||||
uint8 main_windowtable[5][512], sub_windowtable[5][512],
|
||||
main_colorwindowtable[512], sub_colorwindowtable[512];
|
||||
struct _window {
|
||||
bool main_dirty, sub_dirty;
|
||||
uint8 main[512], sub[512];
|
||||
} window_cache[6];
|
||||
|
||||
void build_window_table(uint8 bg, uint8 *wtbl, bool mainscreen);
|
||||
void build_window_table(uint8 bg, bool mainscreen);
|
||||
void build_window_tables(uint8 bg);
|
||||
void build_color_window_table(uint8 *wtbl, uint8 mask);
|
||||
void build_color_window_tables();
|
||||
inline void clear_window_cache();
|
||||
|
||||
//bppu_render_bg.cpp
|
||||
void render_line_bg(uint8 bg, uint8 color_depth, uint8 pri0_pos, uint8 pri1_pos);
|
||||
|
|
|
@ -118,8 +118,8 @@ int xpos, ypos;
|
|||
uint16 map_index, hoffset, voffset, col;
|
||||
|
||||
build_window_tables(bg);
|
||||
uint8 *wt_main = main_windowtable[bg];
|
||||
uint8 *wt_sub = sub_windowtable[bg];
|
||||
uint8 *wt_main = window_cache[bg].main;
|
||||
uint8 *wt_sub = window_cache[bg].sub;
|
||||
|
||||
screen_x = 0;
|
||||
do { //for(screen_x=0;screen_x<_screen_width;screen_x++) {
|
||||
|
@ -141,7 +141,7 @@ uint8 *wt_sub = sub_windowtable[bg];
|
|||
|
||||
if(regs.bg_mode == 4) {
|
||||
pos = regs.bg_scaddr[BG3] + tile_x;
|
||||
t = *((uint16*)vram + (pos >> 1));
|
||||
t = read16(vram, pos);
|
||||
if(t & opt_valid_bit) {
|
||||
if(!(t & 0x8000)) {
|
||||
hoffset = ((t & 0x1ff8) | (hscroll & 7)) & screen_width_mask;
|
||||
|
@ -151,12 +151,12 @@ uint8 *wt_sub = sub_windowtable[bg];
|
|||
}
|
||||
} else {
|
||||
pos = regs.bg_scaddr[BG3] + tile_x;
|
||||
t = *((uint16*)vram + (pos >> 1));
|
||||
t = read16(vram, pos);
|
||||
if(t & opt_valid_bit) {
|
||||
hoffset = ((t & 0x1ff8) | (hscroll & 7)) & screen_width_mask;
|
||||
}
|
||||
pos = regs.bg_scaddr[BG3] + 64 + tile_x;
|
||||
t = *((uint16*)vram + (pos >> 1));
|
||||
t = read16(vram, pos);
|
||||
if(t & opt_valid_bit) {
|
||||
voffset = (t & 0x1fff) & screen_height_mask;
|
||||
}
|
||||
|
@ -186,7 +186,7 @@ uint8 *wt_sub = sub_windowtable[bg];
|
|||
base_xpos = ((mosaic_x >> 3) & 31);
|
||||
base_pos = (((mosaic_y >> tile_height) & 31) << 5) + ((mosaic_x >> tile_width) & 31);
|
||||
pos = _scaddr + map_index + (base_pos << 1);
|
||||
t = *((uint16*)vram + (pos >> 1));
|
||||
t = read16(vram, pos);
|
||||
mirror_y = !!(t & 0x8000);
|
||||
mirror_x = !!(t & 0x4000);
|
||||
|
||||
|
@ -228,7 +228,7 @@ int _pri;
|
|||
if(mirror_x) { xpos = (7 - (mosaic_x & 7)); }
|
||||
else { xpos = ( (mosaic_x & 7)); }
|
||||
col = *(tile_ptr + xpos);
|
||||
if(col && main_colorwindowtable[screen_x]) {
|
||||
if(col && window_cache[COL].main[screen_x]) {
|
||||
if(regs.direct_color == true && bg == BG1 && (regs.bg_mode == 3 || regs.bg_mode == 4)) {
|
||||
col = get_direct_color(pal_num, col);
|
||||
} else {
|
||||
|
|
|
@ -117,3 +117,17 @@ void bPPU::clear_tiledata_cache() {
|
|||
memset(bg_tiledata_state[TILE_4BIT], 0, 2048);
|
||||
memset(bg_tiledata_state[TILE_8BIT], 0, 1024);
|
||||
}
|
||||
|
||||
void bPPU::clear_window_cache() {
|
||||
for(int i=0;i<6;i++) {
|
||||
window_cache[i].main_dirty = true;
|
||||
window_cache[i].sub_dirty = true;
|
||||
}
|
||||
|
||||
build_window_tables(BG1);
|
||||
build_window_tables(BG2);
|
||||
build_window_tables(BG3);
|
||||
build_window_tables(BG4);
|
||||
build_window_tables(OAM);
|
||||
build_window_tables(COL);
|
||||
}
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
inline uint16 bPPU::get_palette(uint8 index) {
|
||||
return *((uint16*)cgram + index);
|
||||
return read16(cgram, index << 1);
|
||||
}
|
||||
|
||||
inline uint16 bPPU::get_direct_color(uint8 p, uint8 t) {
|
||||
//p = 00000bgr
|
||||
//t = BBGGGRRR
|
||||
//r = 0BBb00GGGg0RRRr0
|
||||
//p = 00000bgr <palette data>
|
||||
//t = BBGGGRRR <tilemap data>
|
||||
//r = 0BBb00GGGg0RRRr0 <return data>
|
||||
return ((t & 7) << 2) | ((p & 1) << 1) |
|
||||
(((t >> 3) & 7) << 7) | (((p >> 1) & 1) << 6) |
|
||||
((t >> 6) << 13) | ((p >> 2) << 12);
|
||||
(((t >> 3) & 7) << 7) | (((p >> 1) & 1) << 6) |
|
||||
((t >> 6) << 13) | ((p >> 2) << 12);
|
||||
}
|
||||
|
||||
inline uint16 bPPU::get_pixel(int x) {
|
||||
_pixel *p = &pixel_cache[x];
|
||||
uint16 _r, src_back = get_palette(0);
|
||||
if(p->bg_main && p->bg_sub) {
|
||||
if(p->color_exempt == false && regs.bg_color_enabled[p->bg_main & 0x7f] && sub_colorwindowtable[x]) {
|
||||
if(p->color_exempt == false && regs.color_enabled[p->bg_main & 0x7f] && window_cache[COL].sub[x]) {
|
||||
if(regs.addsub_mode) {
|
||||
_r = addsub_pixels(p->src_main, p->src_sub);
|
||||
} else {
|
||||
|
@ -25,14 +25,14 @@ uint16 _r, src_back = get_palette(0);
|
|||
_r = p->src_main;
|
||||
}
|
||||
} else if(p->bg_main) {
|
||||
if(p->color_exempt == false && regs.bg_color_enabled[p->bg_main & 0x7f] && sub_colorwindowtable[x]) {
|
||||
if(p->color_exempt == false && regs.color_enabled[p->bg_main & 0x7f] && window_cache[COL].sub[x]) {
|
||||
_r = addsub_pixel(p->src_main);
|
||||
} else {
|
||||
_r = p->src_main;
|
||||
}
|
||||
} else if(p->bg_sub) {
|
||||
if(regs.bg_color_enabled[BACK]) {
|
||||
if(sub_colorwindowtable[x]) {
|
||||
if(regs.color_enabled[BACK]) {
|
||||
if(window_cache[COL].sub[x]) {
|
||||
if(regs.addsub_mode) {
|
||||
_r = addsub_pixels(src_back, p->src_sub);
|
||||
} else {
|
||||
|
@ -42,11 +42,11 @@ uint16 _r, src_back = get_palette(0);
|
|||
_r = src_back;
|
||||
}
|
||||
} else {
|
||||
_r = 0x0000;
|
||||
_r = src_back; //was 0x0000 -- possibly another condition here?
|
||||
}
|
||||
} else {
|
||||
if(main_colorwindowtable[x]) {
|
||||
if(regs.bg_color_enabled[BACK] && sub_colorwindowtable[x]) {
|
||||
if(window_cache[COL].main[x]) {
|
||||
if(regs.color_enabled[BACK] && window_cache[COL].sub[x]) {
|
||||
_r = addsub_pixel(src_back);
|
||||
} else {
|
||||
_r = src_back;
|
||||
|
|
|
@ -31,15 +31,16 @@ int32 tx, ty, tile, palette;
|
|||
cx = (int32(regs.m7x) << 19) >> 19;
|
||||
cy = (int32(regs.m7y) << 19) >> 19;
|
||||
hofs = (int32(regs.m7_hofs) << 19) >> 19;
|
||||
vofs = (int32(regs.m7_vofs + 1) << 19) >> 19;
|
||||
//+1 breaks FF5 title screen mirror alignment...
|
||||
vofs = (int32(regs.m7_vofs + 0) << 19) >> 19;
|
||||
|
||||
int _pri, _x;
|
||||
bool _bg_enabled = regs.bg_enabled[bg];
|
||||
bool _bgsub_enabled = regs.bgsub_enabled[bg];
|
||||
|
||||
build_window_tables(bg);
|
||||
uint8 *wt_main = main_windowtable[bg];
|
||||
uint8 *wt_sub = sub_windowtable[bg];
|
||||
uint8 *wt_main = window_cache[bg].main;
|
||||
uint8 *wt_sub = window_cache[bg].sub;
|
||||
|
||||
if(regs.mode7_vflip == true) {
|
||||
y = 255 - _y;
|
||||
|
@ -119,7 +120,7 @@ int32 psy = ((c * CLIP(hofs - cx)) & ~63) + ((d * CLIP(vofs - cy)) & ~63) + ((d
|
|||
_x = x;
|
||||
}
|
||||
|
||||
if(main_colorwindowtable[_x]) {
|
||||
if(window_cache[COL].main[_x]) {
|
||||
uint32 col;
|
||||
if(regs.direct_color == true && bg == BG1) {
|
||||
//direct color mode does not apply to bg2, as it is only 128 colors...
|
||||
|
|
|
@ -207,9 +207,9 @@ int s, x;
|
|||
bool _bg_enabled = regs.bg_enabled[OAM];
|
||||
bool _bgsub_enabled = regs.bgsub_enabled[OAM];
|
||||
|
||||
uint8 *wt_main = main_windowtable[OAM];
|
||||
uint8 *wt_sub = sub_windowtable[OAM];
|
||||
build_window_tables(OAM);
|
||||
uint8 *wt_main = window_cache[OAM].main;
|
||||
uint8 *wt_sub = window_cache[OAM].sub;
|
||||
|
||||
regs.oam_itemcount = 0;
|
||||
regs.oam_tilecount = 0;
|
||||
|
@ -240,6 +240,7 @@ uint8 *wt_sub = sub_windowtable[OAM];
|
|||
regs.range_over |= (regs.oam_itemcount > 32);
|
||||
|
||||
if(_bg_enabled == false && _bgsub_enabled == false)return;
|
||||
|
||||
int _pri;
|
||||
for(x=0;x<_screen_width;x++) {
|
||||
if(oam_line_pri[x] == OAM_PRI_NONE)continue;
|
||||
|
@ -251,7 +252,7 @@ int _pri;
|
|||
case 3:_pri = pri3_pos;break;
|
||||
}
|
||||
|
||||
if(main_colorwindowtable[x]) {
|
||||
if(window_cache[COL].main[x]) {
|
||||
if(_bg_enabled == true && !wt_main[x]) {
|
||||
if(pixel_cache[x].pri_main < _pri) {
|
||||
pixel_cache[x].pri_main = _pri;
|
||||
|
|
|
@ -1,11 +1,50 @@
|
|||
void bPPU::build_window_table(uint8 bg, uint8 *wtbl, bool mainscreen) {
|
||||
if(mainscreen == true && regs.bg_window_enabled[bg] == false) {
|
||||
memset(wtbl, 0, _screen_width);
|
||||
return;
|
||||
void bPPU::build_window_table(uint8 bg, bool mainscreen) {
|
||||
uint8 set = true, clr = false;
|
||||
uint8 *wtbl;
|
||||
if(mainscreen == true) {
|
||||
wtbl = (uint8*)window_cache[bg].main;
|
||||
} else {
|
||||
wtbl = (uint8*)window_cache[bg].sub;
|
||||
}
|
||||
if(mainscreen == false && regs.bgsub_window_enabled[bg] == false) {
|
||||
memset(wtbl, 0, _screen_width);
|
||||
return;
|
||||
|
||||
if(bg != COL) {
|
||||
if(mainscreen == true && regs.window_enabled[bg] == false) {
|
||||
memset(wtbl, 0, _screen_width);
|
||||
return;
|
||||
}
|
||||
if(mainscreen == false && regs.sub_window_enabled[bg] == false) {
|
||||
memset(wtbl, 0, _screen_width);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
uint8 mask;
|
||||
if(mainscreen == true) {
|
||||
mask = regs.color_mask;
|
||||
} else {
|
||||
mask = regs.colorsub_mask;
|
||||
}
|
||||
|
||||
if(mask == 0) {
|
||||
//always
|
||||
memset(wtbl, 1, _screen_width);
|
||||
return;
|
||||
}
|
||||
|
||||
if(mask == 3) {
|
||||
//never
|
||||
memset(wtbl, 0, _screen_width);
|
||||
return;
|
||||
}
|
||||
|
||||
if(mask == 1) {
|
||||
//inside window only
|
||||
set = 1;
|
||||
clr = 0;
|
||||
} else { //mask == 2
|
||||
//outside window only
|
||||
set = 0;
|
||||
clr = 1;
|
||||
}
|
||||
}
|
||||
|
||||
uint16 window1_left, window1_right, window2_left, window2_right;
|
||||
|
@ -24,54 +63,54 @@ bool r;
|
|||
window2_right <<= 1;
|
||||
}
|
||||
|
||||
if(regs.bg_window1_enabled[bg] == false && regs.bg_window2_enabled[bg] == false) {
|
||||
memset(wtbl, 0, _screen_width);
|
||||
} else if(regs.bg_window1_enabled[bg] == true && regs.bg_window2_enabled[bg] == false) {
|
||||
if(regs.bg_window1_invert[bg] == false) {
|
||||
if(regs.window1_enabled[bg] == false && regs.window2_enabled[bg] == false) {
|
||||
memset(wtbl, clr, _screen_width);
|
||||
} else if(regs.window1_enabled[bg] == true && regs.window2_enabled[bg] == false) {
|
||||
if(regs.window1_invert[bg] == false) {
|
||||
for(x=0;x<_screen_width;x++) {
|
||||
wtbl[x] = (x >= window1_left && x <= window1_right)?true:false;
|
||||
wtbl[x] = (x >= window1_left && x <= window1_right) ? set : clr;
|
||||
}
|
||||
} else {
|
||||
for(x=0;x<_screen_width;x++) {
|
||||
wtbl[x] = (x < window1_left || x > window1_right)?true:false;
|
||||
wtbl[x] = (x < window1_left || x > window1_right) ? set : clr;
|
||||
}
|
||||
}
|
||||
} else if(regs.bg_window1_enabled[bg] == false && regs.bg_window2_enabled[bg] == true) {
|
||||
if(regs.bg_window2_invert[bg] == false) {
|
||||
} else if(regs.window1_enabled[bg] == false && regs.window2_enabled[bg] == true) {
|
||||
if(regs.window2_invert[bg] == false) {
|
||||
for(x=0;x<_screen_width;x++) {
|
||||
wtbl[x] = (x >= window2_left && x <= window2_right)?true:false;
|
||||
wtbl[x] = (x >= window2_left && x <= window2_right) ? set : clr;
|
||||
}
|
||||
} else {
|
||||
for(x=0;x<_screen_width;x++) {
|
||||
wtbl[x] = (x < window2_left || x > window2_right)?true:false;
|
||||
wtbl[x] = (x < window2_left || x > window2_right) ? set : clr;
|
||||
}
|
||||
}
|
||||
} else { //if(regs.bg_window1_enabled[bg] == true && regs.bg_window2_enabled[bg] == true) {
|
||||
} else { //if(regs.window1_enabled[bg] == true && regs.window2_enabled[bg] == true) {
|
||||
for(x=0;x<_screen_width;x++) {
|
||||
if(regs.bg_window1_invert[bg] == false) {
|
||||
if(regs.window1_invert[bg] == false) {
|
||||
w1_mask = (x >= window1_left && x <= window1_right);
|
||||
} else {
|
||||
w1_mask = (x < window1_left || x > window1_right);
|
||||
}
|
||||
|
||||
if(regs.bg_window2_invert[bg] == false) {
|
||||
if(regs.window2_invert[bg] == false) {
|
||||
w2_mask = (x >= window2_left && x <= window2_right);
|
||||
} else {
|
||||
w2_mask = (x < window2_left || x > window2_right);
|
||||
}
|
||||
|
||||
switch(regs.bg_window_mask[bg]) {
|
||||
switch(regs.window_mask[bg]) {
|
||||
case 0: //WINDOWMASK_OR:
|
||||
wtbl[x] = ((w1_mask | w2_mask) == 1)?true:false;
|
||||
wtbl[x] = ((w1_mask | w2_mask) == 1) ? set : clr;
|
||||
break;
|
||||
case 1: //WINDOWMASK_AND:
|
||||
wtbl[x] = ((w1_mask & w2_mask) == 1)?true:false;
|
||||
wtbl[x] = ((w1_mask & w2_mask) == 1) ? set : clr;
|
||||
break;
|
||||
case 2: //WINDOWMASK_XOR:
|
||||
wtbl[x] = ((w1_mask ^ w2_mask) == 1)?true:false;
|
||||
wtbl[x] = ((w1_mask ^ w2_mask) == 1) ? set : clr;
|
||||
break;
|
||||
case 3: //WINDOWMASK_XNOR:
|
||||
wtbl[x] = ((w1_mask ^ w2_mask) == 0)?true:false;
|
||||
wtbl[x] = ((w1_mask ^ w2_mask) == 0) ? set : clr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -79,105 +118,13 @@ bool r;
|
|||
}
|
||||
|
||||
void bPPU::build_window_tables(uint8 bg) {
|
||||
build_window_table(bg, main_windowtable[bg], true);
|
||||
build_window_table(bg, sub_windowtable[bg], false);
|
||||
}
|
||||
|
||||
void bPPU::build_color_window_table(uint8 *wtbl, uint8 mask) {
|
||||
if(mask == 0) {
|
||||
//always
|
||||
memset(wtbl, 1, _screen_width);
|
||||
return;
|
||||
if(window_cache[bg].main_dirty == true) {
|
||||
window_cache[bg].main_dirty = false;
|
||||
build_window_table(bg, true);
|
||||
}
|
||||
|
||||
if(mask == 3) {
|
||||
//never
|
||||
memset(wtbl, 0, _screen_width);
|
||||
return;
|
||||
}
|
||||
|
||||
int _true, _false;
|
||||
if(mask == 1) {
|
||||
//inside window only
|
||||
_true = 1;
|
||||
_false = 0;
|
||||
} else { //mask == 2
|
||||
//outside window only
|
||||
_true = 0;
|
||||
_false = 1;
|
||||
}
|
||||
|
||||
uint16 window1_left, window1_right, window2_left, window2_right;
|
||||
int w1_mask, w2_mask; //1 = masked, 0 = not masked
|
||||
int x;
|
||||
bool r;
|
||||
window1_left = regs.window1_left;
|
||||
window1_right = regs.window1_right;
|
||||
window2_left = regs.window2_left;
|
||||
window2_right = regs.window2_right;
|
||||
|
||||
if(_screen_width == 512) {
|
||||
window1_left <<= 1;
|
||||
window1_right <<= 1;
|
||||
window2_left <<= 1;
|
||||
window2_right <<= 1;
|
||||
}
|
||||
|
||||
if(regs.color_window1_enabled == false && regs.color_window2_enabled == false) {
|
||||
memset(wtbl, _false, _screen_width);
|
||||
} else if(regs.color_window1_enabled == true && regs.color_window2_enabled == false) {
|
||||
if(regs.color_window1_invert == false) {
|
||||
for(x=0;x<_screen_width;x++) {
|
||||
wtbl[x] = (x >= window1_left && x <= window1_right)?_true:_false;
|
||||
}
|
||||
} else {
|
||||
for(x=0;x<_screen_width;x++) {
|
||||
wtbl[x] = (x < window1_left || x > window1_right)?_true:_false;
|
||||
}
|
||||
}
|
||||
} else if(regs.color_window1_enabled == false && regs.color_window2_enabled == true) {
|
||||
if(regs.color_window2_invert == false) {
|
||||
for(x=0;x<_screen_width;x++) {
|
||||
wtbl[x] = (x >= window2_left && x <= window2_right)?_true:_false;
|
||||
}
|
||||
} else {
|
||||
for(x=0;x<_screen_width;x++) {
|
||||
wtbl[x] = (x < window2_left || x > window2_right)?_true:_false;
|
||||
}
|
||||
}
|
||||
} else { //if(regs.color_window1_enabled == true && regs.color_window2_enabled == true) {
|
||||
for(x=0;x<_screen_width;x++) {
|
||||
if(regs.color_window1_invert == false) {
|
||||
w1_mask = (x >= window1_left && x <= window1_right);
|
||||
} else {
|
||||
w1_mask = (x < window1_left || x > window1_right);
|
||||
}
|
||||
|
||||
if(regs.color_window2_invert == false) {
|
||||
w2_mask = (x >= window2_left && x <= window2_right);
|
||||
} else {
|
||||
w2_mask = (x < window2_left || x > window2_right);
|
||||
}
|
||||
|
||||
switch(regs.color_window_mask) {
|
||||
case 0: //WINDOWMASK_OR:
|
||||
wtbl[x] = ((w1_mask | w2_mask) == 1)?_true:_false;
|
||||
break;
|
||||
case 1: //WINDOWMASK_AND:
|
||||
wtbl[x] = ((w1_mask & w2_mask) == 1)?_true:_false;
|
||||
break;
|
||||
case 2: //WINDOWMASK_XOR:
|
||||
wtbl[x] = ((w1_mask ^ w2_mask) == 1)?_true:_false;
|
||||
break;
|
||||
case 3: //WINDOWMASK_XNOR:
|
||||
wtbl[x] = ((w1_mask ^ w2_mask) == 0)?_true:_false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(window_cache[bg].sub_dirty == true) {
|
||||
window_cache[bg].sub_dirty = false;
|
||||
build_window_table(bg, false);
|
||||
}
|
||||
}
|
||||
|
||||
void bPPU::build_color_window_tables() {
|
||||
build_color_window_table(main_colorwindowtable, regs.color_mask);
|
||||
build_color_window_table(sub_colorwindowtable, regs.colorsub_mask);
|
||||
}
|
||||
|
|
|
@ -1,148 +0,0 @@
|
|||
#define CLIP_10BIT_SIGNED(x) \
|
||||
((x) & ((1 << 10) - 1)) + (((((x) & (1 << 13)) ^ (1 << 13)) - (1 << 13)) >> 3)
|
||||
|
||||
#define CAST_WORDTOINT(x) \
|
||||
(int32)((((x) & 0x8000) ? ((x) | 0xffff0000) : ((x) & 0x00007fff)))
|
||||
|
||||
void bPPU::render_line_mode7(uint8 bg, uint8 pri0_pos, uint8 pri1_pos) {
|
||||
int32 x;
|
||||
int32 step_m7a, step_m7c, m7a, m7b, m7c, m7d;
|
||||
int32 hoffset, voffset;
|
||||
int32 centerx, centery;
|
||||
int32 xx, yy;
|
||||
int32 px, py;
|
||||
int32 tx, ty, tile, palette;
|
||||
uint8 layer_pos;
|
||||
if(regs.bg_enabled[bg] == false && regs.bgsub_enabled[bg] == false)return;
|
||||
|
||||
uint16 *mtable_x, *mtable_y;
|
||||
if(bg == BG1) {
|
||||
mtable_x = (uint16*)mosaic_table[(regs.mosaic_enabled[BG1] == true) ? regs.mosaic_size : 0];
|
||||
mtable_y = (uint16*)mosaic_table[(regs.mosaic_enabled[BG1] == true) ? regs.mosaic_size : 0];
|
||||
} else { //bg == BG2
|
||||
//Mode7 EXTBG BG2 uses BG1 mosaic enable to control vertical mosaic,
|
||||
//and BG2 mosaic enable to control horizontal mosaic...
|
||||
mtable_x = (uint16*)mosaic_table[(regs.mosaic_enabled[BG2] == true) ? regs.mosaic_size : 0];
|
||||
mtable_y = (uint16*)mosaic_table[(regs.mosaic_enabled[BG1] == true) ? regs.mosaic_size : 0];
|
||||
}
|
||||
|
||||
hoffset = ((int32)regs.m7_hofs << 19) >> 19;
|
||||
voffset = ((int32)regs.m7_vofs << 19) >> 19;
|
||||
|
||||
centerx = ((int32)regs.m7x << 19) >> 19;
|
||||
centery = ((int32)regs.m7y << 19) >> 19;
|
||||
|
||||
if(regs.mode7_vflip == true) {
|
||||
yy = 255 - _y;
|
||||
} else {
|
||||
yy = _y;
|
||||
}
|
||||
yy = mtable_y[yy];
|
||||
yy += CLIP_10BIT_SIGNED(voffset - centery);
|
||||
|
||||
m7b = CAST_WORDTOINT(regs.m7b) * yy + (centerx << 8);
|
||||
m7d = CAST_WORDTOINT(regs.m7d) * yy + (centery << 8);
|
||||
|
||||
step_m7a = CAST_WORDTOINT(regs.m7a);
|
||||
step_m7c = CAST_WORDTOINT(regs.m7c);
|
||||
|
||||
xx = CLIP_10BIT_SIGNED(hoffset - centerx);
|
||||
|
||||
m7a = CAST_WORDTOINT(regs.m7a) * xx;
|
||||
m7c = CAST_WORDTOINT(regs.m7c) * xx;
|
||||
|
||||
int _pri, _x;
|
||||
bool _bg_enabled, _bgsub_enabled;
|
||||
_bg_enabled = regs.bg_enabled[bg];
|
||||
_bgsub_enabled = regs.bgsub_enabled[bg];
|
||||
|
||||
build_window_tables(bg);
|
||||
uint8 *wt_main = main_windowtable[bg];
|
||||
uint8 *wt_sub = sub_windowtable[bg];
|
||||
|
||||
for(x=0;x<256;x++) {
|
||||
px = ((m7a + step_m7a * mtable_x[x] + m7b) >> 8);
|
||||
py = ((m7c + step_m7c * mtable_x[x] + m7d) >> 8);
|
||||
|
||||
switch(regs.mode7_repeat) {
|
||||
case 0: //screen repitition outside of screen area
|
||||
case 1: //same as case 0
|
||||
px &= 1023;
|
||||
py &= 1023;
|
||||
tx = ((px >> 3) & 127);
|
||||
ty = ((py >> 3) & 127);
|
||||
tile = vram[(ty * 128 + tx) << 1];
|
||||
palette = vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
break;
|
||||
case 2: //palette color 0 outside of screen area
|
||||
if(px < 0 || px > 1023 || py < 0 || py > 1023) {
|
||||
palette = 0;
|
||||
} else {
|
||||
px &= 1023;
|
||||
py &= 1023;
|
||||
tx = ((px >> 3) & 127);
|
||||
ty = ((py >> 3) & 127);
|
||||
tile = vram[(ty * 128 + tx) << 1];
|
||||
palette = vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
}
|
||||
break;
|
||||
case 3: //character 0 repetition outside of screen area
|
||||
if(px < 0 || px > 1023 || py < 0 || py > 1023) {
|
||||
tx = 0;
|
||||
ty = 0;
|
||||
} else {
|
||||
px &= 1023;
|
||||
py &= 1023;
|
||||
tx = ((px >> 3) & 127);
|
||||
ty = ((py >> 3) & 127);
|
||||
}
|
||||
tile = vram[(ty * 128 + tx) << 1];
|
||||
palette = vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
break;
|
||||
}
|
||||
|
||||
if(bg == BG1) {
|
||||
_pri = pri0_pos;
|
||||
} else {
|
||||
_pri = (palette >> 7) ? pri1_pos : pri0_pos;
|
||||
palette &= 0x7f;
|
||||
}
|
||||
|
||||
if(!palette)continue;
|
||||
|
||||
if(regs.mode7_hflip == true) {
|
||||
_x = 255 - x;
|
||||
} else {
|
||||
_x = x;
|
||||
}
|
||||
|
||||
if(main_colorwindowtable[_x]) {
|
||||
uint32 col;
|
||||
if(regs.direct_color == true && bg == BG1) {
|
||||
//direct color mode does not apply to bg2 as it is only 128 colors...
|
||||
col = get_direct_color(0, palette);
|
||||
} else {
|
||||
col = get_palette(palette);
|
||||
}
|
||||
|
||||
if(regs.bg_enabled[bg] == true && !wt_main[_x]) {
|
||||
if(pixel_cache[_x].pri_main < _pri) {
|
||||
pixel_cache[_x].pri_main = _pri;
|
||||
pixel_cache[_x].bg_main = 0x80 | bg;
|
||||
pixel_cache[_x].src_main = col;
|
||||
pixel_cache[_x].color_exempt = false;
|
||||
}
|
||||
}
|
||||
if(regs.bgsub_enabled[bg] == true && !wt_sub[_x]) {
|
||||
if(pixel_cache[_x].pri_sub < _pri) {
|
||||
pixel_cache[_x].pri_sub = _pri;
|
||||
pixel_cache[_x].bg_sub = 0x80 | bg;
|
||||
pixel_cache[_x].src_sub = col;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef CLIP_10BIT_SIGNED
|
||||
#undef CAST_WORDTOINT
|
|
@ -5,12 +5,33 @@ void PPU::get_scanline_info(scanline_info *info) {
|
|||
info->interlace = cpu->interlace();
|
||||
}
|
||||
|
||||
void PPU::set_frameskip(int fs) {}
|
||||
bool PPU::render_frame() { return true; }
|
||||
void PPU::enable_renderer(bool r) { status.render_output = r; }
|
||||
bool PPU::renderer_enabled() { return status.render_output; }
|
||||
|
||||
void PPU::frame() {
|
||||
static fr = 0, fe = 0;
|
||||
static time_t prev, curr;
|
||||
fe++;
|
||||
if(status.render_output)fr++;
|
||||
|
||||
time(&curr);
|
||||
if(curr != prev) {
|
||||
status.frames_updated = true;
|
||||
status.frames_rendered = fr;
|
||||
status.frames_executed = fe;
|
||||
fr = fe = 0;
|
||||
}
|
||||
prev = curr;
|
||||
}
|
||||
|
||||
PPU::PPU() {
|
||||
status.render_output = true;
|
||||
status.frames_updated = false;
|
||||
status.frames_rendered = 0;
|
||||
status.frames_executed = 0;
|
||||
|
||||
ppu1_version = 1;
|
||||
ppu2_version = 3;
|
||||
ppu2_version = 1;
|
||||
mmio = &mmio_unmapped;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,16 @@
|
|||
class PPU {
|
||||
public:
|
||||
|
||||
//this struct should be read-only to
|
||||
//functions outside of this class
|
||||
struct {
|
||||
bool render_output;
|
||||
|
||||
bool frames_updated;
|
||||
uint32 frames_rendered;
|
||||
uint32 frames_executed;
|
||||
} status;
|
||||
|
||||
//PPU1 version number
|
||||
//* 1 is known
|
||||
//* reported by $213e
|
||||
|
@ -32,11 +43,11 @@ struct scanline_info {
|
|||
virtual void run() = 0;
|
||||
virtual void scanline() = 0;
|
||||
virtual void render_scanline() = 0;
|
||||
virtual void frame() = 0;
|
||||
virtual void frame();
|
||||
virtual void power() = 0;
|
||||
virtual void reset() = 0;
|
||||
virtual void set_frameskip(int fs);
|
||||
virtual bool render_frame();
|
||||
virtual void enable_renderer(bool r);
|
||||
virtual bool renderer_enabled();
|
||||
|
||||
PPU();
|
||||
~PPU();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
CC = c++
|
||||
CFLAGS = -O2
|
||||
CFLAGS = -O3 -fomit-frame-pointer -ffast-math
|
||||
OBJS = sdlmain.o \
|
||||
libstring.o libconfig.o \
|
||||
reader.o \
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
CC = cl
|
||||
CFLAGS = /nologo /O2 /Ogityb2 /Gr /Gs
|
||||
CFLAGS = /nologo /O2 /Ogityb2 /Gr /Gs /DARCH_LSB
|
||||
OBJS = sdlmain.obj \
|
||||
libstring.obj libconfig.obj \
|
||||
reader.obj \
|
||||
|
|
|
@ -17,17 +17,33 @@ void bSNES::run() {
|
|||
}
|
||||
}
|
||||
|
||||
void bSNES::video_run() { render(); }
|
||||
void bSNES::video_run() {
|
||||
if(ppu->status.frames_updated) {
|
||||
char s[512], t[512];
|
||||
ppu->status.frames_updated = false;
|
||||
// if((bool)config::gui.show_fps == true) {
|
||||
sprintf(s, "%s : %d fps", BSNES_TITLE, ppu->status.frames_executed);
|
||||
// if(w_main->frameskip != 0) {
|
||||
// sprintf(t, " (%d frames)", ppu->status.frames_rendered);
|
||||
// strcat(s, t);
|
||||
// }
|
||||
SDL_WM_SetCaption(s, 0);
|
||||
// }
|
||||
}
|
||||
|
||||
render();
|
||||
}
|
||||
|
||||
void bSNES::sound_run() {}
|
||||
|
||||
/***********************
|
||||
*** Input functions ***
|
||||
***********************/
|
||||
|
||||
//It would appear that keystate does not need to be free'd
|
||||
//It would appear that keystate does not need to be released
|
||||
//after calling SDL_GetKeyState... doing so causes libSDL
|
||||
//to throw error messages about a bad free call to stdout...
|
||||
void bSNES::poll_input() {
|
||||
void bSNES::poll_input(uint8 type) {
|
||||
uint8 *keystate = SDL_GetKeyState(0);
|
||||
joypad1.up = keystate[(int)config::input.joypad1.up];
|
||||
joypad1.down = keystate[(int)config::input.joypad1.down];
|
||||
|
|
|
@ -22,7 +22,7 @@ enum { STOP = 0, RUN };
|
|||
uint32 get_status();
|
||||
|
||||
//input functions
|
||||
void poll_input();
|
||||
void poll_input(uint8 type);
|
||||
bool get_input_status(uint8 device, uint8 button);
|
||||
|
||||
void notify(uint32 message, uint32 param1 = 0, uint32 param2 = 0);
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
# Applies contrast adjust filter to video output when enabled
|
||||
# Works by lowering the brightness of darker colors,
|
||||
# while leaving brighter colors alone; thus reducing saturation
|
||||
# (default = true)
|
||||
snes.video_color_curve = true
|
||||
|
||||
# Selects color adjustment filter for video output
|
||||
# 0 = Normal (no filter, rgb555)
|
||||
# 1 = Grayscale mode (l5)
|
||||
# 2 = VGA mode (rgb332)
|
||||
# 3 = Genesis mode (rgb333)
|
||||
# (default = 0)
|
||||
snes.video_color_adjust_mode = 0
|
||||
|
||||
# Mutes SNES audio output when enabled
|
||||
# (default = true)
|
||||
snes.mute = true
|
||||
|
||||
# Enable fullscreen mode at startup
|
||||
# (default = false)
|
||||
video.fullscreen = false
|
||||
|
||||
# Window / Fullscreen width
|
||||
# (default = 320)
|
||||
video.display_width = 320
|
||||
|
||||
# Window / Fullscreen height
|
||||
# (default = 240)
|
||||
video.display_height = 240
|
||||
|
||||
# SNES video output width
|
||||
# (default = 256)
|
||||
video.output_width = 256
|
||||
|
||||
# SNES video output height
|
||||
# (default = 223)
|
||||
video.output_height = 223
|
||||
|
||||
# Joypad1 up
|
||||
# (default = 0x111)
|
||||
input.joypad1.up = 0x111
|
||||
|
||||
# Joypad1 down
|
||||
# (default = 0x112)
|
||||
input.joypad1.down = 0x112
|
||||
|
||||
# Joypad1 left
|
||||
# (default = 0x114)
|
||||
input.joypad1.left = 0x114
|
||||
|
||||
# Joypad1 right
|
||||
# (default = 0x113)
|
||||
input.joypad1.right = 0x113
|
||||
|
||||
# Joypad1 A
|
||||
# (default = 0x78)
|
||||
input.joypad1.a = 0x78
|
||||
|
||||
# Joypad1 B
|
||||
# (default = 0x7a)
|
||||
input.joypad1.b = 0x7a
|
||||
|
||||
# Joypad1 X
|
||||
# (default = 0x73)
|
||||
input.joypad1.x = 0x73
|
||||
|
||||
# Joypad1 Y
|
||||
# (default = 0x61)
|
||||
input.joypad1.y = 0x61
|
||||
|
||||
# Joypad1 L
|
||||
# (default = 0x64)
|
||||
input.joypad1.l = 0x64
|
||||
|
||||
# Joypad1 R
|
||||
# (default = 0x63)
|
||||
input.joypad1.r = 0x63
|
||||
|
||||
# Joypad1 select
|
||||
# (default = 0x12f)
|
||||
input.joypad1.select = 0x12f
|
||||
|
||||
# Joypad1 start
|
||||
# (default = 0xd)
|
||||
input.joypad1.start = 0xd
|
||||
|
|
@ -55,7 +55,6 @@ int i;
|
|||
for(i=0x2140;i<=0x217f;i++)mem_bus->set_mmio_mapper(i, cpu->mmio);
|
||||
for(i=0x2180;i<=0x2183;i++)mem_bus->set_mmio_mapper(i, cpu->mmio);
|
||||
//input
|
||||
mem_bus->set_mmio_mapper(0x4000, cpu->mmio); //test -- remove this
|
||||
mem_bus->set_mmio_mapper(0x4016, cpu->mmio);
|
||||
mem_bus->set_mmio_mapper(0x4017, cpu->mmio);
|
||||
for(i=0x4200;i<=0x421f;i++)mem_bus->set_mmio_mapper(i, cpu->mmio);
|
||||
|
|
|
@ -14,7 +14,7 @@ enum {
|
|||
|
||||
//The CPU calls poll_input() when the main interface should check the
|
||||
//status of all joypad buttons and cache the results...
|
||||
virtual void poll_input() = 0;
|
||||
virtual void poll_input(uint8 type) = 0;
|
||||
|
||||
//...and then the CPU calls get_input_status() whenever it needs one
|
||||
//of the cached button values to be returned for emulation purposes.
|
||||
|
|
|
@ -10,108 +10,66 @@ const uint8 SNES::color_curve_table[32] = {
|
|||
void SNES::update_color_lookup_table() {
|
||||
int i, l, r, g, b;
|
||||
double lr = 0.2126, lg = 0.7152, lb = 0.0722; //luminance
|
||||
switch(video.depth) {
|
||||
case 15: //rgb565
|
||||
for(i=0;i<32768;i++) {
|
||||
r = (i ) & 31;
|
||||
g = (i >> 5) & 31;
|
||||
b = (i >> 10) & 31;
|
||||
uint32 col;
|
||||
|
||||
if((bool)config::snes.video_color_curve == true) {
|
||||
r = color_curve_table[r] >> 3;
|
||||
g = color_curve_table[g] >> 3;
|
||||
b = color_curve_table[b] >> 3;
|
||||
}
|
||||
for(i=0;i<32768;i++) {
|
||||
//bgr555->rgb888
|
||||
col = ((i & 0x001f) << 19) | ((i & 0x001c) << 14) |
|
||||
((i & 0x03e0) << 6) | ((i & 0x0380) << 1) |
|
||||
((i & 0x7c00) >> 7) | ((i & 0x7000) >> 12);
|
||||
|
||||
if((int)config::snes.video_color_adjust_mode == VCA_GRAYSCALE) {
|
||||
r = (r << 3) | (r >> 2);
|
||||
g = (g << 3) | (g >> 2);
|
||||
b = (b << 3) | (b >> 2);
|
||||
r = (col >> 16) & 0xff;
|
||||
g = (col >> 8) & 0xff;
|
||||
b = (col ) & 0xff;
|
||||
|
||||
l = int((double)r * lr) + ((double)g * lg) + ((double)b * lb);
|
||||
if(l < 0)l = 0;
|
||||
if(l > 255)l = 255;
|
||||
r = g = b = l;
|
||||
if((bool)config::snes.video_color_curve == true) {
|
||||
r = color_curve_table[r >> 3];
|
||||
g = color_curve_table[g >> 3];
|
||||
b = color_curve_table[b >> 3];
|
||||
}
|
||||
|
||||
r >>= 3;
|
||||
g >>= 3;
|
||||
b >>= 3;
|
||||
} else if((int)config::snes.video_color_adjust_mode == VCA_VGA) {
|
||||
//rgb555->rgb332
|
||||
r >>= 2;
|
||||
g >>= 2;
|
||||
b >>= 3;
|
||||
|
||||
r = (r << 2) | (r >> 1);
|
||||
g = (g << 2) | (g >> 1);
|
||||
b = (b << 3) | (b << 1) | (b >> 1);
|
||||
} else if((int)config::snes.video_color_adjust_mode == VCA_GENESIS) {
|
||||
//rgb555->rgb333
|
||||
r >>= 2;
|
||||
g >>= 2;
|
||||
b >>= 2;
|
||||
|
||||
r = (r << 2) | (r >> 1);
|
||||
g = (g << 2) | (g >> 1);
|
||||
b = (b << 2) | (b >> 1);
|
||||
}
|
||||
if((int)config::snes.video_color_adjust_mode == VCA_GRAYSCALE) {
|
||||
l = int((double)r * lr) + ((double)g * lg) + ((double)b * lb);
|
||||
if(l < 0)l = 0;
|
||||
if(l > 255)l = 255;
|
||||
r = g = b = l;
|
||||
} else if((int)config::snes.video_color_adjust_mode == VCA_VGA) {
|
||||
r &= 0xe0;
|
||||
g &= 0xe0;
|
||||
b &= 0xc0;
|
||||
r |= (r >> 3) | (r >> 6);
|
||||
g |= (g >> 3) | (g >> 6);
|
||||
b |= (b >> 2) | (b >> 4) | (b >> 6);
|
||||
} else if((int)config::snes.video_color_adjust_mode == VCA_GENESIS) {
|
||||
r &= 0xe0;
|
||||
g &= 0xe0;
|
||||
b &= 0xe0;
|
||||
r |= (r >> 3) | (r >> 6);
|
||||
g |= (g >> 3) | (g >> 6);
|
||||
b |= (b >> 3) | (b >> 6);
|
||||
}
|
||||
|
||||
switch(video.depth) {
|
||||
case 15:
|
||||
r >>= 3;
|
||||
g >>= 3;
|
||||
b >>= 3;
|
||||
color_lookup_table[i] = (r << 10) | (g << 5) | (b);
|
||||
}
|
||||
break;
|
||||
case 16: //rgb565
|
||||
for(i=0;i<32768;i++) {
|
||||
r = (i ) & 31;
|
||||
g = (i >> 5) & 31;
|
||||
b = (i >> 10) & 31;
|
||||
|
||||
if((bool)config::snes.video_color_curve == true) {
|
||||
r = color_curve_table[r] >> 3;
|
||||
g = color_curve_table[g] >> 2;
|
||||
b = color_curve_table[b] >> 3;
|
||||
} else {
|
||||
g = (g << 1) | (g >> 4);
|
||||
}
|
||||
|
||||
if((int)config::snes.video_color_adjust_mode == VCA_GRAYSCALE) {
|
||||
r = (r << 3) | (r >> 2);
|
||||
g = (g << 2) | (g >> 4);
|
||||
b = (b << 3) | (b >> 2);
|
||||
|
||||
l = int((double)r * lr) + ((double)g * lg) + ((double)b * lb);
|
||||
if(l < 0)l = 0;
|
||||
if(l > 255)l = 255;
|
||||
r = g = b = l;
|
||||
|
||||
r >>= 3;
|
||||
g >>= 2;
|
||||
b >>= 3;
|
||||
} else if((int)config::snes.video_color_adjust_mode == VCA_VGA) {
|
||||
//rgb565->rgb332
|
||||
r >>= 2;
|
||||
g >>= 3;
|
||||
b >>= 3;
|
||||
|
||||
r = (r << 2) | (r >> 1);
|
||||
g = (g << 3) | (g);
|
||||
b = (b << 3) | (b << 1) | (b >> 1);
|
||||
} else if((int)config::snes.video_color_adjust_mode == VCA_GENESIS) {
|
||||
//rgb565->rgb333
|
||||
r >>= 2;
|
||||
g >>= 3;
|
||||
b >>= 2;
|
||||
|
||||
r = (r << 2) | (r >> 1);
|
||||
g = (g << 3) | (g);
|
||||
b = (b << 2) | (b >> 1);
|
||||
}
|
||||
|
||||
break;
|
||||
case 16:
|
||||
r >>= 3;
|
||||
g >>= 2;
|
||||
b >>= 3;
|
||||
color_lookup_table[i] = (r << 11) | (g << 5) | (b);
|
||||
break;
|
||||
case 24:
|
||||
case 32:
|
||||
color_lookup_table[i] = (r << 16) | (g << 8) | (b);
|
||||
break;
|
||||
default:
|
||||
alert("Error: SNES::update_color_lookup_table() -- color depth %d not supported", video.depth);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
alert("Error: SNES::update_color_lookup_table() -- color depth %d not supported", video.depth);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -305,32 +263,32 @@ bool field = !cpu->interlace_field();
|
|||
}
|
||||
|
||||
void SNES::video_update() {
|
||||
if(!ppu->render_frame())return;
|
||||
|
||||
if(video.format_changed == true) {
|
||||
update_video_format();
|
||||
}
|
||||
|
||||
uint16 *src = (uint16*)video.ppu_data + ((int(cpu->overscan()) << 3) * 1024);
|
||||
switch(video.mode) {
|
||||
case VM_256x224:video_update_256x224(src);break;
|
||||
case VM_512x224:video_update_512x224(src);break;
|
||||
case VM_256x448:video_update_256x448(src);break;
|
||||
case VM_512x448:video_update_512x448(src);break;
|
||||
case VM_VARIABLE:
|
||||
switch(int(video.frame_hires) | (int(video.frame_interlace) << 1)) {
|
||||
case 0:video_update_256x224(src);break;
|
||||
case 1:video_update_512x224(src);break;
|
||||
case 2:video_update_256x448(src);break;
|
||||
case 3:video_update_512x448(src);break;
|
||||
if(ppu->renderer_enabled()) {
|
||||
if(video.format_changed == true) {
|
||||
update_video_format();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
//SNES::capture_screenshot() was called by emulation interface
|
||||
if(flag_output_screenshot == true) {
|
||||
output_screenshot();
|
||||
flag_output_screenshot = false;
|
||||
uint16 *src = (uint16*)video.ppu_data + ((int(cpu->overscan()) << 3) * 1024);
|
||||
switch(video.mode) {
|
||||
case VM_256x224:video_update_256x224(src);break;
|
||||
case VM_512x224:video_update_512x224(src);break;
|
||||
case VM_256x448:video_update_256x448(src);break;
|
||||
case VM_512x448:video_update_512x448(src);break;
|
||||
case VM_VARIABLE:
|
||||
switch(int(video.frame_hires) | (int(video.frame_interlace) << 1)) {
|
||||
case 0:video_update_256x224(src);break;
|
||||
case 1:video_update_512x224(src);break;
|
||||
case 2:video_update_256x448(src);break;
|
||||
case 3:video_update_512x448(src);break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
//SNES::capture_screenshot() was called by emulation interface
|
||||
if(flag_output_screenshot == true) {
|
||||
output_screenshot();
|
||||
flag_output_screenshot = false;
|
||||
}
|
||||
}
|
||||
|
||||
video_run();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
CC = cl
|
||||
CFLAGS = /nologo /O2 /Ogityb2 /Gr /Gs
|
||||
CFLAGS = /nologo /O2 /Ogityb2 /Gr /Gs /DARCH_LSB
|
||||
OBJS = winmain.obj \
|
||||
libstring.obj libconfig.obj \
|
||||
reader.obj \
|
||||
|
|
|
@ -114,7 +114,23 @@ void bSNES::run() {
|
|||
}
|
||||
|
||||
void bSNES::video_run() {
|
||||
dd_renderer->update();
|
||||
if(ppu->status.frames_updated) {
|
||||
char s[512], t[512];
|
||||
ppu->status.frames_updated = false;
|
||||
if((bool)config::gui.show_fps == true) {
|
||||
sprintf(s, "%s : %d fps", BSNES_TITLE, ppu->status.frames_executed);
|
||||
if(w_main->frameskip != 0) {
|
||||
sprintf(t, " (%d frames)", ppu->status.frames_rendered);
|
||||
strcat(s, t);
|
||||
}
|
||||
SetWindowText(w_main->hwnd, s);
|
||||
}
|
||||
}
|
||||
|
||||
w_main->frameskip_pos++;
|
||||
w_main->frameskip_pos %= (w_main->frameskip + 1);
|
||||
if(ppu->renderer_enabled())dd_renderer->update();
|
||||
ppu->enable_renderer(w_main->frameskip_pos == 0);
|
||||
}
|
||||
|
||||
void bSNES::sound_run() {
|
||||
|
@ -124,30 +140,58 @@ void bSNES::sound_run() {
|
|||
/***********************
|
||||
*** Input functions ***
|
||||
***********************/
|
||||
void bSNES::poll_input() {
|
||||
void bSNES::poll_input(uint8 type) {
|
||||
//only capture input when main window has focus
|
||||
if(GetForegroundWindow() == w_main->hwnd) {
|
||||
joypad1.up = KeyDown(config::input.joypad1.up);
|
||||
joypad1.down = KeyDown(config::input.joypad1.down);
|
||||
joypad1.left = KeyDown(config::input.joypad1.left);
|
||||
joypad1.right = KeyDown(config::input.joypad1.right);
|
||||
joypad1.select = KeyDown(config::input.joypad1.select);
|
||||
joypad1.start = KeyDown(config::input.joypad1.start);
|
||||
joypad1.y = KeyDown(config::input.joypad1.y);
|
||||
joypad1.b = KeyDown(config::input.joypad1.b);
|
||||
joypad1.x = KeyDown(config::input.joypad1.x);
|
||||
joypad1.a = KeyDown(config::input.joypad1.a);
|
||||
joypad1.l = KeyDown(config::input.joypad1.l);
|
||||
joypad1.r = KeyDown(config::input.joypad1.r);
|
||||
switch(type) {
|
||||
case SNES::DEV_JOYPAD1:
|
||||
joypad1.up = KeyDown(config::input.joypad1.up);
|
||||
joypad1.down = KeyDown(config::input.joypad1.down);
|
||||
joypad1.left = KeyDown(config::input.joypad1.left);
|
||||
joypad1.right = KeyDown(config::input.joypad1.right);
|
||||
joypad1.select = KeyDown(config::input.joypad1.select);
|
||||
joypad1.start = KeyDown(config::input.joypad1.start);
|
||||
joypad1.y = KeyDown(config::input.joypad1.y);
|
||||
joypad1.b = KeyDown(config::input.joypad1.b);
|
||||
joypad1.x = KeyDown(config::input.joypad1.x);
|
||||
joypad1.a = KeyDown(config::input.joypad1.a);
|
||||
joypad1.l = KeyDown(config::input.joypad1.l);
|
||||
joypad1.r = KeyDown(config::input.joypad1.r);
|
||||
break;
|
||||
case SNES::DEV_JOYPAD2:
|
||||
joypad2.up = KeyDown(config::input.joypad2.up);
|
||||
joypad2.down = KeyDown(config::input.joypad2.down);
|
||||
joypad2.left = KeyDown(config::input.joypad2.left);
|
||||
joypad2.right = KeyDown(config::input.joypad2.right);
|
||||
joypad2.select = KeyDown(config::input.joypad2.select);
|
||||
joypad2.start = KeyDown(config::input.joypad2.start);
|
||||
joypad2.y = KeyDown(config::input.joypad2.y);
|
||||
joypad2.b = KeyDown(config::input.joypad2.b);
|
||||
joypad2.x = KeyDown(config::input.joypad2.x);
|
||||
joypad2.a = KeyDown(config::input.joypad2.a);
|
||||
joypad2.l = KeyDown(config::input.joypad2.l);
|
||||
joypad2.r = KeyDown(config::input.joypad2.r);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
joypad1.up = joypad1.down = joypad1.left = joypad1.right =
|
||||
joypad1.select = joypad1.start =
|
||||
joypad1.y = joypad1.b = joypad1.x = joypad1.a =
|
||||
joypad1.l = joypad1.r = 0;
|
||||
switch(type) {
|
||||
case SNES::DEV_JOYPAD1:
|
||||
joypad1.up = joypad1.down = joypad1.left = joypad1.right =
|
||||
joypad1.select = joypad1.start =
|
||||
joypad1.y = joypad1.b = joypad1.x = joypad1.a =
|
||||
joypad1.l = joypad1.r = 0;
|
||||
break;
|
||||
case SNES::DEV_JOYPAD2:
|
||||
joypad2.up = joypad2.down = joypad2.left = joypad2.right =
|
||||
joypad2.select = joypad2.start =
|
||||
joypad2.y = joypad2.b = joypad2.x = joypad2.a =
|
||||
joypad1.l = joypad2.r = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//check for debugger-based key locks
|
||||
if(is_debugger_enabled == true) {
|
||||
if(is_debugger_enabled == true && type == SNES::DEV_JOYPAD1) {
|
||||
if(w_console->joypad_lock.up )joypad1.up = true;
|
||||
if(w_console->joypad_lock.down )joypad1.down = true;
|
||||
if(w_console->joypad_lock.left )joypad1.left = true;
|
||||
|
@ -167,6 +211,9 @@ void bSNES::poll_input() {
|
|||
//this to happen causes glitches in many SNES games.
|
||||
if(joypad1.up) joypad1.down = 0;
|
||||
if(joypad1.left)joypad1.right = 0;
|
||||
|
||||
if(joypad2.up) joypad2.down = 0;
|
||||
if(joypad2.left)joypad2.right = 0;
|
||||
}
|
||||
|
||||
bool bSNES::get_input_status(uint8 device, uint8 button) {
|
||||
|
@ -187,7 +234,24 @@ bool bSNES::get_input_status(uint8 device, uint8 button) {
|
|||
case JOYPAD_START: return joypad1.start;
|
||||
}
|
||||
break;
|
||||
case DEV_JOYPAD2:
|
||||
switch(button) {
|
||||
case JOYPAD_UP: return joypad2.up;
|
||||
case JOYPAD_DOWN: return joypad2.down;
|
||||
case JOYPAD_LEFT: return joypad2.left;
|
||||
case JOYPAD_RIGHT: return joypad2.right;
|
||||
case JOYPAD_A: return joypad2.a;
|
||||
case JOYPAD_B: return joypad2.b;
|
||||
case JOYPAD_X: return joypad2.x;
|
||||
case JOYPAD_Y: return joypad2.y;
|
||||
case JOYPAD_L: return joypad2.l;
|
||||
case JOYPAD_R: return joypad2.r;
|
||||
case JOYPAD_SELECT:return joypad2.select;
|
||||
case JOYPAD_START: return joypad2.start;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ enum { DRAM = 0, SPCRAM = 1, VRAM = 2, OAM = 3, CGRAM = 4 };
|
|||
uint32 get_status();
|
||||
|
||||
//input functions
|
||||
void poll_input();
|
||||
void poll_input(uint8 type);
|
||||
bool get_input_status(uint8 device, uint8 button);
|
||||
|
||||
//debugging functions
|
||||
|
|
Binary file not shown.
|
@ -20,21 +20,36 @@ struct GUI {
|
|||
Setting GUI::show_fps(&config_file, "gui.show_fps", "Show framerate in window title", true, Setting::TRUE_FALSE);
|
||||
|
||||
struct Input {
|
||||
struct Joypad {
|
||||
struct Joypad1 {
|
||||
static Setting up, down, left, right, a, b, x, y, l, r, select, start;
|
||||
} joypad1;
|
||||
struct Joypad2 {
|
||||
static Setting up, down, left, right, a, b, x, y, l, r, select, start;
|
||||
} joypad2;
|
||||
} input;
|
||||
Setting Input::Joypad::up (&config_file, "input.joypad1.up", "Joypad1 up", VK_UP, Setting::HEX);
|
||||
Setting Input::Joypad::down (&config_file, "input.joypad1.down", "Joypad1 down", VK_DOWN, Setting::HEX);
|
||||
Setting Input::Joypad::left (&config_file, "input.joypad1.left", "Joypad1 left", VK_LEFT, Setting::HEX);
|
||||
Setting Input::Joypad::right (&config_file, "input.joypad1.right", "Joypad1 right", VK_RIGHT, Setting::HEX);
|
||||
Setting Input::Joypad::a (&config_file, "input.joypad1.a", "Joypad1 A", 'X', Setting::HEX);
|
||||
Setting Input::Joypad::b (&config_file, "input.joypad1.b", "Joypad1 B", 'Z', Setting::HEX);
|
||||
Setting Input::Joypad::x (&config_file, "input.joypad1.x", "Joypad1 X", 'S', Setting::HEX);
|
||||
Setting Input::Joypad::y (&config_file, "input.joypad1.y", "Joypad1 Y", 'A', Setting::HEX);
|
||||
Setting Input::Joypad::l (&config_file, "input.joypad1.l", "Joypad1 L", 'D', Setting::HEX);
|
||||
Setting Input::Joypad::r (&config_file, "input.joypad1.r", "Joypad1 R", 'C', Setting::HEX);
|
||||
Setting Input::Joypad::select(&config_file, "input.joypad1.select", "Joypad1 select", VK_SHIFT, Setting::HEX);
|
||||
Setting Input::Joypad::start (&config_file, "input.joypad1.start", "Joypad1 start", VK_RETURN, Setting::HEX);
|
||||
Setting Input::Joypad1::up (&config_file, "input.joypad1.up", "Joypad1 up", VK_UP, Setting::HEX);
|
||||
Setting Input::Joypad1::down (&config_file, "input.joypad1.down", "Joypad1 down", VK_DOWN, Setting::HEX);
|
||||
Setting Input::Joypad1::left (&config_file, "input.joypad1.left", "Joypad1 left", VK_LEFT, Setting::HEX);
|
||||
Setting Input::Joypad1::right (&config_file, "input.joypad1.right", "Joypad1 right", VK_RIGHT, Setting::HEX);
|
||||
Setting Input::Joypad1::a (&config_file, "input.joypad1.a", "Joypad1 A", 'X', Setting::HEX);
|
||||
Setting Input::Joypad1::b (&config_file, "input.joypad1.b", "Joypad1 B", 'Z', Setting::HEX);
|
||||
Setting Input::Joypad1::x (&config_file, "input.joypad1.x", "Joypad1 X", 'S', Setting::HEX);
|
||||
Setting Input::Joypad1::y (&config_file, "input.joypad1.y", "Joypad1 Y", 'A', Setting::HEX);
|
||||
Setting Input::Joypad1::l (&config_file, "input.joypad1.l", "Joypad1 L", 'D', Setting::HEX);
|
||||
Setting Input::Joypad1::r (&config_file, "input.joypad1.r", "Joypad1 R", 'C', Setting::HEX);
|
||||
Setting Input::Joypad1::select(&config_file, "input.joypad1.select", "Joypad1 select", VK_SHIFT, Setting::HEX);
|
||||
Setting Input::Joypad1::start (&config_file, "input.joypad1.start", "Joypad1 start", VK_RETURN, Setting::HEX);
|
||||
|
||||
Setting Input::Joypad2::up (&config_file, "input.joypad2.up", "Joypad2 up", 'T', Setting::HEX);
|
||||
Setting Input::Joypad2::down (&config_file, "input.joypad2.down", "Joypad2 down", 'G', Setting::HEX);
|
||||
Setting Input::Joypad2::left (&config_file, "input.joypad2.left", "Joypad2 left", 'F', Setting::HEX);
|
||||
Setting Input::Joypad2::right (&config_file, "input.joypad2.right", "Joypad2 right", 'H', Setting::HEX);
|
||||
Setting Input::Joypad2::a (&config_file, "input.joypad2.a", "Joypad2 A", 'K', Setting::HEX);
|
||||
Setting Input::Joypad2::b (&config_file, "input.joypad2.b", "Joypad2 B", 'J', Setting::HEX);
|
||||
Setting Input::Joypad2::x (&config_file, "input.joypad2.x", "Joypad2 X", 'I', Setting::HEX);
|
||||
Setting Input::Joypad2::y (&config_file, "input.joypad2.y", "Joypad2 Y", 'U', Setting::HEX);
|
||||
Setting Input::Joypad2::l (&config_file, "input.joypad2.l", "Joypad2 L", 'O', Setting::HEX);
|
||||
Setting Input::Joypad2::r (&config_file, "input.joypad2.r", "Joypad2 R", 'L', Setting::HEX);
|
||||
Setting Input::Joypad2::select(&config_file, "input.joypad2.select", "Joypad2 select", '[', Setting::HEX);
|
||||
Setting Input::Joypad2::start (&config_file, "input.joypad2.start", "Joypad2 start", ']', Setting::HEX);
|
||||
};
|
||||
|
|
|
@ -164,33 +164,16 @@ int rx, ry;
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(config::video.vblank) {
|
||||
lpdd->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN, 0);
|
||||
}
|
||||
|
||||
hr = lpdds->Blt(&rd, lpddsb, &lpddrc, DDBLT_WAIT, 0);
|
||||
if(hr == DDERR_SURFACELOST) {
|
||||
lpdds->Restore();
|
||||
lpddsb->Restore();
|
||||
}
|
||||
|
||||
if((int)config::gui.show_fps == false || bsnes->get_status() == bSNES::STOP)return;
|
||||
uint32 fps;
|
||||
char s[256], t[256];
|
||||
fps_timer->tick();
|
||||
if(fps_timer->second_passed() == true) {
|
||||
sprintf(s, BSNES_TITLE);
|
||||
if(rom_image->loaded() == true) {
|
||||
fps = fps_timer->get_ticks();
|
||||
if(w_main->frameskip == 0) {
|
||||
sprintf(t, " : %d fps", fps);
|
||||
} else {
|
||||
sprintf(t, " : %d fps [fs: %d]", fps * (1 + w_main->frameskip), w_main->frameskip);
|
||||
}
|
||||
strcat(s, t);
|
||||
}
|
||||
SetWindowText(w_main->hwnd, s);
|
||||
fps_timer->reset();
|
||||
}
|
||||
}
|
||||
|
||||
#include "dd_renderer16.cpp"
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
class fpstimer {
|
||||
private:
|
||||
SYSTEMTIME st;
|
||||
int second, ticks;
|
||||
public:
|
||||
void start();
|
||||
void tick();
|
||||
int get_ticks();
|
||||
void reset();
|
||||
bool second_passed();
|
||||
|
||||
fpstimer();
|
||||
};
|
||||
|
||||
void fpstimer::start() {
|
||||
GetSystemTime(&st);
|
||||
second = st.wSecond;
|
||||
}
|
||||
|
||||
void fpstimer::tick() {
|
||||
ticks++;
|
||||
}
|
||||
|
||||
int fpstimer::get_ticks() {
|
||||
return ticks;
|
||||
}
|
||||
|
||||
void fpstimer::reset() {
|
||||
ticks = 0;
|
||||
}
|
||||
|
||||
bool fpstimer::second_passed() {
|
||||
GetSystemTime(&st);
|
||||
if(st.wSecond != second) {
|
||||
second = st.wSecond;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
fpstimer::fpstimer() {
|
||||
second = ticks = 0;
|
||||
}
|
|
@ -39,6 +39,7 @@ enum {
|
|||
MENU_SETTINGS_SHOWFPS,
|
||||
MENU_SETTINGS_MUTE,
|
||||
MENU_SETTINGS_INPUTCFG_JOYPAD1,
|
||||
MENU_SETTINGS_INPUTCFG_JOYPAD2,
|
||||
MENU_SETTINGS_DEBUGGER,
|
||||
MENU_MISC_SCREENSHOT,
|
||||
MENU_MISC_LOGAUDIO,
|
||||
|
@ -164,7 +165,7 @@ struct { int width, height; }window;
|
|||
|
||||
class MainWindow : public Window {
|
||||
public:
|
||||
uint8 frameskip;
|
||||
uint8 frameskip, frameskip_pos;
|
||||
int width, height;
|
||||
void create();
|
||||
void to_fullscreen();
|
||||
|
@ -256,7 +257,8 @@ bool auto_update; //update memory window whenever visible value is written to
|
|||
class InputConfig : public Window {
|
||||
public:
|
||||
enum {
|
||||
JOYPAD1 = 0
|
||||
JOYPAD1 = 0,
|
||||
JOYPAD2
|
||||
};
|
||||
enum {
|
||||
ID_COMMAND = 100
|
||||
|
|
|
@ -53,18 +53,40 @@ bool end_config = false;
|
|||
case 12:end_config = true;break;
|
||||
}
|
||||
config_pos++;
|
||||
break;
|
||||
case JOYPAD2:
|
||||
switch(config_pos) {
|
||||
case 0:config::input.joypad2.up = key;break;
|
||||
case 1:config::input.joypad2.down = key;break;
|
||||
case 2:config::input.joypad2.left = key;break;
|
||||
case 3:config::input.joypad2.right = key;break;
|
||||
case 4:config::input.joypad2.select = key;break;
|
||||
case 5:config::input.joypad2.start = key;break;
|
||||
case 6:config::input.joypad2.x = key;break;
|
||||
case 7:config::input.joypad2.y = key;break;
|
||||
case 8:config::input.joypad2.a = key;break;
|
||||
case 9:config::input.joypad2.b = key;break;
|
||||
case 10:config::input.joypad2.l = key;break;
|
||||
case 11:config::input.joypad2.r = key;break;
|
||||
case 12:end_config = true;break;
|
||||
}
|
||||
config_pos++;
|
||||
break;
|
||||
}
|
||||
|
||||
if(end_config == true) {
|
||||
polling = false;
|
||||
hide();
|
||||
return;
|
||||
}
|
||||
|
||||
update_command();
|
||||
}
|
||||
|
||||
void InputConfig::update_command() {
|
||||
switch(config_type) {
|
||||
case JOYPAD1:
|
||||
case JOYPAD2:
|
||||
switch(config_pos) {
|
||||
case 0:set_text("Press key for Up..."); break;
|
||||
case 1:set_text("Press key for Down..."); break;
|
||||
|
@ -90,17 +112,23 @@ void InputConfig::begin_config(int type) {
|
|||
SetFocus(hwnd);
|
||||
return;
|
||||
}
|
||||
|
||||
config_type = type;
|
||||
config_pos = 0;
|
||||
switch(config_type) {
|
||||
case JOYPAD1:
|
||||
SetWindowText(hwnd, "bsnes Input Configuration : Joypad1");
|
||||
SetWindowText(hwnd, "bsnes Input Configuration (Joypad1)");
|
||||
break;
|
||||
case JOYPAD2:
|
||||
SetWindowText(hwnd, "bsnes Input Configuration (Joypad2)");
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
polling = true;
|
||||
update_command();
|
||||
|
||||
center();
|
||||
show();
|
||||
}
|
||||
|
|
|
@ -11,8 +11,8 @@ void MainWindow::set_frameskip(uint8 fs) {
|
|||
CheckMenuItem(w_main->hmenu, MENU_SETTINGS_FRAMESKIP_9, MF_UNCHECKED);
|
||||
|
||||
CheckMenuItem(w_main->hmenu, MENU_SETTINGS_FRAMESKIP_OFF + fs, MF_CHECKED);
|
||||
ppu->set_frameskip(fs);
|
||||
w_main->frameskip = fs;
|
||||
w_main->frameskip = fs;
|
||||
w_main->frameskip_pos = 0;
|
||||
}
|
||||
|
||||
void MainWindow::to_fullscreen() {
|
||||
|
@ -239,6 +239,9 @@ int i;
|
|||
case MENU_SETTINGS_INPUTCFG_JOYPAD1:
|
||||
w_inputconfig->begin_config(InputConfig::JOYPAD1);
|
||||
break;
|
||||
case MENU_SETTINGS_INPUTCFG_JOYPAD2:
|
||||
w_inputconfig->begin_config(InputConfig::JOYPAD2);
|
||||
break;
|
||||
case MENU_SETTINGS_DEBUGGER:
|
||||
if(bsnes->debugger_enabled() == true) {
|
||||
bsnes->debugger_disable();
|
||||
|
@ -350,6 +353,7 @@ HMENU hsubmenu, hbranchmenu;
|
|||
|
||||
hbranchmenu = CreatePopupMenu();
|
||||
AppendMenu(hbranchmenu, MF_STRING, MENU_SETTINGS_INPUTCFG_JOYPAD1, "Joypad 1");
|
||||
AppendMenu(hbranchmenu, MF_STRING, MENU_SETTINGS_INPUTCFG_JOYPAD2, "Joypad 2");
|
||||
AppendMenu(hsubmenu, MF_STRING | MF_POPUP, (unsigned int)hbranchmenu, "&Configure Input Devices");
|
||||
|
||||
AppendMenu(hsubmenu, MF_SEPARATOR, 0, "");
|
||||
|
|
|
@ -15,9 +15,6 @@
|
|||
#include "dd_renderer.h"
|
||||
#include "ds_sound.h"
|
||||
|
||||
#include "timer.cpp"
|
||||
fpstimer *fps_timer;
|
||||
|
||||
#include "lib.cpp"
|
||||
#include "rom.cpp"
|
||||
|
||||
|
@ -27,7 +24,6 @@ fpstimer *fps_timer;
|
|||
void init_snes() {
|
||||
mem_bus = new bMemBus();
|
||||
cpu = new bCPU();
|
||||
cpu->cpu_version = 1;
|
||||
apu = new bAPU();
|
||||
dsp = new bDSP();
|
||||
ppu = new bPPU();
|
||||
|
@ -82,8 +78,6 @@ string cfg_fn;
|
|||
get_config_fn(cfg_fn);
|
||||
config_file.load(cfg_fn);
|
||||
meminit();
|
||||
fps_timer = new fpstimer();
|
||||
fps_timer->start();
|
||||
rom_image = new ROMImage();
|
||||
|
||||
init_ui0();
|
||||
|
|
Loading…
Reference in New Issue